Imported scoped CSS
+PostCSS nesting plugin: this should be pink
diff --git a/playground/css/main.js b/playground/css/main.js index d3e97a7d2525e9..aab2b499ec01b6 100644 --- a/playground/css/main.js +++ b/playground/css/main.js @@ -14,6 +14,9 @@ appendLinkStylesheet(urlCss) import rawCss from './raw-imported.css?raw' text('.raw-imported-css', rawCss) +import { cUsed, a as treeshakeScopedA } from './treeshake-scoped/index.js' +document.querySelector('.scoped').classList.add(treeshakeScopedA(), cUsed()) + import mod from './mod.module.css' document.querySelector('.modules').classList.add(mod['apply-color']) text('.modules-code', JSON.stringify(mod, null, 2)) diff --git a/playground/css/treeshake-scoped/a-scoped.css b/playground/css/treeshake-scoped/a-scoped.css new file mode 100644 index 00000000000000..e18cbb887f4637 --- /dev/null +++ b/playground/css/treeshake-scoped/a-scoped.css @@ -0,0 +1,3 @@ +.treeshake-scoped-a { + color: red; +} diff --git a/playground/css/treeshake-scoped/a.js b/playground/css/treeshake-scoped/a.js new file mode 100644 index 00000000000000..819b7d3cf84e1d --- /dev/null +++ b/playground/css/treeshake-scoped/a.js @@ -0,0 +1,5 @@ +import './a-scoped.css' // should be treeshaken away if `a` is not used + +export default function a() { + return 'treeshake-scoped-a' +} diff --git a/playground/css/treeshake-scoped/another.html b/playground/css/treeshake-scoped/another.html new file mode 100644 index 00000000000000..9500963ec7abee --- /dev/null +++ b/playground/css/treeshake-scoped/another.html @@ -0,0 +1,7 @@ +Imported scoped CSS
+ + diff --git a/playground/css/treeshake-scoped/b-scoped.css b/playground/css/treeshake-scoped/b-scoped.css new file mode 100644 index 00000000000000..9792a332519a81 --- /dev/null +++ b/playground/css/treeshake-scoped/b-scoped.css @@ -0,0 +1,3 @@ +.treeshake-scoped-b { + color: red; +} diff --git a/playground/css/treeshake-scoped/b.js b/playground/css/treeshake-scoped/b.js new file mode 100644 index 00000000000000..798ec76741c429 --- /dev/null +++ b/playground/css/treeshake-scoped/b.js @@ -0,0 +1,5 @@ +import './b-scoped.css' // should be treeshaken away if `b` is not used + +export default function b() { + return 'treeshake-scoped-b' +} diff --git a/playground/css/treeshake-scoped/barrel/a-scoped.css b/playground/css/treeshake-scoped/barrel/a-scoped.css new file mode 100644 index 00000000000000..4c63425a3083ed --- /dev/null +++ b/playground/css/treeshake-scoped/barrel/a-scoped.css @@ -0,0 +1,4 @@ +.treeshake-scoped-barrel-a { + text-decoration-line: underline; + text-decoration-color: red; +} diff --git a/playground/css/treeshake-scoped/barrel/a.js b/playground/css/treeshake-scoped/barrel/a.js new file mode 100644 index 00000000000000..11e780a7fa917e --- /dev/null +++ b/playground/css/treeshake-scoped/barrel/a.js @@ -0,0 +1,5 @@ +import './a-scoped.css' + +export function a() { + return 'treeshake-scoped-barrel-a' +} diff --git a/playground/css/treeshake-scoped/barrel/b-scoped.css b/playground/css/treeshake-scoped/barrel/b-scoped.css new file mode 100644 index 00000000000000..2a7c35d0650e45 --- /dev/null +++ b/playground/css/treeshake-scoped/barrel/b-scoped.css @@ -0,0 +1,4 @@ +.treeshake-scoped-barrel-b { + text-decoration-line: underline; + text-decoration-color: red; +} diff --git a/playground/css/treeshake-scoped/barrel/b.js b/playground/css/treeshake-scoped/barrel/b.js new file mode 100644 index 00000000000000..ac023513c3de8a --- /dev/null +++ b/playground/css/treeshake-scoped/barrel/b.js @@ -0,0 +1,5 @@ +import './b-scoped.css' + +export function b() { + return 'treeshake-scoped-barrel-b' +} diff --git a/playground/css/treeshake-scoped/barrel/index.js b/playground/css/treeshake-scoped/barrel/index.js new file mode 100644 index 00000000000000..630314aa27d554 --- /dev/null +++ b/playground/css/treeshake-scoped/barrel/index.js @@ -0,0 +1,2 @@ +export * from './a' +export * from './b' diff --git a/playground/css/treeshake-scoped/c-scoped.css b/playground/css/treeshake-scoped/c-scoped.css new file mode 100644 index 00000000000000..8901f7303dc9d6 --- /dev/null +++ b/playground/css/treeshake-scoped/c-scoped.css @@ -0,0 +1,3 @@ +.treeshake-scoped-c { + color: red; +} diff --git a/playground/css/treeshake-scoped/c.js b/playground/css/treeshake-scoped/c.js new file mode 100644 index 00000000000000..8a7e2fb89dbaa2 --- /dev/null +++ b/playground/css/treeshake-scoped/c.js @@ -0,0 +1,10 @@ +import './c-scoped.css' // should be treeshaken away if `b` is not used + +export default function c() { + return 'treeshake-scoped-c' +} + +export function cUsed() { + // used but does not depend on scoped css + return 'c-used' +} diff --git a/playground/css/treeshake-scoped/d-scoped.css b/playground/css/treeshake-scoped/d-scoped.css new file mode 100644 index 00000000000000..83c0b0ed176271 --- /dev/null +++ b/playground/css/treeshake-scoped/d-scoped.css @@ -0,0 +1,3 @@ +.treeshake-scoped-d { + color: red; +} diff --git a/playground/css/treeshake-scoped/d.js b/playground/css/treeshake-scoped/d.js new file mode 100644 index 00000000000000..7581688476cf56 --- /dev/null +++ b/playground/css/treeshake-scoped/d.js @@ -0,0 +1,5 @@ +import './d-scoped.css' // should be treeshaken away if `d` is not used + +export default function d() { + return 'treeshake-scoped-d' +} diff --git a/playground/css/treeshake-scoped/index.html b/playground/css/treeshake-scoped/index.html new file mode 100644 index 00000000000000..1e3ca61c50fc8e --- /dev/null +++ b/playground/css/treeshake-scoped/index.html @@ -0,0 +1,8 @@ +Imported scoped CSS
+ + diff --git a/playground/css/treeshake-scoped/index.js b/playground/css/treeshake-scoped/index.js new file mode 100644 index 00000000000000..93bea696056968 --- /dev/null +++ b/playground/css/treeshake-scoped/index.js @@ -0,0 +1,4 @@ +export { default as a } from './a.js' +export { default as b } from './b.js' +export { default as c, cUsed } from './c.js' +export { default as d } from './d.js' diff --git a/playground/css/vite.config.js b/playground/css/vite.config.js index 115db67dcaaa53..17cba9b54e3de2 100644 --- a/playground/css/vite.config.js +++ b/playground/css/vite.config.js @@ -11,9 +11,46 @@ globalThis.window = {} globalThis.location = new URL('http://localhost/') export default defineConfig({ + plugins: [ + { + // Emulate a UI framework component where a framework module would import + // scoped CSS files that should treeshake if the default export is not used. + name: 'treeshake-scoped-css', + enforce: 'pre', + async resolveId(id, importer) { + if (!importer || !id.endsWith('-scoped.css')) return + + const resolved = await this.resolve(id, importer) + if (!resolved) return + + return { + ...resolved, + meta: { + vite: { + cssScopeTo: [ + importer, + resolved.id.includes('barrel') ? undefined : 'default', + ], + }, + }, + } + }, + }, + ], build: { cssTarget: 'chrome61', rollupOptions: { + input: { + index: path.resolve(__dirname, './index.html'), + treeshakeScoped: path.resolve( + __dirname, + './treeshake-scoped/index.html', + ), + treeshakeScopedAnother: path.resolve( + __dirname, + './treeshake-scoped/another.html', + ), + }, output: { manualChunks(id) { if (id.includes('manual-chunk.css')) {