diff --git a/packages/playground/assets/__tests__/assets.spec.ts b/packages/playground/assets/__tests__/assets.spec.ts
index 75c0e57952db24..19dd52f71e114a 100644
--- a/packages/playground/assets/__tests__/assets.spec.ts
+++ b/packages/playground/assets/__tests__/assets.spec.ts
@@ -1,4 +1,3 @@
-import { createHash } from 'crypto'
import {
findAssetFile,
getBg,
@@ -296,6 +295,11 @@ describe('css and assets in css in build watch', () => {
}
})
+test('inline style test', async () => {
+ expect(await getBg('.inline-style')).toMatch(assetMatch)
+ expect(await getBg('.style-url-assets')).toMatch(assetMatch)
+})
+
if (!isBuild) {
test('@import in html style tag hmr', async () => {
await untilUpdated(() => getColor('.import-css'), 'rgb(0, 136, 255)')
@@ -304,6 +308,7 @@ if (!isBuild) {
(code) => code.replace('#0088ff', '#00ff88'),
true
)
+ await page.waitForNavigation()
await untilUpdated(() => getColor('.import-css'), 'rgb(0, 255, 136)')
})
}
diff --git a/packages/playground/assets/index.html b/packages/playground/assets/index.html
index 6678a2da7c2106..99c2c2fe69ae70 100644
--- a/packages/playground/assets/index.html
+++ b/packages/playground/assets/index.html
@@ -207,7 +207,10 @@
+
inline style
use style class
@@ -235,6 +238,21 @@
import module css
+
style in svg
+
+
diff --git a/packages/playground/css-sourcemap/__tests__/serve.spec.ts b/packages/playground/css-sourcemap/__tests__/serve.spec.ts
index 11e33a78af8424..becd792e82293a 100644
--- a/packages/playground/css-sourcemap/__tests__/serve.spec.ts
+++ b/packages/playground/css-sourcemap/__tests__/serve.spec.ts
@@ -17,68 +17,6 @@ if (!isBuild) {
throw new Error('Not found')
}
- test('inline css', async () => {
- const css = await getStyleTagContentIncluding('.inline ')
- const map = extractSourcemap(css)
- expect(formatSourcemapForSnapshot(map)).toMatchInlineSnapshot(`
- Object {
- "mappings": "AAGO;AACP,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACX,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACf,CAAC,CAAC,CAAC;",
- "sources": Array [
- "/root/index.html",
- ],
- "sourcesContent": Array [
- "
-
-
-
-
-
-
CSS Sourcemap
-
-
<inline>
-
-
<linked>: no import
-
<linked>: with import
-
-
<imported>: no import
-
<imported>: with import
-
-
<imported sass>
-
<imported sass> with module
-
-
<imported less> with string additionalData
-
-
<imported stylus>
-
-
-
-
-
- ",
- ],
- "version": 3,
- }
- `)
- })
-
test('linked css', async () => {
const res = await page.request.get(
new URL('./linked.css', page.url()).href,
diff --git a/packages/playground/hmr/__tests__/hmr.spec.ts b/packages/playground/hmr/__tests__/hmr.spec.ts
index 40b2bdf31b7956..34612ee1e7d3d5 100644
--- a/packages/playground/hmr/__tests__/hmr.spec.ts
+++ b/packages/playground/hmr/__tests__/hmr.spec.ts
@@ -1,4 +1,4 @@
-import { isBuild, editFile, untilUpdated } from '../../testUtils'
+import { isBuild, editFile, untilUpdated, getBg } from '../../testUtils'
test('should render', async () => {
expect(await page.textContent('.app')).toBe('1')
@@ -195,6 +195,16 @@ if (!isBuild) {
expect(await btn.textContent()).toBe('Counter 1')
})
+ test('css in html hmr', async () => {
+ await page.goto(viteTestUrl)
+ expect(await getBg('.import-image')).toMatch('icon')
+ await page.goto(viteTestUrl + '/foo/')
+ expect(await getBg('.import-image')).toMatch('icon')
+ editFile('index.html', (code) => code.replace('url("./icon.png")', ''))
+ await page.waitForNavigation()
+ expect(await getBg('.import-image')).toMatch('')
+ })
+
test('HTML', async () => {
await page.goto(viteTestUrl + '/counter/index.html')
let btn = await page.$('button')
diff --git a/packages/playground/hmr/icon.png b/packages/playground/hmr/icon.png
new file mode 100644
index 00000000000000..4388bfdca3d4d7
Binary files /dev/null and b/packages/playground/hmr/icon.png differ
diff --git a/packages/playground/hmr/index.html b/packages/playground/hmr/index.html
index 0add7c26011a01..65a2ed381b027a 100644
--- a/packages/playground/hmr/index.html
+++ b/packages/playground/hmr/index.html
@@ -1,5 +1,13 @@
+
@@ -8,3 +16,4 @@
+
diff --git a/packages/playground/ssr-html/index.html b/packages/playground/ssr-html/index.html
index c37dcc7e366ae8..995c828caae1a8 100644
--- a/packages/playground/ssr-html/index.html
+++ b/packages/playground/ssr-html/index.html
@@ -4,6 +4,11 @@
SSR HTML
+
SSR Dynamic HTML
diff --git a/packages/vite/src/node/plugins/css.ts b/packages/vite/src/node/plugins/css.ts
index f310abc9bc7c56..8b01d48c696465 100644
--- a/packages/vite/src/node/plugins/css.ts
+++ b/packages/vite/src/node/plugins/css.ts
@@ -301,6 +301,7 @@ export function cssPostPlugin(config: ResolvedConfig): Plugin {
const inlined = inlineRE.test(id)
const modules = cssModulesCache.get(config)!.get(id)
+ const isHTMLProxy = htmlProxyRE.test(id)
const modulesCode =
modules && dataToEsm(modules, { namedExports: true, preferConst: true })
@@ -323,6 +324,10 @@ export function cssPostPlugin(config: ResolvedConfig): Plugin {
cssContent = getCodeWithSourcemap('css', css, sourcemap)
}
+ if (isHTMLProxy) {
+ return cssContent
+ }
+
return [
`import { updateStyle as __vite__updateStyle, removeStyle as __vite__removeStyle } from ${JSON.stringify(
path.posix.join(config.base, CLIENT_PUBLIC_PATH)
@@ -347,7 +352,6 @@ export function cssPostPlugin(config: ResolvedConfig): Plugin {
// and then use the cache replace inline-style-flag when `generateBundle` in vite:build-html plugin
const inlineCSS = inlineCSSRE.test(id)
const query = parseRequest(id)
- const isHTMLProxy = htmlProxyRE.test(id)
if (inlineCSS && isHTMLProxy) {
addToHTMLProxyTransformResult(
`${cleanUrl(id)}_${Number.parseInt(query!.index)}`,
@@ -718,12 +722,11 @@ async function compileCSS(
postcssConfig && postcssConfig.plugins ? postcssConfig.plugins.slice() : []
if (needInlineImport) {
- const isHTMLProxy = htmlProxyRE.test(id)
postcssPlugins.unshift(
(await import('postcss-import')).default({
async resolve(id, basedir) {
const publicFile = checkPublicFile(id, config)
- if (isHTMLProxy && publicFile) {
+ if (publicFile) {
return publicFile
}
diff --git a/packages/vite/src/node/server/middlewares/indexHtml.ts b/packages/vite/src/node/server/middlewares/indexHtml.ts
index ca2538bd9507ed..8638492b1c2001 100644
--- a/packages/vite/src/node/server/middlewares/indexHtml.ts
+++ b/packages/vite/src/node/server/middlewares/indexHtml.ts
@@ -16,14 +16,25 @@ import {
import type { ResolvedConfig, ViteDevServer } from '../..'
import { send } from '../send'
import { CLIENT_PUBLIC_PATH, FS_PREFIX } from '../../constants'
-import { cleanUrl, fsPathFromId, normalizePath, injectQuery } from '../../utils'
+import {
+ cleanUrl,
+ fsPathFromId,
+ normalizePath,
+ injectQuery,
+ ensureWatchedFile
+} from '../../utils'
import type { ModuleGraph } from '../moduleGraph'
+interface AssetNode {
+ start: number
+ end: number
+ code: string
+}
+
export function createDevHtmlTransformFn(
server: ViteDevServer
): (url: string, html: string, originalUrl: string) => Promise
{
const [preHooks, postHooks] = resolveHtmlTransforms(server.config.plugins)
-
return (url: string, html: string, originalUrl: string): Promise => {
return applyHtmlTransforms(html, [...preHooks, devHtmlHook, ...postHooks], {
path: url,
@@ -94,14 +105,15 @@ const devHtmlHook: IndexHtmlTransformHook = async (
html,
{ path: htmlPath, filename, server, originalUrl }
) => {
- const { config, moduleGraph } = server!
+ const { config, moduleGraph, watcher } = server!
const base = config.base || '/'
const s = new MagicString(html)
let inlineModuleIndex = -1
const filePath = cleanUrl(htmlPath)
+ const styleUrl: AssetNode[] = []
- const addInlineModule = (node: ElementNode, ext: 'js' | 'css') => {
+ const addInlineModule = (node: ElementNode, ext: 'js') => {
inlineModuleIndex++
const url = filePath.replace(normalizePath(config.root), '')
@@ -128,7 +140,6 @@ const devHtmlHook: IndexHtmlTransformHook = async (
if (module) {
server?.moduleGraph.invalidateModule(module)
}
-
s.overwrite(
node.loc.start.offset,
node.loc.end.offset,
@@ -154,7 +165,12 @@ const devHtmlHook: IndexHtmlTransformHook = async (
}
if (node.tag === 'style' && node.children.length) {
- addInlineModule(node, 'css')
+ const children = node.children[0] as TextNode
+ styleUrl.push({
+ start: children.loc.start.offset,
+ end: children.loc.end.offset,
+ code: children.content
+ })
}
// elements with [href/src] attrs
@@ -172,6 +188,19 @@ const devHtmlHook: IndexHtmlTransformHook = async (
}
})
+ await Promise.all(
+ styleUrl.map(async ({ start, end, code }, index) => {
+ const url = filename + `?html-proxy&${index}.css`
+
+ // ensure module in graph after successful load
+ const mod = await moduleGraph.ensureEntryFromUrl(url, false)
+ ensureWatchedFile(watcher, mod.file, config.root)
+
+ const result = await server!.pluginContainer.transform(code, url)
+ s.overwrite(start, end, result?.code || '')
+ })
+ )
+
html = s.toString()
return {