配置数组:如何在每次Sass编译前注入钩子 #16075
解决Webpack 4.x中Sass编译前修改文件内容的方案
方案一:自定义前置Loader(推荐)
Webpack的Loader按从右到左的顺序执行,我们可以在sass-loader之前添加自定义Loader,专门处理Sass文件内容的修改,完全契合编译前介入的需求。
- 新建自定义Loader文件(如
sass-preprocessor-loader.js):
const fs = require('fs'); const path = require('path'); module.exports = function(source) { // 这里编写你的内容修改逻辑,示例:替换Sass中的占位变量为共享配置 const yourSharedConfig = this.options.siteConfig; // 从Webpack配置传递的共享配置 const modifiedSource = source.replace( /@import "shared-config";/, `$site-config: ${JSON.stringify(yourSharedConfig).replace(/"/g, "'")};` ); return modifiedSource; };
- 在Webpack配置中引入该Loader,注意顺序要放在
sass-loader之前(数组中靠后的位置,因为执行顺序反向):
const path = require('path'); module.exports = { // 传递共享配置给Loader siteConfig: { /* 你的多站点共享配置数组 */ }, // ...其他Webpack配置 module: { rules: [ { test: /\.s[ac]ss$/i, use: [ 'style-loader', 'css-loader', 'sass-loader', { loader: path.resolve(__dirname, './sass-preprocessor-loader.js'), } ], }, ], }, };
方案二:利用Webpack Compiler钩子拦截模块
通过监听Webpack的模块加载钩子,在Sass文件进入sass-loader前拦截并修改内容:
const fs = require('fs'); module.exports = { // ...其他Webpack配置 plugins: [ { apply(compiler) { // 监听模块解析前的钩子 compiler.hooks.normalModuleFactory.tap('SassPreHook', (nmf) => { nmf.hooks.afterResolve.tap('ModifySassContent', (result) => { // 仅处理Sass文件 if (result.resource.match(/\.s[ac]ss$/i)) { // 读取原文件内容并修改 const originalContent = fs.readFileSync(result.resource, 'utf8'); const modifiedContent = originalContent.replace( /\$default-theme/g, '$custom-theme: #2c3e50;' ); // 替换模块的原始内容 result.loaders.unshift({ loader: 'string-replace-loader', options: { search: originalContent, replace: modifiedContent, }, }); } return result; }); }); } } ] };
为什么之前的方法无效?
sass-loader的选项仅用于配置Sass编译器的行为(如includePaths、sourceMap等),没有提供直接修改源文件内容的入口。webpack-shell-plugin的before钩子是在Webpack启动前执行脚本,此时还未开始处理具体模块文件,无法触达即将编译的Sass内容。
内容的提问来源于stack exchange,提问作者Cristialt
相关产品推荐
相关产品推荐

