Skip to content

Commit 25c64d7

Browse files
authored
fix: importmap should insert before module preload link (#11492)
1 parent f12a1ab commit 25c64d7

File tree

4 files changed

+48
-14
lines changed

4 files changed

+48
-14
lines changed

packages/vite/src/node/plugins/html.ts

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,12 @@ const importMapRE =
5050
/[ \t]*<script[^>]*type\s*=\s*(?:"importmap"|'importmap'|importmap)[^>]*>.*?<\/script>/is
5151
const moduleScriptRE =
5252
/[ \t]*<script[^>]*type\s*=\s*(?:"module"|'module'|module)[^>]*>/i
53+
const modulePreloadLinkRE =
54+
/[ \t]*<link[^>]*rel\s*=\s*(?:"modulepreload"|'modulepreload'|modulepreload)[\s\S]*?\/>/i
55+
const importMapAppendRE = new RegExp(
56+
[moduleScriptRE, modulePreloadLinkRE].map((r) => r.source).join('|'),
57+
'i',
58+
)
5359

5460
export const isHTMLProxy = (id: string): boolean => htmlProxyRE.test(id)
5561

@@ -891,17 +897,17 @@ export function preImportMapHook(
891897
const importMapIndex = html.match(importMapRE)?.index
892898
if (importMapIndex === undefined) return
893899

894-
const moduleScriptIndex = html.match(moduleScriptRE)?.index
895-
if (moduleScriptIndex === undefined) return
900+
const importMapAppendIndex = html.match(importMapAppendRE)?.index
901+
if (importMapAppendIndex === undefined) return
896902

897-
if (moduleScriptIndex < importMapIndex) {
903+
if (importMapAppendIndex < importMapIndex) {
898904
const relativeHtml = normalizePath(
899905
path.relative(config.root, ctx.filename),
900906
)
901907
config.logger.warnOnce(
902908
colors.yellow(
903909
colors.bold(
904-
`(!) <script type="importmap"> should come before <script type="module"> in /${relativeHtml}`,
910+
`(!) <script type="importmap"> should come before <script type="module"> and <link rel="modulepreload"> in /${relativeHtml}`,
905911
),
906912
),
907913
)
@@ -910,19 +916,23 @@ export function preImportMapHook(
910916
}
911917

912918
/**
913-
* Move importmap before the first module script
919+
* Move importmap before the first module script and modulepreload link
914920
*/
915921
export function postImportMapHook(): IndexHtmlTransformHook {
916922
return (html) => {
917-
if (!moduleScriptRE.test(html)) return
923+
if (!importMapAppendRE.test(html)) return
918924

919925
let importMap: string | undefined
920926
html = html.replace(importMapRE, (match) => {
921927
importMap = match
922928
return ''
923929
})
930+
924931
if (importMap) {
925-
html = html.replace(moduleScriptRE, (match) => `${importMap}\n${match}`)
932+
html = html.replace(
933+
importMapAppendRE,
934+
(match) => `${importMap}\n${match}`,
935+
)
926936
}
927937

928938
return html

playground/html/__tests__/html.spec.ts

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -251,12 +251,6 @@ describe.runIf(isServe)('invalid', () => {
251251
})
252252
})
253253

254-
test('importmap', () => {
255-
expect(browserLogs).not.toContain(
256-
'An import map is added after module script load was triggered.',
257-
)
258-
})
259-
260254
describe('Valid HTML', () => {
261255
test('valid HTML is parsed', async () => {
262256
await page.goto(viteTestUrl + '/valid.html')
@@ -267,3 +261,16 @@ describe('Valid HTML', () => {
267261
expect(await getColor('#duplicated-attrs')).toBe('green')
268262
})
269263
})
264+
265+
describe('importmap', () => {
266+
beforeAll(async () => {
267+
await page.goto(viteTestUrl + '/importmapOrder.html')
268+
})
269+
270+
// Should put this test at the end to get all browser logs above
271+
test('importmap should be prepended', async () => {
272+
expect(browserLogs).not.toContain(
273+
'An import map is added after module script load was triggered.',
274+
)
275+
})
276+
})

playground/html/importmapOrder.html

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<script type="importmap">
5+
{
6+
"imports": {
7+
"some-pkg": "url-of-pkg"
8+
}
9+
}
10+
</script>
11+
<link rel="modulepreload" href="url-of-pkg" />
12+
<script type="module" src="/main.js"></script>
13+
</head>
14+
</html>

playground/html/vite.config.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ module.exports = {
2828
),
2929
linkProps: resolve(__dirname, 'link-props/index.html'),
3030
valid: resolve(__dirname, 'valid.html'),
31+
importmapOrder: resolve(__dirname, 'importmapOrder.html'),
3132
},
3233
},
3334
},
@@ -168,7 +169,9 @@ ${
168169
},
169170
{
170171
name: 'head-prepend-importmap',
171-
transformIndexHtml() {
172+
transformIndexHtml(_, ctx) {
173+
if (ctx.path.includes('importmapOrder')) return
174+
172175
return [
173176
{
174177
tag: 'script',

0 commit comments

Comments
 (0)