@import/@use/@forward 的区别和使用

前言

sass是开发中常用的预处理器,帮助开发者可以简单的在css中实现逻辑操作,提高代码的可读性和复用性。

业务中经常看到@import/@use/@forward混用,尽管官方明确表示逐步废弃@import,但是业务中任然大量出现,我觉得有必要将 @import out了。

sass的基本语法都比较常见,本文主要对sass中经典的三种导入方法进行区分。

@import

我们知道@import 是一个逐渐被官方弃用的语法,主要有如下原因:

  1. 定义的内容全局可见
  2. 不好追溯来源
  3. 重复输出

这三点缺点用sass的应该都听过一些(懂了又似乎没完全懂)。逐步解释下:

什么是全局可见??

我们三个样式表 a,b,c,在a中声明了一个变量和一个实体样式,然后我们需要编写bc样式表,需要用到a中的样式和变量;

最后我们在入口处index中引入module bc,此时会发现:为什么在index中能使用$red??

事实上我们的初衷是在bc中导入使用,而不是暴露给上游。

这就是全局可见,因为我们不可避免的会多个模块之间有依赖关系,那么每次@import一次,都会暴露给下游所有的内容-即全局。

不好追溯来源

其实问题一就是问题二的主要原因:当前能使用的内容大于我们显示导入的内容。我们只显示导入了b,c,但是能使用的内容却是a,b,c

因为没有命名空间,还会造成变量污染;

重复输出

@import实际上是每次导入一个模块,就会向当前文件编译输出一次。

可以看到上图输出结果中包含了两次.text-red的样式,这是没有必要的,不仅会增加输出的包体积,还会影响编译速度增加编译时间

@use

@use解决了以上问题

  1. 为什么说解决了全局可见的问题?

从定义上来看,这是sass的模块化实现方法,可以类比esm中的import;如果你在bc中需要使用a,那就import a from 'a',注意,此处只是使用,却没有向外暴露,所以依赖bc的样式表是不能访问a的内容的。这也就是说为什么@use可以解决全局可见的问题,准确来说是模块化的正确实现。

  1. 由于要使用就得显示@use,也就来源可溯了
  2. @use导入的文件,无论导入多少次,结果中只会输出一次

@use主要是针对性的解决了@import的问题

@forward

@forwrad主要是和@use一起使用,作用是模块转发

模块转发??

其实意思就是向外暴露模块,类比esm中的export,举个例子:

css 复制代码
/* a.scss  */
$red: red;
.text-red {
  color: $red;
}

/*b.scss  */
@forward './a.scss';//类比js export * from './a'
$b: green;

/* c.scss */
@forward './a.scss';//类比js export * from './a'
$c: yellow;



/*index.scss  */
@use './c.scss' as *;//类比js import * from 'c'
@use './b.scss' as *;//类比js import * from 'b'
.idx {
  color: $b;
  color: $c;
  color: $red;//这里就可以使用a的变量啦
}

我们之前说过@use就是使用,是不对外暴露模块的,也就是说,在index中不能访问a的内容,如果需要访问,那就通过@forward暴露

值得一提的是,@forward也不会产生重复导入的问题

项目中的使用(以vite为例)

既然@import不好,那我们就直接弃用吧(就好像esm逐步淘汰cjs一样)

先下个结论:@use@forward完全可以替换掉@import

项目中一般有一个静态变量的定义文件,比如variables/mixin/function.scss这些是需要全局都能访问的

typescript 复制代码
//variables.scss
$jm-text-color-primary: #303133 !default;
$jm-text-color-regular: #606266 !default;
$jm-text-color-secondary: #909399 !default;
$jm-text-color-placeholder: #c0c4cc !default;

// vite.config
  css: {
      preprocessorOptions: {
        //全局css
        scss: {
          additionalData: `
          @use "@/styles/theme/${env.VITE_APP_BASE_THEME}.scss" as *;
          @use "@/styles/variables.scss" as *;
          `
        }
      }
    },

vite config中有一个配置项:additionalData,在这可以注入全局的变量

注意:这里是'注入',additionalData 的本质是在每一个样式文件首行都注入我们的内容,类似于 sassFileSource = additionalData+ sassFileSource 这也就是为什么可以全局访问变量的原因 所以不要在这里加实体样式!,否则会在所有的样式文件中都会多出注入的实体样式,这是没有意义的

定义一个分离的样式:

typescript 复制代码
@forward './c.scss';
@forward './b.scss';
@use './c.scss' as *;
@use './b.scss' as *;
.idx {
  color: $b;
  color: $c;
  color: $red;
}

在vue模版中导入样式:

vue 复制代码
<style lang="scss" scoped>
  @use './index.scss';
</style>

总结

@import 因为重复输出,全局污染等问题,可以直接弃用。
@use@forward配合使用,@use负责导入使用,@forward负责向外暴露转发模块

相关推荐
-代号952735 分钟前
【React】一、JSX的使用
前端·react.js·前端框架
uhakadotcom1 小时前
AI搜索引擎的尽头是电商?从perplexity开始卖货说起...
前端·人工智能·后端
selfsuer1 小时前
Element-plus 【el-input输入框】和【el-select下拉选择框】样式修改
前端·javascript·vue.js
咔叽布吉2 小时前
【前端学习笔记】ES6 新特性
前端·笔记·学习
推开世界的门3 小时前
web 中 canvas 污染 以及解决方案
前端
星离~3 小时前
css—轮播图实现
前端·css
龙雨LongYu124 小时前
vue3+ts 我写了一个跟swagger.yml生成请求和响应实体(接口)
前端·vue.js·typescript
Stanford_11064 小时前
关于IDE的相关知识之一【使用技巧】
前端·ide·windows·微信小程序·微信公众平台·twitter·微信开放平台
_志哥_4 小时前
web开发环境下启动HTTPS服务访问
前端·javascript·https
爱健身的小刘同学4 小时前
安装 electron 依赖报错
前端·javascript·electron