Skip to content

Commit 283c6cb

Browse files
authored
Merge pull request #85 from CatchABus/svelte-native-ns8
feat: Svelte native HMR compatibility for NativeScript 8
2 parents 02fa71c + 836ea9d commit 283c6cb

File tree

2 files changed

+29
-119
lines changed

2 files changed

+29
-119
lines changed

packages/svelte-hmr/lib/make-hot.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,9 @@ const renderApplyHmr = ({
7676
emitCss,
7777
imports = [
7878
`import * as ${globalName} from ${JSON.stringify(hotApiImport)}`,
79-
`import { adapter as ${importAdapterName} } from ${JSON.stringify(adapterImport)}`,
79+
`import { adapter as ${importAdapterName} } from ${JSON.stringify(
80+
adapterImport
81+
)}`,
8082
],
8183
}) =>
8284
// this silly formatting keeps all original characters in their position,

packages/svelte-hmr/runtime/svelte-native/proxy-adapter-native.js

Lines changed: 26 additions & 118 deletions
Original file line numberDiff line numberDiff line change
@@ -47,65 +47,11 @@ const getNavTransition = ({ transition }) => {
4747
return transition ? { animated: true, transition } : { animated: false }
4848
}
4949

50-
// copied from TNS FrameBase.replacePage
51-
//
52-
// it is not public but there is a comment in there indicating it is for
53-
// HMR (probably their own core HMR though)
54-
//
55-
// NOTE this "worked" in TNS 5, but not anymore in TNS 6: updated version bellow
56-
//
57-
// eslint-disable-next-line no-unused-vars
58-
const replacePage_tns5 = (frame, newPageElement, hotOptions) => {
59-
const currentBackstackEntry = frame._currentEntry
60-
frame.navigationType = 2
61-
frame.performNavigation({
62-
isBackNavigation: false,
63-
entry: {
64-
resolvedPage: newPageElement.nativeView,
65-
//
66-
// entry: currentBackstackEntry.entry,
67-
entry: Object.assign(
68-
currentBackstackEntry.entry,
69-
getNavTransition(hotOptions)
70-
),
71-
navDepth: currentBackstackEntry.navDepth,
72-
fragmentTag: currentBackstackEntry.fragmentTag,
73-
frameId: currentBackstackEntry.frameId,
74-
},
75-
})
76-
}
77-
78-
// Updated for TNS v6
79-
//
80-
// https://github.com/NativeScript/NativeScript/blob/6.1.1/tns-core-modules/ui/frame/frame-common.ts#L656
81-
const replacePage = (frame, newPageElement) => {
82-
const currentBackstackEntry = frame._currentEntry
83-
const newPage = newPageElement.nativeView
84-
const newBackstackEntry = {
85-
entry: currentBackstackEntry.entry,
86-
resolvedPage: newPage,
87-
navDepth: currentBackstackEntry.navDepth,
88-
fragmentTag: currentBackstackEntry.fragmentTag,
89-
frameId: currentBackstackEntry.frameId,
90-
}
91-
const navigationContext = {
92-
entry: newBackstackEntry,
93-
isBackNavigation: false,
94-
navigationType: 2 /* NavigationType replace */,
95-
}
96-
frame._navigationQueue.push(navigationContext)
97-
frame._processNextNavigationEntry()
98-
}
99-
10050
export const adapter = class ProxyAdapterNative extends ProxyAdapterDom {
10151
constructor(instance) {
10252
super(instance)
10353

10454
this.nativePageElement = null
105-
this.originalNativeView = null
106-
this.navigatedFromHandler = null
107-
108-
this.relayNativeNavigatedFrom = this.relayNativeNavigatedFrom.bind(this)
10955
}
11056

11157
dispose() {
@@ -120,31 +66,6 @@ export const adapter = class ProxyAdapterNative extends ProxyAdapterDom {
12066
}
12167
}
12268

123-
// svelte-native uses navigateFrom event + e.isBackNavigation to know
124-
// when to $destroy the component -- but we don't want our proxy instance
125-
// destroyed when we renavigate to the same page for navigation purposes!
126-
interceptPageNavigation(pageElement) {
127-
const originalNativeView = pageElement.nativeView
128-
const { on } = originalNativeView
129-
const ownOn = originalNativeView.hasOwnProperty('on')
130-
// tricks svelte-native into giving us its handler
131-
originalNativeView.on = function(type, handler) {
132-
if (type === 'navigatedFrom') {
133-
this.navigatedFromHandler = handler
134-
if (ownOn) {
135-
originalNativeView.on = on
136-
} else {
137-
delete originalNativeView.on
138-
}
139-
} else {
140-
//some other handler wireup, we will just pass it on.
141-
if (on) {
142-
on(type, handler)
143-
}
144-
}
145-
}
146-
}
147-
14869
afterMount(target, anchor) {
14970
// nativePageElement needs to be updated each time (only for page
15071
// components, native component that are not pages follow normal flow)
@@ -168,7 +89,6 @@ export const adapter = class ProxyAdapterNative extends ProxyAdapterDom {
16889
target.firstChild.tagName == 'page'
16990
if (isNativePage) {
17091
const nativePageElement = target.firstChild
171-
this.interceptPageNavigation(nativePageElement)
17292
this.nativePageElement = nativePageElement
17393
} else {
17494
// try to protect against components changing from page to no-page
@@ -216,6 +136,15 @@ export const adapter = class ProxyAdapterNative extends ProxyAdapterDom {
216136
throw new Error('Failed to create updated page')
217137
}
218138
const isFirstPage = !frame.canGoBack()
139+
const nativeView = newPageElement.nativeView
140+
const navigationEntry = Object.assign(
141+
{},
142+
{
143+
create: () => nativeView,
144+
clearHistory: true,
145+
},
146+
getNavTransition(hotOptions)
147+
)
219148

220149
if (isFirstPage) {
221150
// NOTE not so sure of bellow with the new NS6 method for replace
@@ -233,19 +162,9 @@ export const adapter = class ProxyAdapterNative extends ProxyAdapterDom {
233162
//
234163
// Fortunately, we can overwrite history in this case.
235164
//
236-
const nativeView = newPageElement.nativeView
237-
frame.navigate(
238-
Object.assign(
239-
{},
240-
{
241-
create: () => nativeView,
242-
clearHistory: true,
243-
},
244-
getNavTransition(hotOptions)
245-
)
246-
)
165+
frame.navigate(navigationEntry)
247166
} else {
248-
replacePage(frame, newPageElement, hotOptions)
167+
frame.replacePage(navigationEntry)
249168
}
250169
} else {
251170
const backEntry = frame.backStack.find(
@@ -295,42 +214,31 @@ export const adapter = class ProxyAdapterNative extends ProxyAdapterDom {
295214
const {
296215
instance: { refreshComponent },
297216
} = this
298-
const { nativePageElement, relayNativeNavigatedFrom } = this
299-
const oldNativeView = nativePageElement.nativeView
217+
const { nativePageElement: oldNativePageElement } = this
218+
const oldNativeView = oldNativePageElement.nativeView
300219
// rerender
301220
const target = document.createElement('fragment')
221+
302222
// not using conservative for now, since there's nothing in place here to
303223
// leverage it (yet?) -- and it might be easier to miss breakages in native
304224
// only code paths
305225
refreshComponent(target, null)
226+
306227
// this.nativePageElement is updated in afterMount, triggered by proxy / hooks
307228
const newPageElement = this.nativePageElement
308-
// update event proxy
309-
oldNativeView.off('navigatedFrom', relayNativeNavigatedFrom)
310-
nativePageElement.nativeView.on('navigatedFrom', relayNativeNavigatedFrom)
311-
return newPageElement
312-
}
313229

314-
relayNativeNavigatedFrom({ isBackNavigation }) {
315-
const { originalNativeView, navigatedFromHandler } = this
316-
if (!isBackNavigation) {
317-
return
318-
}
319-
if (originalNativeView) {
320-
const { off } = originalNativeView
321-
const ownOff = originalNativeView.hasOwnProperty('off')
322-
originalNativeView.off = function() {
323-
this.navigatedFromHandler = null
324-
if (ownOff) {
325-
originalNativeView.off = off
326-
} else {
327-
delete originalNativeView.off
328-
}
329-
}
330-
}
331-
if (navigatedFromHandler) {
332-
return navigatedFromHandler.apply(this, arguments)
230+
// svelte-native uses navigateFrom event + e.isBackNavigation to know when to $destroy the component.
231+
// To keep that behaviour after refresh, we move event handler from old native view to the new one using
232+
// __navigateFromHandler property that svelte-native provides us with.
233+
const navigateFromHandler = oldNativeView.__navigateFromHandler
234+
if (navigateFromHandler) {
235+
oldNativeView.off('navigatedFrom', navigateFromHandler)
236+
newPageElement.nativeView.on('navigatedFrom', navigateFromHandler)
237+
newPageElement.nativeView.__navigateFromHandler = navigateFromHandler
238+
delete oldNativeView.__navigateFromHandler
333239
}
240+
241+
return newPageElement
334242
}
335243

336244
renderError(err /* , target, anchor */) {

0 commit comments

Comments
 (0)