fix(vite): emit assets referenced in inline css (#21790)

This commit is contained in:
Daniel Roe 2023-06-26 13:11:12 +01:00 committed by GitHub
parent 58e75689d8
commit 12403d160f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 26 additions and 13 deletions

View File

@ -41,15 +41,13 @@ export function ssrStylesPlugin (options: SSRStylePluginOptions): Plugin {
resolveId: { resolveId: {
order: 'pre', order: 'pre',
async handler (id, importer, _options) { async handler (id, importer, _options) {
// We deliberately prevent importing `#build/css` to avoid including it in the client bundle // We want to remove side effects (namely, emitting CSS) from `.vue` files and explicitly imported `.css` files
// in its entirety. We will instead include _just_ the styles that can't be inlined, // but only as long as we are going to inline that CSS.
// in the <NuxtRoot> component below if ((options.shouldInline === false || (typeof options.shouldInline === 'function' && !options.shouldInline(importer)))) {
if (options.mode === 'client' && id === '#build/css' && (options.shouldInline === true || (typeof options.shouldInline === 'function' && options.shouldInline(importer)))) { return
return this.resolve('unenv/runtime/mock/empty', importer, _options)
} }
if (options.mode === 'client' || !id.endsWith('.vue')) { return } if (id === '#build/css' || id.endsWith('.vue') || isCSS(id)) {
const res = await this.resolve(id, importer, { ..._options, skipSelf: true }) const res = await this.resolve(id, importer, { ..._options, skipSelf: true })
if (res) { if (res) {
return { return {
@ -58,6 +56,7 @@ export function ssrStylesPlugin (options: SSRStylePluginOptions): Plugin {
} }
} }
} }
}
}, },
generateBundle (outputOptions) { generateBundle (outputOptions) {
if (options.mode === 'client') { return } if (options.mode === 'client') { return }

View File

@ -1180,6 +1180,13 @@ describe.skipIf(isDev() || isWebpack)('inlining component styles', () => {
} }
}) })
it('should emit assets referenced in inlined CSS', async () => {
// @ts-expect-error ssssh! untyped secret property
const publicDir = useTestContext().nuxt._nitro.options.output.publicDir
const files = await readdir(join(publicDir, '_nuxt')).catch(() => [])
expect(files.map(m => m.replace(/\.\w+(\.\w+)$/, '$1'))).toContain('css-only-asset.svg')
})
it('should not include inlined CSS in generated CSS file', async () => { it('should not include inlined CSS in generated CSS file', async () => {
const html: string = await $fetch('/styles') const html: string = await $fetch('/styles')
const cssFiles = new Set([...html.matchAll(/<link [^>]*href="([^"]*\.css)">/g)].map(m => m[1])) const cssFiles = new Set([...html.matchAll(/<link [^>]*href="([^"]*\.css)">/g)].map(m => m[1]))

View File

@ -0,0 +1,7 @@
<svg viewBox="0 0 221 65" fill="none" xmlns="http://www.w3.org/2000/svg" class="h-8">
<defs>
<clipPath id="a">
<path fill="#fff" d="M0 0h221v65H0z"></path>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 201 B

View File

@ -1,4 +1,4 @@
:root { :root {
--global: 'global'; --global: 'global';
--asset: url('~/assets/logo.svg'); --asset: url('~/assets/css-only-asset.svg');
} }