diff --git a/packages/vite/src/node/plugins/html.ts b/packages/vite/src/node/plugins/html.ts index b8cd3713edfeea..4c46d988890462 100644 --- a/packages/vite/src/node/plugins/html.ts +++ b/packages/vite/src/node/plugins/html.ts @@ -7,6 +7,7 @@ import type { SourceMapInput } from 'rollup' import MagicString from 'magic-string' +import colors from 'picocolors' import type { AttributeNode, CompilerError, @@ -54,6 +55,10 @@ const inlineImportRE = /(?]*type\s*=\s*["']?importmap["']?[^>]*>.*?<\/script>/is +const moduleScriptRE = /[ \t]*]*type\s*=\s*["']?module["']?[^>]*>/is + export const isHTMLProxy = (id: string): boolean => htmlProxyRE.test(id) export const isHTMLRequest = (request: string): boolean => @@ -225,6 +230,8 @@ function handleParseError( */ export function buildHtmlPlugin(config: ResolvedConfig): Plugin { const [preHooks, postHooks] = resolveHtmlTransforms(config.plugins) + preHooks.unshift(preImportMapHook(config)) + postHooks.push(postImportMapHook()) const processedHtml = new Map() const isExcludedUrl = (url: string) => url.startsWith('#') || @@ -796,6 +803,51 @@ export type IndexHtmlTransform = transform: IndexHtmlTransformHook } +export function preImportMapHook( + config: ResolvedConfig +): IndexHtmlTransformHook { + return (html, ctx) => { + const importMapIndex = html.match(importMapRE)?.index + if (importMapIndex === undefined) return + + const moduleScriptIndex = html.match(moduleScriptRE)?.index + if (moduleScriptIndex === undefined) return + + if (moduleScriptIndex < importMapIndex) { + const relativeHtml = normalizePath( + path.relative(config.root, ctx.filename) + ) + config.logger.warnOnce( + colors.yellow( + colors.bold( + `(!)