From a4fac68393e3a905b824b8ed1b6a7c7b427bbf30 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Thu, 9 Dec 2021 14:36:12 +0100 Subject: [PATCH] use same method for setting version and build hash placeholder in sw also better naming in service worker plugin --- scripts/build-plugins/service-worker.js | 46 +++++++++++++------------ src/platform/web/sw.js | 6 ++-- vite.config.js | 5 +-- 3 files changed, 27 insertions(+), 30 deletions(-) diff --git a/scripts/build-plugins/service-worker.js b/scripts/build-plugins/service-worker.js index e86bf27c..a6817278 100644 --- a/scripts/build-plugins/service-worker.js +++ b/scripts/build-plugins/service-worker.js @@ -8,7 +8,7 @@ function contentHash(str) { return hasher.digest(); } -module.exports = function injectServiceWorker(swFile, otherUncachedFiles, globalHashChunkReplaceMap) { +module.exports = function injectServiceWorker(swFile, otherUnhashedFiles, globalHashPlaceholderLiteral, chunkNamesWithGlobalHash) { const swName = path.basename(swFile); let root; let version; @@ -29,8 +29,8 @@ module.exports = function injectServiceWorker(swFile, otherUncachedFiles, global version = JSON.parse(config.define.HYDROGEN_VERSION); // unquote }, generateBundle: async function(options, bundle) { - const uncachedFileNames = [swName].concat(otherUncachedFiles); - const uncachedFileContentMap = uncachedFileNames.reduce((map, fileName) => { + const unhashedFilenames = [swName].concat(otherUnhashedFiles); + const unhashedFileContentMap = unhashedFilenames.reduce((map, fileName) => { const chunkOrAsset = bundle[fileName]; if (!chunkOrAsset) { throw new Error("could not get content for uncached asset or chunk " + fileName); @@ -39,21 +39,21 @@ module.exports = function injectServiceWorker(swFile, otherUncachedFiles, global return map; }, {}); const assets = Object.values(bundle); - const cachedFileNames = assets.map(o => o.fileName).filter(fileName => !uncachedFileContentMap[fileName]); - const globalHash = getBuildHash(cachedFileNames, uncachedFileContentMap); + const hashedFileNames = assets.map(o => o.fileName).filter(fileName => !unhashedFileContentMap[fileName]); + const globalHash = getBuildHash(hashedFileNames, unhashedFileContentMap); const sw = bundle[swName]; - sw.code = replaceConstsInServiceWorker(sw.code, version, globalHash, assets); - replaceGlobalHashPlaceholderInChunks(assets, globalHashChunkReplaceMap, globalHash); + sw.code = replaceCacheFilenamesInServiceWorker(sw, unhashedFilenames, assets); + replaceGlobalHashPlaceholderInChunks(assets, chunkNamesWithGlobalHash, globalHashPlaceholderLiteral, `"${globalHash}"`); console.log(`\nBuilt ${version} (${globalHash})`); } }; } -function getBuildHash(cachedFileNames, uncachedFileContentMap) { - const unhashedHashes = Object.entries(uncachedFileContentMap).map(([fileName, content]) => { +function getBuildHash(hashedFileNames, unhashedFileContentMap) { + const unhashedHashes = Object.entries(unhashedFileContentMap).map(([fileName, content]) => { return `${fileName}-${contentHash(Buffer.from(content))}`; }); - const globalHashAssets = cachedFileNames.concat(unhashedHashes); + const globalHashAssets = hashedFileNames.concat(unhashedHashes); globalHashAssets.sort(); return contentHash(globalHashAssets.join(",")).toString(); } @@ -76,19 +76,24 @@ function isPreCached(asset) { fileName.endsWith(".js") && !NON_PRECACHED_JS.includes(path.basename(name)); } -function replaceConstsInServiceWorker(swSource, version, globalHash, assets) { +function replaceCacheFilenamesInServiceWorker(swChunk, unhashedFilenames, assets) { + let swSource = swChunk.code; const unhashedPreCachedAssets = []; const hashedPreCachedAssets = []; const hashedCachedOnRequestAssets = []; for (const asset of assets) { - const {name: unresolved, fileName: resolved} = asset; - if (!unresolved || resolved === unresolved) { - unhashedPreCachedAssets.push(resolved); + const {name, fileName} = asset; + // the service worker should not be cached at all, + // it's how updates happen + if (fileName === swChunk.fileName) { + continue; + } else if (unhashedFilenames.includes(fileName)) { + unhashedPreCachedAssets.push(fileName); } else if (isPreCached(asset)) { - hashedPreCachedAssets.push(resolved); + hashedPreCachedAssets.push(fileName); } else { - hashedCachedOnRequestAssets.push(resolved); + hashedCachedOnRequestAssets.push(fileName); } } @@ -107,9 +112,6 @@ function replaceConstsInServiceWorker(swSource, version, globalHash, assets) { return newSource; }; - // write service worker - swSource = swSource.replace(`"%%VERSION%%"`, `"${version}"`); - swSource = swSource.replace(`"%%GLOBAL_HASH%%"`, `"${globalHash}"`); swSource = replaceArrayInSource("UNHASHED_PRECACHED_ASSETS", unhashedPreCachedAssets); swSource = replaceArrayInSource("HASHED_PRECACHED_ASSETS", hashedPreCachedAssets); swSource = replaceArrayInSource("HASHED_CACHED_ON_REQUEST_ASSETS", hashedCachedOnRequestAssets); @@ -117,12 +119,12 @@ function replaceConstsInServiceWorker(swSource, version, globalHash, assets) { return swSource; } -function replaceGlobalHashPlaceholderInChunks(assets, globalHashChunkReplaceMap, globalHash) { - for (const [name, placeholder] of Object.entries(globalHashChunkReplaceMap)) { +function replaceGlobalHashPlaceholderInChunks(assets, chunkNamesWithGlobalHash, globalHashPlaceholderLiteral, globalHashLiteral) { + for (const name of chunkNamesWithGlobalHash) { const chunk = assets.find(a => a.type === "chunk" && a.name === name); if (!chunk) { throw new Error(`could not find chunk ${name} to replace global hash placeholder`); } - chunk.code = chunk.code.replaceAll(placeholder, `"${globalHash}"`); + chunk.code = chunk.code.replaceAll(globalHashPlaceholderLiteral, globalHashLiteral); } } diff --git a/src/platform/web/sw.js b/src/platform/web/sw.js index 1dbe21f9..3404275d 100644 --- a/src/platform/web/sw.js +++ b/src/platform/web/sw.js @@ -15,13 +15,11 @@ See the License for the specific language governing permissions and limitations under the License. */ -const VERSION = "%%VERSION%%"; -const GLOBAL_HASH = "%%GLOBAL_HASH%%"; const UNHASHED_PRECACHED_ASSETS = []; const HASHED_PRECACHED_ASSETS = []; const HASHED_CACHED_ON_REQUEST_ASSETS = []; const NOTIFICATION_BADGE_ICON = "assets/icon.png"; -const unhashedCacheName = `hydrogen-assets-${GLOBAL_HASH}`; +const unhashedCacheName = `hydrogen-assets-${HYDROGEN_GLOBAL_HASH}`; const hashedCacheName = `hydrogen-assets`; const mediaThumbnailCacheName = `hydrogen-media-thumbnails-v2`; @@ -175,7 +173,7 @@ self.addEventListener('message', (event) => { } else { switch (event.data?.type) { case "version": - reply({version: VERSION, buildHash: GLOBAL_HASH}); + reply({version: HYDROGEN_VERSION, buildHash: HYDROGEN_GLOBAL_HASH}); break; case "skipWaiting": self.skipWaiting(); diff --git a/vite.config.js b/vite.config.js index 9a4e66f9..d9599cc4 100644 --- a/vite.config.js +++ b/vite.config.js @@ -51,10 +51,7 @@ export default { // important this comes before service worker // otherwise the manifest and the icons it refers to won't be cached injectWebManifest("assets/manifest.json"), - injectServiceWorker("./src/platform/web/sw.js", ["index.html"], { - // replace global hash placeholder in index chunk - "index": JSON.stringify(GLOBAL_HASH_PLACEHOLDER) - }), + injectServiceWorker("./src/platform/web/sw.js", ["index.html"], JSON.stringify(GLOBAL_HASH_PLACEHOLDER), ["index", "sw"]), ], define: { "HYDROGEN_VERSION": JSON.stringify(version),