diff --git a/bundle-config-loader.js b/bundle-config-loader.js index 343e25b7..c3d379ff 100644 --- a/bundle-config-loader.js +++ b/bundle-config-loader.js @@ -10,11 +10,16 @@ module.exports = function (source) { if (!angular && registerModules) { const hmr = ` if (module.hot) { + const fileSystemModule = require("tns-core-modules/file-system"); + const applicationFiles = fileSystemModule.knownFolders.currentApp(); + global.__hmrLivesyncBackup = global.__onLiveSync; global.__onLiveSync = function () { - console.log("LiveSyncing..."); - require("nativescript-dev-webpack/hot")("", {}); + console.log("HMR Sync..."); + require("nativescript-dev-webpack/hot")(__webpack_require__.h(), (fileName) => applicationFiles.getFile(fileName)); }; + global.__hmrInitialSync = true; // needed to determine if we are performing initial sync + global.__onLiveSync(); } `; diff --git a/hot-loader-helper.js b/hot-loader-helper.js index cc5dcd76..a11bf1cc 100644 --- a/hot-loader-helper.js +++ b/hot-loader-helper.js @@ -1,11 +1,11 @@ -module.exports.reload = ` +module.exports.reload = function(type) { return ` if (module.hot) { module.hot.accept(); module.hot.dispose(() => { setTimeout(() => { global.__hmrLivesyncBackup(); - }); + }, ${type === 'style' ? "global.__hmrInitialSync ? 1000 : 0" : 0}); }) } -`; - +`}; +// we need to add a timeout of 1000 if we have a css change, otherwise the app crashes on initial hmr sync \ No newline at end of file diff --git a/hot.js b/hot.js index 90c00665..80dca41f 100644 --- a/hot.js +++ b/hot.js @@ -1,5 +1,5 @@ const log = console; -const refresh = 'Please refresh the page.'; +const refresh = 'Please restart the application.'; const hotOptions = { ignoreUnaccepted: true, ignoreDeclined: true, @@ -73,7 +73,7 @@ function check(options) { .then((modules) => { if (!modules) { log.warn( - `Cannot find update. The server may have been restarted. ${refresh}` + `Cannot find update. ${refresh}` ); return null; } @@ -82,8 +82,7 @@ function check(options) { .apply(hotOptions) .then((appliedModules) => { if (!upToDate()) { - log.warn("Hashes don't match. Ignoring second update..."); - // check(options); + check(options); } result(modules, appliedModules); @@ -122,7 +121,7 @@ if (module.hot) { console.error('Hot Module Replacement is disabled.'); } -module.exports = function update(currentHash, options) { +function update(currentHash, options) { lastHash = currentHash; if (!upToDate()) { const status = module.hot.status(); @@ -138,3 +137,24 @@ module.exports = function update(currentHash, options) { } }; +function getCurrentHash(currentHash, getFileContent) { + const file = getFileContent(`${currentHash}.hot-update.json`); + return file.readText().then(hotUpdateContent => { + if(hotUpdateContent) { + const manifest = JSON.parse(hotUpdateContent); + const newHash = manifest.h; + return getCurrentHash(newHash, getFileContent); + } else { + return Promise.resolve(currentHash); + } + }).catch(error => Promise.reject(error)); +} + +module.exports = function checkState(initialHash, getFileContent) { + getCurrentHash(initialHash, getFileContent).then(currentHash => { + if(currentHash != initialHash) { + update(currentHash, {}); + } + }) +} + diff --git a/markup-hot-loader.js b/markup-hot-loader.js index 3b4f19c2..6d330447 100644 --- a/markup-hot-loader.js +++ b/markup-hot-loader.js @@ -1,5 +1,5 @@ const { reload } = require("./hot-loader-helper"); module.exports = function (source) { - return `${source};${reload}`; + return `${source};${reload('markup')}`; }; diff --git a/page-hot-loader.js b/page-hot-loader.js index 3b4f19c2..eaa4bcdf 100644 --- a/page-hot-loader.js +++ b/page-hot-loader.js @@ -1,5 +1,5 @@ const { reload } = require("./hot-loader-helper"); module.exports = function (source) { - return `${source};${reload}`; + return `${source};${reload('page')}`; }; diff --git a/plugins/WatchStateLoggerPlugin.ts b/plugins/WatchStateLoggerPlugin.ts index a3fb0813..2396f7cf 100644 --- a/plugins/WatchStateLoggerPlugin.ts +++ b/plugins/WatchStateLoggerPlugin.ts @@ -32,7 +32,7 @@ export class WatchStateLoggerPlugin { console.log(messages.compilationComplete); } - const emittedFiles = Object + let emittedFiles = Object .keys(compilation.assets) .filter(assetKey => compilation.assets[assetKey].emitted); @@ -40,6 +40,8 @@ export class WatchStateLoggerPlugin { WatchStateLoggerPlugin.rewriteHotUpdateChunk(compiler, compilation, emittedFiles); } + emittedFiles = WatchStateLoggerPlugin.getUpdatedEmittedFiles(emittedFiles); + // provide fake paths to the {N} CLI - relative to the 'app' folder // in order to trigger the livesync process const emittedFilesFakePaths = emittedFiles @@ -90,6 +92,19 @@ export class WatchStateLoggerPlugin { return content.substring(startIndex, endIndex); } + /** + * Checks if there's a file in the following pattern 5e0326f3bb50f9f26cf0.hot-update.json + * if yes this is a HMR update and remove all bundle files as we don't need them to be synced, + * but only the update chunks + */ + static getUpdatedEmittedFiles(emittedFiles) { + if(emittedFiles.some(x => x.endsWith('.hot-update.json'))) { + return emittedFiles.filter(x => x.indexOf('.hot-update.') > 0); + } else { + return emittedFiles; + } + } + /** * Gets the webpackHotUpdate call with updated modules not to include the ones with errors */ diff --git a/style-hot-loader.js b/style-hot-loader.js index 3b4f19c2..23e6ad72 100644 --- a/style-hot-loader.js +++ b/style-hot-loader.js @@ -1,5 +1,5 @@ const { reload } = require("./hot-loader-helper"); module.exports = function (source) { - return `${source};${reload}`; + return `${source};${reload('style')}`; };