使用Webpack4+Express中间件时SCSS Loader加载失败问题排查
为什么会出现这个错误?
这个报错的核心原因很明确:Node.js原生根本不认识SCSS语法,但你的服务端环境在运行时直接尝试解析了bootstrap.scss里的@import "functions";代码。
虽然你给服务端Webpack配置了SCSS loader,但在开发模式下,webpack-hot-server-middleware或者你用的babel-register并没有正确拦截SCSS文件的加载流程——简单说就是,有部分代码绕过了Webpack的编译,直接让Node去加载了SCSS文件,自然就抛出语法错误了。
而且你引入的是bootstrap.scss这种全局样式,服务端渲染场景下完全不需要处理它的样式内容(样式只需要在客户端生效),这就更没必要让Node去碰这些文件了。
快速解决方法(推荐)
直接让服务端Webpack忽略所有样式文件,安装ignore-loader就能搞定:
- 先安装依赖:
npm install ignore-loader --save-dev # 或者用 yarn:yarn add ignore-loader --dev
- 修改你的服务端Webpack配置,把原来的SCSS规则替换成:
module.exports = merge({ // ... 其他原有配置 module: { rules: [ // ... 保留已有的js/jsx处理规则 { test: /\.(scss|css)$/, use: 'ignore-loader' } ] } }, commonConfig);
这样Webpack在打包服务端代码时,会直接跳过所有CSS/SCSS文件,不会把它们编译进服务端bundle里,Node自然也就不会去解析SCSS语法了。
如果你需要CSS Modules支持(可选)
如果你的项目里用了CSS Modules,需要在服务端获取类名映射,那不能直接忽略样式文件,得改用css-loader/locals来处理——它只会导出类名,不会生成实际的样式代码:
修改服务端的SCSS规则:
{ test:/\.scss/, use: [ { loader: 'css-loader/locals', options: { modules: true, localIdentName: '[name]__[local]--[hash:base64:5]' } }, { loader: 'sass-loader' } ] }
但注意,bootstrap.scss是全局样式,没有CSS Modules类名,所以这种情况还是用上面的ignore-loader方案更合适。
额外兜底方案
如果上面的配置还是没解决问题,可能是你的babel-register没有忽略node_modules里的SCSS文件,你可以在服务端入口文件的最开头加一段代码,手动让Node忽略样式文件:
// 让Node遇到SCSS/CSS文件时直接返回空对象,不解析 require.extensions['.scss'] = () => {}; require.extensions['.css'] = () => {};
这样就能彻底避免Node去碰样式文件了。
内容的提问来源于stack exchange,提问作者ShiiRochi

