Skip to content

Commit

Permalink
refactor: copy loaders from the builtin CSS rule (#2417)
Browse files Browse the repository at this point in the history
  • Loading branch information
chenjiahan authored May 22, 2024
1 parent 0a62130 commit 74e5efb
Show file tree
Hide file tree
Showing 9 changed files with 97 additions and 88 deletions.
3 changes: 0 additions & 3 deletions packages/core/src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,6 @@ import { join } from 'node:path';

export const PLUGIN_SWC_NAME = 'rsbuild:swc';
export const PLUGIN_CSS_NAME = 'rsbuild:css';
export const PLUGIN_LESS_NAME = 'rsbuild:less';
export const PLUGIN_SASS_NAME = 'rsbuild:sass';
export const PLUGIN_STYLUS_NAME = 'rsbuild:stylus';

// loaders will be emitted to the same folder of the main bundle
export const LOADER_PATH = join(__dirname);
Expand Down
8 changes: 1 addition & 7 deletions packages/core/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,7 @@ export { logger } from '@rsbuild/shared';
export { mergeRsbuildConfig } from './mergeConfig';

// Constants
export {
PLUGIN_SWC_NAME,
PLUGIN_CSS_NAME,
PLUGIN_SASS_NAME,
PLUGIN_LESS_NAME,
PLUGIN_STYLUS_NAME,
} from './constants';
export { PLUGIN_SWC_NAME, PLUGIN_CSS_NAME } from './constants';

// Types
export type {
Expand Down
1 change: 0 additions & 1 deletion packages/core/src/internal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ export { createContext, createPublicContext } from './createContext';
export { initPlugins, createPluginManager } from './pluginManager';
export { initHooks, type Hooks } from './initHooks';
export { initRsbuildConfig } from './provider/initConfigs';
export { applyCSSRule } from './plugins/css';
export { getPluginAPI } from './initPlugins';
export type { InternalContext } from './types';
export {
Expand Down
2 changes: 1 addition & 1 deletion packages/core/src/plugins/css.ts
Original file line number Diff line number Diff line change
Expand Up @@ -238,7 +238,7 @@ const getCSSLoaderOptions = ({
return cssLoaderOptions;
};

export async function applyCSSRule({
async function applyCSSRule({
rule,
config,
context,
Expand Down
40 changes: 24 additions & 16 deletions packages/plugin-less/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,17 @@
import path from 'node:path';
import {
type RsbuildPlugin,
type Rspack,
__internalHelper,
} from '@rsbuild/core';
import type { RsbuildPlugin, Rspack } from '@rsbuild/core';
import {
type ChainedConfigWithUtils,
type FileFilterUtil,
castArray,
cloneDeep,
deepmerge,
mergeChainedOptions,
} from '@rsbuild/shared';
import type Less from '../compiled/less';

export const PLUGIN_LESS_NAME = 'rsbuild:less';

export type LessLoaderOptions = {
lessOptions?: Less.Options;
additionalData?:
Expand Down Expand Up @@ -93,12 +92,17 @@ const getLessLoaderOptions = (
export const pluginLess = ({
lessLoaderOptions,
}: PluginLessOptions = {}): RsbuildPlugin => ({
name: 'rsbuild:less',
name: PLUGIN_LESS_NAME,

setup(api) {
api.modifyBundlerChain(async (chain, utils) => {
api.modifyBundlerChain(async (chain, { CHAIN_ID }) => {
const config = api.getNormalizedConfig();
const rule = chain.module.rule(utils.CHAIN_ID.RULE.LESS).test(/\.less$/);
const rule = chain.module
.rule(CHAIN_ID.RULE.LESS)
.test(/\.less$/)
.merge({ sideEffects: true })
.resolve.preferRelative(true)
.end();

const { excludes, options } = getLessLoaderOptions(
lessLoaderOptions,
Expand All @@ -110,16 +114,20 @@ export const pluginLess = ({
rule.exclude.add(item);
}

await __internalHelper.applyCSSRule({
rule,
utils,
config,
context: api.context,
importLoaders: 2,
});
const cssRule = chain.module.rules.get(CHAIN_ID.RULE.CSS);

// Copy the builtin CSS rules
for (const id of Object.keys(cssRule.uses.entries())) {
const loader = cssRule.uses.get(id);
const options = cloneDeep(loader.get('options'));
if (id === CHAIN_ID.USE.CSS) {
options.importLoaders = 2;
}
rule.use(id).loader(loader.get('loader')).options(options);
}

rule
.use(utils.CHAIN_ID.USE.LESS)
.use(CHAIN_ID.USE.LESS)
.loader(path.join(__dirname, '../compiled/less-loader/index.js'))
.options(options);
});
Expand Down
1 change: 0 additions & 1 deletion packages/plugin-sass/src/helpers.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import path from 'node:path';
import { pathToFileURL } from 'node:url';
import { __internalHelper } from '@rsbuild/core';
import type { CompilerTapFn } from '@rsbuild/shared';

const GLOBAL_PATCHED_SYMBOL: unique symbol = Symbol('GLOBAL_PATCHED_SYMBOL');
Expand Down
42 changes: 25 additions & 17 deletions packages/plugin-sass/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
import { join } from 'node:path';
import { type RsbuildPlugin, __internalHelper } from '@rsbuild/core';
import type { RsbuildPlugin } from '@rsbuild/core';
import {
type FileFilterUtil,
castArray,
cloneDeep,
deepmerge,
mergeChainedOptions,
} from '@rsbuild/shared';
import { getResolveUrlJoinFn, patchCompilerGlobalLocation } from './helpers';
import type { PluginSassOptions, SassLoaderOptions } from './types';

export const PLUGIN_SASS_NAME = 'rsbuild:sass';

const getSassLoaderOptions = (
userOptions: PluginSassOptions['sassLoaderOptions'],
isUseCssSourceMap: boolean,
Expand Down Expand Up @@ -63,16 +66,14 @@ const getSassLoaderOptions = (
export const pluginSass = (
pluginOptions: PluginSassOptions = {},
): RsbuildPlugin => ({
name: 'rsbuild:sass',
name: PLUGIN_SASS_NAME,

setup(api) {
api.onAfterCreateCompiler(({ compiler }) => {
patchCompilerGlobalLocation(compiler);
});

api.modifyBundlerChain(async (chain, utils) => {
const config = api.getNormalizedConfig();

api.modifyBundlerChain(async (chain, { CHAIN_ID }) => {
const { excludes, options } = getSassLoaderOptions(
pluginOptions.sassLoaderOptions,
// source-maps required for loaders preceding resolve-url-loader
Expand All @@ -81,24 +82,31 @@ export const pluginSass = (
);

const rule = chain.module
.rule(utils.CHAIN_ID.RULE.SASS)
.test(/\.s(?:a|c)ss$/);
.rule(CHAIN_ID.RULE.SASS)
.test(/\.s(?:a|c)ss$/)
.merge({ sideEffects: true })
.resolve.preferRelative(true)
.end();

for (const item of excludes) {
rule.exclude.add(item);
}

await __internalHelper.applyCSSRule({
rule,
utils,
config,
context: api.context,
// postcss-loader, resolve-url-loader, sass-loader
importLoaders: 3,
});
const cssRule = chain.module.rules.get(CHAIN_ID.RULE.CSS);

// Copy the builtin CSS rules
for (const id of Object.keys(cssRule.uses.entries())) {
const loader = cssRule.uses.get(id);
const options = cloneDeep(loader.get('options'));
if (id === CHAIN_ID.USE.CSS) {
// postcss-loader, resolve-url-loader, sass-loader
options.importLoaders = 3;
}
rule.use(id).loader(loader.get('loader')).options(options);
}

rule
.use(utils.CHAIN_ID.USE.RESOLVE_URL)
.use(CHAIN_ID.USE.RESOLVE_URL)
.loader(join(__dirname, '../compiled/resolve-url-loader/index.js'))
.options({
join: await getResolveUrlJoinFn(),
Expand All @@ -108,7 +116,7 @@ export const pluginSass = (
sourceMap: false,
})
.end()
.use(utils.CHAIN_ID.USE.SASS)
.use(CHAIN_ID.USE.SASS)
.loader(join(__dirname, '../compiled/sass-loader/index.js'))
.options(options);
});
Expand Down
81 changes: 40 additions & 41 deletions packages/plugin-stylus/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
import {
PLUGIN_STYLUS_NAME,
type RsbuildPlugin,
__internalHelper,
} from '@rsbuild/core';
import { deepmerge, mergeChainedOptions } from '@rsbuild/shared';
import type { RsbuildPlugin } from '@rsbuild/core';
import { cloneDeep, deepmerge, mergeChainedOptions } from '@rsbuild/shared';

export const PLUGIN_STYLUS_NAME = 'rsbuild:stylus';

type StylusOptions = {
use?: string[];
Expand All @@ -14,7 +12,7 @@ type StylusOptions = {
hoistAtrules?: boolean;
};

type StylusLoaderOptions = {
export type PluginStylusOptions = {
/**
* Options passed to Stylus.
*/
Expand All @@ -25,43 +23,44 @@ type StylusLoaderOptions = {
sourceMap?: boolean;
};

export type PluginStylusOptions = StylusLoaderOptions;

export function pluginStylus(options?: PluginStylusOptions): RsbuildPlugin {
return {
name: PLUGIN_STYLUS_NAME,
export const pluginStylus = (options?: PluginStylusOptions): RsbuildPlugin => ({
name: PLUGIN_STYLUS_NAME,

setup(api) {
const STYLUS_REGEX = /\.styl(us)?$/;
setup(api) {
api.modifyBundlerChain(async (chain, { CHAIN_ID }) => {
const config = api.getNormalizedConfig();

api.modifyBundlerChain(async (chain, utils) => {
const config = api.getNormalizedConfig();
const mergedOptions = mergeChainedOptions({
defaults: {
sourceMap: config.output.sourceMap.css,
},
options,
mergeFn: deepmerge,
});

const mergedOptions = mergeChainedOptions({
defaults: {
sourceMap: config.output.sourceMap.css,
},
options,
mergeFn: deepmerge,
});
const rule = chain.module
.rule(CHAIN_ID.RULE.STYLUS)
.test(/\.styl(us)?$/)
.merge({ sideEffects: true })
.resolve.preferRelative(true)
.end();

const rule = chain.module
.rule(utils.CHAIN_ID.RULE.STYLUS)
.test(STYLUS_REGEX);
const cssRule = chain.module.rules.get(CHAIN_ID.RULE.CSS);

await __internalHelper.applyCSSRule({
rule,
config,
context: api.context,
utils,
importLoaders: 2,
});
// Copy the builtin CSS rules
for (const id of Object.keys(cssRule.uses.entries())) {
const loader = cssRule.uses.get(id);
const options = cloneDeep(loader.get('options'));
if (id === CHAIN_ID.USE.CSS) {
options.importLoaders = 2;
}
rule.use(id).loader(loader.get('loader')).options(options);
}

rule
.use(utils.CHAIN_ID.USE.STYLUS)
.loader(require.resolve('stylus-loader'))
.options(mergedOptions);
});
},
};
}
rule
.use(CHAIN_ID.USE.STYLUS)
.loader(require.resolve('stylus-loader'))
.options(mergedOptions);
});
},
});
7 changes: 6 additions & 1 deletion packages/shared/src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,12 @@ export const kebabCase = (str: string) =>
.toLowerCase()
.replace(/^-/, '');

export const cloneDeep = <T>(value: T): T => deepmerge({}, value);
export const cloneDeep = <T>(value: T): T => {
if (value === null || value === undefined) {
return value;
}
return deepmerge({}, value);
};

const DEP_MATCH_TEMPLATE = /[\\/]node_modules[\\/](<SOURCES>)[\\/]/.source;

Expand Down

0 comments on commit 74e5efb

Please sign in to comment.