Skip to content

Commit 333094f

Browse files
sapphi-rededison1105
andauthoredMar 17, 2025··
feat(css): tree shake scoped styles (#533)
Co-authored-by: edison <daiwei521@126.com>
1 parent 906cebb commit 333094f

File tree

8 files changed

+47
-9
lines changed

8 files changed

+47
-9
lines changed
 

‎packages/plugin-vue/src/index.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import { version } from '../package.json'
1313
import { resolveCompiler } from './compiler'
1414
import { parseVueRequest } from './utils/query'
1515
import {
16+
type ExtendedSFCDescriptor,
1617
getDescriptor,
1718
getSrcDescriptor,
1819
getTempSrcDescriptor,
@@ -412,7 +413,7 @@ export default function vuePlugin(rawOptions: Options = {}): Plugin<Api> {
412413
)
413414
} else {
414415
// sub block request
415-
const descriptor = query.src
416+
const descriptor: ExtendedSFCDescriptor = query.src
416417
? getSrcDescriptor(filename, query) ||
417418
getTempSrcDescriptor(filename, query)
418419
: getDescriptor(filename, options.value)!

‎packages/plugin-vue/src/main.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -275,9 +275,9 @@ export async function transformMain(
275275

276276
return {
277277
code: resolvedCode,
278-
map: resolvedMap || {
278+
map: (resolvedMap || {
279279
mappings: '',
280-
},
280+
}) as any,
281281
meta: {
282282
vite: {
283283
lang: descriptor.script?.lang || descriptor.scriptSetup?.lang || 'js',

‎packages/plugin-vue/src/style.ts

+10-2
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
1-
import type { SFCDescriptor } from 'vue/compiler-sfc'
21
import type { ExistingRawSourceMap, TransformPluginContext } from 'rollup'
32
import type { RawSourceMap } from 'source-map-js'
43
import { formatPostcssSourceMap } from 'vite'
4+
import type { ExtendedSFCDescriptor } from './utils/descriptorCache'
55
import type { ResolvedOptions } from './index'
66

77
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
88
export async function transformStyle(
99
code: string,
10-
descriptor: SFCDescriptor,
10+
descriptor: ExtendedSFCDescriptor,
1111
index: number,
1212
options: ResolvedOptions,
1313
pluginContext: TransformPluginContext,
@@ -62,5 +62,13 @@ export async function transformStyle(
6262
return {
6363
code: result.code,
6464
map: map,
65+
meta:
66+
block.scoped && !descriptor.isTemp
67+
? {
68+
vite: {
69+
cssScopeTo: [descriptor.filename, 'default'],
70+
},
71+
}
72+
: undefined,
6573
}
6674
}

‎packages/plugin-vue/src/utils/descriptorCache.ts

+8-3
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,10 @@ export function invalidateDescriptor(filename: string, hmr = false): void {
7575
}
7676
}
7777

78+
export interface ExtendedSFCDescriptor extends SFCDescriptor {
79+
isTemp?: boolean
80+
}
81+
7882
export function getDescriptor(
7983
filename: string,
8084
options: ResolvedOptions,
@@ -113,7 +117,7 @@ export function getSrcDescriptor(
113117
export function getTempSrcDescriptor(
114118
filename: string,
115119
query: VueQuery,
116-
): SFCDescriptor {
120+
): ExtendedSFCDescriptor {
117121
// this is only used for pre-compiled <style src> with scoped flag
118122
return {
119123
filename,
@@ -124,9 +128,10 @@ export function getTempSrcDescriptor(
124128
loc: {
125129
start: { line: 0, column: 0 },
126130
},
127-
},
131+
} as any,
128132
],
129-
} as SFCDescriptor
133+
isTemp: true,
134+
} as ExtendedSFCDescriptor
130135
}
131136

132137
export function setSrcDescriptor(

‎playground/ssr-vue/vite.config.js

+3-1
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,9 @@ export default defineConfig(({ command, ssrBuild, isSsrBuild }) => ({
9393
) {
9494
return {
9595
code:
96-
`import { __ssr_vue_processAssetPath } from '${virtualId}';__ssr_vue_processAssetPath;` +
96+
`import { __ssr_vue_processAssetPath } from '${virtualId}';` +
97+
// make `__ssr_vue_processAssetPath` not to be tree-shaken (`globalThis.__ssr_vue` doesn't exist)
98+
`globalThis.__ssr_vue?.(__ssr_vue_processAssetPath);` +
9799
code,
98100
sourcemap: null, // no sourcemap support to speed up CI
99101
}

‎playground/vue/Main.vue

+7
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,13 @@ import PreCompiledExternalScoped from './pre-compiled/external-scoped.vue'
6868
import PreCompiledExternalCssModules from './pre-compiled/external-cssmodules.vue'
6969
import ParserOptions from './ParserOptions.vue'
7070
import HmrCircularReference from './HmrCircularReference.vue'
71+
import TreeShakeScopedStyle from './TreeShakeScopedStyle.vue'
72+
73+
// NOTE: this function is not used intentionally
74+
function foo() {
75+
console.log(TreeShakeScopedStyle)
76+
}
77+
7178
import ExportTypeProps1 from './ExportTypeProps1.vue'
7279
import ExportTypeProps2 from './ExportTypeProps2.vue'
7380
+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<template>
2+
<div>tree shake scoped style</div>
3+
</template>
4+
5+
<style scoped>
6+
.tree-shake-scoped-style {
7+
color: red;
8+
}
9+
</style>

‎playground/vue/__tests__/vue.spec.ts

+6
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { version } from 'vue'
33
import {
44
browserLogs,
55
editFile,
6+
findAssetFile,
67
getBg,
78
getColor,
89
isBuild,
@@ -455,3 +456,8 @@ describe('template parse options', () => {
455456
)
456457
})
457458
})
459+
460+
test.runIf(isBuild)('scoped style should be tree-shakeable', async () => {
461+
const indexCss = findAssetFile(/index-[\w-]+\.css/)
462+
expect(indexCss).not.toContain('.tree-shake-scoped-style')
463+
})

0 commit comments

Comments
 (0)
Please sign in to comment.