mirror of
https://github.com/PR0M3TH3AN/bitvid.git
synced 2026-10-27 07:52:24 +00:00
Add content-hashed asset manifest and HTML rewrite in dist build
This commit is contained in:
1 parent
d58cff2eac
commit
8c84f0a052
3 files changed
+95
-9
No files matched your search
+3
-3
@@ -67,7 +67,7 @@
|
||||
})();
|
||||
</script>
|
||||
|
||||
<link href="css/tailwind.generated.css?v=2024.11.09" rel="stylesheet" />
|
||||
<link href="css/tailwind.generated.css" rel="stylesheet" />
|
||||
</head>
|
||||
<body class="h-screen w-screen overflow-hidden bg-transparent text-text" data-ds="new">
|
||||
<main
|
||||
@@ -214,7 +214,7 @@
|
||||
</section>
|
||||
</main>
|
||||
|
||||
<script type="module" src="js/nostrToolsBootstrap.js?v=2024.11.09"></script>
|
||||
<script type="module" src="js/embed.js?v=2024.11.09"></script>
|
||||
<script type="module" src="js/nostrToolsBootstrap.js"></script>
|
||||
<script type="module" src="js/embed.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
+6
-6
@@ -107,12 +107,12 @@
|
||||
|
||||
<!-- Styles -->
|
||||
<!--
|
||||
Cache busting: keep these query strings in sync with config/asset-version.js
|
||||
so browsers pick up the latest sidebar markup and styling without
|
||||
hard-refreshing around CDN caches.
|
||||
Build-time asset hashing rewrites these source paths to content-hashed
|
||||
files in dist/, keeping source templates readable while preserving cache
|
||||
busting semantics.
|
||||
-->
|
||||
<link href="css/tailwind.generated.css?v=2024.11.09-2" rel="stylesheet" />
|
||||
<link href="css/docs.css?v=2024.11.09-2" rel="stylesheet" />
|
||||
<link href="css/tailwind.generated.css" rel="stylesheet" />
|
||||
<link href="css/docs.css" rel="stylesheet" />
|
||||
</head>
|
||||
<body class="sidebar-collapsed" data-ds="new">
|
||||
<!--
|
||||
@@ -423,7 +423,7 @@
|
||||
</div>
|
||||
|
||||
<!-- Additional Scripts -->
|
||||
<script type="module" src="js/index.js?v=2024.11.09"></script>
|
||||
<script type="module" src="js/index.js"></script>
|
||||
<script src="vendor/marked.min.js"></script>
|
||||
<script src="vendor/highlight.min.js"></script>
|
||||
<div id="uiOverlay" data-overlay-root aria-hidden="true"></div>
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import fs from 'node:fs';
|
||||
import path from 'node:path';
|
||||
import { execSync } from 'node:child_process';
|
||||
import crypto from 'node:crypto';
|
||||
|
||||
const DIST = 'dist';
|
||||
const FILES_TO_COPY = [
|
||||
@@ -26,6 +27,15 @@ const DIRS_TO_COPY = [
|
||||
'vendor',
|
||||
'views'
|
||||
];
|
||||
const HASHED_ENTRY_HTML_FILES = ['index.html', 'embed.html'];
|
||||
const HASHED_ASSET_PATHS = [
|
||||
'css/docs.css',
|
||||
'css/tailwind.generated.css',
|
||||
'js/embed.js',
|
||||
'js/index.js',
|
||||
'js/nostrToolsBootstrap.js'
|
||||
];
|
||||
const ASSET_MANIFEST_PATH = 'asset-manifest.json';
|
||||
|
||||
function cleanDist() {
|
||||
if (fs.existsSync(DIST)) {
|
||||
@@ -74,6 +84,76 @@ function copyDir(src, dest) {
|
||||
}
|
||||
}
|
||||
|
||||
function hashContent(content) {
|
||||
return crypto.createHash('sha256').update(content).digest('hex');
|
||||
}
|
||||
|
||||
function createHashedFilePath(assetPath, hash) {
|
||||
const ext = path.extname(assetPath);
|
||||
const baseName = path.basename(assetPath, ext);
|
||||
const dirName = path.dirname(assetPath);
|
||||
const shortHash = hash.slice(0, 16);
|
||||
const hashedName = `${baseName}.${shortHash}${ext}`;
|
||||
return dirName === '.' ? hashedName : path.posix.join(dirName, hashedName);
|
||||
}
|
||||
|
||||
function escapeForRegExp(value) {
|
||||
return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
||||
}
|
||||
|
||||
function generateHashedAssetManifest() {
|
||||
const sortedAssetPaths = [...HASHED_ASSET_PATHS].sort();
|
||||
const manifest = {};
|
||||
|
||||
for (const logicalAssetPath of sortedAssetPaths) {
|
||||
const sourcePath = path.join(DIST, logicalAssetPath);
|
||||
if (!fs.existsSync(sourcePath)) {
|
||||
throw new Error(`Missing required asset for hashing: ${logicalAssetPath}`);
|
||||
}
|
||||
|
||||
const content = fs.readFileSync(sourcePath);
|
||||
const hash = hashContent(content);
|
||||
const hashedRelativePath = createHashedFilePath(logicalAssetPath, hash);
|
||||
const hashedDistPath = path.join(DIST, hashedRelativePath);
|
||||
|
||||
fs.mkdirSync(path.dirname(hashedDistPath), { recursive: true });
|
||||
fs.writeFileSync(hashedDistPath, content);
|
||||
manifest[logicalAssetPath] = hashedRelativePath;
|
||||
}
|
||||
|
||||
const sortedManifest = Object.fromEntries(
|
||||
Object.entries(manifest).sort(([a], [b]) => a.localeCompare(b))
|
||||
);
|
||||
fs.writeFileSync(
|
||||
path.join(DIST, ASSET_MANIFEST_PATH),
|
||||
`${JSON.stringify(sortedManifest, null, 2)}\n`
|
||||
);
|
||||
|
||||
return sortedManifest;
|
||||
}
|
||||
|
||||
function rewriteEntryHtmlAssetPaths(manifest) {
|
||||
for (const htmlFile of HASHED_ENTRY_HTML_FILES) {
|
||||
const htmlPath = path.join(DIST, htmlFile);
|
||||
if (!fs.existsSync(htmlPath)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let htmlContent = fs.readFileSync(htmlPath, 'utf8');
|
||||
|
||||
for (const [logicalPath, hashedPath] of Object.entries(manifest)) {
|
||||
const escapedLogicalPath = escapeForRegExp(logicalPath);
|
||||
const attributePattern = new RegExp(
|
||||
`((?:src|href)=["'])${escapedLogicalPath}(?:\\?[^"']*)?(["'])`,
|
||||
'g'
|
||||
);
|
||||
htmlContent = htmlContent.replace(attributePattern, `$1${hashedPath}$2`);
|
||||
}
|
||||
|
||||
fs.writeFileSync(htmlPath, htmlContent);
|
||||
}
|
||||
}
|
||||
|
||||
function main() {
|
||||
console.log('Cleaning dist...');
|
||||
cleanDist();
|
||||
@@ -115,6 +195,12 @@ function main() {
|
||||
copyDir(dir, path.join(DIST, dir));
|
||||
}
|
||||
|
||||
console.log('Generating hashed asset manifest...');
|
||||
const manifest = generateHashedAssetManifest();
|
||||
|
||||
console.log('Rewriting HTML entry points with hashed assets...');
|
||||
rewriteEntryHtmlAssetPaths(manifest);
|
||||
|
||||
console.log('Build complete.');
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user