From 1132d9ec57105c1aca1f6b53dd0a944211889020 Mon Sep 17 00:00:00 2001 From: Jack Hsu Date: Mon, 20 Jan 2020 15:52:34 -0500 Subject: [PATCH] feat(react): add support for css modules (#2349) Closes #1744 --- e2e/utils.ts | 2 + e2e/web.test.ts | 22 +++++++++ package.json | 2 + packages/web/package.json | 4 +- packages/web/src/utils/web.config.spec.ts | 12 ----- packages/web/src/utils/web.config.ts | 24 +++++++++- yarn.lock | 54 +++++++++++++++++++++++ 7 files changed, 106 insertions(+), 14 deletions(-) diff --git a/e2e/utils.ts b/e2e/utils.ts index 9f906c22f3caf..614c4baa72bec 100644 --- a/e2e/utils.ts +++ b/e2e/utils.ts @@ -274,6 +274,8 @@ export function copyMissingPackages(): void { 'istanbul-instrumenter-loader', 'semver', + 'css-loader', + 'css-modules-typescript-loader', 'mime', 'less', 'send', diff --git a/e2e/web.test.ts b/e2e/web.test.ts index 98fd8049eb766..df14d65cfa1b0 100644 --- a/e2e/web.test.ts +++ b/e2e/web.test.ts @@ -98,5 +98,27 @@ forEachCli(currentCLIName => { expect(e2eResults).toContain('All specs passed!'); } }); + + it('should support CSS modules', () => { + ensureProject(); + const appName = uniq('app'); + + runCLI(`generate @nrwl/web:app ${appName} --no-interactive`); + updateFile( + `apps/${appName}/src/app/app.module.css`, + '.foo { color: red; }' + ); + const mainPath = `apps/${appName}/src/app/app.element.ts`; + const content = readFile(mainPath); + updateFile( + mainPath, + `import styles from './app.module.css';\n${content}` + ); + + if (supportUi()) { + const e2eResults = runCLI(`e2e ${appName}-e2e`); + expect(e2eResults).toContain('All specs passed!'); + } + }); }); }); diff --git a/package.json b/package.json index 550d38462e7c2..d4ff58a73fa08 100644 --- a/package.json +++ b/package.json @@ -114,6 +114,8 @@ "copy-webpack-plugin": "5.1.1", "core-js": "^2.6.9", "cosmiconfig": "^4.0.0", + "css-loader": "3.4.2", + "css-modules-typescript-loader": "4.0.0", "cypress": "3.4.1", "cz-conventional-changelog": "^3.0.2", "cz-customizable": "^6.2.0", diff --git a/packages/web/package.json b/packages/web/package.json index 14b907c215db7..517e435dcc5be 100644 --- a/packages/web/package.json +++ b/packages/web/package.json @@ -61,6 +61,8 @@ "clean-css": "4.2.1", "copy-webpack-plugin": "5.1.1", "core-js": "^3.2.1", + "css-loader": "3.4.2", + "css-modules-typescript-loader": "4.0.0", "file-loader": "4.2.0", "find-cache-dir": "3.0.0", "fork-ts-checker-webpack-plugin": "^3.1.1", @@ -107,7 +109,7 @@ "terser-webpack-plugin": "2.3.1", "ts-loader": "5.4.5", "tsconfig-paths-webpack-plugin": "3.2.0", - "webpack": "4.39.2", + "webpack": "4.41.2", "webpack-dev-middleware": "3.7.0", "webpack-merge": "4.2.1", "webpack-sources": "1.4.3", diff --git a/packages/web/src/utils/web.config.spec.ts b/packages/web/src/utils/web.config.spec.ts index 05e420521b1dc..edb4a9ffaa110 100644 --- a/packages/web/src/utils/web.config.spec.ts +++ b/packages/web/src/utils/web.config.spec.ts @@ -61,18 +61,6 @@ describe('getWebConfig', () => { expect(result.resolve.mainFields).toContain('browser'); }); - it('should use the style-loader to load styles', () => { - const result = getWebPartial(root, sourceRoot, input, logger, false, false); - expect( - result.module.rules.find(rule => rule.test.test('styles.css')).use[0] - .loader - ).toEqual('style-loader'); - expect( - result.module.rules.find(rule => rule.test.test('styles.scss')).use[0] - .loader - ).toEqual('style-loader'); - }); - describe('without differential loading', () => { describe('polyfills', () => { it('should set the polyfills entry', () => { diff --git a/packages/web/src/utils/web.config.ts b/packages/web/src/utils/web.config.ts index a899f1f78ab36..2f25a9993ea83 100644 --- a/packages/web/src/utils/web.config.ts +++ b/packages/web/src/utils/web.config.ts @@ -106,7 +106,7 @@ function getCommonPartial(wco: any): Configuration { function getStylesPartial(wco: any): Configuration { const partial = getStylesConfig(wco); - partial.module.rules = partial.module.rules.map(rule => { + const rules = partial.module.rules.map(rule => { if (!Array.isArray(rule.use)) { return rule; } @@ -123,6 +123,28 @@ function getStylesPartial(wco: any): Configuration { }); return rule; }); + partial.module.rules = [ + { + test: /\.css$|\.scss$|\.sass$|\.less$|\.styl$/, + oneOf: [ + { + test: /\.module\.css$/, + use: [ + { loader: 'style-loader' }, + { loader: 'css-modules-typescript-loader' }, + { + loader: 'css-loader', + options: { + modules: true, + importLoaders: 1 + } + } + ] + }, + ...rules + ] + } + ]; return partial; } diff --git a/yarn.lock b/yarn.lock index 9efd1f26abe99..66faeb9dd840e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8257,6 +8257,24 @@ css-loader@3.2.0, css-loader@^3.0.0: postcss-value-parser "^4.0.0" schema-utils "^2.0.0" +css-loader@3.4.2: + version "3.4.2" + resolved "https://registry.yarnpkg.com/css-loader/-/css-loader-3.4.2.tgz#d3fdb3358b43f233b78501c5ed7b1c6da6133202" + integrity sha512-jYq4zdZT0oS0Iykt+fqnzVLRIeiPWhka+7BqPn+oSIpWJAHak5tmB/WZrJ2a21JhCeFyNnnlroSl8c+MtVndzA== + dependencies: + camelcase "^5.3.1" + cssesc "^3.0.0" + icss-utils "^4.1.1" + loader-utils "^1.2.3" + normalize-path "^3.0.0" + postcss "^7.0.23" + postcss-modules-extract-imports "^2.0.0" + postcss-modules-local-by-default "^3.0.2" + postcss-modules-scope "^2.1.1" + postcss-modules-values "^3.0.0" + postcss-value-parser "^4.0.2" + schema-utils "^2.6.0" + css-modules-loader-core@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/css-modules-loader-core/-/css-modules-loader-core-1.1.0.tgz#5908668294a1becd261ae0a4ce21b0b551f21d16" @@ -8269,6 +8287,14 @@ css-modules-loader-core@^1.1.0: postcss-modules-scope "1.1.0" postcss-modules-values "1.3.0" +css-modules-typescript-loader@4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/css-modules-typescript-loader/-/css-modules-typescript-loader-4.0.0.tgz#17c0924107f45c7d9998fb59be5c59d6398aac5c" + integrity sha512-K6ii0+kt2i3sHN+VKTWdF728x+N4PFitsjE8aldUO+N98XlZhanJYIEZrnh4FMTZzDvOjyBialU0LnkCSeeUig== + dependencies: + line-diff "^2.0.1" + loader-utils "^1.2.3" + css-parse@1.7.x: version "1.7.0" resolved "https://registry.yarnpkg.com/css-parse/-/css-parse-1.7.0.tgz#321f6cf73782a6ff751111390fc05e2c657d8c9b" @@ -13515,6 +13541,11 @@ less@^3.8.0: request "^2.83.0" source-map "~0.6.0" +levdist@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/levdist/-/levdist-1.0.0.tgz#91d7a3044964f2ccc421a0477cac827fe75c5718" + integrity sha1-kdejBElk8szEIaBHfKyCf+dcVxg= + leven@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/leven/-/leven-3.1.0.tgz#77891de834064cccba82ae7842bb6b14a13ed7f2" @@ -13548,6 +13579,13 @@ lightercollective@^0.3.0: resolved "https://registry.yarnpkg.com/lightercollective/-/lightercollective-0.3.0.tgz#1f07638642ec645d70bdb69ab2777676f35a28f0" integrity sha512-RFOLSUVvwdK3xA0P8o6G7QGXLIyy1L2qv5caEI7zXN5ciaEjbAriRF182kbsoJ1S1TgvpyGcN485fMky6qxOPw== +line-diff@^2.0.1: + version "2.1.0" + resolved "https://registry.yarnpkg.com/line-diff/-/line-diff-2.1.0.tgz#4c407100471b4ebe1617bf37e877554a67abaa08" + integrity sha512-EciuZHwQfFG5ITBdIjN+zyJtcJXRVgbDSxtv6sz8BBf16rw4iGRO28AwIDVlNSoKlpDzp1UzRti54j3wBlU9Fw== + dependencies: + levdist "^1.0.0" + lines-and-columns@^1.1.6: version "1.1.6" resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.1.6.tgz#1c00c743b433cd0a4e80758f7b64a57440d9ff00" @@ -16330,6 +16368,14 @@ postcss-modules-scope@^2.1.0: postcss "^7.0.6" postcss-selector-parser "^6.0.0" +postcss-modules-scope@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/postcss-modules-scope/-/postcss-modules-scope-2.1.1.tgz#33d4fc946602eb5e9355c4165d68a10727689dba" + integrity sha512-OXRUPecnHCg8b9xWvldG/jUpRIGPNRka0r4D4j0ESUU2/5IOnpsjfPPmDprM3Ih8CgZ8FXjWqaniK5v4rWt3oQ== + dependencies: + postcss "^7.0.6" + postcss-selector-parser "^6.0.0" + postcss-modules-values@1.3.0, postcss-modules-values@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/postcss-modules-values/-/postcss-modules-values-1.3.0.tgz#ecffa9d7e192518389f42ad0e83f72aec456ea20" @@ -18439,6 +18485,14 @@ schema-utils@^2.4.1: ajv "^6.10.2" ajv-keywords "^3.4.1" +schema-utils@^2.6.0: + version "2.6.4" + resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-2.6.4.tgz#a27efbf6e4e78689d91872ee3ccfa57d7bdd0f53" + integrity sha512-VNjcaUxVnEeun6B2fiiUDjXXBtD4ZSH7pdbfIu1pOFwgptDPLMo/z9jr4sUfsjFVPqDCEin/F7IYlq7/E6yDbQ== + dependencies: + ajv "^6.10.2" + ajv-keywords "^3.4.1" + schema-utils@^2.6.1: version "2.6.1" resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-2.6.1.tgz#eb78f0b945c7bcfa2082b3565e8db3548011dc4f"