Skip to content

Commit

Permalink
feat: use CssExtractRspackPlugin to extract CSS (#1577)
Browse files Browse the repository at this point in the history
Co-authored-by: neverland <chenjiahan.jait@bytedance.com>
  • Loading branch information
9aoy and chenjiahan authored May 13, 2024
1 parent 29a4a38 commit 658b81a
Show file tree
Hide file tree
Showing 31 changed files with 2,525 additions and 4,402 deletions.
22 changes: 22 additions & 0 deletions e2e/cases/css/css-assets/index.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import path from 'node:path';
import { build } from '@e2e/helper';
import { globContentJSON } from '@e2e/helper';
import { expect, test } from '@playwright/test';

test('should build CSS assets correctly', async () => {
await expect(
build({
cwd: __dirname,
rsbuildConfig: {},
}),
).resolves.toBeDefined();

const outputs = await globContentJSON(path.join(__dirname, 'dist'));
const outputFiles = Object.keys(outputs);

expect(
outputFiles.find(
(item) => item.includes('static/image/image') && item.endsWith('.jpeg'),
),
).toBeTruthy();
});
7 changes: 7 additions & 0 deletions e2e/cases/css/css-assets/rsbuild.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { defineConfig } from '@rsbuild/core';
import { pluginReact } from '@rsbuild/plugin-react';

export default defineConfig({
plugins: [pluginReact()],
output: {}
});
7 changes: 7 additions & 0 deletions e2e/cases/css/css-assets/src/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
function load(key: string) {
import(`./test/${key}`).then(res => {
console.log('res', res);
})
}

load('a');
5 changes: 5 additions & 0 deletions e2e/cases/css/css-assets/src/test/a.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import styles from './index.module.less';

console.log('s', styles);

export const a = 1;
3 changes: 3 additions & 0 deletions e2e/cases/css/css-assets/src/test/index.module.less
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
.header {
background: url('@assets/image.jpeg') no-repeat;
}
10 changes: 10 additions & 0 deletions e2e/cases/css/css-modules-named-export/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,16 @@ rspackOnlyTest(
const rsbuild = await build({
cwd: __dirname,
runServer: true,
rsbuildConfig: {
tools: {
cssLoader: {
modules: {
// TODO: css-loader need support named export when namedExports: false.
namedExport: true
}
}
}
}
});
const files = await rsbuild.unwrapOutputJSON();

Expand Down
6 changes: 6 additions & 0 deletions e2e/cases/server/hmr/rsbuild.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { defineConfig } from '@rsbuild/core';
import { pluginReact } from '@rsbuild/plugin-react';

export default defineConfig({
plugins: [pluginReact()],
});
21 changes: 21 additions & 0 deletions e2e/scripts/shared.ts
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,27 @@ export async function dev({

const rsbuild = await createRsbuild(options, plugins);

rsbuild.addPlugins([
{
// fix hmr problem temporary (only appears in rsbuild repo, because css-loader is not in node_modules/ )
// https://github.com/web-infra-dev/rspack/issues/5723
name: 'fix-react-refresh-in-rsbuild',
setup(api) {
api.modifyBundlerChain({
order: 'post',
handler: (chain, { CHAIN_ID }) => {
if (chain.plugins.has(CHAIN_ID.PLUGIN.REACT_FAST_REFRESH)) {
chain.plugin(CHAIN_ID.PLUGIN.REACT_FAST_REFRESH).tap((config) => {
config[0].exclude = [/node_modules/, /css-loader/];
return config;
});
}
},
});
},
},
]);

const result = await rsbuild.startDevServer();

return {
Expand Down
117 changes: 8 additions & 109 deletions packages/compat/webpack/src/plugins/css.ts
Original file line number Diff line number Diff line change
@@ -1,26 +1,18 @@
import {
type BundlerChainRule,
type CSSExtractOptions,
CSS_REGEX,
type ModifyChainUtils,
type NormalizedConfig,
type RsbuildContext,
type RsbuildPlugin,
getBrowserslistWithDefault,
getCssLoaderOptions,
getCssModuleLocalIdentName,
getPostcssLoaderOptions,
getSharedPkgCompiledPath,
isUseCssExtract,
mergeChainedOptions,
resolvePackage,
applyCSSRule,
} from '@rsbuild/shared';

export async function applyBaseCSSRule({
rule,
config,
context,
utils: { target, isProd, isServer, CHAIN_ID, isWebWorker },
utils,
importLoaders = 1,
}: {
rule: BundlerChainRule;
Expand All @@ -29,108 +21,15 @@ export async function applyBaseCSSRule({
utils: ModifyChainUtils;
importLoaders?: number;
}) {
const browserslist = await getBrowserslistWithDefault(
context.rootPath,
config,
target,
);

// 1. Check user config
const enableExtractCSS = isUseCssExtract(config, target);
const enableCSSModuleTS = Boolean(config.output.enableCssModuleTSDeclaration);

// 2. Prepare loader options
const localIdentName = getCssModuleLocalIdentName(config, isProd);

const cssLoaderOptions = getCssLoaderOptions({
const { default: cssExtractPlugin } = await import('mini-css-extract-plugin');
return applyCSSRule({
rule,
config,
context,
utils,
importLoaders,
isServer,
isWebWorker,
localIdentName,
cssExtractPlugin,
});

// 3. Create webpack rule
// Order: style-loader/mini-css-extract -> css-loader -> postcss-loader
if (!isServer && !isWebWorker) {
// use mini-css-extract-plugin loader
if (enableExtractCSS) {
const extraCSSOptions: Required<CSSExtractOptions> =
typeof config.tools.cssExtract === 'object'
? config.tools.cssExtract
: {
loaderOptions: {},
pluginOptions: {},
};

rule
.use(CHAIN_ID.USE.MINI_CSS_EXTRACT)
.loader(require('mini-css-extract-plugin').loader)
.options(extraCSSOptions.loaderOptions)
.end();
}
// use style-loader
else {
const styleLoaderOptions = mergeChainedOptions({
defaults: {},
options: config.tools.styleLoader,
});

rule
.use(CHAIN_ID.USE.STYLE)
.loader(getSharedPkgCompiledPath('style-loader'))
.options(styleLoaderOptions)
.end();
}

// use css-modules-typescript-loader
if (enableCSSModuleTS && cssLoaderOptions.modules) {
rule
.use(CHAIN_ID.USE.CSS_MODULES_TS)
.loader(
resolvePackage(
'@rsbuild/shared/css-modules-typescript-loader',
__dirname,
),
)
.options({
modules: cssLoaderOptions.modules,
})
.end();
}
} else {
rule
.use(CHAIN_ID.USE.IGNORE_CSS)
.loader(resolvePackage('@rsbuild/shared/ignore-css-loader', __dirname))
.end();
}

rule
.use(CHAIN_ID.USE.CSS)
.loader(getSharedPkgCompiledPath('css-loader'))
.options(cssLoaderOptions)
.end();

if (!isServer && !isWebWorker) {
const postcssLoaderOptions = await getPostcssLoaderOptions({
browserslist,
config,
root: context.rootPath,
});

rule
.use(CHAIN_ID.USE.POSTCSS)
.loader(getSharedPkgCompiledPath('postcss-loader'))
.options(postcssLoaderOptions)
.end();
}

// CSS imports should always be treated as sideEffects
rule.merge({ sideEffects: true });

// Enable preferRelative by default, which is consistent with the default behavior of css-loader
// see: https://github.com/webpack-contrib/css-loader/blob/579fc13/src/plugins/postcss-import-parser.js#L234
rule.resolve.preferRelative(true);
}

export const pluginCss = (): RsbuildPlugin => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ exports[`plugin-css > should not apply postcss-loader when target is node 1`] =
"test": /\\\\\\.css\\$/,
"use": [
{
"loader": "@rsbuild/shared/ignore-css-loader",
"loader": "<ROOT>/packages/shared/dist/loaders/ignoreCssLoader",
},
{
"loader": "<ROOT>/packages/shared/compiled/css-loader",
Expand Down
12 changes: 6 additions & 6 deletions packages/compat/webpack/tests/__snapshots__/default.test.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -1288,7 +1288,7 @@ exports[`applyDefaultPlugins > should apply default plugins correctly when targe
"test": /\\\\\\.css\\$/,
"use": [
{
"loader": "@rsbuild/shared/ignore-css-loader",
"loader": "<ROOT>/packages/shared/dist/loaders/ignoreCssLoader",
},
{
"loader": "<ROOT>/packages/shared/compiled/css-loader",
Expand All @@ -1314,7 +1314,7 @@ exports[`applyDefaultPlugins > should apply default plugins correctly when targe
"test": /\\\\\\.s\\(\\?:a\\|c\\)ss\\$/,
"use": [
{
"loader": "@rsbuild/shared/ignore-css-loader",
"loader": "<ROOT>/packages/shared/dist/loaders/ignoreCssLoader",
},
{
"loader": "<ROOT>/packages/shared/compiled/css-loader",
Expand Down Expand Up @@ -1354,7 +1354,7 @@ exports[`applyDefaultPlugins > should apply default plugins correctly when targe
"test": /\\\\\\.less\\$/,
"use": [
{
"loader": "@rsbuild/shared/ignore-css-loader",
"loader": "<ROOT>/packages/shared/dist/loaders/ignoreCssLoader",
},
{
"loader": "<ROOT>/packages/shared/compiled/css-loader",
Expand Down Expand Up @@ -1634,7 +1634,7 @@ exports[`applyDefaultPlugins > should apply default plugins correctly when targe
"test": /\\\\\\.css\\$/,
"use": [
{
"loader": "@rsbuild/shared/ignore-css-loader",
"loader": "<ROOT>/packages/shared/dist/loaders/ignoreCssLoader",
},
{
"loader": "<ROOT>/packages/shared/compiled/css-loader",
Expand All @@ -1660,7 +1660,7 @@ exports[`applyDefaultPlugins > should apply default plugins correctly when targe
"test": /\\\\\\.s\\(\\?:a\\|c\\)ss\\$/,
"use": [
{
"loader": "@rsbuild/shared/ignore-css-loader",
"loader": "<ROOT>/packages/shared/dist/loaders/ignoreCssLoader",
},
{
"loader": "<ROOT>/packages/shared/compiled/css-loader",
Expand Down Expand Up @@ -1700,7 +1700,7 @@ exports[`applyDefaultPlugins > should apply default plugins correctly when targe
"test": /\\\\\\.less\\$/,
"use": [
{
"loader": "@rsbuild/shared/ignore-css-loader",
"loader": "<ROOT>/packages/shared/dist/loaders/ignoreCssLoader",
},
{
"loader": "<ROOT>/packages/shared/compiled/css-loader",
Expand Down
2 changes: 1 addition & 1 deletion packages/core/src/internal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ export { createContext, createPublicContext } from './createContext';
export { initPlugins, createPluginManager } from './pluginManager';
export { initHooks, type Hooks } from './initHooks';
export { initRsbuildConfig } from './provider/initConfigs';
export { applyBaseCSSRule } from './provider/plugins/css';
export { getPluginAPI } from './initPlugins';
export { applyBaseCSSRule, applyCSSModuleRule } from './provider/plugins/css';
export type { InternalContext } from './types';
export { setHTMLPlugin, getHTMLPlugin } from './htmlUtils';
export { formatStats, getStatsOptions } from './provider/shared';
Expand Down
Loading

0 comments on commit 658b81a

Please sign in to comment.