Skip to content

Commit e8e718f

Browse files
committed
fix unclear js name mapping
1 parent 70f137b commit e8e718f

8 files changed

Lines changed: 53 additions & 47 deletions

File tree

modules/markup/render.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -240,7 +240,7 @@ func RenderWithRenderer(ctx *RenderContext, renderer Renderer, input io.Reader,
240240
return RenderIFrame(ctx, extOpts.ContentSandbox, output)
241241
}
242242
// else: this is a standalone page, fallthrough to the real rendering, and add extra JS/CSS
243-
extraScriptSrc := public.AssetURI("js/standalone-external-render.js")
243+
extraScriptSrc := public.AssetURI("js/external-render-helper.js")
244244
// "<script>" must go before "<link>", to make Golang's http.DetectContentType() can still recognize the content as "text/html"
245245
// DO NOT use "type=module", the script must run as early as possible, to set up the environment in the iframe
246246
extraHeadHTML = htmlutil.HTMLFormat(`<script crossorigin src="%s"></script>`, extraScriptSrc)

modules/public/manifest.go

Lines changed: 20 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -125,27 +125,33 @@ func getManifestData() *manifestDataStruct {
125125
return data
126126
}
127127

128-
// getHashedPath resolves an unhashed asset path (origin path) to its content-hashed path from the frontend manifest.
129-
// Example: getHashedPath("js/index.js") returns "js/index.C6Z2MRVQ.js"
130-
// Falls back to returning the input path unchanged if the manifest is unavailable.
131-
func getHashedPath(originPath string) string {
132-
data := getManifestData()
133-
if p, ok := data.paths[originPath]; ok {
134-
return p
135-
}
136-
return originPath
137-
}
138-
139128
// AssetURI returns the URI for a frontend asset.
140129
// It may return a relative path or a full URL depending on the StaticURLPrefix setting.
141130
// In Vite dev mode, known entry points are mapped to their source paths
142131
// so the reverse proxy serves them from the Vite dev server.
143132
// In production, it resolves the content-hashed path from the manifest.
144133
func AssetURI(originPath string) string {
145-
if src := viteDevSourceURL(originPath); src != "" {
146-
return src
134+
if IsViteDevMode() {
135+
if src := viteDevSourceURL(originPath); src != "" {
136+
return src
137+
}
138+
// it should be caused by incorrect vite config
139+
setting.PanicInDevOrTesting("Failed to locate local path for managed asset URI: %s", originPath)
147140
}
148-
return setting.StaticURLPrefix + "/assets/" + getHashedPath(originPath)
141+
142+
// Try to resolve an unhashed asset path (origin path) to its content-hashed path from the frontend manifest.
143+
// Example: "js/index.js" -> "js/index.C6Z2MRVQ.js"
144+
data := getManifestData()
145+
assetPath := data.paths[originPath]
146+
if assetPath == "" {
147+
// it should be caused by either: "incorrect vite config" or "user's custom theme"
148+
assetPath = originPath
149+
if !setting.IsProd {
150+
log.Warn("Failed to find managed asset URI for origin path: %s", originPath)
151+
}
152+
}
153+
154+
return setting.StaticURLPrefix + "/assets/" + assetPath
149155
}
150156

151157
// AssetNameFromHashedPath returns the asset entry name for a given hashed asset path.

modules/public/vitedev.go

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -149,9 +149,6 @@ func detectWebSrcPath(webSrcPath string) string {
149149
}
150150

151151
func viteDevSourceURL(name string) string {
152-
if !IsViteDevMode() {
153-
return ""
154-
}
155152
if strings.HasPrefix(name, "css/theme-") {
156153
// Only redirect built-in themes to Vite source; custom themes are served from custom/public/assets/css/
157154
themeFilePath := "css/themes/" + strings.TrimPrefix(name, "css/")

tests/integration/markup_external_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ func TestExternalMarkupRenderer(t *testing.T) {
108108
// default sandbox in sub page response
109109
assert.Equal(t, "frame-src 'self'; sandbox allow-scripts allow-popups", respSub.Header().Get("Content-Security-Policy"))
110110
// FIXME: actually here is a bug (legacy design problem), the "PostProcess" will escape "<script>" tag, but it indeed is the sanitizer's job
111-
assert.Equal(t, `<script crossorigin src="`+public.AssetURI("js/standalone-external-render.js")+`"></script><div><any attr="val">&lt;script&gt;&lt;/script&gt;</any></div>`, respSub.Body.String())
111+
assert.Equal(t, `<script crossorigin src="`+public.AssetURI("js/external-render-helper.js")+`"></script><div><any attr="val">&lt;script&gt;&lt;/script&gt;</any></div>`, respSub.Body.String())
112112
})
113113
})
114114

@@ -131,7 +131,7 @@ func TestExternalMarkupRenderer(t *testing.T) {
131131
t.Run("HTMLContentWithExternalRenderIframeHelper", func(t *testing.T) {
132132
req := NewRequest(t, "GET", "/user2/repo1/render/branch/master/html.no-sanitizer")
133133
respSub := MakeRequest(t, req, http.StatusOK)
134-
assert.Equal(t, `<script crossorigin src="`+public.AssetURI("js/standalone-external-render.js")+`"></script><script>foo("raw")</script>`, respSub.Body.String())
134+
assert.Equal(t, `<script crossorigin src="`+public.AssetURI("js/external-render-helper.js")+`"></script><script>foo("raw")</script>`, respSub.Body.String())
135135
assert.Equal(t, "frame-src 'self'", respSub.Header().Get("Content-Security-Policy"))
136136
})
137137
})

vite.config.ts

Lines changed: 30 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -77,11 +77,13 @@ function commonViteOpts({build, ...other}: InlineConfig): InlineConfig {
7777
};
7878
}
7979

80-
function iifeBuildOpts({sourceFileName, entryFileName, write}: {sourceFileName: string, entryFileName: string, write?: boolean}) {
80+
function iifeBuildOpts({sourceFileName, write}: {sourceFileName: string, write?: boolean}) {
8181
const sourceBaseName = basename(sourceFileName, '.ts');
82+
// HINT: VITE-OUTPUT-DIR: all outputted JS files are in "js" directory
83+
const entryFileName = `js/${sourceBaseName}.[hash:8].js`;
8284
return commonViteOpts({
8385
build: {
84-
lib: {entry: join(import.meta.dirname, 'web_src', sourceFileName), name: camelize(sourceBaseName), formats: ['iife']},
86+
lib: {entry: join(import.meta.dirname, 'web_src/js', sourceFileName), name: camelize(sourceBaseName), formats: ['iife']},
8587
rolldownOptions: {output: {entryFileNames: entryFileName}},
8688
...(write === false && {write: false}),
8789
},
@@ -96,17 +98,12 @@ function iifePlugin(sourceFileName: string): Plugin {
9698
const iifeModules = new Set<string>();
9799
let isBuilding = false;
98100

99-
const sourceDir = path.dirname(sourceFileName), sourceBaseName = path.basename(sourceFileName, '.ts');
100-
const sourcePathPrefix = `${sourceDir}/${sourceBaseName}`;
101+
const sourceBaseName = path.basename(sourceFileName, '.ts');
101102
return {
102-
name: `iife:${sourcePathPrefix}`, // plugin name
103+
name: `iife:${sourceFileName}`, // plugin name
103104
async configureServer(server) {
104105
const buildAndCache = async () => {
105-
const result = await build(iifeBuildOpts({
106-
sourceFileName: `${sourcePathPrefix}.ts`,
107-
entryFileName: `${sourceDir}/${sourceBaseName}.js`,
108-
write: false,
109-
}));
106+
const result = await build(iifeBuildOpts({sourceFileName, write: false}));
110107
const output = (Array.isArray(result) ? result[0] : result) as Rolldown.RolldownOutput;
111108
const chunk = output.output[0];
112109
iifeCode = chunk.code.replace(/\/\/# sourceMappingURL=.*/, `//# sourceMappingURL=${sourceBaseName}.js.map`);
@@ -139,11 +136,11 @@ function iifePlugin(sourceFileName: string): Plugin {
139136
const pathname = req.url!.split('?')[0];
140137
if (pathname === '/web_src/js/__vite_dev_server_check') {
141138
res.end('ok');
142-
} else if (pathname === `/web_src/${sourcePathPrefix}.ts`) {
139+
} else if (pathname === `/web_src/js/${sourceFileName}`) {
143140
res.setHeader('Content-Type', 'application/javascript');
144141
res.setHeader('Cache-Control', 'no-store');
145142
res.end(iifeCode);
146-
} else if (pathname === `/web_src/js/${sourcePathPrefix}.js.map`) {
143+
} else if (pathname === `/web_src/js/${sourceBaseName}.js.map`) {
147144
res.setHeader('Content-Type', 'application/json');
148145
res.setHeader('Cache-Control', 'no-store');
149146
res.end(iifeMap);
@@ -153,32 +150,38 @@ function iifePlugin(sourceFileName: string): Plugin {
153150
});
154151
},
155152
async closeBundle() {
156-
for (const file of globSync(`${sourcePathPrefix}.*.js*`, {cwd: outDir})) unlinkSync(join(outDir, file));
157-
const result = await build(iifeBuildOpts({
158-
sourceFileName: `${sourcePathPrefix}.ts`,
159-
entryFileName: `${sourcePathPrefix}.[hash:8].js`,
160-
}));
153+
for (const file of globSync(`js/${sourceBaseName}.*.js*`, {cwd: outDir})) unlinkSync(join(outDir, file));
154+
155+
const result = await build(iifeBuildOpts({sourceFileName}));
161156
const buildOutput = (Array.isArray(result) ? result[0] : result) as Rolldown.RolldownOutput;
162-
const entry = buildOutput.output.find((o) => o.fileName.startsWith(`${sourcePathPrefix}.`));
157+
const entry = buildOutput.output.find((o) => o.fileName.startsWith(`js/${sourceBaseName}.`));
163158
if (!entry) throw new Error('IIFE build produced no output');
164159

165160
const manifestPath = join(outDir, '.vite', 'manifest.json');
166161
const manifestData = JSON.parse(readFileSync(manifestPath, 'utf8'));
167-
manifestData[`web_src/${sourcePathPrefix}.js`] = {file: entry.fileName, name: sourceBaseName, isEntry: true};
162+
manifestData[`web_src/js/${sourceFileName}`] = {file: entry.fileName, name: sourceBaseName, isEntry: true};
168163
writeFileSync(manifestPath, JSON.stringify(manifestData, null, 2));
169164
},
170165
};
171166
}
172167

173168
// In reduced sourcemap mode, only keep sourcemaps for main files
174169
function reducedSourcemapPlugin(): Plugin {
170+
const standalonePrefixes = [
171+
'js/index.',
172+
'js/iife.',
173+
'js/swagger.',
174+
'js/external-render-helper.',
175+
'js/eventsource.sharedworker.',
176+
];
175177
return {
176178
name: 'reduced-sourcemap',
177179
apply: 'build',
178180
closeBundle() {
179181
if (enableSourcemap !== 'reduced') return;
180182
for (const file of globSync('{js,css}/*.map', {cwd: outDir})) {
181-
if (!file.startsWith('js/index.') && !file.startsWith('js/iife.') && !file.startsWith('js/standalone-')) unlinkSync(join(outDir, file));
183+
if (standalonePrefixes.some((prefix) => file.startsWith(prefix))) continue;
184+
unlinkSync(join(outDir, file));
182185
}
183186
},
184187
};
@@ -255,15 +258,15 @@ export default defineConfig(commonViteOpts({
255258
rolldownOptions: {
256259
input: {
257260
index: join(import.meta.dirname, 'web_src/js/index.ts'),
258-
swagger: join(import.meta.dirname, 'web_src/js/standalone-swagger.ts'),
259-
'external-render-iframe': join(import.meta.dirname, 'web_src/js/standalone-external-render.ts'),
260-
'eventsource.sharedworker': join(import.meta.dirname, 'web_src/js/features/eventsource.sharedworker.ts'),
261+
swagger: join(import.meta.dirname, 'web_src/js/swagger.ts'),
262+
'eventsource.sharedworker': join(import.meta.dirname, 'web_src/js/eventsource.sharedworker.ts'),
261263
devtest: join(import.meta.dirname, 'web_src/css/devtest.css'),
262264
...themes,
263265
},
264266
output: {
265-
// all outputted JS files are in "/js" directory, so standalone source files should also be in "js" directory
266-
// to keep consistent between production and dev server and avoid unexpected behaviors.
267+
// HINT: VITE-OUTPUT-DIR: all outputted JS files are in "js" directory
268+
// So standalone/iife source files should also be in "js" directory,
269+
// to keep consistent between production and dev server, avoid unexpected behaviors.
267270
entryFileNames: 'js/[name].[hash:8].js',
268271
chunkFileNames: 'js/[name].[hash:8].js',
269272
assetFileNames: ({names}) => {
@@ -297,8 +300,8 @@ export default defineConfig(commonViteOpts({
297300
__VUE_PROD_HYDRATION_MISMATCH_DETAILS__: false,
298301
},
299302
plugins: [
300-
iifePlugin('js/iife.ts'),
301-
iifePlugin('js/standalone-external-render.ts'),
303+
iifePlugin('iife.ts'),
304+
iifePlugin('external-render-helper.ts'),
302305
viteDevServerPortPlugin(),
303306
reducedSourcemapPlugin(),
304307
filterCssUrlPlugin(),
File renamed without changes.

0 commit comments

Comments
 (0)