node-sass 迁移 sass(dart-sass) 后样式报错?用 loader 先把构建救回来

Vue CLI 老项目迁移 dart-sass:用一个插件兼容 /deep/>>>calc(100%-16px)

仓库:vue-cli-plugin-sass-compat

GitHub:github.com/myltx/vue-c...

老的 Vue CLI 项目升级 Node/依赖后,经常会被迫从 node-sass(libsass) 迁移到 sass(dart-sass)。真正卡人的往往不是"装上 sass 就完事",而是项目里存在大量历史写法,导致迁移后构建直接报错或样式编译不符合预期。

这篇笔记记录一个"过渡期方案":通过 vue-cli-plugin-sass-compatsass-loader 后插入一个轻量 loader,对源码做字符串级兼容替换,让你先把构建跑起来,再逐步治理样式。

你可能遇到的两类典型坑

1) 深度选择器旧写法:/deep/>>>

在一些链路/组合下,旧写法可能触发解析问题(例如 dart-sass 报 Expected selector),或者在升级过程中需要统一成 Vue 推荐的写法。

目标:将这些旧写法尽量自动转换为 ::v-deep

2) calc() 运算符空格:calc(100%-16px)

sass(dart-sass)calc() 表达式更严格,常见历史写法例如:

scss 复制代码
.a { width: calc(100%-16px); }

可能需要改成:

scss 复制代码
.a { width: calc(100% - 16px); }

目标:在迁移过渡期,自动补上二元运算符(+/-)两侧空格,避免全仓库手工替换造成巨大 diff。

方案:vue-cli-plugin-sass-compat

这个插件做的事情很克制:

  • 作为 Vue CLI Service 插件,通过 chainWebpacksass-loader 后插入一个 loader
  • 只处理你项目内的 .scss/.sass 文件(默认跳过 node_modules
  • 以"迁移过渡"为目标做最小替换:
    • /deep/>>>::v-deep
    • calc(...) 中的二元 +/- 自动补空格(尽量避开一元运算等场景)

使用前置:先完成依赖迁移(必做)

本插件不负责 替你替换依赖。使用前请先把项目从 node-sass 迁移到 sass(dart-sass)

bash 复制代码
npm rm node-sass
npm i -D sass

然后正常跑一遍安装:

bash 复制代码
rm -rf node_modules
npm i

安装与使用

方式 A:已发布到 npm(推荐)

bash 复制代码
npm i -D vue-cli-plugin-sass-compat

可选:迁移检查命令(doctor)

插件在 serve/build 首次执行时会做一次轻量检查:如果检测到仍存在 node-sass 或尚未安装 sass,会打印提示。

也可以手动运行:

bash 复制代码
vue-cli-service sass-compat:doctor

可选配置(vue.config.js

默认两项修复都开启(true)。需要精细控制时可以这样写:

js 复制代码
module.exports = {
  pluginOptions: {
    sassCompat: {
      fixDeep: true,
      fixCalc: true
    }
  }
}
  • fixDeep:是否将 /deep/>>> 等旧写法转换为 ::v-deep
  • fixCalc:是否修复 calc(100%-16px)calc()+/- 运算符空格

转换示例

深度选择器

输入:

scss 复制代码
.a /deep/ .b {}
.a >>> .b {}

输出(示意):

scss 复制代码
.a ::v-deep .b {}
.a ::v-deep .b {}

calc() 空格

输入:

scss 复制代码
.a { width: calc(100%-16px); }

输出:

scss 复制代码
.a { width: calc(100% - 16px); }

工作原理(简述)

  • index.js:通过 api.chainWebpack,在 sass/scss 规则里找到 sass-loader,并在其后插入 sass-compat-loader
  • sass-compat-loader.js:拿到每个样式文件的源码做字符串替换
    • 跳过 node_modules
    • /deep/ 直接替换为 ::v-deep
    • >>> 替换为 ::v-deep,并尽量补齐必要空格
    • calc(...) 做一次括号配对扫描,只在 calc() 内尝试给二元 +/- 补空格

边界与建议

  • 这是"迁移过渡"工具:建议你在构建恢复稳定后,逐步把业务代码里真正的历史写法治理掉,最终可以移除该插件
  • calc() 修复目前只处理二元 +/-,不会尝试覆盖 */ 等更复杂场景
  • 如果你项目里对 ::v-deep 的使用有更严格的团队规范,建议在过渡期结束后统一做一次规范化替换

最后

如果你也在做 Vue CLI 老项目的 node-sass -> sass(dart-sass) 迁移,欢迎直接试用这个插件;也欢迎提 issue 描述你遇到的"历史写法",我会优先考虑把高频场景纳入兼容范围。

相关推荐
Listen·Rain1 小时前
Vue概述
前端·javascript·vue.js
尽兴-1 小时前
传统 Java/Vue 系统如何一步步接入 AI 维护
java·vue.js·人工智能·ai·大模型
张人玉1 小时前
基于Vue 3 + ECharts / ECharts-GL / echarts-wordcloud 的数据可视化大屏——地形与产业数据可视化大屏
vue.js·信息可视化·echarts
十铭忘2 小时前
Vue3实现Pixso中的钢笔工具3——梳理函数调用
前端·vue.js
碎碎念_49215 小时前
SpringBoot + Vue 前后端分离从 0 到 1 完整环境配置流程
vue.js·spring boot·后端
shuaijie051816 小时前
强制修改调用接口的api地址。
javascript·vue.js·ecmascript
花椒技术20 小时前
Skill 落地系列一:Harness 试点复盘6 类真实业务场景的 Skill,全拆开给你看
agent·ai编程·前端工程化
katiua20 小时前
Vue-i18n TypeScript 补全提示
vue.js
Fuzio20 小时前
用 Spring Boot + Vue + Fuzio 构建现代 Java 桌面应用
vue.js·spring boot
kisshyshy20 小时前
从0到1彻底理解流式输出:先读懂Vue的“乐高积木”,再拧开LLM的“数据水龙头”
javascript·vue.js·人工智能