RsPack Css
一、认识
基于 RsPack
, 我们支持 Css
以及 Scss
、Less
等预处理器。配置策略如下:
1. 插入/或者分离 Css
文件: 为了提高开发效率,RsPack
在开发模式下会启用热重载(Hot Module Replacement
)和快速构建,CSS
会通过 style-loader
注入到页面中,而不是单独提取成文件,这样可以避免每次修改都重新加载整个 CSS
文件。在生产环境下,为了提升性能和缓存效果,CSS
会被提取成独立的文件,使用 RsPack
原生的 CssExtractRspackPlugin
插件来实现。可以减小主产物体积, 也可以可以避免重复加载 CSS
,提高页面的加载速度。CssExtractRspackPlugin
同时提供了 loader
, 将这个 loader
放在最前面即可。CssExtractRspackPlugin
可以配置 filename
和 chunkFilename
,可以自定义 Css
样式名和位置。
2. 处理 Css
文件: 通过 css-loader
处理 Css
文件, 使其可以在JS
中被引用和加载。并针对 *.module.css
的文件设置 modules: true / modules: { xx: 配置}
配置 Css Modules
, 开启 CSS
样式模块化、局部化,解决了全局样式冲突的问题。
3. 优化、兼容、转换 Css
: 通过 postcss-loader
优化、转换、兼容 Css
。通过 Autoprefixer
插件自动为 CSS
添加浏览器前缀,保证不同浏览器的兼容性。postcss-preset-env
:允许你使用未来的 CSS
特性,比如 CSS
自定义属性、嵌套等,并将其转换为当前浏览器可以理解的 CSS
。
4. Sass
、Less
预处理 Css
: 使用 sass-loader
、less-loader
来预处理 .scss
和 .less
文件, 使其转换为 .css
文件。
二、准备
安装相关依赖如下
# Css 相关依赖
pnpm add css-loader style-loader sass-loader sass less less-loader postcss-loader postcss-preset-env autoprefixer -D
# React 相关依赖
pnpm add react react-dom -D
# Webpack 相关依赖
pnpm add cross-env @rspack/cli @rspack/core webpack-merge -D
# Typescript 相关依赖
pnpm add @swc/cli @swc/core typescript swc-loader @types/react @types/react-dom -D
三、配置
3.1 definitions
definitions/style.d.ts
declare module "*.css" {
const content: { [className: string]: string };
export default content;
}
declare module "*.scss" {
const content: { [className: string]: string };
export default content;
}
declare module "*.less" {
const content: { [className: string]: string };
export default content;
}
declare module "*.module.css" {
const content: { [className: string]: string };
export default content;
}
declare module "*.module.scss" {
const content: { [className: string]: string };
export default content;
}
declare module "*.module.less" {
const content: { [className: string]: string };
export default content;
}
3.2 package.json
"scripts": {
"build": "cross-env NODE_ENV=production rspack build"
}
3.3 typescript.json
{
"compilerOptions": {
"target": "es5",
"module": "esnext",
"jsx": "react-jsx",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"moduleResolution": "node",
"resolveJsonModule": true,
"noEmit": true,
"baseUrl": "./",
"paths": {
"@/*": ["src/*"]
}
},
"include": ["src/**/*", "definitions/**/*"],
"exclude": ["node_modules", "dist"]
}
3.4 rspack.config.js
const Path = require("path");
const rspack = require("@rspack/core");
const { merge } = require("webpack-merge");
const devMode = process.env.NODE_ENV !== "production";
const cssLoader = (modules = false) => {
return [
devMode ? "style-loader" : rspack.CssExtractRspackPlugin.loader,
{
loader: "css-loader",
options: {
modules: modules
? {
namedExport: false,
}
: false,
},
},
{
loader: "postcss-loader",
options: {
postcssOptions: {
plugins: ["autoprefixer", ["postcss-preset-env", {}]],
},
},
},
];
};
const sassLoader = (modules = false) => [...cssLoader(modules), "sass-loader"];
const lessLoader = (modules = false) => [...cssLoader(modules), "less-loader"];
const cssRules = [
{
test: /\.css$/,
exclude: /\.module\.css$/,
use: cssLoader(),
},
{
type: "javascript/auto",
test: /\.module\.css$/,
use: cssLoader(true),
},
];
const sassRules = [
{
test: /\.(sa|sc)ss$/,
exclude: /\.module\.(sa|sc)ss$/,
use: sassLoader(),
},
{
type: "javascript/auto",
test: /\.module\.(sa|sc)ss$/,
use: sassLoader(true),
},
];
const lessRules = [
{
test: /\.less$/,
exclude: /\.module\.less$/,
use: lessLoader(),
},
{
type: "javascript/auto",
test: /\.module\.less$/,
use: lessLoader(true),
},
];
/** @type {import('@rspack/cli').Configuration} */
module.exports = {
entry: {
main: Path.resolve(process.cwd(), "src/index.tsx"),
},
output: {
clean: true,
path: Path.resolve(process.cwd(), "dist"),
filename: devMode ? "[name]/[name].js" : "[name]/[name].[contenthash:8].js",
chunkFilename: devMode
? "[name]/[name].js"
: "[name]/[name].[contenthash:8].js",
},
experiments: {
css: false,
},
resolve: {
extensions: [".js", ".jsx", ".ts", ".tsx"],
alias: {
"@": Path.resolve(__dirname, "../", "src"),
},
},
module: {
rules: [
{
test: /\.(js|ts)$/,
type: "javascript/auto",
exclude: [/node_modules/],
use: [
{
loader: "builtin:swc-loader",
options: {
sourceMap: true,
jsc: {
parser: {
syntax: "typescript",
},
externalHelpers: true,
},
},
},
],
},
{
test: /\.(jsx|tsx)$/,
type: "javascript/auto",
exclude: [/node_modules/],
use: [
{
loader: "builtin:swc-loader",
options: {
sourceMap: true,
jsc: {
parser: {
tsx: true,
syntax: "typescript",
},
externalHelpers: true,
transform: {
react: {
useBuiltins: false,
runtime: "automatic",
throwIfNamespace: true,
},
},
},
},
},
],
},
{
type: "asset",
test: /\.(png|jpg|jpeg|gif|svg)$/,
parser: {
dataUrlCondition: {
maxSize: 1 * 1024,
},
},
generator: {
filename: "images/[name].[hash:8].[ext]",
},
},
{
type: "asset",
test: /\.(woff|woff2|eot|ttf|otf)$/,
parser: {
dataUrlCondition: {
maxSize: 1 * 1024,
},
},
generator: {
filename: "fonts/[name].[hash:8].[ext]",
},
},
...cssRules,
...sassRules,
...lessRules,
],
},
plugins: [
new rspack.HtmlRspackPlugin({
filename: "index.html",
template: Path.resolve(process.cwd(), "public", `index.html`),
}),
...(devMode
? []
: [
new rspack.CssExtractRspackPlugin({
filename: "[name]/[name].[contenthash:8].css",
chunkFilename: "[name]/[name].[contenthash:8].css",
}),
]),
],
};