From 0d5642428137609e14ec28e450524cfcd08aae7b Mon Sep 17 00:00:00 2001 From: Dimitris - Rafail Katsampas Date: Wed, 25 Oct 2023 21:06:13 +0000 Subject: [PATCH 1/5] feat(svelte-native): NS 8 compatibility --- .../svelte-native/proxy-adapter-native.js | 170 +++++++----------- 1 file changed, 60 insertions(+), 110 deletions(-) diff --git a/packages/svelte-hmr/runtime/svelte-native/proxy-adapter-native.js b/packages/svelte-hmr/runtime/svelte-native/proxy-adapter-native.js index f927072..81a8048 100644 --- a/packages/svelte-hmr/runtime/svelte-native/proxy-adapter-native.js +++ b/packages/svelte-hmr/runtime/svelte-native/proxy-adapter-native.js @@ -47,65 +47,15 @@ const getNavTransition = ({ transition }) => { return transition ? { animated: true, transition } : { animated: false } } -// copied from TNS FrameBase.replacePage -// -// it is not public but there is a comment in there indicating it is for -// HMR (probably their own core HMR though) -// -// NOTE this "worked" in TNS 5, but not anymore in TNS 6: updated version bellow -// -// eslint-disable-next-line no-unused-vars -const replacePage_tns5 = (frame, newPageElement, hotOptions) => { - const currentBackstackEntry = frame._currentEntry - frame.navigationType = 2 - frame.performNavigation({ - isBackNavigation: false, - entry: { - resolvedPage: newPageElement.nativeView, - // - // entry: currentBackstackEntry.entry, - entry: Object.assign( - currentBackstackEntry.entry, - getNavTransition(hotOptions) - ), - navDepth: currentBackstackEntry.navDepth, - fragmentTag: currentBackstackEntry.fragmentTag, - frameId: currentBackstackEntry.frameId, - }, - }) -} - -// Updated for TNS v6 -// -// https://github.com/NativeScript/NativeScript/blob/6.1.1/tns-core-modules/ui/frame/frame-common.ts#L656 -const replacePage = (frame, newPageElement) => { - const currentBackstackEntry = frame._currentEntry - const newPage = newPageElement.nativeView - const newBackstackEntry = { - entry: currentBackstackEntry.entry, - resolvedPage: newPage, - navDepth: currentBackstackEntry.navDepth, - fragmentTag: currentBackstackEntry.fragmentTag, - frameId: currentBackstackEntry.frameId, - } - const navigationContext = { - entry: newBackstackEntry, - isBackNavigation: false, - navigationType: 2 /* NavigationType replace */, - } - frame._navigationQueue.push(navigationContext) - frame._processNextNavigationEntry() -} - export const adapter = class ProxyAdapterNative extends ProxyAdapterDom { constructor(instance) { super(instance) this.nativePageElement = null this.originalNativeView = null - this.navigatedFromHandler = null + //this.navigatedFromHandler = null - this.relayNativeNavigatedFrom = this.relayNativeNavigatedFrom.bind(this) + //this.relayNativeNavigatedFrom = this.relayNativeNavigatedFrom.bind(this) } dispose() { @@ -123,27 +73,27 @@ export const adapter = class ProxyAdapterNative extends ProxyAdapterDom { // svelte-native uses navigateFrom event + e.isBackNavigation to know // when to $destroy the component -- but we don't want our proxy instance // destroyed when we renavigate to the same page for navigation purposes! - interceptPageNavigation(pageElement) { - const originalNativeView = pageElement.nativeView - const { on } = originalNativeView - const ownOn = originalNativeView.hasOwnProperty('on') - // tricks svelte-native into giving us its handler - originalNativeView.on = function(type, handler) { - if (type === 'navigatedFrom') { - this.navigatedFromHandler = handler - if (ownOn) { - originalNativeView.on = on - } else { - delete originalNativeView.on - } - } else { - //some other handler wireup, we will just pass it on. - if (on) { - on(type, handler) - } - } - } - } + // interceptPageNavigation(pageElement) { + // const originalNativeView = pageElement.nativeView + // const { on } = originalNativeView + // const ownOn = originalNativeView.hasOwnProperty('on') + // // tricks svelte-native into giving us its handler + // originalNativeView.on = function(type, handler) { + // if (type === 'navigatedFrom') { + // this.navigatedFromHandler = handler + // if (ownOn) { + // originalNativeView.on = on + // } else { + // delete originalNativeView.on + // } + // } else { + // //some other handler wireup, we will just pass it on. + // if (on) { + // on(type, handler) + // } + // } + // } + // } afterMount(target, anchor) { // nativePageElement needs to be updated each time (only for page @@ -168,7 +118,8 @@ export const adapter = class ProxyAdapterNative extends ProxyAdapterDom { target.firstChild.tagName == 'page' if (isNativePage) { const nativePageElement = target.firstChild - this.interceptPageNavigation(nativePageElement) + // Commented this out as it breaks navigation events + //this.interceptPageNavigation(nativePageElement) this.nativePageElement = nativePageElement } else { // try to protect against components changing from page to no-page @@ -216,6 +167,15 @@ export const adapter = class ProxyAdapterNative extends ProxyAdapterDom { throw new Error('Failed to create updated page') } const isFirstPage = !frame.canGoBack() + const nativeView = newPageElement.nativeView + const navigationEntry = Object.assign( + {}, + { + create: () => nativeView, + clearHistory: true, + }, + getNavTransition(hotOptions) + ); if (isFirstPage) { // NOTE not so sure of bellow with the new NS6 method for replace @@ -233,19 +193,9 @@ export const adapter = class ProxyAdapterNative extends ProxyAdapterDom { // // Fortunately, we can overwrite history in this case. // - const nativeView = newPageElement.nativeView - frame.navigate( - Object.assign( - {}, - { - create: () => nativeView, - clearHistory: true, - }, - getNavTransition(hotOptions) - ) - ) + frame.navigate(navigationEntry) } else { - replacePage(frame, newPageElement, hotOptions) + frame.replacePage(navigationEntry) } } else { const backEntry = frame.backStack.find( @@ -295,7 +245,7 @@ export const adapter = class ProxyAdapterNative extends ProxyAdapterDom { const { instance: { refreshComponent }, } = this - const { nativePageElement, relayNativeNavigatedFrom } = this + const { nativePageElement /*, relayNativeNavigatedFrom */ } = this const oldNativeView = nativePageElement.nativeView // rerender const target = document.createElement('fragment') @@ -306,32 +256,32 @@ export const adapter = class ProxyAdapterNative extends ProxyAdapterDom { // this.nativePageElement is updated in afterMount, triggered by proxy / hooks const newPageElement = this.nativePageElement // update event proxy - oldNativeView.off('navigatedFrom', relayNativeNavigatedFrom) - nativePageElement.nativeView.on('navigatedFrom', relayNativeNavigatedFrom) + //oldNativeView.off('navigatedFrom', relayNativeNavigatedFrom) + //nativePageElement.nativeView.on('navigatedFrom', relayNativeNavigatedFrom) return newPageElement } - relayNativeNavigatedFrom({ isBackNavigation }) { - const { originalNativeView, navigatedFromHandler } = this - if (!isBackNavigation) { - return - } - if (originalNativeView) { - const { off } = originalNativeView - const ownOff = originalNativeView.hasOwnProperty('off') - originalNativeView.off = function() { - this.navigatedFromHandler = null - if (ownOff) { - originalNativeView.off = off - } else { - delete originalNativeView.off - } - } - } - if (navigatedFromHandler) { - return navigatedFromHandler.apply(this, arguments) - } - } + // relayNativeNavigatedFrom({ isBackNavigation }) { + // const { originalNativeView, navigatedFromHandler } = this + // if (!isBackNavigation) { + // return + // } + // if (originalNativeView) { + // const { off } = originalNativeView + // const ownOff = originalNativeView.hasOwnProperty('off') + // originalNativeView.off = function() { + // this.navigatedFromHandler = null + // if (ownOff) { + // originalNativeView.off = off + // } else { + // delete originalNativeView.off + // } + // } + // } + // if (navigatedFromHandler) { + // return navigatedFromHandler.apply(this, arguments) + // } + // } renderError(err /* , target, anchor */) { // TODO fallback on TNS error handler for now... at least our error From 9a85b83bcaf8cc65687ea8911080593c2e4b2e4e Mon Sep 17 00:00:00 2001 From: Dimitris - Rafail Katsampas Date: Thu, 26 Oct 2023 07:51:42 +0000 Subject: [PATCH 2/5] fix: Navigation handler is not passed to new native view --- .../svelte-native/proxy-adapter-native.js | 73 ++++--------------- 1 file changed, 15 insertions(+), 58 deletions(-) diff --git a/packages/svelte-hmr/runtime/svelte-native/proxy-adapter-native.js b/packages/svelte-hmr/runtime/svelte-native/proxy-adapter-native.js index 81a8048..c85a927 100644 --- a/packages/svelte-hmr/runtime/svelte-native/proxy-adapter-native.js +++ b/packages/svelte-hmr/runtime/svelte-native/proxy-adapter-native.js @@ -52,10 +52,6 @@ export const adapter = class ProxyAdapterNative extends ProxyAdapterDom { super(instance) this.nativePageElement = null - this.originalNativeView = null - //this.navigatedFromHandler = null - - //this.relayNativeNavigatedFrom = this.relayNativeNavigatedFrom.bind(this) } dispose() { @@ -70,31 +66,6 @@ export const adapter = class ProxyAdapterNative extends ProxyAdapterDom { } } - // svelte-native uses navigateFrom event + e.isBackNavigation to know - // when to $destroy the component -- but we don't want our proxy instance - // destroyed when we renavigate to the same page for navigation purposes! - // interceptPageNavigation(pageElement) { - // const originalNativeView = pageElement.nativeView - // const { on } = originalNativeView - // const ownOn = originalNativeView.hasOwnProperty('on') - // // tricks svelte-native into giving us its handler - // originalNativeView.on = function(type, handler) { - // if (type === 'navigatedFrom') { - // this.navigatedFromHandler = handler - // if (ownOn) { - // originalNativeView.on = on - // } else { - // delete originalNativeView.on - // } - // } else { - // //some other handler wireup, we will just pass it on. - // if (on) { - // on(type, handler) - // } - // } - // } - // } - afterMount(target, anchor) { // nativePageElement needs to be updated each time (only for page // components, native component that are not pages follow normal flow) @@ -118,8 +89,6 @@ export const adapter = class ProxyAdapterNative extends ProxyAdapterDom { target.firstChild.tagName == 'page' if (isNativePage) { const nativePageElement = target.firstChild - // Commented this out as it breaks navigation events - //this.interceptPageNavigation(nativePageElement) this.nativePageElement = nativePageElement } else { // try to protect against components changing from page to no-page @@ -245,44 +214,32 @@ export const adapter = class ProxyAdapterNative extends ProxyAdapterDom { const { instance: { refreshComponent }, } = this - const { nativePageElement /*, relayNativeNavigatedFrom */ } = this - const oldNativeView = nativePageElement.nativeView + const { nativePageElement: oldNativePageElement } = this + const oldNativeView = oldNativePageElement.nativeView // rerender const target = document.createElement('fragment') + // not using conservative for now, since there's nothing in place here to // leverage it (yet?) -- and it might be easier to miss breakages in native // only code paths refreshComponent(target, null) + // this.nativePageElement is updated in afterMount, triggered by proxy / hooks const newPageElement = this.nativePageElement - // update event proxy - //oldNativeView.off('navigatedFrom', relayNativeNavigatedFrom) - //nativePageElement.nativeView.on('navigatedFrom', relayNativeNavigatedFrom) + + // svelte-native uses navigateFrom event + e.isBackNavigation to know when to $destroy the component. + // To keep that behaviour after refresh, we move event handler from old native view to the new one using + // __navigationFromHandler property that svelte-native provides us with. + const navigationFromHandler = oldNativeView.__navigationFromHandler; + if (navigationFromHandler) { + oldNativeView.off('navigatedFrom', navigationFromHandler) + newPageElement.nativeView.on('navigatedFrom', navigationFromHandler) + delete oldNativeView.__navigationFromHandler; + } + return newPageElement } - // relayNativeNavigatedFrom({ isBackNavigation }) { - // const { originalNativeView, navigatedFromHandler } = this - // if (!isBackNavigation) { - // return - // } - // if (originalNativeView) { - // const { off } = originalNativeView - // const ownOff = originalNativeView.hasOwnProperty('off') - // originalNativeView.off = function() { - // this.navigatedFromHandler = null - // if (ownOff) { - // originalNativeView.off = off - // } else { - // delete originalNativeView.off - // } - // } - // } - // if (navigatedFromHandler) { - // return navigatedFromHandler.apply(this, arguments) - // } - // } - renderError(err /* , target, anchor */) { // TODO fallback on TNS error handler for now... at least our error // is more informative From ddac1f2ab0640af0b64cfbd7f9079eaede66f8b8 Mon Sep 17 00:00:00 2001 From: Dimitris - Rafail Katsampas Date: Thu, 26 Oct 2023 15:53:33 +0000 Subject: [PATCH 3/5] chore: Handler property renaming --- .../runtime/svelte-native/proxy-adapter-native.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/svelte-hmr/runtime/svelte-native/proxy-adapter-native.js b/packages/svelte-hmr/runtime/svelte-native/proxy-adapter-native.js index c85a927..a2cb0f1 100644 --- a/packages/svelte-hmr/runtime/svelte-native/proxy-adapter-native.js +++ b/packages/svelte-hmr/runtime/svelte-native/proxy-adapter-native.js @@ -229,12 +229,12 @@ export const adapter = class ProxyAdapterNative extends ProxyAdapterDom { // svelte-native uses navigateFrom event + e.isBackNavigation to know when to $destroy the component. // To keep that behaviour after refresh, we move event handler from old native view to the new one using - // __navigationFromHandler property that svelte-native provides us with. - const navigationFromHandler = oldNativeView.__navigationFromHandler; - if (navigationFromHandler) { - oldNativeView.off('navigatedFrom', navigationFromHandler) - newPageElement.nativeView.on('navigatedFrom', navigationFromHandler) - delete oldNativeView.__navigationFromHandler; + // __navigateFromHandler property that svelte-native provides us with. + const navigateFromHandler = oldNativeView.__navigateFromHandler; + if (navigateFromHandler) { + oldNativeView.off('navigatedFrom', navigateFromHandler) + newPageElement.nativeView.on('navigatedFrom', navigateFromHandler) + delete oldNativeView.__navigateFromHandler; } return newPageElement From 3a2cf4b43a02fa26cd91c0631badc46eb4ddc2aa Mon Sep 17 00:00:00 2001 From: Dimitris - Rafail Katsampas Date: Thu, 26 Oct 2023 16:05:09 +0000 Subject: [PATCH 4/5] fix: Relay handler to new native view --- .../runtime/svelte-native/proxy-adapter-native.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/packages/svelte-hmr/runtime/svelte-native/proxy-adapter-native.js b/packages/svelte-hmr/runtime/svelte-native/proxy-adapter-native.js index a2cb0f1..c742bfd 100644 --- a/packages/svelte-hmr/runtime/svelte-native/proxy-adapter-native.js +++ b/packages/svelte-hmr/runtime/svelte-native/proxy-adapter-native.js @@ -144,7 +144,7 @@ export const adapter = class ProxyAdapterNative extends ProxyAdapterDom { clearHistory: true, }, getNavTransition(hotOptions) - ); + ) if (isFirstPage) { // NOTE not so sure of bellow with the new NS6 method for replace @@ -230,11 +230,12 @@ export const adapter = class ProxyAdapterNative extends ProxyAdapterDom { // svelte-native uses navigateFrom event + e.isBackNavigation to know when to $destroy the component. // To keep that behaviour after refresh, we move event handler from old native view to the new one using // __navigateFromHandler property that svelte-native provides us with. - const navigateFromHandler = oldNativeView.__navigateFromHandler; + const navigateFromHandler = oldNativeView.__navigateFromHandler if (navigateFromHandler) { oldNativeView.off('navigatedFrom', navigateFromHandler) newPageElement.nativeView.on('navigatedFrom', navigateFromHandler) - delete oldNativeView.__navigateFromHandler; + newPageElement.nativeView.__navigateFromHandler = navigateFromHandler + delete oldNativeView.__navigateFromHandler } return newPageElement From 836ea9d5d6a3d7cbce5d23723e13e464bc122354 Mon Sep 17 00:00:00 2001 From: Dimitris - Rafail Katsampas Date: Fri, 27 Oct 2023 20:15:22 +0000 Subject: [PATCH 5/5] chore: Lint fixes --- packages/svelte-hmr/lib/make-hot.js | 4 +++- .../svelte-hmr/runtime/svelte-native/proxy-adapter-native.js | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/svelte-hmr/lib/make-hot.js b/packages/svelte-hmr/lib/make-hot.js index b9a68fe..c4c0e70 100644 --- a/packages/svelte-hmr/lib/make-hot.js +++ b/packages/svelte-hmr/lib/make-hot.js @@ -76,7 +76,9 @@ const renderApplyHmr = ({ emitCss, imports = [ `import * as ${globalName} from ${JSON.stringify(hotApiImport)}`, - `import { adapter as ${importAdapterName} } from ${JSON.stringify(adapterImport)}`, + `import { adapter as ${importAdapterName} } from ${JSON.stringify( + adapterImport + )}`, ], }) => // this silly formatting keeps all original characters in their position, diff --git a/packages/svelte-hmr/runtime/svelte-native/proxy-adapter-native.js b/packages/svelte-hmr/runtime/svelte-native/proxy-adapter-native.js index c742bfd..dc4a0c3 100644 --- a/packages/svelte-hmr/runtime/svelte-native/proxy-adapter-native.js +++ b/packages/svelte-hmr/runtime/svelte-native/proxy-adapter-native.js @@ -228,7 +228,7 @@ export const adapter = class ProxyAdapterNative extends ProxyAdapterDom { const newPageElement = this.nativePageElement // svelte-native uses navigateFrom event + e.isBackNavigation to know when to $destroy the component. - // To keep that behaviour after refresh, we move event handler from old native view to the new one using + // To keep that behaviour after refresh, we move event handler from old native view to the new one using // __navigateFromHandler property that svelte-native provides us with. const navigateFromHandler = oldNativeView.__navigateFromHandler if (navigateFromHandler) {