feat(rspack): replace css by postcss and bump/remove dependencies (#10724)

This commit is contained in:
Juan de Dios Martínez Vallejo
2025-03-23 18:07:47 +01:00
committed by GitHub
parent 490c168571
commit d18fb092ad
4 changed files with 422 additions and 2107 deletions

File diff suppressed because it is too large Load Diff

View File

@ -21,10 +21,7 @@
"dependencies": {
"@babel/core": "^7.26.9",
"@pmmmwh/react-refresh-webpack-plugin": "^0.5.15",
"@rsbuild/plugin-node-polyfill": "^1.3.0",
"@rspack/cli": "^1.2.7",
"@rspack/core": "^1.2.8",
"@swc/helpers": "^0.5.15",
"@vue/compiler-sfc": "^3.5.13",
"acorn": "^8.14.0",
"acorn-stage3": "^4.0.0",
@ -32,21 +29,19 @@
"babel-loader": "^8.0.0",
"cli-highlight": "^2.1.11",
"commander": "^8.3.0",
"css": "^3.0.0",
"css-loader": "^6.11.0",
"css-loader": "^7.1.2",
"dotenv-webpack": "^8.1.0",
"loader-utils": "^2.0.0 || ^3.0.0",
"loader-utils": "^3.3.1",
"postcss": "^8.5.3",
"postcss-import": "^14.0.0",
"postcss-import": "^16.1.0",
"postcss-loader": "^8.1.1",
"raw-loader": "^4.0.2",
"react-refresh": "^0.14.2",
"rspack-plugin-virtual-module": "^0.1.13",
"sass": "^1.0.0",
"sass-embedded": "^1.85.1",
"sass": "^1.86.0",
"sass-embedded": "^1.86.0",
"sass-loader": "^16.0.5",
"sax": "^1.4.1",
"source-map": "^0.7.4",
"swc-loader": "^0.2.6",
"ts-checker-rspack-plugin": "^1.1.1",
"ts-dedent": "^2.2.0",

View File

@ -15,6 +15,10 @@ export default function (config: Config, env: IWebpackEnv = _env): Config {
// we need to patch VueLoader if we want to enable hmr
if (env.hmr) {
patchVueLoaderForHMR();
// TODO: fix hmr in child components
// https://github.com/web-infra-dev/rsbuild/issues/3217#issuecomment-2290946740
// config.devtool(false);
}
// resolve .vue files

View File

@ -1,4 +1,4 @@
import { parse, Import, Stylesheet } from 'css';
import postcss, { Root, Rule, Declaration, AtRule } from 'postcss';
import { urlToRequest } from 'loader-utils';
import { dedent } from 'ts-dedent';
@ -11,21 +11,22 @@ export default function loader(content: string, map: any) {
const inline = !!options.useForImports;
const requirePrefix = inline ? inlineLoader : '';
const ast = parse(content);
const ast = postcss.parse(content);
// todo: revise if this is necessary
// todo: perhaps use postCSS and just build imports into a single file?
let dependencies = [];
getAndRemoveImportRules(ast)
.map(extractUrlFromRule)
.map(createRequireUri)
.forEach(({ uri, requireURI }) => {
.forEach(({ requireURI }) => {
dependencies.push(`require("${requirePrefix}${requireURI}")`);
});
const str = JSON.stringify(ast, (k, v) => (k === 'position' ? undefined : v));
const cssCompatibleAST = transformPostcssASTtoCSS(ast);
// map.mappings = map.mappings.replace(/;{2,}/, '')
const str = JSON.stringify(cssCompatibleAST);
const code = dedent`
/* CSS2JSON */
@ -33,41 +34,29 @@ export default function loader(content: string, map: any) {
const ___CSS2JSON_LOADER_EXPORT___ = ${str}
export default ___CSS2JSON_LOADER_EXPORT___
`;
this.callback(
null,
code, //`${dependencies.join('\n')}module.exports = ${str};`,
map,
);
this.callback(null, code, map);
}
function getImportRules(ast: Stylesheet): Import[] {
if (!ast || (<any>ast).type !== 'stylesheet' || !ast.stylesheet) {
return [];
}
return <Import[]>(
ast.stylesheet.rules.filter(
(rule) => rule.type === 'import' && (<any>rule).import,
)
);
}
function getAndRemoveImportRules(ast: Stylesheet): Import[] {
const imports = getImportRules(ast);
ast.stylesheet.rules = ast.stylesheet.rules.filter(
(rule) => rule.type !== 'import',
);
/**
* Extract @import and remove them from the AST
*/
function getAndRemoveImportRules(ast: Root): AtRule[] {
const imports = ast.nodes.filter(
(node) => node.type === 'atrule' && node.name === 'import',
) as AtRule[];
imports.forEach((rule) => rule.remove());
return imports;
}
/**
* Extracts the url from import rule (ex. `url("./platform.css")`)
*/
function extractUrlFromRule(importRule: Import): string {
const urlValue = importRule.import;
function extractUrlFromRule(importRule: AtRule): string {
const params = importRule.params;
const unpackedUrlMatch = urlValue.match(unpackUrlPattern);
const unpackedValue = unpackedUrlMatch ? unpackedUrlMatch[1] : urlValue;
const unpackedUrlMatch = params.match(unpackUrlPattern);
const unpackedValue = unpackedUrlMatch ? unpackedUrlMatch[1] : params;
const quotesMatch = unpackedValue.match(betweenQuotesPattern);
return quotesMatch ? quotesMatch[2] : unpackedValue;
@ -75,7 +64,40 @@ function extractUrlFromRule(importRule: Import): string {
function createRequireUri(uri): { uri: string; requireURI: string } {
return {
uri: uri,
uri,
requireURI: urlToRequest(uri),
};
}
/**
* TRANSFORMING THE POSTCSS AST TO THE ORIGINAL CSS AST
*/
function transformPostcssASTtoCSS(ast: Root) {
return {
type: 'stylesheet',
stylesheet: {
rules: ast.nodes
.filter((node) => node.type === 'rule') // Solo reglas CSS, no comentarios ni otros
.map(transformRule),
parsingErrors: [],
},
};
}
function transformRule(rule: Rule) {
return {
type: 'rule',
selectors: rule.selectors,
declarations: rule.nodes
.filter((node) => node.type === 'decl')
.map(transformDeclaration),
};
}
function transformDeclaration(decl: Declaration) {
return {
type: 'declaration',
property: decl.prop,
value: decl.value,
};
}