Skip to content

Commit

Permalink
feat(css) add experimental webpack CSS support
Browse files Browse the repository at this point in the history
  • Loading branch information
noreiller committed Apr 14, 2023
1 parent 43519cf commit b396ace
Show file tree
Hide file tree
Showing 11 changed files with 121 additions and 3 deletions.
25 changes: 22 additions & 3 deletions packages/next/src/build/webpack-config.ts
Expand Up @@ -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:
Expand Down Expand Up @@ -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),
}

Expand Down Expand Up @@ -2357,6 +2373,7 @@ export default async function getBaseWebpackConfig(
...config.experimental.urlImports,
}
: undefined,
css: config.experimental.webpackCssExperiment,
}

webpack5Config.module!.parser = {
Expand Down Expand Up @@ -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
Expand Down
21 changes: 21 additions & 0 deletions packages/next/src/build/webpack/config/blocks/css/index.ts
Expand Up @@ -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)
})
1 change: 1 addition & 0 deletions packages/next/src/server/config-shared.ts
Expand Up @@ -146,6 +146,7 @@ export interface ExperimentalConfig {
// Use Record<string, unknown> as critters doesn't export its Option type
// https://github.com/GoogleChromeLabs/critters/blob/a590c05f9197b656d2aeaae9369df2483c26b072/packages/critters/src/index.d.ts
optimizeCss?: boolean | Record<string, unknown>
webpackCssExperiment?: boolean
nextScriptWorkers?: boolean
scrollRestoration?: boolean
externalDir?: boolean
Expand Down
51 changes: 51 additions & 0 deletions 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)')
})
})
})
4 changes: 4 additions & 0 deletions test/e2e/css-webpack-experiment/pages/_app.js
@@ -0,0 +1,4 @@
import '../styles/global.css'
export default function MyApp({ Component, pageProps }) {
return <Component {...pageProps} />
}
4 changes: 4 additions & 0 deletions 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 <p className={styles.hello}>hello world</p>
}
3 changes: 3 additions & 0 deletions test/e2e/css-webpack-experiment/pages/index.js
@@ -0,0 +1,3 @@
export default function Page() {
return <p>hello world</p>
}
4 changes: 4 additions & 0 deletions 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 <p className={styles.hello}>hello world</p>
}
4 changes: 4 additions & 0 deletions test/e2e/css-webpack-experiment/styles/global.css
@@ -0,0 +1,4 @@
p {
color: green;
font-size: 2rem;
}
3 changes: 3 additions & 0 deletions test/e2e/css-webpack-experiment/styles/styles.module.css
@@ -0,0 +1,3 @@
.hello {
color: red;
}
4 changes: 4 additions & 0 deletions test/e2e/css-webpack-experiment/styles/styles.module.sass
@@ -0,0 +1,4 @@
$color: blue

.hello
color: $color

0 comments on commit b396ace

Please sign in to comment.