From fbacb7129f9f17215e6b80597e6450330de399aa Mon Sep 17 00:00:00 2001 From: Devon Govett Date: Sat, 21 May 2022 17:54:52 -0400 Subject: [PATCH 1/6] Opt-in support for renaming and removing unused CSS variables --- .../integration-tests/test/css-modules.js | 26 ++++++++++++---- .../integration/css-modules-vars/index.js | 4 +++ .../css-modules-vars/index.module.css | 3 ++ .../integration/css-modules-vars/package.json | 7 +++++ .../css-modules-vars/vars.module.css | 10 +++++++ .../integration/css-modules-vars/yarn.lock | 0 packages/packagers/css/src/CSSPackager.js | 30 ++++++++++++++----- .../transformers/css/src/CSSTransformer.js | 28 +++++++++++++---- 8 files changed, 89 insertions(+), 19 deletions(-) create mode 100644 packages/core/integration-tests/test/integration/css-modules-vars/index.js create mode 100644 packages/core/integration-tests/test/integration/css-modules-vars/index.module.css create mode 100644 packages/core/integration-tests/test/integration/css-modules-vars/package.json create mode 100644 packages/core/integration-tests/test/integration/css-modules-vars/vars.module.css create mode 100644 packages/core/integration-tests/test/integration/css-modules-vars/yarn.lock diff --git a/packages/core/integration-tests/test/css-modules.js b/packages/core/integration-tests/test/css-modules.js index 26ace5c1642..184137a3023 100644 --- a/packages/core/integration-tests/test/css-modules.js +++ b/packages/core/integration-tests/test/css-modules.js @@ -45,7 +45,7 @@ describe('css modules', () => { __dirname, '/integration/postcss-modules-import-default/index.js', ), - {mode: 'production'}, + { mode: 'production' }, ); assertBundles(b, [ @@ -80,7 +80,7 @@ describe('css modules', () => { __dirname, '/integration/postcss-modules-import-namespace/index.js', ), - {mode: 'production'}, + { mode: 'production' }, ); assertBundles(b, [ @@ -142,7 +142,7 @@ describe('css modules', () => { }, ]); - let {output} = await run(b, null, {require: false}); + let { output } = await run(b, null, { require: false }); assert(/[_0-9a-zA-Z]+_b-2/.test(output)); let css = await outputFS.readFile( @@ -164,7 +164,7 @@ describe('css modules', () => { __dirname, '/integration/postcss-modules-import-namespace-whole/index.js', ), - {mode: 'production'}, + { mode: 'production' }, ); assertBundles(b, [ @@ -467,7 +467,7 @@ describe('css modules', () => { ]); let res = await run(b); - assert.deepEqual(res, {color: 'red'}); + assert.deepEqual(res, { color: 'red' }); }); it('should optimize away unused @keyframes', async function () { @@ -552,7 +552,7 @@ describe('css modules', () => { path.join(__dirname, '/integration/css-modules-import/page1.html'), path.join(__dirname, '/integration/css-modules-import/page2.html'), ], - {mode: 'production'}, + { mode: 'production' }, ); let res = []; @@ -621,4 +621,18 @@ describe('css modules', () => { ); assert(contents.includes('.index {')); }); + + it.only('should optimize away unused variables when dashedIdents option is used', async function () { + let b = await bundle( + path.join(__dirname, '/integration/css-modules-vars/index.js'), + { mode: 'production' } + ); + let contents = await outputFS.readFile( + b.getBundles().find(b => b.type === 'css').filePath, + 'utf8', + ); + console.log(contents) + let res = await run(b); + console.log(res) + }); }); diff --git a/packages/core/integration-tests/test/integration/css-modules-vars/index.js b/packages/core/integration-tests/test/integration/css-modules-vars/index.js new file mode 100644 index 00000000000..779f1867c39 --- /dev/null +++ b/packages/core/integration-tests/test/integration/css-modules-vars/index.js @@ -0,0 +1,4 @@ +var foo = require('./index.module.css'); +var vars = require('./vars.module.css'); + +output = [foo.foo, vars['--from-js']]; diff --git a/packages/core/integration-tests/test/integration/css-modules-vars/index.module.css b/packages/core/integration-tests/test/integration/css-modules-vars/index.module.css new file mode 100644 index 00000000000..6218b060677 --- /dev/null +++ b/packages/core/integration-tests/test/integration/css-modules-vars/index.module.css @@ -0,0 +1,3 @@ +.foo { + color: var(--color from "./vars.module.css"); +} \ No newline at end of file diff --git a/packages/core/integration-tests/test/integration/css-modules-vars/package.json b/packages/core/integration-tests/test/integration/css-modules-vars/package.json new file mode 100644 index 00000000000..0f8b6aff7f2 --- /dev/null +++ b/packages/core/integration-tests/test/integration/css-modules-vars/package.json @@ -0,0 +1,7 @@ +{ + "@parcel/transformer-css": { + "cssModules": { + "dashedIdents": true + } + } +} \ No newline at end of file diff --git a/packages/core/integration-tests/test/integration/css-modules-vars/vars.module.css b/packages/core/integration-tests/test/integration/css-modules-vars/vars.module.css new file mode 100644 index 00000000000..700c49ee541 --- /dev/null +++ b/packages/core/integration-tests/test/integration/css-modules-vars/vars.module.css @@ -0,0 +1,10 @@ +:root { + --color: red; + --font: Helvetica; + --from-js: purple; + --unused: green; +} + +body { + font: var(--font); +} \ No newline at end of file diff --git a/packages/core/integration-tests/test/integration/css-modules-vars/yarn.lock b/packages/core/integration-tests/test/integration/css-modules-vars/yarn.lock new file mode 100644 index 00000000000..e69de29bb2d diff --git a/packages/packagers/css/src/CSSPackager.js b/packages/packagers/css/src/CSSPackager.js index ae2fbbef49b..90a751a8df3 100644 --- a/packages/packagers/css/src/CSSPackager.js +++ b/packages/packagers/css/src/CSSPackager.js @@ -1,12 +1,12 @@ // @flow -import type {Root} from 'postcss'; -import type {Asset, Dependency} from '@parcel/types'; +import type { Root } from 'postcss'; +import type { Asset, Dependency } from '@parcel/types'; import typeof PostCSS from 'postcss'; import path from 'path'; import SourceMap from '@parcel/source-map'; -import {Packager} from '@parcel/plugin'; +import { Packager } from '@parcel/plugin'; import { PromiseQueue, countLines, @@ -75,6 +75,20 @@ export default (new Packager({ return Promise.all([ asset, asset.getCode().then((css: string) => { + if (asset.meta.hasReferences) { + for (let dep of asset.getDependencies()) { + for (let [exported, { local }] of dep.symbols) { + let resolved = bundleGraph.getResolvedAsset(dep, bundle); + if (resolved) { + let resolution = bundleGraph.getSymbolResolution(resolved, exported, bundle); + if (resolution.symbol) { + css = css.replaceAll(local, resolution.symbol); + } + } + } + } + } + if (media.length) { return `@media ${media.join(', ')} {\n${css}\n}\n`; } @@ -124,7 +138,7 @@ export default (new Packager({ } } - ({contents, map} = replaceURLReferences({ + ({ contents, map } = replaceURLReferences({ bundle, bundleGraph, contents, @@ -165,7 +179,7 @@ async function processCSSModule( bundle, asset, media, -): Promise<[Asset, string, ?Buffer]> { +): Promise<[Asset, string,?Buffer]> { let postcss: PostCSS = await options.packageManager.require( 'postcss', options.projectRoot + '/index', @@ -181,7 +195,7 @@ async function processCSSModule( let usedSymbols = bundleGraph.getUsedSymbols(asset); if (usedSymbols != null) { let localSymbols = new Set( - [...asset.symbols].map(([, {local}]) => `.${local}`), + [...asset.symbols].map(([, { local }]) => `.${local}`), ); let defaultImport = null; @@ -197,7 +211,7 @@ async function processCSSModule( codeFrames: [ { filePath: nullthrows(loc?.filePath ?? defaultImport.sourcePath), - codeHighlights: [{start: loc.start, end: loc.end}], + codeHighlights: [{ start: loc.start, end: loc.end }], }, ], }), @@ -227,7 +241,7 @@ async function processCSSModule( } } - let {content, map} = await postcss().process(ast, { + let { content, map } = await postcss().process(ast, { from: undefined, to: options.projectRoot + '/index', map: { diff --git a/packages/transformers/css/src/CSSTransformer.js b/packages/transformers/css/src/CSSTransformer.js index 1917bf2b298..af474e73925 100644 --- a/packages/transformers/css/src/CSSTransformer.js +++ b/packages/transformers/css/src/CSSTransformer.js @@ -2,25 +2,25 @@ import path from 'path'; import SourceMap from '@parcel/source-map'; -import {Transformer} from '@parcel/plugin'; +import { Transformer } from '@parcel/plugin'; import { transform, transformStyleAttribute, browserslistToTargets, } from '@parcel/css'; -import {remapSourceLocation, relativePath} from '@parcel/utils'; +import { remapSourceLocation, relativePath } from '@parcel/utils'; import browserslist from 'browserslist'; import nullthrows from 'nullthrows'; -import ThrowableDiagnostic, {errorToDiagnostic} from '@parcel/diagnostic'; +import ThrowableDiagnostic, { errorToDiagnostic } from '@parcel/diagnostic'; export default (new Transformer({ - async loadConfig({config, options}) { + async loadConfig({ config, options }) { let conf = await config.getConfigFrom(options.projectRoot + '/index', [], { packageKey: '@parcel/transformer-css', }); return conf?.contents; }, - async transform({asset, config, options}) { + async transform({ asset, config, options }) { // Normalize the asset's environment so that properties that only affect JS don't cause CSS to be duplicated. // For example, with ESModule and CommonJS targets, only a single shared CSS bundle should be produced. let env = asset.env; @@ -212,6 +212,24 @@ export default (new Transformer({ } } + if (res.references != null) { + let references = res.references; + for (let symbol in references) { + let reference = references[symbol]; + asset.addDependency({ + specifier: reference.specifier, + specifierType: 'esm', + symbols: new Map([ + [reference.name, { local: symbol, isWeak: false, loc: null }] + ]) + }); + + asset.meta.hasReferences = true; + } + } + + console.log(depjs + js) + assets.push({ type: 'js', content: depjs + js, From 7792d021c91b3fe4873cf276fd3d070a39e68b44 Mon Sep 17 00:00:00 2001 From: Devon Govett Date: Sun, 22 May 2022 00:06:40 -0400 Subject: [PATCH 2/6] More tests, fix escaping --- .../integration-tests/test/css-modules.js | 23 ++++--- .../css-modules-vars/index.module.css | 2 + .../css-modules-vars/vars.module.css | 1 + packages/packagers/css/src/CSSPackager.js | 64 +++++++++++++++---- .../transformers/css/src/CSSTransformer.js | 16 ++--- 5 files changed, 78 insertions(+), 28 deletions(-) diff --git a/packages/core/integration-tests/test/css-modules.js b/packages/core/integration-tests/test/css-modules.js index 184137a3023..65001ae23c6 100644 --- a/packages/core/integration-tests/test/css-modules.js +++ b/packages/core/integration-tests/test/css-modules.js @@ -45,7 +45,7 @@ describe('css modules', () => { __dirname, '/integration/postcss-modules-import-default/index.js', ), - { mode: 'production' }, + {mode: 'production'}, ); assertBundles(b, [ @@ -80,7 +80,7 @@ describe('css modules', () => { __dirname, '/integration/postcss-modules-import-namespace/index.js', ), - { mode: 'production' }, + {mode: 'production'}, ); assertBundles(b, [ @@ -142,7 +142,7 @@ describe('css modules', () => { }, ]); - let { output } = await run(b, null, { require: false }); + let {output} = await run(b, null, {require: false}); assert(/[_0-9a-zA-Z]+_b-2/.test(output)); let css = await outputFS.readFile( @@ -164,7 +164,7 @@ describe('css modules', () => { __dirname, '/integration/postcss-modules-import-namespace-whole/index.js', ), - { mode: 'production' }, + {mode: 'production'}, ); assertBundles(b, [ @@ -467,7 +467,7 @@ describe('css modules', () => { ]); let res = await run(b); - assert.deepEqual(res, { color: 'red' }); + assert.deepEqual(res, {color: 'red'}); }); it('should optimize away unused @keyframes', async function () { @@ -552,7 +552,7 @@ describe('css modules', () => { path.join(__dirname, '/integration/css-modules-import/page1.html'), path.join(__dirname, '/integration/css-modules-import/page2.html'), ], - { mode: 'production' }, + {mode: 'production'}, ); let res = []; @@ -625,14 +625,19 @@ describe('css modules', () => { it.only('should optimize away unused variables when dashedIdents option is used', async function () { let b = await bundle( path.join(__dirname, '/integration/css-modules-vars/index.js'), - { mode: 'production' } + {mode: 'production'}, ); let contents = await outputFS.readFile( b.getBundles().find(b => b.type === 'css').filePath, 'utf8', ); - console.log(contents) + console.log(contents); + assert.equal( + contents.split('\n')[0], + ':root{--wGsoEa_color:red;--wGsoEa_font:Helvetica;--wGsoEa_theme-sizes-1\\/12:2;--wGsoEa_from-js:purple}body{font:var(--wGsoEa_font)}._4fY2uG_foo{color:var(--wGsoEa_color);width:var(--wGsoEa_theme-sizes-1\\/12);height:var(--height)}', + ); let res = await run(b); - console.log(res) + console.log('HJI', res); + assert.deepEqual(res, ['_4fY2uG_foo', '--wGsoEa_from-js']); }); }); diff --git a/packages/core/integration-tests/test/integration/css-modules-vars/index.module.css b/packages/core/integration-tests/test/integration/css-modules-vars/index.module.css index 6218b060677..f5c58018001 100644 --- a/packages/core/integration-tests/test/integration/css-modules-vars/index.module.css +++ b/packages/core/integration-tests/test/integration/css-modules-vars/index.module.css @@ -1,3 +1,5 @@ .foo { color: var(--color from "./vars.module.css"); + width: var(--theme-sizes-1\/12 from "./vars.module.css"); + height: var(--height from global); } \ No newline at end of file diff --git a/packages/core/integration-tests/test/integration/css-modules-vars/vars.module.css b/packages/core/integration-tests/test/integration/css-modules-vars/vars.module.css index 700c49ee541..eda222dcca6 100644 --- a/packages/core/integration-tests/test/integration/css-modules-vars/vars.module.css +++ b/packages/core/integration-tests/test/integration/css-modules-vars/vars.module.css @@ -1,6 +1,7 @@ :root { --color: red; --font: Helvetica; + --theme-sizes-1\/12: 2; --from-js: purple; --unused: green; } diff --git a/packages/packagers/css/src/CSSPackager.js b/packages/packagers/css/src/CSSPackager.js index 90a751a8df3..6e9dfd0521a 100644 --- a/packages/packagers/css/src/CSSPackager.js +++ b/packages/packagers/css/src/CSSPackager.js @@ -1,12 +1,12 @@ // @flow -import type { Root } from 'postcss'; -import type { Asset, Dependency } from '@parcel/types'; +import type {Root} from 'postcss'; +import type {Asset, Dependency} from '@parcel/types'; import typeof PostCSS from 'postcss'; import path from 'path'; import SourceMap from '@parcel/source-map'; -import { Packager } from '@parcel/plugin'; +import {Packager} from '@parcel/plugin'; import { PromiseQueue, countLines, @@ -75,18 +75,33 @@ export default (new Packager({ return Promise.all([ asset, asset.getCode().then((css: string) => { + // Replace CSS variable references with resolved symbols. if (asset.meta.hasReferences) { + let replacements = new Map(); for (let dep of asset.getDependencies()) { - for (let [exported, { local }] of dep.symbols) { + for (let [exported, {local}] of dep.symbols) { let resolved = bundleGraph.getResolvedAsset(dep, bundle); if (resolved) { - let resolution = bundleGraph.getSymbolResolution(resolved, exported, bundle); + let resolution = bundleGraph.getSymbolResolution( + resolved, + exported, + bundle, + ); if (resolution.symbol) { - css = css.replaceAll(local, resolution.symbol); + replacements.set(local, resolution.symbol); } } } } + if (replacements.size > 0) { + let regex = new RegExp( + [...replacements.keys()].join('|'), + 'g', + ); + css = css.replace(regex, m => + escapeDashedIdent(replacements.get(m) || m), + ); + } } if (media.length) { @@ -138,7 +153,7 @@ export default (new Packager({ } } - ({ contents, map } = replaceURLReferences({ + ({contents, map} = replaceURLReferences({ bundle, bundleGraph, contents, @@ -179,7 +194,7 @@ async function processCSSModule( bundle, asset, media, -): Promise<[Asset, string,?Buffer]> { +): Promise<[Asset, string, ?Buffer]> { let postcss: PostCSS = await options.packageManager.require( 'postcss', options.projectRoot + '/index', @@ -195,7 +210,7 @@ async function processCSSModule( let usedSymbols = bundleGraph.getUsedSymbols(asset); if (usedSymbols != null) { let localSymbols = new Set( - [...asset.symbols].map(([, { local }]) => `.${local}`), + [...asset.symbols].map(([, {local}]) => `.${local}`), ); let defaultImport = null; @@ -211,7 +226,7 @@ async function processCSSModule( codeFrames: [ { filePath: nullthrows(loc?.filePath ?? defaultImport.sourcePath), - codeHighlights: [{ start: loc.start, end: loc.end }], + codeHighlights: [{start: loc.start, end: loc.end}], }, ], }), @@ -241,7 +256,7 @@ async function processCSSModule( } } - let { content, map } = await postcss().process(ast, { + let {content, map} = await postcss().process(ast, { from: undefined, to: options.projectRoot + '/index', map: { @@ -265,3 +280,30 @@ async function processCSSModule( return [asset, content, sourceMap?.toBuffer()]; } + +function escapeDashedIdent(name) { + // https://drafts.csswg.org/cssom/#serialize-an-identifier + let chunkStart = 0; + let res = ''; + for (let c of name) { + let code = c.codePointAt(0); + if (code === 0) { + res += '\ufffd'; + } else if ((code >= 0x1 && code <= 0x1f) || code === 0x7f) { + res += '\\' + code.toString(16) + ' '; + } else if ( + (code >= 48 /* '0' */ && code <= 57) /* '9' */ || + (code >= 65 /* 'A' */ && code <= 90) /* 'Z' */ || + (code >= 97 /* 'a' */ && code <= 122) /* 'z' */ || + code === 95 /* '_' */ || + code === 45 /* '-' */ || + code & 128 // non-ascii + ) { + res += c; + } else { + res += '\\' + c; + } + } + + return res; +} diff --git a/packages/transformers/css/src/CSSTransformer.js b/packages/transformers/css/src/CSSTransformer.js index af474e73925..25248f13df5 100644 --- a/packages/transformers/css/src/CSSTransformer.js +++ b/packages/transformers/css/src/CSSTransformer.js @@ -2,25 +2,25 @@ import path from 'path'; import SourceMap from '@parcel/source-map'; -import { Transformer } from '@parcel/plugin'; +import {Transformer} from '@parcel/plugin'; import { transform, transformStyleAttribute, browserslistToTargets, } from '@parcel/css'; -import { remapSourceLocation, relativePath } from '@parcel/utils'; +import {remapSourceLocation, relativePath} from '@parcel/utils'; import browserslist from 'browserslist'; import nullthrows from 'nullthrows'; -import ThrowableDiagnostic, { errorToDiagnostic } from '@parcel/diagnostic'; +import ThrowableDiagnostic, {errorToDiagnostic} from '@parcel/diagnostic'; export default (new Transformer({ - async loadConfig({ config, options }) { + async loadConfig({config, options}) { let conf = await config.getConfigFrom(options.projectRoot + '/index', [], { packageKey: '@parcel/transformer-css', }); return conf?.contents; }, - async transform({ asset, config, options }) { + async transform({asset, config, options}) { // Normalize the asset's environment so that properties that only affect JS don't cause CSS to be duplicated. // For example, with ESModule and CommonJS targets, only a single shared CSS bundle should be produced. let env = asset.env; @@ -220,15 +220,15 @@ export default (new Transformer({ specifier: reference.specifier, specifierType: 'esm', symbols: new Map([ - [reference.name, { local: symbol, isWeak: false, loc: null }] - ]) + [reference.name, {local: symbol, isWeak: false, loc: null}], + ]), }); asset.meta.hasReferences = true; } } - console.log(depjs + js) + console.log(depjs + js); assets.push({ type: 'js', From 56ed276225fcdcf8a92d0d024b6ed237ad665e7d Mon Sep 17 00:00:00 2001 From: Devon Govett Date: Sun, 22 May 2022 11:01:36 -0400 Subject: [PATCH 3/6] Support global css modules with object config --- .../integration-tests/test/css-modules.js | 22 +++++++++++++++--- .../css-modules-global/a/index.css | 3 +++ .../integration/css-modules-global/a/index.js | 3 +++ .../css-modules-global/a/package.json | 5 ++++ .../css-modules-global/a/yarn.lock | 0 .../css-modules-global/b/index.css | 3 +++ .../integration/css-modules-global/b/index.js | 3 +++ .../css-modules-global/b/package.json | 7 ++++++ .../css-modules-global/b/yarn.lock | 0 .../transformers/css/src/CSSTransformer.js | 23 +++++++++++++------ 10 files changed, 59 insertions(+), 10 deletions(-) create mode 100644 packages/core/integration-tests/test/integration/css-modules-global/a/index.css create mode 100644 packages/core/integration-tests/test/integration/css-modules-global/a/index.js create mode 100644 packages/core/integration-tests/test/integration/css-modules-global/a/package.json create mode 100644 packages/core/integration-tests/test/integration/css-modules-global/a/yarn.lock create mode 100644 packages/core/integration-tests/test/integration/css-modules-global/b/index.css create mode 100644 packages/core/integration-tests/test/integration/css-modules-global/b/index.js create mode 100644 packages/core/integration-tests/test/integration/css-modules-global/b/package.json create mode 100644 packages/core/integration-tests/test/integration/css-modules-global/b/yarn.lock diff --git a/packages/core/integration-tests/test/css-modules.js b/packages/core/integration-tests/test/css-modules.js index 65001ae23c6..d5ab4c9a405 100644 --- a/packages/core/integration-tests/test/css-modules.js +++ b/packages/core/integration-tests/test/css-modules.js @@ -622,7 +622,25 @@ describe('css modules', () => { assert(contents.includes('.index {')); }); - it.only('should optimize away unused variables when dashedIdents option is used', async function () { + it('should support global css modules via boolean config', async function () { + let b = await bundle( + path.join(__dirname, '/integration/css-modules-global/a/index.js'), + {mode: 'production'}, + ); + let res = await run(b); + assert.deepEqual(res, 'C-gzXq_foo'); + }); + + it('should support global css modules via object config', async function () { + let b = await bundle( + path.join(__dirname, '/integration/css-modules-global/b/index.js'), + {mode: 'production'}, + ); + let res = await run(b); + assert.deepEqual(res, 'C-gzXq_foo'); + }); + + it('should optimize away unused variables when dashedIdents option is used', async function () { let b = await bundle( path.join(__dirname, '/integration/css-modules-vars/index.js'), {mode: 'production'}, @@ -631,13 +649,11 @@ describe('css modules', () => { b.getBundles().find(b => b.type === 'css').filePath, 'utf8', ); - console.log(contents); assert.equal( contents.split('\n')[0], ':root{--wGsoEa_color:red;--wGsoEa_font:Helvetica;--wGsoEa_theme-sizes-1\\/12:2;--wGsoEa_from-js:purple}body{font:var(--wGsoEa_font)}._4fY2uG_foo{color:var(--wGsoEa_color);width:var(--wGsoEa_theme-sizes-1\\/12);height:var(--height)}', ); let res = await run(b); - console.log('HJI', res); assert.deepEqual(res, ['_4fY2uG_foo', '--wGsoEa_from-js']); }); }); diff --git a/packages/core/integration-tests/test/integration/css-modules-global/a/index.css b/packages/core/integration-tests/test/integration/css-modules-global/a/index.css new file mode 100644 index 00000000000..a2c2b35f533 --- /dev/null +++ b/packages/core/integration-tests/test/integration/css-modules-global/a/index.css @@ -0,0 +1,3 @@ +.foo { + color: red; +} \ No newline at end of file diff --git a/packages/core/integration-tests/test/integration/css-modules-global/a/index.js b/packages/core/integration-tests/test/integration/css-modules-global/a/index.js new file mode 100644 index 00000000000..703cc0437d5 --- /dev/null +++ b/packages/core/integration-tests/test/integration/css-modules-global/a/index.js @@ -0,0 +1,3 @@ +var foo = require('./index.css'); + +output = foo.foo; diff --git a/packages/core/integration-tests/test/integration/css-modules-global/a/package.json b/packages/core/integration-tests/test/integration/css-modules-global/a/package.json new file mode 100644 index 00000000000..c12320b6d91 --- /dev/null +++ b/packages/core/integration-tests/test/integration/css-modules-global/a/package.json @@ -0,0 +1,5 @@ +{ + "@parcel/transformer-css": { + "cssModules": true + } +} \ No newline at end of file diff --git a/packages/core/integration-tests/test/integration/css-modules-global/a/yarn.lock b/packages/core/integration-tests/test/integration/css-modules-global/a/yarn.lock new file mode 100644 index 00000000000..e69de29bb2d diff --git a/packages/core/integration-tests/test/integration/css-modules-global/b/index.css b/packages/core/integration-tests/test/integration/css-modules-global/b/index.css new file mode 100644 index 00000000000..a2c2b35f533 --- /dev/null +++ b/packages/core/integration-tests/test/integration/css-modules-global/b/index.css @@ -0,0 +1,3 @@ +.foo { + color: red; +} \ No newline at end of file diff --git a/packages/core/integration-tests/test/integration/css-modules-global/b/index.js b/packages/core/integration-tests/test/integration/css-modules-global/b/index.js new file mode 100644 index 00000000000..703cc0437d5 --- /dev/null +++ b/packages/core/integration-tests/test/integration/css-modules-global/b/index.js @@ -0,0 +1,3 @@ +var foo = require('./index.css'); + +output = foo.foo; diff --git a/packages/core/integration-tests/test/integration/css-modules-global/b/package.json b/packages/core/integration-tests/test/integration/css-modules-global/b/package.json new file mode 100644 index 00000000000..ab90e8d5c06 --- /dev/null +++ b/packages/core/integration-tests/test/integration/css-modules-global/b/package.json @@ -0,0 +1,7 @@ +{ + "@parcel/transformer-css": { + "cssModules": { + "global": true + } + } +} \ No newline at end of file diff --git a/packages/core/integration-tests/test/integration/css-modules-global/b/yarn.lock b/packages/core/integration-tests/test/integration/css-modules-global/b/yarn.lock new file mode 100644 index 00000000000..e69de29bb2d diff --git a/packages/transformers/css/src/CSSTransformer.js b/packages/transformers/css/src/CSSTransformer.js index 25248f13df5..0babf4e5c9f 100644 --- a/packages/transformers/css/src/CSSTransformer.js +++ b/packages/transformers/css/src/CSSTransformer.js @@ -49,14 +49,25 @@ export default (new Transformer({ targets, }); } else { + let cssModules = false; + if ( + asset.meta.type !== 'tag' && + asset.meta.cssModulesCompiled == null + ) { + let cssModulesConfig = config?.cssModules; + if ( + typeof cssModulesConfig === 'boolean' || + cssModulesConfig?.global || + /\.module\./.test(asset.filePath) + ) { + cssModules = cssModulesConfig ?? true; + } + } + res = transform({ filename: path.relative(options.projectRoot, asset.filePath), code, - cssModules: - asset.meta.type !== 'tag' && - (config?.cssModules ?? - (asset.meta.cssModulesCompiled == null && - /\.module\./.test(asset.filePath))), + cssModules, analyzeDependencies: asset.meta.hasDependencies !== false, sourceMap: !!asset.env.sourceMap, drafts: config?.drafts, @@ -228,8 +239,6 @@ export default (new Transformer({ } } - console.log(depjs + js); - assets.push({ type: 'js', content: depjs + js, From bbd0c894e0318c97cf6034172cd104416059b630 Mon Sep 17 00:00:00 2001 From: Devon Govett Date: Sun, 22 May 2022 11:07:59 -0400 Subject: [PATCH 4/6] lint --- packages/packagers/css/src/CSSPackager.js | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/packagers/css/src/CSSPackager.js b/packages/packagers/css/src/CSSPackager.js index 6e9dfd0521a..c602e9044bf 100644 --- a/packages/packagers/css/src/CSSPackager.js +++ b/packages/packagers/css/src/CSSPackager.js @@ -283,7 +283,6 @@ async function processCSSModule( function escapeDashedIdent(name) { // https://drafts.csswg.org/cssom/#serialize-an-identifier - let chunkStart = 0; let res = ''; for (let c of name) { let code = c.codePointAt(0); From 84e1974c4b39dd8ddbd24cc157dff2b88e0e2d2c Mon Sep 17 00:00:00 2001 From: Devon Govett Date: Sun, 22 May 2022 11:42:17 -0400 Subject: [PATCH 5/6] Don't apply non-standard syntax in node_modules --- packages/core/integration-tests/test/css-modules.js | 13 +++++++++++++ .../test/integration/css-modules-global/a/index.js | 1 + .../a/node_modules/test/index.css | 3 +++ .../a/node_modules/test/package.json | 3 +++ .../test/integration/css-modules-global/b/index.js | 1 + .../b/node_modules/test/index.css | 3 +++ .../b/node_modules/test/package.json | 3 +++ packages/transformers/css/src/CSSTransformer.js | 9 +++++++-- 8 files changed, 34 insertions(+), 2 deletions(-) create mode 100644 packages/core/integration-tests/test/integration/css-modules-global/a/node_modules/test/index.css create mode 100644 packages/core/integration-tests/test/integration/css-modules-global/a/node_modules/test/package.json create mode 100644 packages/core/integration-tests/test/integration/css-modules-global/b/node_modules/test/index.css create mode 100644 packages/core/integration-tests/test/integration/css-modules-global/b/node_modules/test/package.json diff --git a/packages/core/integration-tests/test/css-modules.js b/packages/core/integration-tests/test/css-modules.js index d5ab4c9a405..ce5c73a9f1a 100644 --- a/packages/core/integration-tests/test/css-modules.js +++ b/packages/core/integration-tests/test/css-modules.js @@ -629,6 +629,13 @@ describe('css modules', () => { ); let res = await run(b); assert.deepEqual(res, 'C-gzXq_foo'); + + let contents = await outputFS.readFile( + b.getBundles().find(b => b.type === 'css').filePath, + 'utf8', + ); + assert(contents.includes('.C-gzXq_foo')); + assert(contents.includes('.x')); }); it('should support global css modules via object config', async function () { @@ -638,6 +645,12 @@ describe('css modules', () => { ); let res = await run(b); assert.deepEqual(res, 'C-gzXq_foo'); + let contents = await outputFS.readFile( + b.getBundles().find(b => b.type === 'css').filePath, + 'utf8', + ); + assert(contents.includes('.C-gzXq_foo')); + assert(contents.includes('.x')); }); it('should optimize away unused variables when dashedIdents option is used', async function () { diff --git a/packages/core/integration-tests/test/integration/css-modules-global/a/index.js b/packages/core/integration-tests/test/integration/css-modules-global/a/index.js index 703cc0437d5..916bf8772cf 100644 --- a/packages/core/integration-tests/test/integration/css-modules-global/a/index.js +++ b/packages/core/integration-tests/test/integration/css-modules-global/a/index.js @@ -1,3 +1,4 @@ var foo = require('./index.css'); +require('test/index.css'); output = foo.foo; diff --git a/packages/core/integration-tests/test/integration/css-modules-global/a/node_modules/test/index.css b/packages/core/integration-tests/test/integration/css-modules-global/a/node_modules/test/index.css new file mode 100644 index 00000000000..4f9c1a611af --- /dev/null +++ b/packages/core/integration-tests/test/integration/css-modules-global/a/node_modules/test/index.css @@ -0,0 +1,3 @@ +.x { + color: red; +} \ No newline at end of file diff --git a/packages/core/integration-tests/test/integration/css-modules-global/a/node_modules/test/package.json b/packages/core/integration-tests/test/integration/css-modules-global/a/node_modules/test/package.json new file mode 100644 index 00000000000..2f37dc5b093 --- /dev/null +++ b/packages/core/integration-tests/test/integration/css-modules-global/a/node_modules/test/package.json @@ -0,0 +1,3 @@ +{ + "name": "test" +} \ No newline at end of file diff --git a/packages/core/integration-tests/test/integration/css-modules-global/b/index.js b/packages/core/integration-tests/test/integration/css-modules-global/b/index.js index 703cc0437d5..916bf8772cf 100644 --- a/packages/core/integration-tests/test/integration/css-modules-global/b/index.js +++ b/packages/core/integration-tests/test/integration/css-modules-global/b/index.js @@ -1,3 +1,4 @@ var foo = require('./index.css'); +require('test/index.css'); output = foo.foo; diff --git a/packages/core/integration-tests/test/integration/css-modules-global/b/node_modules/test/index.css b/packages/core/integration-tests/test/integration/css-modules-global/b/node_modules/test/index.css new file mode 100644 index 00000000000..4f9c1a611af --- /dev/null +++ b/packages/core/integration-tests/test/integration/css-modules-global/b/node_modules/test/index.css @@ -0,0 +1,3 @@ +.x { + color: red; +} \ No newline at end of file diff --git a/packages/core/integration-tests/test/integration/css-modules-global/b/node_modules/test/package.json b/packages/core/integration-tests/test/integration/css-modules-global/b/node_modules/test/package.json new file mode 100644 index 00000000000..2f37dc5b093 --- /dev/null +++ b/packages/core/integration-tests/test/integration/css-modules-global/b/node_modules/test/package.json @@ -0,0 +1,3 @@ +{ + "name": "test" +} \ No newline at end of file diff --git a/packages/transformers/css/src/CSSTransformer.js b/packages/transformers/css/src/CSSTransformer.js index 0babf4e5c9f..ece80fccbf6 100644 --- a/packages/transformers/css/src/CSSTransformer.js +++ b/packages/transformers/css/src/CSSTransformer.js @@ -56,10 +56,15 @@ export default (new Transformer({ ) { let cssModulesConfig = config?.cssModules; if ( - typeof cssModulesConfig === 'boolean' || - cssModulesConfig?.global || + (asset.isSource && + (typeof cssModulesConfig === 'boolean' || + cssModulesConfig?.global)) || /\.module\./.test(asset.filePath) ) { + if (cssModulesConfig?.dashedIdents && !asset.isSource) { + cssModulesConfig.dashedIdents = false; + } + cssModules = cssModulesConfig ?? true; } } From 16b799fd138a7329e060fc2017110b35fdd96622 Mon Sep 17 00:00:00 2001 From: Devon Govett Date: Wed, 25 May 2022 00:06:44 -0400 Subject: [PATCH 6/6] Bump @parcel/css --- packages/optimizers/css/package.json | 4 +- packages/transformers/css/package.json | 4 +- yarn.lock | 88 +++++++++++++------------- 3 files changed, 48 insertions(+), 48 deletions(-) diff --git a/packages/optimizers/css/package.json b/packages/optimizers/css/package.json index 4e136b7cf84..d8a364537ab 100644 --- a/packages/optimizers/css/package.json +++ b/packages/optimizers/css/package.json @@ -20,7 +20,7 @@ "parcel": "^2.5.0" }, "dependencies": { - "@parcel/css": "^1.8.2", + "@parcel/css": "^1.9.0", "@parcel/diagnostic": "2.5.0", "@parcel/plugin": "2.5.0", "@parcel/source-map": "^2.0.0", @@ -28,4 +28,4 @@ "browserslist": "^4.6.6", "nullthrows": "^1.1.1" } -} +} \ No newline at end of file diff --git a/packages/transformers/css/package.json b/packages/transformers/css/package.json index a0b689d6608..17ede2ba053 100644 --- a/packages/transformers/css/package.json +++ b/packages/transformers/css/package.json @@ -20,7 +20,7 @@ "parcel": "^2.5.0" }, "dependencies": { - "@parcel/css": "^1.8.2", + "@parcel/css": "^1.9.0", "@parcel/diagnostic": "2.5.0", "@parcel/plugin": "2.5.0", "@parcel/source-map": "^2.0.0", @@ -28,4 +28,4 @@ "browserslist": "^4.6.6", "nullthrows": "^1.1.1" } -} +} \ No newline at end of file diff --git a/yarn.lock b/yarn.lock index f53b75c51c1..d4cf5c4e2ce 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2056,61 +2056,61 @@ dependencies: "@octokit/openapi-types" "^6.2.0" -"@parcel/css-darwin-arm64@1.8.2": - version "1.8.2" - resolved "https://registry.yarnpkg.com/@parcel/css-darwin-arm64/-/css-darwin-arm64-1.8.2.tgz#ac26b249e9f2ade2b674f51b8b1684901cf79449" - integrity sha512-p5etxX3kPCuEQcipjqH9yc5j0x5/Yc++uB4MvG/sFbRgL2gI2zUuRo9sIgqA21boOP8lE4bQgz1ovPD/W1hj+Q== +"@parcel/css-darwin-arm64@1.9.0": + version "1.9.0" + resolved "https://registry.yarnpkg.com/@parcel/css-darwin-arm64/-/css-darwin-arm64-1.9.0.tgz#5a020c604249180afcf69ce0f6978b807e2011b3" + integrity sha512-f/guZseS2tNKtKw94LgpNTItZqdVA0mnznqPsmQaR5lSB+cM3IPrSV8cgOOpAS7Vwo9ggxuJartToxBBN+dWSw== -"@parcel/css-darwin-x64@1.8.2": - version "1.8.2" - resolved "https://registry.yarnpkg.com/@parcel/css-darwin-x64/-/css-darwin-x64-1.8.2.tgz#cf976783475e93f3feea09404bb946181b12bef6" - integrity sha512-c3xi5DXRZYec5db4KPTxp69eHbomOuasgZNiuPPOi80k7jlOwfzCFQs0h6/KwWvTcJrKEFsLl8BKJU/aX7mETw== +"@parcel/css-darwin-x64@1.9.0": + version "1.9.0" + resolved "https://registry.yarnpkg.com/@parcel/css-darwin-x64/-/css-darwin-x64-1.9.0.tgz#b808c042ba71592901f787b68f0f4677833ff971" + integrity sha512-4SpuwiM/4ayOgKflqSLd87XT7YwyC3wd2QuzOOkasjbe38UU+tot/87l2lQYEB538YinLdfwFQuFLDY0x9MxgA== -"@parcel/css-linux-arm-gnueabihf@1.8.2": - version "1.8.2" - resolved "https://registry.yarnpkg.com/@parcel/css-linux-arm-gnueabihf/-/css-linux-arm-gnueabihf-1.8.2.tgz#e87ce228a81a5147e4d10c4b0c041beb4b28ad2a" - integrity sha512-+ih3+mMpwbwtOjr/XW5pP0frsV1PMN+Qz7jCAM84h8xX+8UE/1IR0UVi3EPa8wQiIlcVcEwszQ1MV2UHacvo/A== +"@parcel/css-linux-arm-gnueabihf@1.9.0": + version "1.9.0" + resolved "https://registry.yarnpkg.com/@parcel/css-linux-arm-gnueabihf/-/css-linux-arm-gnueabihf-1.9.0.tgz#d97457f821867a4937453baf15caac3aa83704b1" + integrity sha512-KxCyX5fFvX5636Y8LSXwCxXMtIncgP7Lkw8nLsqd24C5YqMokmuOtAcHb/vQ9zQG6YiUWTv0MybqDuL7dBDfVw== -"@parcel/css-linux-arm64-gnu@1.8.2": - version "1.8.2" - resolved "https://registry.yarnpkg.com/@parcel/css-linux-arm64-gnu/-/css-linux-arm64-gnu-1.8.2.tgz#bedae0a7ff3f52003a6c4df0b20b65bced9dcc3a" - integrity sha512-jIoyXbjJ1trUHXtyJhi3hlF1ck6xM4CDyaY5N6eN+3+ovkdw6wxog9IiheYJ1jf9ellYevLvTF5kiYE9MiP04A== +"@parcel/css-linux-arm64-gnu@1.9.0": + version "1.9.0" + resolved "https://registry.yarnpkg.com/@parcel/css-linux-arm64-gnu/-/css-linux-arm64-gnu-1.9.0.tgz#7dd9c5d8d91354cce6f70e1a59bc3bbe2fa86296" + integrity sha512-wZ6Gsn6l+lSuvRdfWoyr7TdY24l29eGCD8QhXcqA1ALnFI7+KOTMBJ6aV3tjWUjMw3sg5qkosMHVqlWZzvrgXw== -"@parcel/css-linux-arm64-musl@1.8.2": - version "1.8.2" - resolved "https://registry.yarnpkg.com/@parcel/css-linux-arm64-musl/-/css-linux-arm64-musl-1.8.2.tgz#be3b912c0127745dda70757e18d7e7628118076d" - integrity sha512-QVTc5a+HatoywIei3djKYmp3s5dbI2Q3QaYZf3gqhyjOkeC7bm6j5eeNzFO+wa5xtga5jdHkIuTRrJ/wCojKKw== +"@parcel/css-linux-arm64-musl@1.9.0": + version "1.9.0" + resolved "https://registry.yarnpkg.com/@parcel/css-linux-arm64-musl/-/css-linux-arm64-musl-1.9.0.tgz#5c26ae07c372d615c67a53b9664d5c9ba6196eb7" + integrity sha512-N6n5HhMzcNR5oXWr0Md91gKYtuDhqDlp+aGDb3VT21uSCNLOvijOUz248v/VaPoRno1BPFYlMxn0fYYTTReB3A== -"@parcel/css-linux-x64-gnu@1.8.2": - version "1.8.2" - resolved "https://registry.yarnpkg.com/@parcel/css-linux-x64-gnu/-/css-linux-x64-gnu-1.8.2.tgz#b38a07f461fd45657676326ee50ee5b6abccfd2b" - integrity sha512-9r2tSfa6i3ZQ3a6C9XufJWuTv3LB7JYzxzEqsI35SSA8D/DrfAHMaIhqog5wSxKZRWmQxckh2wdT96eIIGHSGA== +"@parcel/css-linux-x64-gnu@1.9.0": + version "1.9.0" + resolved "https://registry.yarnpkg.com/@parcel/css-linux-x64-gnu/-/css-linux-x64-gnu-1.9.0.tgz#029e4588956c5151da9d5746364e11381d09abed" + integrity sha512-QufawDkaiOjsh6jcZk/dgDBPMqBtIs+LGTOgcJDM6XL4mcbDNxO6VkDANssRUgPnbG66YYy419CUWFta9aeVOg== -"@parcel/css-linux-x64-musl@1.8.2": - version "1.8.2" - resolved "https://registry.yarnpkg.com/@parcel/css-linux-x64-musl/-/css-linux-x64-musl-1.8.2.tgz#e7ce666f76943bfb73998e0b3908c2636f239f99" - integrity sha512-5SetLWkxXRQ3NU6QwwbGf9tOmGW2m1cGt07Moybbe4RCXOY6R5wAYUtauZUp7pD/fJlE9mHge4jnNHKpVO9pvw== +"@parcel/css-linux-x64-musl@1.9.0": + version "1.9.0" + resolved "https://registry.yarnpkg.com/@parcel/css-linux-x64-musl/-/css-linux-x64-musl-1.9.0.tgz#bf8a21a3cdd17e3d21f00021a57e67b020037843" + integrity sha512-s528buicSd83/5M5DN31JqwefZ8tqx4Jm97srkLDVBCZg+XEe9P0bO7q1Ngz5ZVFqfwvv8OYLPOtAtBmEppG3g== -"@parcel/css-win32-x64-msvc@1.8.2": - version "1.8.2" - resolved "https://registry.yarnpkg.com/@parcel/css-win32-x64-msvc/-/css-win32-x64-msvc-1.8.2.tgz#cbef99d007d19511c1d6bd0b0124d988f180d343" - integrity sha512-/EdW5Ejlnkvc/AYrAi/FmLNvM6a6eAx+A4Y7oW+8JSMvk6bYa2zmXi7XLU/QOQuH2VQa/3gIIMA+sYjPndvDpw== +"@parcel/css-win32-x64-msvc@1.9.0": + version "1.9.0" + resolved "https://registry.yarnpkg.com/@parcel/css-win32-x64-msvc/-/css-win32-x64-msvc-1.9.0.tgz#e0d729c510b0f41a526b32843348a995c41c030d" + integrity sha512-L4s84iK4PXnO/SzZyTsazAuzadtEYLGHgi1dyKYxMMGCjToCDjuwsn5K8bykeewZxjoL7RaunQGqCBRt5dfB5Q== -"@parcel/css@^1.8.2": - version "1.8.2" - resolved "https://registry.yarnpkg.com/@parcel/css/-/css-1.8.2.tgz#98647159c8f1c7ce23675cd3c742dacbd55f73f5" - integrity sha512-3vTyKHy2LnZ3YJEut+UQPVIxsaY/mdGk7cDXtmvH4xR48Pd6rYzChHCMl4Ru2DUkCBpr0KCQRPZTdYcsJhUmIA== +"@parcel/css@^1.9.0": + version "1.9.0" + resolved "https://registry.yarnpkg.com/@parcel/css/-/css-1.9.0.tgz#23d13d097a0897215d224a09ffa634c96b4d52c7" + integrity sha512-egCetUQ1H6pgYxOIxVQ8X/YT5e8G0R8eq6aVaUHrqnZ7A8cc6FYgknl9XRmoy2Xxo9h1htrbzdaEShQ5gROwvw== dependencies: detect-libc "^1.0.3" optionalDependencies: - "@parcel/css-darwin-arm64" "1.8.2" - "@parcel/css-darwin-x64" "1.8.2" - "@parcel/css-linux-arm-gnueabihf" "1.8.2" - "@parcel/css-linux-arm64-gnu" "1.8.2" - "@parcel/css-linux-arm64-musl" "1.8.2" - "@parcel/css-linux-x64-gnu" "1.8.2" - "@parcel/css-linux-x64-musl" "1.8.2" - "@parcel/css-win32-x64-msvc" "1.8.2" + "@parcel/css-darwin-arm64" "1.9.0" + "@parcel/css-darwin-x64" "1.9.0" + "@parcel/css-linux-arm-gnueabihf" "1.9.0" + "@parcel/css-linux-arm64-gnu" "1.9.0" + "@parcel/css-linux-arm64-musl" "1.9.0" + "@parcel/css-linux-x64-gnu" "1.9.0" + "@parcel/css-linux-x64-musl" "1.9.0" + "@parcel/css-win32-x64-msvc" "1.9.0" "@parcel/source-map@^2.0.0": version "2.0.0"