From a503e0821b77d38ef582ce39aeedc75935498b22 Mon Sep 17 00:00:00 2001 From: kamilic Date: Sat, 24 Jul 2021 16:39:28 +0800 Subject: [PATCH 1/4] feat(css.ts): support cssmodule compose/from path resolution --- packages/vite/package.json | 2 +- packages/vite/src/node/plugins/css.ts | 16 ++++++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/packages/vite/package.json b/packages/vite/package.json index e8a5f6693f8bbc..d3c22d41af206a 100644 --- a/packages/vite/package.json +++ b/packages/vite/package.json @@ -111,7 +111,7 @@ "periscopic": "^2.0.3", "postcss-import": "^14.0.2", "postcss-load-config": "^3.0.0", - "postcss-modules": "^4.1.3", + "postcss-modules": "^4.2.2", "resolve.exports": "^1.0.2", "rollup-plugin-license": "^2.5.0", "selfsigned": "^1.10.11", diff --git a/packages/vite/src/node/plugins/css.ts b/packages/vite/src/node/plugins/css.ts index 1a145f4b592efd..df71ed0f9ce5e8 100644 --- a/packages/vite/src/node/plugins/css.ts +++ b/packages/vite/src/node/plugins/css.ts @@ -516,6 +516,12 @@ function createCSSResolvers(config: ResolvedConfig): CSSAtImportResolvers { } } +function getCssResolversKeys( + resolvers: CSSAtImportResolvers +): Array { + return Object.keys(resolvers) as unknown as Array +} + async function compileCSS( id: string, code: string, @@ -641,6 +647,16 @@ async function compileCSS( if (modulesOptions && typeof modulesOptions.getJSON === 'function') { modulesOptions.getJSON(cssFileName, _modules, outputFileName) } + }, + async resolve(id: string) { + for (const key of getCssResolversKeys(atImportResolvers)) { + const resolved = await atImportResolvers[key](id) + if (resolved) { + return path.resolve(resolved) + } + } + + return id } }) ) From e3692f5b5aa7c852bf953f0aef12e86801efe5c4 Mon Sep 17 00:00:00 2001 From: kamilic Date: Sun, 25 Jul 2021 14:53:25 +0800 Subject: [PATCH 2/4] test: test case for compose/from path resolution --- .../src/node/__tests__/plugins/css.spec.ts | 75 ++++++++++++++++++- 1 file changed, 74 insertions(+), 1 deletion(-) diff --git a/packages/vite/src/node/__tests__/plugins/css.spec.ts b/packages/vite/src/node/__tests__/plugins/css.spec.ts index 43ad248fb59bbe..f838795df6b883 100644 --- a/packages/vite/src/node/__tests__/plugins/css.spec.ts +++ b/packages/vite/src/node/__tests__/plugins/css.spec.ts @@ -1,4 +1,7 @@ -import { cssUrlRE } from '../../plugins/css' +import { cssUrlRE, cssPlugin } from '../../plugins/css' +import { resolveConfig } from '../../config' +import fs from 'fs' +import path from 'path' describe('search css url function', () => { test('some spaces before it', () => { @@ -41,3 +44,73 @@ describe('search css url function', () => { ).toBe(true) }) }) + +describe('css path resolutions', () => { + const mockedProjectPath = '/foo/bar/project' + const mockedBarCssRelativePath = '/css/bar.module.css' + const mockedFooCssRelativePath = '/css/foo.module.css' + + test('cssmodule compose/from path resolutions', async () => { + const config = await resolveConfig( + { + resolve: { + alias: [ + { + find: '@', + replacement: mockedProjectPath + } + ] + } + }, + 'serve' + ) + + const { transform, buildStart } = cssPlugin(config) + + await buildStart.call({}) + + const mockFs = jest + .spyOn(fs, 'readFile') + // @ts-ignore jest.spyOn not recognize overrided `fs.readFile` definition. + .mockImplementationOnce((p, encoding, callback) => { + expect(p).toBe(path.join(mockedProjectPath, mockedBarCssRelativePath)) + expect(encoding).toBe('utf-8') + callback( + null, + Buffer.from(` +.bar { + display: block; + background: #f0f; +} + `) + ) + }) + + const { code } = await transform.call( + { + addWatchFile() { + return + } + }, + ` +.foo { + position: fixed; + composes: bar from '@${mockedBarCssRelativePath}'; +} + `, + path.join(mockedProjectPath, mockedFooCssRelativePath) + ) + + expect(code).toBe(` +._bar_soicv_2 { + display: block; + background: #f0f; +} +._foo_sctn3_2 { + position: fixed; +} + `) + + mockFs.mockReset() + }) +}) From 16fa93bcd82d716be1e1055349a09615f4b15d36 Mon Sep 17 00:00:00 2001 From: kamilic Date: Sun, 25 Jul 2021 15:22:51 +0800 Subject: [PATCH 3/4] fix: fix css test case failure on windows --- packages/vite/src/node/__tests__/plugins/css.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/vite/src/node/__tests__/plugins/css.spec.ts b/packages/vite/src/node/__tests__/plugins/css.spec.ts index f838795df6b883..539ec2f1af1810 100644 --- a/packages/vite/src/node/__tests__/plugins/css.spec.ts +++ b/packages/vite/src/node/__tests__/plugins/css.spec.ts @@ -46,7 +46,7 @@ describe('search css url function', () => { }) describe('css path resolutions', () => { - const mockedProjectPath = '/foo/bar/project' + const mockedProjectPath = path.join(process.cwd(), '/foo/bar/project') const mockedBarCssRelativePath = '/css/bar.module.css' const mockedFooCssRelativePath = '/css/foo.module.css' From 5d2836d95546e63467bb76607c2fd12f3203939b Mon Sep 17 00:00:00 2001 From: kamilic Date: Sat, 31 Jul 2021 13:07:03 +0800 Subject: [PATCH 4/4] test: add playground test for composes/from path resolution. --- packages/playground/css/__tests__/css.spec.ts | 63 +++++++++++++++++++ packages/playground/css/composed.module.css | 3 + packages/playground/css/composed.module.less | 3 + packages/playground/css/composed.module.scss | 3 + .../css/composes-path-resolving.module.css | 11 ++++ packages/playground/css/index.html | 12 ++++ packages/playground/css/main.js | 15 +++++ 7 files changed, 110 insertions(+) create mode 100644 packages/playground/css/composed.module.css create mode 100644 packages/playground/css/composed.module.less create mode 100644 packages/playground/css/composed.module.scss create mode 100644 packages/playground/css/composes-path-resolving.module.css diff --git a/packages/playground/css/__tests__/css.spec.ts b/packages/playground/css/__tests__/css.spec.ts index 8025d5766656b5..463a647c68a37a 100644 --- a/packages/playground/css/__tests__/css.spec.ts +++ b/packages/playground/css/__tests__/css.spec.ts @@ -152,6 +152,69 @@ test('css modules', async () => { await untilUpdated(() => getColor(imported), 'red') }) +test('css modules composes/from path resolving', async () => { + const imported = await page.$('.path-resolved-modules-css') + expect(await getColor(imported)).toBe('turquoise') + + // check if the generated CSS module class name is indeed using the + // format specified in vite.config.js + expect(await imported.getAttribute('class')).toMatch( + /.composed-module__apply-color___[\w-]{5}/ + ) + + expect(await imported.getAttribute('class')).toMatch( + /.composes-path-resolving-module__path-resolving-css___[\w-]{5}/ + ) + + // @todo HMR is not working on this situation. + // editFile('composed.module.css', (code) => + // code.replace('color: turquoise', 'color: red') + // ) + // await untilUpdated(() => getColor(imported), 'red') +}) + +test('sass modules composes/from path resolving', async () => { + const imported = await page.$('.path-resolved-modules-sass') + expect(await getColor(imported)).toBe('orangered') + + // check if the generated CSS module class name is indeed using the + // format specified in vite.config.js + expect(await imported.getAttribute('class')).toMatch( + /.composed-module__apply-color___[\w-]{5}/ + ) + + expect(await imported.getAttribute('class')).toMatch( + /.composes-path-resolving-module__path-resolving-sass___[\w-]{5}/ + ) + + // @todo HMR is not working on this situation. + // editFile('composed.module.scss', (code) => + // code.replace('color: orangered', 'color: red') + // ) + // await untilUpdated(() => getColor(imported), 'red') +}) + +test('less modules composes/from path resolving', async () => { + const imported = await page.$('.path-resolved-modules-less') + expect(await getColor(imported)).toBe('blue') + + // check if the generated CSS module class name is indeed using the + // format specified in vite.config.js + expect(await imported.getAttribute('class')).toMatch( + /.composed-module__apply-color___[\w-]{5}/ + ) + + expect(await imported.getAttribute('class')).toMatch( + /.composes-path-resolving-module__path-resolving-less___[\w-]{5}/ + ) + + // @todo HMR is not working on this situation. + // editFile('composed.module.scss', (code) => + // code.replace('color: orangered', 'color: red') + // ) + // await untilUpdated(() => getColor(imported), 'red') +}) + test('css modules w/ sass', async () => { const imported = await page.$('.modules-sass') expect(await getColor(imported)).toBe('orangered') diff --git a/packages/playground/css/composed.module.css b/packages/playground/css/composed.module.css new file mode 100644 index 00000000000000..b2ae0e967dced1 --- /dev/null +++ b/packages/playground/css/composed.module.css @@ -0,0 +1,3 @@ +.apply-color { + color: turquoise; +} diff --git a/packages/playground/css/composed.module.less b/packages/playground/css/composed.module.less new file mode 100644 index 00000000000000..707e77f6571681 --- /dev/null +++ b/packages/playground/css/composed.module.less @@ -0,0 +1,3 @@ +.apply-color { + color: blue; +} diff --git a/packages/playground/css/composed.module.scss b/packages/playground/css/composed.module.scss new file mode 100644 index 00000000000000..e0a819f1c628f9 --- /dev/null +++ b/packages/playground/css/composed.module.scss @@ -0,0 +1,3 @@ +.apply-color { + color: orangered; +} diff --git a/packages/playground/css/composes-path-resolving.module.css b/packages/playground/css/composes-path-resolving.module.css new file mode 100644 index 00000000000000..3cd0db470de4b9 --- /dev/null +++ b/packages/playground/css/composes-path-resolving.module.css @@ -0,0 +1,11 @@ +.path-resolving-css { + composes: apply-color from '@/composed.module.css'; +} + +.path-resolving-sass { + composes: apply-color from '@/composed.module.scss'; +} + +.path-resolving-less { + composes: apply-color from '@/composed.module.less'; +} \ No newline at end of file diff --git a/packages/playground/css/index.html b/packages/playground/css/index.html index 306f2c5169599c..9b85c9442b936f 100644 --- a/packages/playground/css/index.html +++ b/packages/playground/css/index.html @@ -68,6 +68,18 @@

CSS

Imported SASS module:


 
+  

Imported compose/from CSS/SASS module:

+

+ CSS modules composes path resolving: this should be turquoise +

+

+ CSS modules composes path resolving: this should be orangered +

+

+ CSS modules composes path resolving: this should be blue +

+

+
   

@import dependency w/ style enrtrypoints: this should be purple

diff --git a/packages/playground/css/main.js b/packages/playground/css/main.js index d8073a86981f0a..1f3d621ee3a14f 100644 --- a/packages/playground/css/main.js +++ b/packages/playground/css/main.js @@ -18,6 +18,21 @@ import sassMod from './mod.module.scss' document.querySelector('.modules-sass').classList.add(sassMod['apply-color']) text('.modules-sass-code', JSON.stringify(sassMod, null, 2)) +import composesPathResolvingMod from './composes-path-resolving.module.css' +document + .querySelector('.path-resolved-modules-css') + .classList.add(...composesPathResolvingMod['path-resolving-css'].split(' ')) +document + .querySelector('.path-resolved-modules-sass') + .classList.add(...composesPathResolvingMod['path-resolving-sass'].split(' ')) +document + .querySelector('.path-resolved-modules-less') + .classList.add(...composesPathResolvingMod['path-resolving-less'].split(' ')) +text( + '.path-resolved-modules-code', + JSON.stringify(composesPathResolvingMod, null, 2) +) + import './dep.css' import './glob-dep.css'