fix: preserve workspace cascade in production build
Some checks failed
Build and tests / test (push) Has been cancelled
Some checks failed
Build and tests / test (push) Has been cancelled
This commit is contained in:
@@ -1,4 +1,12 @@
|
|||||||
import { copyFileSync, existsSync, mkdirSync, readdirSync } from 'node:fs';
|
import { createHash } from 'node:crypto';
|
||||||
|
import {
|
||||||
|
copyFileSync,
|
||||||
|
existsSync,
|
||||||
|
mkdirSync,
|
||||||
|
readFileSync,
|
||||||
|
readdirSync,
|
||||||
|
writeFileSync
|
||||||
|
} from 'node:fs';
|
||||||
import path from 'node:path';
|
import path from 'node:path';
|
||||||
import { fileURLToPath } from 'node:url';
|
import { fileURLToPath } from 'node:url';
|
||||||
|
|
||||||
@@ -32,3 +40,26 @@ for (const entry of ['libs', 'favicon.ico']) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Vite hoists linked stylesheets into <head>, ahead of legacy inline styles in
|
||||||
|
// app.html. Re-emit the workspace layer after those styles so production and
|
||||||
|
// development use the same cascade order.
|
||||||
|
const workspaceSourcePath = path.join(frontendRoot, 'workspace.css');
|
||||||
|
const workspaceContents = readFileSync(workspaceSourcePath);
|
||||||
|
const workspaceHash = createHash('sha256').update(workspaceContents).digest('hex').slice(0, 12);
|
||||||
|
const workspaceFileName = `workspace-${workspaceHash}.css`;
|
||||||
|
copyFileSync(workspaceSourcePath, path.join(outputDirectory, workspaceFileName));
|
||||||
|
|
||||||
|
const builtAppPath = path.join(outputDirectory, 'app.html');
|
||||||
|
const builtAppHtml = readFileSync(builtAppPath, 'utf8');
|
||||||
|
const runtimeStylesheet = ` <link rel="stylesheet" href="/${workspaceFileName}" data-workspace-runtime>\n`;
|
||||||
|
const nextBuiltAppHtml = builtAppHtml.includes('data-workspace-runtime')
|
||||||
|
? builtAppHtml.replace(/\s*<link[^>]+data-workspace-runtime[^>]*>\s*/u, `\n${runtimeStylesheet}`)
|
||||||
|
: builtAppHtml.replace('</body>', `${runtimeStylesheet}</body>`);
|
||||||
|
|
||||||
|
if (!nextBuiltAppHtml.includes('data-workspace-runtime')) {
|
||||||
|
throw new Error('Unable to inject the runtime workspace stylesheet into dist/app.html');
|
||||||
|
}
|
||||||
|
|
||||||
|
writeFileSync(builtAppPath, nextBuiltAppHtml, 'utf8');
|
||||||
|
console.log(`Injected runtime workspace stylesheet: ${workspaceFileName}`);
|
||||||
|
|||||||
@@ -32,4 +32,21 @@ for (const fileName of ['app.html', 'share.html']) {
|
|||||||
assert.strictEqual(/vue\.global(?:\.prod)?\.js|axios\.min\.js/.test(html), false, `${fileName} still loads global Vue/Axios`);
|
assert.strictEqual(/vue\.global(?:\.prod)?\.js|axios\.min\.js/.test(html), false, `${fileName} still loads global Vue/Axios`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const builtAppHtml = readFileSync(path.join(outputDirectory, 'app.html'), 'utf8');
|
||||||
|
const runtimeWorkspaceMatch = builtAppHtml.match(
|
||||||
|
/<link rel="stylesheet" href="\/(workspace-[a-f0-9]{12}\.css)" data-workspace-runtime>/
|
||||||
|
);
|
||||||
|
assert.ok(runtimeWorkspaceMatch, 'app.html is missing the hashed runtime workspace stylesheet');
|
||||||
|
|
||||||
|
const runtimeWorkspacePath = path.join(outputDirectory, runtimeWorkspaceMatch[1]);
|
||||||
|
assert.ok(existsSync(runtimeWorkspacePath), 'runtime workspace stylesheet is missing');
|
||||||
|
assert.ok(
|
||||||
|
builtAppHtml.indexOf(runtimeWorkspaceMatch[0]) > builtAppHtml.lastIndexOf('</style>'),
|
||||||
|
'runtime workspace stylesheet must load after every legacy inline style'
|
||||||
|
);
|
||||||
|
|
||||||
|
const runtimeWorkspaceCss = readFileSync(runtimeWorkspacePath, 'utf8');
|
||||||
|
assert.ok(runtimeWorkspaceCss.includes('.mobile-file-create-trigger'), 'runtime workspace stylesheet is incomplete');
|
||||||
|
assert.ok(runtimeWorkspaceCss.includes('@media (max-width: 900px)'), 'runtime workspace mobile breakpoint is missing');
|
||||||
|
|
||||||
console.log(`Verified ${htmlFiles.length} HTML entries and their emitted assets.`);
|
console.log(`Verified ${htmlFiles.length} HTML entries and their emitted assets.`);
|
||||||
|
|||||||
Reference in New Issue
Block a user