Webpack 5 Split Chunks处理SCSS导入时失效问题排查
我搭建了基础的Webpack 5(v5.75.0)环境,配置如下:
webpack.config.js:
const path = require('path'); const MiniCssExtractPlugin = require("mini-css-extract-plugin"); module.exports = { entry: { home: './src/home.js', about: './src/about.js' }, mode: "development", resolve: { extensions: ['.js', '.jsx', '.scss'] }, output: { path: path.resolve(__dirname, 'dist'), filename: 'js/[name].js', clean: true }, module: { rules: [ { test: /\.s[ac]ss$/i, use: [ MiniCssExtractPlugin.loader, "css-loader", "sass-loader", ], }, ], }, plugins: [new MiniCssExtractPlugin({ filename: "css/[name].css"})], optimization: { splitChunks: { chunks: 'all', minSize: 0, }, }, };
Home.js:
import "./home.scss";
About.js:
import "./about.scss";
home.scss:
@import "./card.scss";
about.scss:
@import "./card.scss";
按照Split Chunks配置,我预期会生成包含card样式的共享CSS文件以实现复用,但实际输出的home.css和about.css均包含重复的card样式,未生成共享文件。
有趣的是,若将home/about.js中改为直接导入card.css,则能正常拆分出共享chunk文件。
请问我哪里配置出错了?
原因分析
问题出在sass-loader的默认处理逻辑:当你在.scss文件中用@import导入其他.scss时,sass-loader会在编译阶段直接把被导入文件的内容合并到当前SCSS文件中,最终输出的是两个独立的、已经包含card样式的完整CSS资源。Webpack无法识别这两个资源的共享部分,自然不会触发splitChunks拆分。
而直接在JS里导入.css文件时,Webpack会把每个CSS文件当作独立模块处理,重复导入的模块能被splitChunks检测到并拆分。
解决方法
要让Webpack识别SCSS中的共享模块,需要让sass-loader把@import的SCSS文件当作Webpack模块处理,而非直接合并:
修改sass-loader的配置,启用Webpack模块解析器:
在module.rules的sass-loader配置中添加webpackImporter: true选项,让sass-loader使用Webpack的模块解析逻辑处理@import。修改后的
module.rules部分代码:module: { rules: [ { test: /\.s[ac]ss$/i, use: [ MiniCssExtractPlugin.loader, "css-loader", { loader: "sass-loader", options: { webpackImporter: true, // 启用Webpack模块解析器 }, }, ], }, ], },验证效果:重新运行Webpack后,dist目录下会生成类似
vendors~home~about.css的共享文件,其中包含card的样式,home.css和about.css则只保留各自独有的样式。
内容的提问来源于stack exchange,提问作者Benji40

