node-sass 替换为 dart-sass

732 阅读2分钟

你好,我是本文作者南一。如果有发现错误或者可完善的地方,恳请斧正,万分感谢!!

背景

为缩短前端工程的构建时长,决定将构建工具 webpack4 替换为 rspack。rspack最低要求的node版本为16,而工程中使用的 node-sass 却不支持,因此不得不将 node-sass 替换为 dart-sass。

实现步骤

1.依赖更新

sass 使用 1.78.0 版本,因为高版本有很多break更新,解析不了当前代码使用的语法

tnpm uninstall node-sass;
tnpm install sass-loader sass@1.78.0 -D;

2. 配置更新

sass 无法解析深度选择器/deep/需要替换成::v-deep。sass-loader 有一个配置项additionalData 可以在编译过程修改文件内容,利用其将完成替换。

{
  test: /\.(sass|scss)$/,
  use: [
    isProd ? rspack.CssExtractRspackPlugin.loader : 'vue-style-loader',
    'css-loader',
    {
      loader: 'sass-loader',
      options: {
        additionalData: async (content, loaderContext) => {
          return content.replaceAll('/deep/', '::v-deep');
        },
      }
    },
  ],
  type: 'javascript/auto',
},

npm run build 后发现还是报错了,原来被引入的.scss文件不会经过sass-loader解析,sass-loader仅作用于.vue文件style块内的代码。只能单独处理了...

3. 替换 .scss 文件的内容

编写脚本遍历src所有文件,将后缀为.scss的文件替换深度选择器;在build时执行脚本。

{
  "scripts": {
    "build": "node ./replaceDeep.js && rspack build"
  },
}
const fs = require('fs');
const path = require('path');

// 递归遍历文件夹内的所有文件
function walkDir(dirPath) {
  const files = fs.readdirSync(dirPath);
  files.forEach(file => {
    if(['node_modules', 'dist'].includes(file)) return;
    const filePath = path.join(dirPath, file);
    const stat = fs.lstatSync(filePath);
    if (stat.isDirectory()) {
      walkDir(filePath);
    } else if (file.endsWith('.scss')) {
      replaceDeep(filePath);
    }
  });
}

// 替换文件内的'/deep/'为'::v-deep'
function replaceDeep(filePath) {
  fs.readFile(filePath, 'utf8', function (err, data) {
    if (err) {
      return console.log(err);
    }
    const result = data.replaceAll(/\/deep\//g, '::v-deep');
    fs.writeFile(filePath, result, 'utf8', function (err) {
      if (err) return console.log(err);
    });
  });
}

walkDir(__dirname);

总结

node-sass已经不再维护了,官方也推荐使用dart-sass解析sass代码。在替换之后,需要同步组内同学使用新语法::v-deep