Skip to content

Commit

Permalink
fix: importmap should insert before module preload link (#11492)
Browse files Browse the repository at this point in the history
  • Loading branch information
fi3ework committed Jan 2, 2023
1 parent f12a1ab commit 25c64d7
Show file tree
Hide file tree
Showing 4 changed files with 48 additions and 14 deletions.
24 changes: 17 additions & 7 deletions packages/vite/src/node/plugins/html.ts
Expand Up @@ -50,6 +50,12 @@ const importMapRE =
/[ \t]*<script[^>]*type\s*=\s*(?:"importmap"|'importmap'|importmap)[^>]*>.*?<\/script>/is
const moduleScriptRE =
/[ \t]*<script[^>]*type\s*=\s*(?:"module"|'module'|module)[^>]*>/i
const modulePreloadLinkRE =
/[ \t]*<link[^>]*rel\s*=\s*(?:"modulepreload"|'modulepreload'|modulepreload)[\s\S]*?\/>/i
const importMapAppendRE = new RegExp(
[moduleScriptRE, modulePreloadLinkRE].map((r) => r.source).join('|'),
'i',
)

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

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

const moduleScriptIndex = html.match(moduleScriptRE)?.index
if (moduleScriptIndex === undefined) return
const importMapAppendIndex = html.match(importMapAppendRE)?.index
if (importMapAppendIndex === undefined) return

if (moduleScriptIndex < importMapIndex) {
if (importMapAppendIndex < importMapIndex) {
const relativeHtml = normalizePath(
path.relative(config.root, ctx.filename),
)
config.logger.warnOnce(
colors.yellow(
colors.bold(
`(!) <script type="importmap"> should come before <script type="module"> in /${relativeHtml}`,
`(!) <script type="importmap"> should come before <script type="module"> and <link rel="modulepreload"> in /${relativeHtml}`,
),
),
)
Expand All @@ -910,19 +916,23 @@ export function preImportMapHook(
}

/**
* Move importmap before the first module script
* Move importmap before the first module script and modulepreload link
*/
export function postImportMapHook(): IndexHtmlTransformHook {
return (html) => {
if (!moduleScriptRE.test(html)) return
if (!importMapAppendRE.test(html)) return

let importMap: string | undefined
html = html.replace(importMapRE, (match) => {
importMap = match
return ''
})

if (importMap) {
html = html.replace(moduleScriptRE, (match) => `${importMap}\n${match}`)
html = html.replace(
importMapAppendRE,
(match) => `${importMap}\n${match}`,
)
}

return html
Expand Down
19 changes: 13 additions & 6 deletions playground/html/__tests__/html.spec.ts
Expand Up @@ -251,12 +251,6 @@ describe.runIf(isServe)('invalid', () => {
})
})

test('importmap', () => {
expect(browserLogs).not.toContain(
'An import map is added after module script load was triggered.',
)
})

describe('Valid HTML', () => {
test('valid HTML is parsed', async () => {
await page.goto(viteTestUrl + '/valid.html')
Expand All @@ -267,3 +261,16 @@ describe('Valid HTML', () => {
expect(await getColor('#duplicated-attrs')).toBe('green')
})
})

describe('importmap', () => {
beforeAll(async () => {
await page.goto(viteTestUrl + '/importmapOrder.html')
})

// Should put this test at the end to get all browser logs above
test('importmap should be prepended', async () => {
expect(browserLogs).not.toContain(
'An import map is added after module script load was triggered.',
)
})
})
14 changes: 14 additions & 0 deletions playground/html/importmapOrder.html
@@ -0,0 +1,14 @@
<!DOCTYPE html>
<html lang="en">
<head>
<script type="importmap">
{
"imports": {
"some-pkg": "url-of-pkg"
}
}
</script>
<link rel="modulepreload" href="url-of-pkg" />
<script type="module" src="/main.js"></script>
</head>
</html>
5 changes: 4 additions & 1 deletion playground/html/vite.config.js
Expand Up @@ -28,6 +28,7 @@ module.exports = {
),
linkProps: resolve(__dirname, 'link-props/index.html'),
valid: resolve(__dirname, 'valid.html'),
importmapOrder: resolve(__dirname, 'importmapOrder.html'),
},
},
},
Expand Down Expand Up @@ -168,7 +169,9 @@ ${
},
{
name: 'head-prepend-importmap',
transformIndexHtml() {
transformIndexHtml(_, ctx) {
if (ctx.path.includes('importmapOrder')) return

return [
{
tag: 'script',
Expand Down

0 comments on commit 25c64d7

Please sign in to comment.