Embed build-local asset groups in stamped indexes
This commit is contained in:
@@ -8,6 +8,15 @@ const tagHash = bytes => createHash('sha256').update(bytes).digest('hex').slice(
|
|||||||
export const injectBuildTag = (source, tag) => source.replace(
|
export const injectBuildTag = (source, tag) => source.replace(
|
||||||
/typeof __BUILD_TAG__ !== 'undefined' \? __BUILD_TAG__ : '[^']*'/, JSON.stringify(tag));
|
/typeof __BUILD_TAG__ !== 'undefined' \? __BUILD_TAG__ : '[^']*'/, JSON.stringify(tag));
|
||||||
|
|
||||||
|
function embedAssets(source, files, groups, buildTag, hashing) {
|
||||||
|
const pageFiles = {};
|
||||||
|
for (const group of Object.values(groups)) for (const path of group.files) {
|
||||||
|
if (path !== '/index.html' && path !== '/sw.js') pageFiles[path] = { ...files[path], h: hashing ? files[path].h : buildTag };
|
||||||
|
}
|
||||||
|
const json = JSON.stringify({ buildTag, groups, files: pageFiles }).replace(/</g, '\\u003c');
|
||||||
|
return source.replace(/(<script type="application\/json" id="ytp-assets">)[\s\S]*?(<\/script>)/, (_, open, close) => open + json + close);
|
||||||
|
}
|
||||||
|
|
||||||
export function stampIndex(source, files, { hashing = true, buildTag = '__BUILD_TAG__' } = {}) {
|
export function stampIndex(source, files, { hashing = true, buildTag = '__BUILD_TAG__' } = {}) {
|
||||||
if (!hashing) return source.replace('__BUILD_TAG__', buildTag)
|
if (!hashing) return source.replace('__BUILD_TAG__', buildTag)
|
||||||
.replace(/((?:href|src)=")((?![a-z]+:|\/)[^"?]+\.(?:css|js))(")/g, `$1$2?v=${buildTag}$3`);
|
.replace(/((?:href|src)=")((?![a-z]+:|\/)[^"?]+\.(?:css|js))(")/g, `$1$2?v=${buildTag}$3`);
|
||||||
@@ -66,11 +75,11 @@ export function createAssetManifest(publicDir = './public', { hashing = true, bu
|
|||||||
// Derived build metadata cannot be an input to its own hash. Canonicalize
|
// Derived build metadata cannot be an input to its own hash. Canonicalize
|
||||||
// the index meta and SW injected tag, then publish hashes of the final bytes.
|
// the index meta and SW injected tag, then publish hashes of the final bytes.
|
||||||
// All original bytes (including index/SW source) remain inputs via source hashes.
|
// All original bytes (including index/SW source) remain inputs via source hashes.
|
||||||
let canonicalIndex = source === null ? null : stampIndex(source, files, { hashing });
|
let canonicalIndex = source === null ? null : stampIndex(embedAssets(source, files, groups, '__BUILD_TAG__', hashing), files, { hashing });
|
||||||
const canonical = { assetSync, files: { ...files }, groups, contracts };
|
const canonical = { assetSync, files: { ...files }, groups, contracts };
|
||||||
if (canonicalIndex !== null && hashing) canonical.files['/index.html'] = { ...files['/index.html'], h: assetHash(canonicalIndex), s: Buffer.byteLength(canonicalIndex), source: files['/index.html'].h };
|
if (canonicalIndex !== null && hashing) canonical.files['/index.html'] = { ...files['/index.html'], h: assetHash(canonicalIndex), s: Buffer.byteLength(canonicalIndex), source: files['/index.html'].h };
|
||||||
const buildTag = hashing ? tagHash(JSON.stringify(canonical)) : (override || legacy.digest('hex').slice(0, 12));
|
const buildTag = hashing ? tagHash(JSON.stringify(canonical)) : (override || legacy.digest('hex').slice(0, 12));
|
||||||
const index = source === null ? null : stampIndex(source, files, { hashing, buildTag });
|
const index = source === null ? null : embedAssets(stampIndex(source, files, { hashing, buildTag }), files, groups, buildTag, hashing);
|
||||||
const sw = swSource === null ? null : injectBuildTag(swSource, buildTag)
|
const sw = swSource === null ? null : injectBuildTag(swSource, buildTag)
|
||||||
.replace("typeof __ASSET_SYNC__ !== 'undefined' ? __ASSET_SYNC__ : true", JSON.stringify(assetSync))
|
.replace("typeof __ASSET_SYNC__ !== 'undefined' ? __ASSET_SYNC__ : true", JSON.stringify(assetSync))
|
||||||
.replace("importScripts('/asset-sync-core.js')", "importScripts('/asset-sync-core.js?v=" + (files['/asset-sync-core.js']?.h || '') + "')");
|
.replace("importScripts('/asset-sync-core.js')", "importScripts('/asset-sync-core.js?v=" + (files['/asset-sync-core.js']?.h || '') + "')");
|
||||||
|
|||||||
@@ -72,3 +72,19 @@ test('single-tag hashing rollback also selects the legacy worker', () => fixture
|
|||||||
writeFileSync(join(dir,'sw.js'), "const VERSION = typeof __BUILD_TAG__ !== 'undefined' ? __BUILD_TAG__ : 'old'; const SYNC = typeof __ASSET_SYNC__ !== 'undefined' ? __ASSET_SYNC__ : true;");
|
writeFileSync(join(dir,'sw.js'), "const VERSION = typeof __BUILD_TAG__ !== 'undefined' ? __BUILD_TAG__ : 'old'; const SYNC = typeof __ASSET_SYNC__ !== 'undefined' ? __ASSET_SYNC__ : true;");
|
||||||
expect(createAssetManifest(dir,{hashing:false}).sw).toContain('const SYNC = false');
|
expect(createAssetManifest(dir,{hashing:false}).sw).toContain('const SYNC = false');
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
test('index embeds build-local group hashes without recursively embedding index/SW hashes', () => fixture(dir => {
|
||||||
|
writeFileSync(join(dir, 'index.html'), '<meta name="ytp-build" content="__BUILD_TAG__"><script type="application/json" id="ytp-assets">{}</script><script src="app.js"></script>');
|
||||||
|
const result=createAssetManifest(dir);
|
||||||
|
const map=JSON.parse(result.index.match(/id="ytp-assets">([^<]+)<\/script>/)[1]);
|
||||||
|
expect(map.buildTag).toBe(result.manifest.buildTag);
|
||||||
|
expect(map.groups).toEqual(result.manifest.groups);
|
||||||
|
expect(map.files['/app.js'].h).toBe(result.manifest.files['/app.js'].h);
|
||||||
|
expect(map.files['/index.html']).toBeUndefined();
|
||||||
|
expect(map.files['/sw.js']).toBeUndefined();
|
||||||
|
expect(createAssetManifest(dir).manifest).toEqual(result.manifest);
|
||||||
|
expect(result.manifest.files['/index.html'].h).toBe(hash(result.index));
|
||||||
|
const off=createAssetManifest(dir,{hashing:false});
|
||||||
|
const legacy=JSON.parse(off.index.match(/id="ytp-assets">([^<]+)<\/script>/)[1]);
|
||||||
|
expect(legacy.files['/app.js'].h).toBe(off.manifest.buildTag);
|
||||||
|
}));
|
||||||
|
|||||||
Reference in New Issue
Block a user