Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: style hmr reduce replace style code #7869

Merged
merged 22 commits into from Apr 30, 2022
Merged
Show file tree
Hide file tree
Changes from 13 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
7 changes: 6 additions & 1 deletion packages/playground/assets/__tests__/assets.spec.ts
@@ -1,4 +1,3 @@
import { createHash } from 'crypto'
import {
findAssetFile,
getBg,
Expand Down Expand Up @@ -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)')
Expand All @@ -304,6 +308,7 @@ if (!isBuild) {
(code) => code.replace('#0088ff', '#00ff88'),
true
)
await page.waitForNavigation()
await untilUpdated(() => getColor('.import-css'), 'rgb(0, 255, 136)')
})
}
Expand Down
5 changes: 4 additions & 1 deletion packages/playground/assets/index.html
Expand Up @@ -207,7 +207,10 @@ <h3>url</h3>
background-size: 10px 10px;
}
</style>
<div style="background: url('./nested/asset.png'); background-size: 10px 10px">
<div
class="inline-style"
style="background: url('./nested/asset.png'); background-size: 10px 10px"
>
inline style
</div>
<div class="style-url-assets">use style class</div>
Expand Down
62 changes: 0 additions & 62 deletions packages/playground/css-sourcemap/__tests__/serve.spec.ts
Expand Up @@ -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 [
"<link rel=\\"stylesheet\\" href=\\"./linked.css\\" />
<link rel=\\"stylesheet\\" href=\\"./linked-with-import.css\\" />

<style>
.inline {
color: red;
}
</style>

<div class=\\"wrapper\\">
<h1>CSS Sourcemap</h1>

<p class=\\"inline\\">&lt;inline&gt;</p>

<p class=\\"linked\\">&lt;linked&gt;: no import</p>
<p class=\\"linked-with-import\\">&lt;linked&gt;: with import</p>

<p class=\\"imported\\">&lt;imported&gt;: no import</p>
<p class=\\"imported-with-import\\">&lt;imported&gt;: with import</p>

<p class=\\"imported-sass\\">&lt;imported sass&gt;</p>
<p class=\\"imported-sass-module\\">&lt;imported sass&gt; with module</p>

<p class=\\"imported-less\\">&lt;imported less&gt; with string additionalData</p>

<p class=\\"imported-stylus\\">&lt;imported stylus&gt;</p>
</div>

<script type=\\"module\\">
import './imported.css'
import './imported-with-import.css'

import './imported.sass'
import sassModule from './imported.module.sass'

document
.querySelector('.imported-sass-module')
.classList.add(sassModule['imported-sass-module'])

import './imported.less'

import './imported.styl'
</script>

<iframe src=\\"virtual.html\\"></iframe>
",
],
"version": 3,
}
`)
})

test('linked css', async () => {
const res = await page.request.get(
new URL('./linked.css', page.url()).href,
Expand Down
12 changes: 11 additions & 1 deletion 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')
Expand Down Expand Up @@ -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')
Expand Down
Binary file added packages/playground/hmr/icon.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
9 changes: 9 additions & 0 deletions packages/playground/hmr/index.html
@@ -1,5 +1,13 @@
<link id="global-css" rel="stylesheet" href="./global.css?param=required" />
<script type="module" src="./hmr.ts"></script>
<style>
.import-image {
width: 30px;
height: 30px;
background: url('./icon.png') no-repeat;
background-size: contain;
}
</style>

<div class="app"></div>
<div class="dep"></div>
Expand All @@ -8,3 +16,4 @@
<div class="custom-communication"></div>
<div class="css-prev"></div>
<div class="css-post"></div>
<div class="import-image"></div>
5 changes: 5 additions & 0 deletions packages/playground/ssr-html/index.html
Expand Up @@ -4,6 +4,11 @@
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>SSR HTML</title>
<style>
body {
background-color: white;
}
</style>
</head>
<body>
<h1>SSR Dynamic HTML</h1>
Expand Down
2 changes: 1 addition & 1 deletion packages/playground/testUtils.ts
Expand Up @@ -63,7 +63,7 @@ function rgbToHex(rgb: string): string {
}
}

const timeout = (n: number) => new Promise((r) => setTimeout(r, n))
export const timeout = (n: number) => new Promise((r) => setTimeout(r, n))
poyoho marked this conversation as resolved.
Show resolved Hide resolved

async function toEl(el: string | ElementHandle): Promise<ElementHandle> {
if (typeof el === 'string') {
Expand Down
31 changes: 27 additions & 4 deletions packages/vite/src/node/plugins/css.ts
Expand Up @@ -21,6 +21,7 @@ import type {
ExistingRawSourceMap,
NormalizedOutputOptions,
OutputChunk,
PluginContext,
RenderedChunk,
RollupError,
SourceMapInput
Expand Down Expand Up @@ -300,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 })

Expand All @@ -311,7 +313,7 @@ export function cssPostPlugin(config: ResolvedConfig): Plugin {
if (options?.ssr) {
return modulesCode || `export default ${JSON.stringify(css)}`
}
if (inlined) {
if (inlined || isHTMLProxy) {
return `export default ${JSON.stringify(css)}`
}

Expand Down Expand Up @@ -346,7 +348,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)}`,
Expand Down Expand Up @@ -614,6 +615,29 @@ function getCssResolversKeys(
return Object.keys(resolvers) as unknown as Array<keyof CSSAtImportResolvers>
}

export function createCSSCompiler(config: ResolvedConfig, ctx: PluginContext) {
const resolveUrl = config.createResolver({
preferRelative: true,
tryIndex: false,
extensions: []
})
const atImportResolvers = createCSSResolvers(config)

const urlReplacer: CssUrlReplacer = async (url, importer) => {
if (checkPublicFile(url, config)) {
return config.base + url.slice(1)
}
const resolved = await resolveUrl(url, importer)
if (resolved) {
return fileToUrl(resolved, config, ctx)
}
return url
}

return (id: string, code: string) =>
compileCSS(id, code, config, urlReplacer, atImportResolvers)
}

async function compileCSS(
id: string,
code: string,
Expand Down Expand Up @@ -717,12 +741,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
}

Expand Down
40 changes: 32 additions & 8 deletions packages/vite/src/node/server/middlewares/indexHtml.ts
Expand Up @@ -18,12 +18,18 @@ import { send } from '../send'
import { CLIENT_PUBLIC_PATH, FS_PREFIX } from '../../constants'
import { cleanUrl, fsPathFromId, normalizePath, injectQuery } from '../../utils'
import type { ModuleGraph } from '../moduleGraph'
import { createCSSCompiler } from '../../plugins/css'

interface AssetNode {
start: number
end: number
code: string
}

export function createDevHtmlTransformFn(
server: ViteDevServer
): (url: string, html: string, originalUrl: string) => Promise<string> {
const [preHooks, postHooks] = resolveHtmlTransforms(server.config.plugins)

return (url: string, html: string, originalUrl: string): Promise<string> => {
return applyHtmlTransforms(html, [...preHooks, devHtmlHook, ...postHooks], {
path: url,
Expand Down Expand Up @@ -94,12 +100,15 @@ const devHtmlHook: IndexHtmlTransformHook = async (
html,
{ path: htmlPath, filename, server, originalUrl }
) => {
// css compile need to emitFile in build mode, and serve mode is not need.
const compileCSS = createCSSCompiler(server!.config, null as any)
const { config, moduleGraph } = 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') => {
inlineModuleIndex++
Expand Down Expand Up @@ -128,13 +137,17 @@ const devHtmlHook: IndexHtmlTransformHook = async (
if (module) {
server?.moduleGraph.invalidateModule(module)
}

s.overwrite(
node.loc.start.offset,
node.loc.end.offset,
`<script type="module" src="${modulePath}"></script>`,
{ contentOnly: true }
)
if (ext === 'js') {
s.overwrite(
node.loc.start.offset,
node.loc.end.offset,
`<script type="module" src="${modulePath}"></script>`,
{ contentOnly: true }
)
} else if (ext === 'css') {
// just use the style update hmr don't render css
s.append(`<script type="module" src="${modulePath}"></script>`)
}
poyoho marked this conversation as resolved.
Show resolved Hide resolved
}

await traverseHtml(html, htmlPath, (node) => {
Expand All @@ -154,6 +167,12 @@ const devHtmlHook: IndexHtmlTransformHook = async (
}

if (node.tag === 'style' && node.children.length) {
const children = node.children[0] as TextNode
styleUrl.push({
start: children.loc.start.offset,
end: children.loc.end.offset,
code: children.content
})
addInlineModule(node, 'css')
}

Expand All @@ -172,6 +191,11 @@ const devHtmlHook: IndexHtmlTransformHook = async (
}
})

for (const { start, end, code } of styleUrl) {
const compliedCode = await compileCSS(filename + '.css', code)
s.overwrite(start, end, compliedCode.code)
}

html = s.toString()

return {
Expand Down