记一次 sass 导出变量在 Webpack 5 不生效的解决过程

1,299 阅读3分钟

TL;NR 太长不看

涉及到了 CSS Modules

在 Webpack 的 css-loader 中,默认情况下,为所有匹配 /.module.\w+$/i.test(filename) 与 /.icss.\w+$/i.test(filename) 正则表达式的文件启用 CSS 模块,这样可以支持诸如 :export 等 css modules 特性。

在将 Webpack 4 升级到 5 时,往往 css-loader 也会升级。那么需要将原有的 *.scss 改名为 *.module.scss 即可;其他诸如 css、less 等同理。


这是一篇过气的碎碎念,只是自己记录一下了,众看官莫笑。

失效了的 :export 魔法

最近在尝试将一个 Webpack 4 升级到 5 (Vite 以后再说),项目基于 花裤衩Vue Element Adminpanjiachen.gitee.io/vue-element…

Vue Element Admin 用的是 Vue CLI 4,也就是对应了 Webpack 4;升级到 Vue CLI 5 之后(已经处于维护模式,使用的 Webpack 5),主题什么的全丢了,最明显的是默认为黑色的左侧导航栏变成了白色。找到对应的组件,位于 src\layout\components\Sidebar\index.vue,不难发现这一句:

import variables from '@/styles/variables.scss'

看来主题颜色是通过这种方式动态调整的,采用的是 :export 这个魔法,见: gitee.com/panjiachen/…

// the :export directive is the magic sauce for webpack
// https://www.bluematador.com/blog/how-to-share-variables-between-js-and-sass
:export {
  menuText: $menuText;
  menuActiveText: $menuActiveText;
  subMenuActiveText: $subMenuActiveText;
  menuBg: $menuBg;
  menuHover: $menuHover;
  subMenuBg: $subMenuBg;
  subMenuHover: $subMenuHover;
  sideBarWidth: $sideBarWidth;
}

通过该魔法,可以将 scss 、 css 变量共享给 js ,相关文章掘金里就很多,不一一列举。

然而,升级到 Webpack 5 之后这个魔法失效了?在注释提供的文章地址中也看到了近几年的评论:

This doesn't work. 这不好用啊老铁

What version of sass-loader supports this? 哪个 sass-loader 版本支持这特性?

都是这种画风。然后...就没然后了...

背后一凉:这咋办?

好吧,开始搜索关键词: webpack 5 sass :export

无果...

换了几个关键词也不行...

不是 Webpack 5 都出了这么久了,怎么会这么难搜呢?

甚至去 Sass官网,也搜不到 :export。那这魔法哪里来的?

不过搜到了一些其他的方案,比如:

魔法来源:CSS Modules

CSS modules 我早有耳闻,不过一直认为离 Vue 很远。这让我意识到之前的思路不对劲,要正视这个工具了。

官方仓库 并没有提及该黑魔法,但是文末提及了 Webpack 的 css loader,于是去查 Webpack 文档,找到了这样的描述:

modules

类型:Boolean|String|Object 默认值:undefined

启用/禁用 CSS 模块或者 ICSS 及其配置:

  • undefined - 为所有匹配/.module.\w+$/i.test(filename) 与 /.icss.\w+$/i.test(filename) 正则表达式的文件启用 CSS 模块。

ICSS ?

前面 将 SCSS 变量分享给 JS 这篇文章提及了:

坑 1:必须让 css-loader 使用 icss 模式,否则 vars 为空对象!

这里就没看懂,不过我 console.log 了一下,对应的 vars 确实为空对象,然后就跳过了。看来关键点在这里。

接下来搜索关键词: css modules icss export

找到了 ICSS 仓库。 ICSS, Interoperable CSS ,即:互操作 CSS —— 互操作?原来就是用来做跨语言交换的啊!

果然,找到了 :export 魔法的来源了,就是这里!

:export

An :export block defines the symbols that are going to be exported to the consumer. It can be thought of functionally equivalent to the following JS:

module.exports = {
	"exportedKey": "exportedValue"
}

收尾

做完上面的了解,立即将原有的 variables.scss 重命名为 variables.module.scss,问题解决!

看来原有的注释需要再改进一下,然后重新戳开了注释里的那篇文章,才发现...原来人家已经写明了这是 CSS Module 的魔法...😑

面对非母语的文章容易不怎么耐心下来看,反而花费了更多的时间绕弯。日后还是要多些耐心才是。

还是得好好去看一下 CSS Module...之前太想当然了...