use same method for setting version and build hash placeholder in sw

also better naming in service worker plugin
This commit is contained in:
Bruno Windels 2021-12-09 14:36:12 +01:00
parent f934262e35
commit a4fac68393
3 changed files with 27 additions and 30 deletions

View file

@ -8,7 +8,7 @@ function contentHash(str) {
return hasher.digest(); return hasher.digest();
} }
module.exports = function injectServiceWorker(swFile, otherUncachedFiles, globalHashChunkReplaceMap) { module.exports = function injectServiceWorker(swFile, otherUnhashedFiles, globalHashPlaceholderLiteral, chunkNamesWithGlobalHash) {
const swName = path.basename(swFile); const swName = path.basename(swFile);
let root; let root;
let version; let version;
@ -29,8 +29,8 @@ module.exports = function injectServiceWorker(swFile, otherUncachedFiles, global
version = JSON.parse(config.define.HYDROGEN_VERSION); // unquote version = JSON.parse(config.define.HYDROGEN_VERSION); // unquote
}, },
generateBundle: async function(options, bundle) { generateBundle: async function(options, bundle) {
const uncachedFileNames = [swName].concat(otherUncachedFiles); const unhashedFilenames = [swName].concat(otherUnhashedFiles);
const uncachedFileContentMap = uncachedFileNames.reduce((map, fileName) => { const unhashedFileContentMap = unhashedFilenames.reduce((map, fileName) => {
const chunkOrAsset = bundle[fileName]; const chunkOrAsset = bundle[fileName];
if (!chunkOrAsset) { if (!chunkOrAsset) {
throw new Error("could not get content for uncached asset or chunk " + fileName); 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; return map;
}, {}); }, {});
const assets = Object.values(bundle); const assets = Object.values(bundle);
const cachedFileNames = assets.map(o => o.fileName).filter(fileName => !uncachedFileContentMap[fileName]); const hashedFileNames = assets.map(o => o.fileName).filter(fileName => !unhashedFileContentMap[fileName]);
const globalHash = getBuildHash(cachedFileNames, uncachedFileContentMap); const globalHash = getBuildHash(hashedFileNames, unhashedFileContentMap);
const sw = bundle[swName]; const sw = bundle[swName];
sw.code = replaceConstsInServiceWorker(sw.code, version, globalHash, assets); sw.code = replaceCacheFilenamesInServiceWorker(sw, unhashedFilenames, assets);
replaceGlobalHashPlaceholderInChunks(assets, globalHashChunkReplaceMap, globalHash); replaceGlobalHashPlaceholderInChunks(assets, chunkNamesWithGlobalHash, globalHashPlaceholderLiteral, `"${globalHash}"`);
console.log(`\nBuilt ${version} (${globalHash})`); console.log(`\nBuilt ${version} (${globalHash})`);
} }
}; };
} }
function getBuildHash(cachedFileNames, uncachedFileContentMap) { function getBuildHash(hashedFileNames, unhashedFileContentMap) {
const unhashedHashes = Object.entries(uncachedFileContentMap).map(([fileName, content]) => { const unhashedHashes = Object.entries(unhashedFileContentMap).map(([fileName, content]) => {
return `${fileName}-${contentHash(Buffer.from(content))}`; return `${fileName}-${contentHash(Buffer.from(content))}`;
}); });
const globalHashAssets = cachedFileNames.concat(unhashedHashes); const globalHashAssets = hashedFileNames.concat(unhashedHashes);
globalHashAssets.sort(); globalHashAssets.sort();
return contentHash(globalHashAssets.join(",")).toString(); return contentHash(globalHashAssets.join(",")).toString();
} }
@ -76,19 +76,24 @@ function isPreCached(asset) {
fileName.endsWith(".js") && !NON_PRECACHED_JS.includes(path.basename(name)); 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 unhashedPreCachedAssets = [];
const hashedPreCachedAssets = []; const hashedPreCachedAssets = [];
const hashedCachedOnRequestAssets = []; const hashedCachedOnRequestAssets = [];
for (const asset of assets) { for (const asset of assets) {
const {name: unresolved, fileName: resolved} = asset; const {name, fileName} = asset;
if (!unresolved || resolved === unresolved) { // the service worker should not be cached at all,
unhashedPreCachedAssets.push(resolved); // it's how updates happen
if (fileName === swChunk.fileName) {
continue;
} else if (unhashedFilenames.includes(fileName)) {
unhashedPreCachedAssets.push(fileName);
} else if (isPreCached(asset)) { } else if (isPreCached(asset)) {
hashedPreCachedAssets.push(resolved); hashedPreCachedAssets.push(fileName);
} else { } else {
hashedCachedOnRequestAssets.push(resolved); hashedCachedOnRequestAssets.push(fileName);
} }
} }
@ -107,9 +112,6 @@ function replaceConstsInServiceWorker(swSource, version, globalHash, assets) {
return newSource; return newSource;
}; };
// write service worker
swSource = swSource.replace(`"%%VERSION%%"`, `"${version}"`);
swSource = swSource.replace(`"%%GLOBAL_HASH%%"`, `"${globalHash}"`);
swSource = replaceArrayInSource("UNHASHED_PRECACHED_ASSETS", unhashedPreCachedAssets); swSource = replaceArrayInSource("UNHASHED_PRECACHED_ASSETS", unhashedPreCachedAssets);
swSource = replaceArrayInSource("HASHED_PRECACHED_ASSETS", hashedPreCachedAssets); swSource = replaceArrayInSource("HASHED_PRECACHED_ASSETS", hashedPreCachedAssets);
swSource = replaceArrayInSource("HASHED_CACHED_ON_REQUEST_ASSETS", hashedCachedOnRequestAssets); swSource = replaceArrayInSource("HASHED_CACHED_ON_REQUEST_ASSETS", hashedCachedOnRequestAssets);
@ -117,12 +119,12 @@ function replaceConstsInServiceWorker(swSource, version, globalHash, assets) {
return swSource; return swSource;
} }
function replaceGlobalHashPlaceholderInChunks(assets, globalHashChunkReplaceMap, globalHash) { function replaceGlobalHashPlaceholderInChunks(assets, chunkNamesWithGlobalHash, globalHashPlaceholderLiteral, globalHashLiteral) {
for (const [name, placeholder] of Object.entries(globalHashChunkReplaceMap)) { for (const name of chunkNamesWithGlobalHash) {
const chunk = assets.find(a => a.type === "chunk" && a.name === name); const chunk = assets.find(a => a.type === "chunk" && a.name === name);
if (!chunk) { if (!chunk) {
throw new Error(`could not find chunk ${name} to replace global hash placeholder`); 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);
} }
} }

View file

@ -15,13 +15,11 @@ See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
*/ */
const VERSION = "%%VERSION%%";
const GLOBAL_HASH = "%%GLOBAL_HASH%%";
const UNHASHED_PRECACHED_ASSETS = []; const UNHASHED_PRECACHED_ASSETS = [];
const HASHED_PRECACHED_ASSETS = []; const HASHED_PRECACHED_ASSETS = [];
const HASHED_CACHED_ON_REQUEST_ASSETS = []; const HASHED_CACHED_ON_REQUEST_ASSETS = [];
const NOTIFICATION_BADGE_ICON = "assets/icon.png"; 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 hashedCacheName = `hydrogen-assets`;
const mediaThumbnailCacheName = `hydrogen-media-thumbnails-v2`; const mediaThumbnailCacheName = `hydrogen-media-thumbnails-v2`;
@ -175,7 +173,7 @@ self.addEventListener('message', (event) => {
} else { } else {
switch (event.data?.type) { switch (event.data?.type) {
case "version": case "version":
reply({version: VERSION, buildHash: GLOBAL_HASH}); reply({version: HYDROGEN_VERSION, buildHash: HYDROGEN_GLOBAL_HASH});
break; break;
case "skipWaiting": case "skipWaiting":
self.skipWaiting(); self.skipWaiting();

View file

@ -51,10 +51,7 @@ export default {
// important this comes before service worker // important this comes before service worker
// otherwise the manifest and the icons it refers to won't be cached // otherwise the manifest and the icons it refers to won't be cached
injectWebManifest("assets/manifest.json"), injectWebManifest("assets/manifest.json"),
injectServiceWorker("./src/platform/web/sw.js", ["index.html"], { injectServiceWorker("./src/platform/web/sw.js", ["index.html"], JSON.stringify(GLOBAL_HASH_PLACEHOLDER), ["index", "sw"]),
// replace global hash placeholder in index chunk
"index": JSON.stringify(GLOBAL_HASH_PLACEHOLDER)
}),
], ],
define: { define: {
"HYDROGEN_VERSION": JSON.stringify(version), "HYDROGEN_VERSION": JSON.stringify(version),