From b396ace3411065d03073ef34c288400f3679713c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aur=C3=A9lien=20MANCA?= Date: Thu, 9 Jun 2022 09:49:40 +0200 Subject: [PATCH] feat(css) add experimental webpack CSS support --- packages/next/src/build/webpack-config.ts | 25 +++++++-- .../build/webpack/config/blocks/css/index.ts | 21 ++++++++ packages/next/src/server/config-shared.ts | 1 + test/e2e/css-webpack-experiment/index.test.ts | 51 +++++++++++++++++++ test/e2e/css-webpack-experiment/pages/_app.js | 4 ++ .../pages/css-modules.js | 4 ++ .../e2e/css-webpack-experiment/pages/index.js | 3 ++ test/e2e/css-webpack-experiment/pages/sass.js | 4 ++ .../css-webpack-experiment/styles/global.css | 4 ++ .../styles/styles.module.css | 3 ++ .../styles/styles.module.sass | 4 ++ 11 files changed, 121 insertions(+), 3 deletions(-) create mode 100644 test/e2e/css-webpack-experiment/index.test.ts create mode 100644 test/e2e/css-webpack-experiment/pages/_app.js create mode 100644 test/e2e/css-webpack-experiment/pages/css-modules.js create mode 100644 test/e2e/css-webpack-experiment/pages/index.js create mode 100644 test/e2e/css-webpack-experiment/pages/sass.js create mode 100644 test/e2e/css-webpack-experiment/styles/global.css create mode 100644 test/e2e/css-webpack-experiment/styles/styles.module.css create mode 100644 test/e2e/css-webpack-experiment/styles/styles.module.sass diff --git a/packages/next/src/build/webpack-config.ts b/packages/next/src/build/webpack-config.ts index 24eca3b1c2d7..ef7eb7afeeab 100644 --- a/packages/next/src/build/webpack-config.ts +++ b/packages/next/src/build/webpack-config.ts @@ -1695,6 +1695,7 @@ export default async function getBaseWebpackConfig( dev ? '' : appDir ? '-[chunkhash]' : '-[contenthash]' }.js`, library: isClient || isEdgeServer ? '_N_E' : undefined, + uniqueName: config.experimental.webpackCssExperiment ? '_N_E' : undefined, libraryTarget: isClient || isEdgeServer ? 'assign' : 'commonjs2', hotUpdateChunkFilename: 'static/webpack/[id].[fullhash].hot-update.js', hotUpdateMainFilename: @@ -2303,6 +2304,21 @@ export default async function getBaseWebpackConfig( ].filter<[Feature, boolean]>(Boolean as any) ) ), + ...(config.experimental.webpackCssExperiment + ? [ + new webpack.ids.DeterministicModuleIdsPlugin({ + maxLength: 5, + failOnConflict: true, + fixedLength: true, + test: (m) => m.type.startsWith('css'), + }), + new webpack.experiments.ids.SyncModuleIdsPlugin({ + test: (m) => m.type.startsWith('css'), + path: path.resolve(distDir, 'module-ids.json'), + mode: 'create', + }), + ] + : []), ].filter(Boolean as any as ExcludesFalse), } @@ -2357,6 +2373,7 @@ export default async function getBaseWebpackConfig( ...config.experimental.urlImports, } : undefined, + css: config.experimental.webpackCssExperiment, } webpack5Config.module!.parser = { @@ -2730,9 +2747,11 @@ export default async function getBaseWebpackConfig( } const hasUserCssConfig = - webpackConfig.module?.rules?.some( - (rule: any) => canMatchCss(rule.test) || canMatchCss(rule.include) - ) ?? false + (config.experimental.webpackCssExperiment || + webpackConfig.module?.rules?.some( + (rule: any) => canMatchCss(rule.test) || canMatchCss(rule.include) + )) ?? + false if (hasUserCssConfig) { // only show warning for one build diff --git a/packages/next/src/build/webpack/config/blocks/css/index.ts b/packages/next/src/build/webpack/config/blocks/css/index.ts index 48e53c9a4b28..81a393410a13 100644 --- a/packages/next/src/build/webpack/config/blocks/css/index.ts +++ b/packages/next/src/build/webpack/config/blocks/css/index.ts @@ -563,6 +563,27 @@ export const css = curry(async function css( ) } + if (ctx.experimental.webpackCssExperiment) { + fns.push( + loader({ + oneOf: [ + { + test: regexSassModules, + issuerLayer: ctx.hasAppDir ? APP_LAYER_RULE : PAGES_LAYER_RULE, + use: require.resolve('next/dist/compiled/sass-loader'), + type: 'css/module', + }, + { + test: regexSassGlobal, + issuerLayer: ctx.hasAppDir ? APP_LAYER_RULE : PAGES_LAYER_RULE, + use: require.resolve('next/dist/compiled/sass-loader'), + type: 'css', + }, + ], + }) + ) + } + const fn = pipe(...fns) return fn(config) }) diff --git a/packages/next/src/server/config-shared.ts b/packages/next/src/server/config-shared.ts index 95277fefaa9c..dabcb3f84b2b 100644 --- a/packages/next/src/server/config-shared.ts +++ b/packages/next/src/server/config-shared.ts @@ -146,6 +146,7 @@ export interface ExperimentalConfig { // Use Record as critters doesn't export its Option type // https://github.com/GoogleChromeLabs/critters/blob/a590c05f9197b656d2aeaae9369df2483c26b072/packages/critters/src/index.d.ts optimizeCss?: boolean | Record + webpackCssExperiment?: boolean nextScriptWorkers?: boolean scrollRestoration?: boolean externalDir?: boolean diff --git a/test/e2e/css-webpack-experiment/index.test.ts b/test/e2e/css-webpack-experiment/index.test.ts new file mode 100644 index 000000000000..2563a17bc62e --- /dev/null +++ b/test/e2e/css-webpack-experiment/index.test.ts @@ -0,0 +1,51 @@ +import { createNext, FileRef } from 'e2e-utils' +import { NextInstance } from 'test/lib/next-modes/base' +import webdriver from 'next-webdriver' + +describe('CSS webpack Experiment', () => { + describe('with basic CSS', () => { + let next: NextInstance + + beforeAll(async () => { + next = await createNext({ + files: new FileRef(__dirname), + nextConfig: { + experimental: { + webpackCssExperiment: true, + }, + }, + dependencies: { + react: 'latest', + 'react-dom': 'latest', + sass: 'latest', + }, + }) + }) + + afterAll(() => next.destroy()) + + it('should work with basic CSS', async () => { + const browser = await webdriver(next.url, `/`) + const element = await browser.elementByCss('p') + const color = await element.getComputedCss('color') + + expect(color).toBe('rgb(0, 128, 0)') + }) + + it('should work with CSS modules', async () => { + const browser = await webdriver(next.url, `/css-modules`) + const element = await browser.elementByCss('p') + const color = await element.getComputedCss('color') + + expect(color).toBe('rgb(255, 0, 0)') + }) + + it('should work with SASS', async () => { + const browser = await webdriver(next.url, `/sass`) + const element = await browser.elementByCss('p') + const color = await element.getComputedCss('color') + + expect(color).toBe('rgb(0, 0, 255)') + }) + }) +}) diff --git a/test/e2e/css-webpack-experiment/pages/_app.js b/test/e2e/css-webpack-experiment/pages/_app.js new file mode 100644 index 000000000000..29b32046a1d3 --- /dev/null +++ b/test/e2e/css-webpack-experiment/pages/_app.js @@ -0,0 +1,4 @@ +import '../styles/global.css' +export default function MyApp({ Component, pageProps }) { + return +} diff --git a/test/e2e/css-webpack-experiment/pages/css-modules.js b/test/e2e/css-webpack-experiment/pages/css-modules.js new file mode 100644 index 000000000000..f6f52ff41afe --- /dev/null +++ b/test/e2e/css-webpack-experiment/pages/css-modules.js @@ -0,0 +1,4 @@ +import * as styles from '../styles/styles.module.css' +export default function Page() { + return

hello world

+} diff --git a/test/e2e/css-webpack-experiment/pages/index.js b/test/e2e/css-webpack-experiment/pages/index.js new file mode 100644 index 000000000000..ff7159d9149f --- /dev/null +++ b/test/e2e/css-webpack-experiment/pages/index.js @@ -0,0 +1,3 @@ +export default function Page() { + return

hello world

+} diff --git a/test/e2e/css-webpack-experiment/pages/sass.js b/test/e2e/css-webpack-experiment/pages/sass.js new file mode 100644 index 000000000000..20b5d6564920 --- /dev/null +++ b/test/e2e/css-webpack-experiment/pages/sass.js @@ -0,0 +1,4 @@ +import * as styles from '../styles/styles.module.sass' +export default function Page() { + return

hello world

+} diff --git a/test/e2e/css-webpack-experiment/styles/global.css b/test/e2e/css-webpack-experiment/styles/global.css new file mode 100644 index 000000000000..f951410a671d --- /dev/null +++ b/test/e2e/css-webpack-experiment/styles/global.css @@ -0,0 +1,4 @@ +p { + color: green; + font-size: 2rem; +} diff --git a/test/e2e/css-webpack-experiment/styles/styles.module.css b/test/e2e/css-webpack-experiment/styles/styles.module.css new file mode 100644 index 000000000000..bcc3583dffd2 --- /dev/null +++ b/test/e2e/css-webpack-experiment/styles/styles.module.css @@ -0,0 +1,3 @@ +.hello { + color: red; +} diff --git a/test/e2e/css-webpack-experiment/styles/styles.module.sass b/test/e2e/css-webpack-experiment/styles/styles.module.sass new file mode 100644 index 000000000000..fe6bd10606a9 --- /dev/null +++ b/test/e2e/css-webpack-experiment/styles/styles.module.sass @@ -0,0 +1,4 @@ +$color: blue + +.hello + color: $color \ No newline at end of file