lable  

版本:

vue@2.6.14
@vue/cli 5.0.4

在前端的样式代码中我们经常会看到全局变量共享:

$menuText:#bfcbd9;
$menuActiveText:#409EFF;
$subMenuActiveText:#f4f4f5;

$menuBg:#304156;
$menuHover:#263445;

$subMenuBg:#1f2d3d;
$subMenuHover:#001528;

$sideBarWidth: 210px;

:export {
  menuText: $menuText;
  menuActiveText: $menuActiveText;
  subMenuActiveText: $subMenuActiveText;
  menuBg: $menuBg;
  menuHover: $menuHover;
  subMenuBg: $subMenuBg;
  subMenuHover: $subMenuHover;
  sideBarWidth: $sideBarWidth;
}

vue中获取css对象

<template>
  <div :class="{'has-logo':showLogo}">
    <el-scrollbar wrap-class="scrollbar-wrapper">
      <el-menu
        :default-active="activeMenu"
        :collapse="isCollapse"
        :background-color="variables.menuBg"
        :text-color="variables.menuText"
        :unique-opened="false"
        :active-text-color="variables.menuActiveText"
        :collapse-transition="false"
        mode="vertical"
      >
    </el-scrollbar>
  </div>
</template>

<script>
import variables from '@/styles/variables.scss'

export default {
  components: { },
  computed: {
    variables() {
      console.log("-=---variables", variables)
      return variables
    }
  }
}
</script>

上面的代码摘抄自vue-admin-template的variables.scss,这样的目的是把样式变量共享给js使用,但由于工具版本的不同配置约定也不一样,可能会导致这样的写法不会生效。

通过阅读源码的文档我们可以发现css module的配置项发生了几次变动,这里摘抄几个跟:export相关的变动日志

5.0.0-alpha.6 (2021-03-10)

🚀 New Features

  • @vue/cli-service
    • #6332 feat!: upgrade to css-loader 5; remove css.requireModuleExtension & css.modules options (@sodatea)

4.0.0-beta.3 (2019-08-08)

🚀 New Features

  • @vue/cli-service
    • #4387 feat!: deprecate css.modules in favor of css.requireModuleExtension (@sodatea)

从上面变更日志可以看出,在vue-cli v5版本中requireModuleExtension是已经被移除了的。确实在没有任何配置的情况下console.log("-=---variables", variables)打印出来的就是一个空对象

-=---variables 
{}
[[Prototype]]: Object
constructor: ƒ Object()
hasOwnProperty: ƒ hasOwnProperty()
isPrototypeOf: ƒ isPrototypeOf()
propertyIsEnumerable: ƒ propertyIsEnumerable()
toLocaleString: ƒ toLocaleString()
toString: ƒ toString()
valueOf: ƒ valueOf()
__defineGetter__: ƒ __defineGetter__()
__defineSetter__: ƒ __defineSetter__()
__lookupGetter__: ƒ __lookupGetter__()
__lookupSetter__: ƒ __lookupSetter__()
__proto__: (...)
get __proto__: ƒ __proto__()
set __proto__: ƒ __proto__()

解决方案

通过阅读官方文档,发现可以根据约定将文件名改为.module.(css|scss|sass|less|styl(us)?)结尾,这样就可以识别出css module。

这里是将自己项目中的variables.less改成了variables.module.less,可以发现确实生效可以获取到正常的js对象。

-=---variables 
{menuText: '#bfcbd9', menuActiveText: '#409EFF', subMenuActiveText: '#f4f4f5', menuBg: '#304156', menuHover: '#263445', …}
menuActiveText: "#409EFF"
menuBg: "#304156"
menuHover: "#263445"
menuText: "#bfcbd9"
sideBarWidth: "210px"
subMenuActiveText: "#f4f4f5"
subMenuBg: "#1f2d3d"
subMenuHover: "#001528"
[[Prototype]]: Object

从源码上也可以对比看出,@vue/cli-service v4.4.4上使用的css.requireModuleExtension@vue/cli-service v5.0.4已经无法搜索到。

@vue/cli-service v4.4.4

...
      // rules for normal CSS imports
      const normalRule = baseRule.oneOf('normal')
      applyLoaders(normalRule, !requireModuleExtension)
...
        const cssLoaderOptions = Object.assign({
          sourceMap,
          importLoaders: (
            1 + // stylePostLoader injected by vue-loader
            1 + // postcss-loader
            (needInlineMinification ? 1 : 0)
          )
        }, loaderOptions.css)

        if (isCssModule) {
          // 通过requireModuleExtension标记来生成modules配置
          cssLoaderOptions.modules = {
            localIdentName: '[name]_[local]_[hash:base64:5]',
            ...cssLoaderOptions.modules
          }
        } else {
          delete cssLoaderOptions.modules
        }
...

@vue/cli-service v5.0.4

...
        const cssLoaderOptions = Object.assign({
          sourceMap,
          importLoaders: (
            1 + // stylePostLoader injected by vue-loader
            1 + // postcss-loader
            (needInlineMinification ? 1 : 0)
          )
        }, loaderOptions.css)
...
        if (forceCssModule) {
          cssLoaderOptions.modules = {
            ...cssLoaderOptions.modules,
            auto: () => true
          }
        }
        // 依赖外部传入的cssLoaderOptions.modules即loaderOptions.css
        if (cssLoaderOptions.modules) {
          cssLoaderOptions.modules = {
            localIdentName: '[name]_[local]_[hash:base64:5]',
            ...cssLoaderOptions.modules
          }
        }
...

总结

vue-cli版本变动还是挺频繁的,v5版本实际上已经将css.requireModuleExtension选项弃用但官方文档并没有更新,网上搜到的方案经常会是不适用的方案。如果发现一些配置项已失效或不可用当前版本对应的插件版本是不是和之前使用的不一致,然后看看源码的变更日志,翻一翻插件的文档及其源码就可以找到相应的解决方案。

posted on 2022-04-26 16:47  lable  阅读(404)  评论(0编辑  收藏  举报