Skip to content

Commit 584d306

Browse files
authored
Fix static subresource paths for server/viewer (GoogleChrome#879)
1 parent d7240dc commit 584d306

File tree

5 files changed

+53
-19
lines changed

5 files changed

+53
-19
lines changed

packages/server/package.json

+2-2
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@
1313
"scripts": {
1414
"clean": "rm -rf ./dist ./storybook-static",
1515
"build": "npm run build:esbuild && npm run build:storybook",
16-
"build:esbuild": "node ../../scripts/build-app.js build ./src/ui/index.html ./dist /app",
17-
"build:watch": "node ../../scripts/build-app.js watch ./src/ui/index.html ./dist /app",
16+
"build:esbuild": "node ../../scripts/build-app.js build ./src/ui/index.html ./dist /app/",
17+
"build:watch": "node ../../scripts/build-app.js watch ./src/ui/index.html ./dist /app/",
1818
"build:source-map-explorer": "npm run clean && npm run build && ../../scripts/source-map-explorer.sh",
1919
"build:storybook": "build-storybook",
2020
"start:storybook": "start-storybook -p 6006"

packages/viewer/package.json

+2-2
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@
1212
"scripts": {
1313
"clean": "rm -rf ./dist",
1414
"start": "npm run build:watch",
15-
"build": "node ../../scripts/build-app.js build ./src/ui/index.html ./dist",
16-
"build:watch": "node ../../scripts/build-app.js watch ./src/ui/index.html ./dist"
15+
"build": "node ../../scripts/build-app.js build ./src/ui/index.html ./dist ./",
16+
"build:watch": "node ../../scripts/build-app.js watch ./src/ui/index.html ./dist ./"
1717
},
1818
"devDependencies": {
1919
"clsx": "^1.0.4",

scripts/build-app.js

+43-12
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
'use strict';
77

88
const fs = require('fs');
9+
const path = require('path');
910

1011
const esbuild = require('esbuild');
1112

@@ -23,33 +24,63 @@ if (!['build', 'watch'].includes(command)) {
2324
}
2425

2526
/**
27+
* All of this is dumb but esbuild-plugin-html is limited and paths are hard.
28+
*
29+
* FYI If you see a static resource served as HTML, then the express router attempted use
30+
* a static file, but didnt see it on disk, and instead served the HTML. The problem will probably
31+
* be in here.
2632
* @param {esbuild.BuildResult} result
33+
* @param {esbuild.BuildOptions} buildOptions
2734
*/
28-
function fixHtmlSubresourceUrls(result) {
29-
if (publicPath !== '/app') return;
35+
function fixHtmlSubresourceUrls(result, buildOptions) {
3036
if (!result.metafile) throw new Error('expected metafile');
3137

3238
const htmls = Object.keys(result.metafile.outputs).filter(o => o.endsWith('.html'));
33-
const html = htmls[0];
39+
const csss = Object.keys(result.metafile.outputs).filter(o => o.endsWith('.css'));
3440
if (htmls.length !== 1) throw new Error('expected exactly one generated html');
41+
if (csss.length !== 1) throw new Error('expected exactly one generated html');
42+
const htmlDistPath = htmls[0];
43+
const cssDistPath = csss[0];
3544

36-
const htmlText = fs.readFileSync(html, 'utf-8');
45+
// Viewer uses a publicPath of ./, Server uses /app.
46+
if (!buildOptions.outdir || !buildOptions.publicPath) {
47+
throw new Error('missing args');
48+
}
49+
const relativeCssPath = path.relative(buildOptions.outdir, cssDistPath);
50+
51+
// Rewrite the HTML
52+
const htmlText = fs.readFileSync(htmlDistPath, 'utf-8');
3753
const newHtmlText = htmlText
38-
.replace('<script src="chunks/', '<script src="/app/chunks/')
39-
.replace('<link rel="stylesheet" href="chunks/', '<link rel="stylesheet" href="/app/chunks/');
40-
fs.writeFileSync(html, newHtmlText);
54+
// Inject publicPath on JS references
55+
.replace('<script src="chunks/', `<script src="${buildOptions.publicPath}chunks/`)
56+
// noop @chialab/esbuild-plugin-html's stupid css loading technique
57+
.replace('<script type="application/javascript">', '<script type="dumb-dont-run-this">')
58+
// ... and instead use a proper stylesheet link. (with a fixed path)
59+
.replace(
60+
'</head>',
61+
`
62+
<link rel="stylesheet" href="${buildOptions.publicPath}${relativeCssPath}">
63+
</head>
64+
`
65+
);
66+
fs.writeFileSync(htmlDistPath, newHtmlText);
67+
68+
// Rewrite the CSS, making sure we don't source icons relative to the chunks/css file.
69+
const newCssText = fs
70+
.readFileSync(cssDistPath, 'utf-8')
71+
.replaceAll(`url(./assets`, `url(../assets`);
72+
fs.writeFileSync(cssDistPath, newCssText);
4173
}
4274

4375
async function main() {
4476
const htmlPlugin = (await import('@chialab/esbuild-plugin-html')).default;
45-
4677
/** @type {esbuild.BuildOptions} */
4778
const buildOptions = {
4879
entryPoints: [entryPoint],
4980
entryNames: '[name]',
5081
assetNames: 'assets/[name]-[hash]',
51-
// Defined chunknames breaks the viewer (probably cuz the -plugin-html), but pairs with fixHtmlSubresourceUrls.
52-
chunkNames: publicPath ? `chunks/[name]-[hash]` : undefined,
82+
// See the special handling in fixHtmlSubresourceUrls.
83+
chunkNames: `chunks/[name]-[hash]`,
5384
plugins: [htmlPlugin()],
5485
loader: {
5586
'.svg': 'file',
@@ -70,15 +101,15 @@ async function main() {
70101
? {
71102
onRebuild(err, result) {
72103
if (!err && result) {
73-
fixHtmlSubresourceUrls(result);
104+
fixHtmlSubresourceUrls(result, buildOptions);
74105
}
75106
},
76107
}
77108
: undefined,
78109
};
79110

80111
const result = await esbuild.build(buildOptions);
81-
fixHtmlSubresourceUrls(result);
112+
fixHtmlSubresourceUrls(result, buildOptions);
82113

83114
console.log('Built.', new Date());
84115
if (result.errors.length) console.error(result.errors);

scripts/source-map-explorer.sh

+4-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
#!/bin/bash
22

3-
sed -i '' 's/sourceMappingURL=\/app/sourceMappingURL=./' ./dist/*.js
4-
source-map-explorer dist/entry.*.js
3+
set -euo pipefail
4+
5+
sed -i '' 's/sourceMappingURL=\/app\/chunks/sourceMappingURL=./' ./dist/chunks/*.js
6+
source-map-explorer dist/chunks/entry*.js

tsconfig.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@
22
"compilerOptions": {
33
"noEmit": true,
44
"module": "commonjs",
5-
"target": "ES2017",
5+
"target": "ES2021",
6+
"lib": ["ES2021"],
67
"allowJs": true,
78
"checkJs": true,
89
"strict": true,

0 commit comments

Comments
 (0)