From c44660252914f2d2a0721cfa68c345f0a435d55b Mon Sep 17 00:00:00 2001 From: Daniel Roe Date: Sun, 28 Jan 2024 21:25:42 +0000 Subject: [PATCH] fix(vite): extract styles for shared chunks (#25455) --- packages/vite/src/plugins/ssr-styles.ts | 40 +++++++++++-------- packages/vite/src/utils/index.ts | 2 + test/basic.test.ts | 15 +++++-- .../components/ServerOnlyComponent.server.vue | 1 + .../components/ServerOnlyComponentChild.vue | 11 +++++ .../basic/components/SharedComponent.vue | 9 +++++ test/fixtures/basic/pages/styles.vue | 1 + test/fixtures/basic/pages/vueuse-head.vue | 2 + 8 files changed, 60 insertions(+), 21 deletions(-) create mode 100644 test/fixtures/basic/components/ServerOnlyComponentChild.vue create mode 100644 test/fixtures/basic/components/SharedComponent.vue diff --git a/packages/vite/src/plugins/ssr-styles.ts b/packages/vite/src/plugins/ssr-styles.ts index cb779f689b..46a6e5345f 100644 --- a/packages/vite/src/plugins/ssr-styles.ts +++ b/packages/vite/src/plugins/ssr-styles.ts @@ -8,7 +8,7 @@ import type { Component } from '@nuxt/schema' import MagicString from 'magic-string' import { findStaticImports } from 'mlly' -import { isCSS } from '../utils' +import { isCSS, isVue } from '../utils' interface SSRStylePluginOptions { srcDir: string @@ -107,25 +107,31 @@ export function ssrStylesPlugin (options: SSRStylePluginOptions): Plugin { }) }, renderChunk (_code, chunk) { - if (!chunk.facadeModuleId) { return null } - - // 'Teleport' CSS chunks that made it into the bundle on the client side - // to be inlined on server rendering - if (options.mode === 'client') { - options.clientCSSMap[chunk.facadeModuleId] ||= new Set() - for (const id of chunk.moduleIds) { - if (isCSS(id)) { - options.clientCSSMap[chunk.facadeModuleId].add(id) - } - } - return + const isEntry = chunk.facadeModuleId === options.entry + if (isEntry) { + options.clientCSSMap[chunk.facadeModuleId!] ||= new Set() } + for (const moduleId of [chunk.facadeModuleId, ...chunk.moduleIds].filter(Boolean) as string[]) { + // 'Teleport' CSS chunks that made it into the bundle on the client side + // to be inlined on server rendering + if (options.mode === 'client') { + options.clientCSSMap[moduleId] ||= new Set() + if (isCSS(moduleId)) { + // Vue files can (also) be their own entrypoints as they are tracked separately + if (isVue(moduleId)) { + options.clientCSSMap[moduleId].add(moduleId) + } + // This is required to track CSS in entry chunk + if (isEntry) { + options.clientCSSMap[chunk.facadeModuleId!].add(moduleId) + } + } + continue + } - const id = relativeToSrcDir(chunk.facadeModuleId) - for (const file in chunk.modules) { - const relativePath = relativeToSrcDir(file) + const relativePath = relativeToSrcDir(moduleId) if (relativePath in cssMap) { - cssMap[relativePath].inBundle = cssMap[relativePath].inBundle ?? !!id + cssMap[relativePath].inBundle = cssMap[relativePath].inBundle ?? ((isVue(moduleId) && relativeToSrcDir(moduleId)) || isEntry) } } diff --git a/packages/vite/src/utils/index.ts b/packages/vite/src/utils/index.ts index 7ef4bdf192..ef1262cffb 100644 --- a/packages/vite/src/utils/index.ts +++ b/packages/vite/src/utils/index.ts @@ -1,5 +1,7 @@ import { hash } from 'ohash' +export { isVue } from '../../../nuxt/src/core/utils/plugins' + export function uniq (arr: T[]): T[] { return Array.from(new Set(arr)) } diff --git a/test/basic.test.ts b/test/basic.test.ts index 44f7045564..fc6dd4d9f5 100644 --- a/test/basic.test.ts +++ b/test/basic.test.ts @@ -112,7 +112,7 @@ describe('pages', () => { // should apply attributes to client-only components expect(html).toContain('
') // should render server-only components - expect(html.replace(/ data-island-uid="[^"]*"/, '')).toContain('
server-only component
') + expect(html.replace(/ data-island-uid="[^"]*"/, '')).toContain('
server-only component
server-only component child (non-server-only)
') // should register global components automatically expect(html).toContain('global component registered automatically') expect(html).toContain('global component via suffix') @@ -1382,6 +1382,8 @@ describe.skipIf(isDev() || isWebpack)('inlining component styles', () => { '{--assets:"assets"}', //