用 Sass 模块化系统取代全局导入,消除 1.80.0 引入的 @import 弃用警告

目录

前言

问题

[@import 的缺陷](#@import 的缺陷)

命名冲突

重复导入

模块系统

[@use 规则](#@use 规则)

[@forward 规则](#@forward 规则)

实际修改


前言

最初,Sass 使用 @import 规则通过单个全局命名空间加载其他文件,所有内置函数也可全局使用。由于模块系统(@use@forward 规则)已经推出多年,我们现已弃用 Sass @import 规则和全局内置函数。

@import 会导致许多问题,需要手动为 Sass 成员指定命名空间以避免冲突,当多次导入同一个文件时会减慢编译速度,并且使人类和工具都很难分辨给定变量、混合或函数来自何处。

模块系统修复了这些问题,并使 Sass 的模块化与其他现代语言的最佳实践相媲美,但只要 @import 仍保留在语言中,我们就无法获得它的全部好处。

@import 现在从 Dart Sass 1.80.0 开始已弃用。此外,我们还将弃用 sass: 模块中可用的 Sass 内置函数的全局版本。

问题

将 Sass 升级到 1.80.0 及以上版本后,你可能会遇到如下警告:

复制代码
WARN  Dart Sass: [file].scss:[line]:8: Sass @import rules are deprecated and will be removed in Dart Sass 3.0.0.

该警告表示 @import 规则已被弃用,并且将在 Sass 3.0.0 版本中移除。这看上去很宽容,毕竟 Sass 2.0 还未发布呢。但实际上取代 @import 的现代化方案已经推出好几年了,可它仍然被广泛使用。这大概就是 Sass 在 2.0 之前就弃用它的原因吧。

这个警告是值得修正的,消除它的正面效果绝不仅是清理碍眼的输出。

@import 的缺陷

命名冲突

假设我们有以下三个 SCSS 文件:

复制代码
// file1.scss
$color: blue;
@mixin button {
  // button styles
}

// file2.scss
$color: red; // 会覆盖 file1 的 $color
@mixin button {
  // 会覆盖 file1 的 button
  // different button styles
}

// main.scss
@import "file1";
@import "file2";
// 此时 $color 是 red, button mixin 是 file2 的版本

如上代码中的注释所示,@import 导致了命名冲突。因为 @import 是全局性的,而不是模块化的。对于 IDE 和工具而言也不友好,它们可能很难推断你使用的变量、mixin 等来自哪个文件。全局导入这种东西在现代化语言中不应该存在,或者限制使用。其副作用难以琢磨的。

重复导入

再假设,你有如下文件:

复制代码
// header.scss
@import "variables";
@import "mixins";

// footer.scss
@import "variables"; // 重复导入
@import "mixins"; // 重复导入

// main.scss
@import "header";
@import "footer";
// variables 和 mixins 被导入了两次

如上代码中的注释所示,@import 会重复导入。因为 @import 并不关心导入的文件是否已经导入过。重复导入会降低编译速度,在大型项目中尤为明显。

模块系统

@use 规则

基于 @import 的全局导入特性,我们很容易将变量集中到某个文件中然后直接引入到当前的代码环境中:

复制代码
// app.scss
@import "vars/colors";

h1 {
  color: $title-color; // <- 直接使用 var/colors.scss 中的变量
}

将以上的 @import 改为 @use,现在 Sass 会为我们自动创建命名空间。以避免全局带来的冲突和污染:

复制代码
// app.scss
@use "vars/colors";

h1 {
  color: colors.$title-color; // <- 使用命名空间访问 var/colors.scss 中的变量
}
复制代码
注意,这会带来一个显著的迁移难题。首先,我们以及工具都可能很难推断此前代码中直接使用的变量来自哪里(换作模块化系统就是哪个命名空间),尤其是组织不严谨的项目。该如何准确修改呢?好办:
复制代码
// app.scss
@use "vars/colors" as *;

h1 {
  color: $title-color; // <- 直接使用 var/colors.scss 中的变量
}

as 语法和 *,将所有成员直接导入进来。类似于 JS 的 import *。这样可以让我们的代码平缓迁移,逐渐的改用为命名空间。并且不存在全局范围带来的各种问题。

@forward 规则

仅靠 @use 带来的模块化改变,有时候也会增加更多的样板代码。例如你有一批变量文件,按类型归类如 colors.scssfonts.scsssizes.scss 等。你需要在每一个使用变量的文件中分别导入它们。

组件 1:

复制代码
// compoent1.scss
@use "vars/colors";
@use "vars/fonts";
@use "vars/sizes";

// compoent1 代码...

组件 2:

复制代码
// compoent2.scss
@use "vars/colors";
@use "vars/fonts";
@use "vars/sizes";

// compoent2 代码...

使用 @forward 改善这一情况:

复制代码
// vars.scss
@forward "colors";
@forward "fonts";
@forward "sizes";

// 更多的变量文件...

然后我们仅导入 vars 即可:

复制代码
// compoent1.scss
@use "vars";

// component2.scss
@use "vars";

@forward 规则用于将一个模块的内容"转发"到另一个模块中。这样,你可以在不直接使用模块的情况下,通过转发的模块间接使用原始模块的内容。

Sass 为我们提供了迁移工具 sass-migrator,通过它可以自动化的将样式代码迁移到模块化系统。运行命令:

复制代码
px sass-migrator module --verbose --migrate-deps styles.scss

styles.scss 替换为你的入口样式文件即可。其中 --migrate-deps 参数表示不仅是修改显式传递给命令行的样式文件,还会修改它的依赖。基于模块系统章节的基本知识,你应该对修改会具有一些审查能力。

实际修改

1. Sass @import rules are deprecated and will be removed in Dart Sass 3.0.0

sass 1.80 不再支持 @import 需要使用 `@use'

  • 错误提示:

    Deprecation Warning on line 1, column 9 of src\About.vue:
    Sass @import rules are deprecated and will be removed in Dart Sass 3.0.0.

    More info and automated migrator: https://sass-lang.com/d/import

    1 │ @import "@/variables.scss";
    │ ^^^^^^^^^^^^^^^^^^

  • 修改方法:

    @use "@/variables.scss";

Deprecation Warning: The legacy JS API is deprecated and will be removed in Dart Sass 2.0.0.

sass 1.80 不再支持老的 js api 接口

  • 错误提示:

    Deprecation Warning: The legacy JS API is deprecated and will be removed in Dart Sass 2.0.0.

    More info: https://sass-lang.com/d/legacy-js-api

  • 修改方法 vue.config.js:

    export default defineConfig({
    ...
    css: {
    preprocessorOptions: {
    scss: {
    api: 'modern-compiler', // 修改api调用方式
    },
    },
    },
    ...
    });

Internal server error: [sass] Undefined variable.

sass 1.80 全局变量和 mixin 需要手动导出

  • 错误提示:

    14:20:18 [vite] Internal server error: [sass] Undefined variable.

    13 │ color: $color-blue;
    │ ^^^^^^^^^^^

    14:18:52 [vite] Internal server error: [sass] Undefined mixin.

    6 │ @include func(css);
    │ ^^^^^^^^^^^^^^^

  • 修改方法 vue.config.js:

    export default defineConfig({
    ...
    css: {
    preprocessorOptions: {
    scss: {
    api: "modern-compiler",
    javascriptEnabled: true, // 启用javascript
    additionalData: '@use "@/style/variable.scss" as *;',
    },
    },
    },
    ...
    });

相关推荐
搬砖-无恙6 分钟前
vue+uniapp 获取上一页直接传递的参数
前端·vue.js·uni-app
树上有只程序猿6 分钟前
聚焦应用常用功能,提升用户体验与分发效率
前端
喆星时瑜10 分钟前
HBuilder运行uni-app程序报错【Error: listen EACCES: permission denied 0.0.0.0:5173】
前端·javascript·uni-app·hbuilder·error·端口占用
前端三叶草14 分钟前
记一次为js库开发声明文件的过程
前端·npm
37手游后端团队32 分钟前
websocket连接管理
前端·后端·websocket
bin915341 分钟前
DeepSeek 助力 Vue3 开发:打造丝滑的日历(Calendar)
前端·javascript·vue.js·ecmascript·deepseek
YiHanXii44 分钟前
XSS(跨站脚本攻击)
前端·网络·xss
LinDaiuuj1 小时前
编程中,!! 双感叹号的理解
前端·javascript
呦呦鹿鸣Rzh1 小时前
SpringMVC的请求-文件上传
java·前端·html
samroom1 小时前
ES6规范新特性总结
前端·javascript·es6