/vue-style-variables-loader

Webpack loader for loading global variable.less/styl/sass files in every vue component

Primary LanguageJavaScript

vue-style-variables-loader

npm version Build Status

NPM

这个基于 webpack 的 loader 试图解决使用 Vue 开发中的两个问题:

  1. 在 Vue 单文件中自动引入变量文件
  2. 选用了一个 UI 框架并使用了框架提供的主题解决方案,在组件中想使用这些主题变量,但又不想使用框架指定的预处理器

下面让我们分别看下这两个问题。

问题1:在 Vue 单文件中引入变量文件

通常我们的项目中包含一个定义了常用变量的文件,以开发选择的预处理器格式存在。 使用时,在每个 Vue 单文件组件的 style 块中都需要手动引入这个变量文件。虽然使用 webpack alias 之后不用考虑路径问题,但如果能自动引入将方便很多。

// Component.vue

<style lang="scss">
    // 引入变量文件
    @import "@/styles/variables.scss";
    // 开始使用变量
</style>

有人针对这个问题向 vue-loader 提出了相关 issue。而 vue-loader 认为这个工作应该交给各个预处理器 loader 完成。

例如使用 sass 时,可以使用 sass-resources-loader

{
    loader: 'sass-resources-loader',
    options: {
        resources: 'variables.scss'
    }
}

或者使用 sass-loader的注入环境变量功能。keen-ui就采用了这种方式支持用户覆盖预定义的主题变量

plugins: [
    new webpack.LoaderOptionsPlugin({
        options: {
            sassLoader: {
                data: '@import "src/styles/variables.scss";',
                includePaths: 'src/styles'
            },
            context: path.resolve(__dirname) // your project root
        }
    })
]

而在 stylus-loader 中,可以使用import达到引入全局变量的目的。

plugins: [
    new webpack.LoaderOptionsPlugin({
        test: /\.styl$/,
        stylus: {
            use: [require('nib')()],
            import: ['~nib/lib/nib/index.styl']
        }
    })
]

less-loader 中并没有找到解决方法,似乎只能每次手动引入了。

可以看出,各个预处理器 loader 都有自己的方式解决这个问题。而且就算是手动引入,代价也并不高,让我们继续来看第二个问题。

问题2:选用和 UI 框架不同的预处理器开发

各个 UI 框架都有自己的主题解决方案,例如:

可以看出在使用变量文件覆盖的方案中,主题变量必须使用框架指定的预处理器定义。 例如选择了 vuetify,那开发者自定义的变量文件就必须使用 stylus 来写。这样在实际组件开发中,如果选择 less,就无法使用 stylus 定义的这些变量了。

// Component.vue

<style lang="less">
    // 引入变量文件
    @import "@/styles/variables.styl";
    // 出错了,less 并不认识 stylus 定义的变量 $bg-color
    background: @bg-color;
</style>

所以在上述场景中,我们需要将文件中使用 stylus 定义的每一个主题变量都转换成 less 变量,然后注入.vue文件的<style>块中。 如果能实现这一点,其实第一个问题也就顺便解决了。

实现思路

首先,开发者使用所选 UI 框架的主题解决方案,使用框架指定的预处理器创建一个变量文件,由于该文件只包含变量,对于开发者而言,学习特定预处理器语法的成本并不高。

然后,使用 loader 处理每一个.vue文件。该 loader 接受之前的变量文件作为输入,在每个.vue文件的每个<style>块中,根据当前<style>块指定的预处理器语言,将包含的所有变量进行转换并注入。这样开发者就可以直接使用自己熟悉的预处理器语法开发了。

并不需要做类似stylus,less,sass之间全部语法的互相转换。只需要转换变量声明语句。例如我们选用了 vuetify,会使用 stylus 编写一个文件theme.styl,里面包含了 stylus hash 类型的主题变量:

// theme.styl

$theme := {
    primary: white
    secondary: #fff
}

经过 loader 对theme.styl文件内容的解析, 在开发者的组件中,不需要添加任何额外语句,就可以直接使用 less 的语法访问这些变量:

// Component.vue

<style lang="less">
.selector {
    background: @theme-primary;
    color: @theme-secondary;
}
</style>

<style lang="sass">
.selector
    background: $theme-primary
    color: $theme-secondary
</style>

要注意 less 和 sass 中变量名称中不能包含.,所以我使用了-。所以需要通过@theme-primary而非@theme.primary这样的形式访问 hash 变量。

最后,对于问题一,由于在 less,stylus 和 sass 中,都支持使用@import "foo.scss";这样的语句引入文件。对于不需要不同预处理器间的语法转换,只想自动批量引入多个变量文件的场景,loader 不会对这些文件的内容进行解析,只会简单的把这些@import语句插入<style>块中。

使用方法

安装

npm install vue-style-variables-loader --save-dev

在 webpack 中配置规则,处理项目中每一个.vue文件,要注意配置include/exclude规则,使 loader 只作用于开发者项目内的文件,不包含第三方文件。

{
    test: /\.vue$/,
    use: [
        {
            loader: 'vue-loader',
            options: vueLoaderConfig
        },
        {
            loader: 'vue-style-variables-loader',
            options: {
                variablesFiles: [
                    resolve('./src/styles/theme-variables.styl')
                ],
                importStatements: [
                    '@import "~@/styles/other-variables.less";'
                ]
            }
        }
    ],
    include: [resolve('src')]
},
{
    test: /\.vue$/,
    use: [
        {
            loader: 'vue-loader',
            options: vueLoaderConfig
        }
    ],
    exclude: [resolve('src')]
},

参数说明

两个参数:

  • variablesFiles 变量文件路径,Array 类型。指定主题变量文件。
  • importStatements import 语句,Array 类型。需要插入.vue文件<style>块头部的@import语句。在这里可以引入其他项目中使用的变量文件,要注意 loader 不会对这些文件做任何解析工作,只是简单的添加而已。

参数注意事项

使用variablesFiles时,传入的变量文件只允许包含定义变量语法。诸如 mixin,@import语句等都不能使用。

使用importStatements有两点需要注意:

  1. 由于 css-loader 中认为@import路径是相对当前路径,所以需要加上~前缀使 webpack alias 生效。例如上面使用示例中:'@import "~@/styles/other-variables.less";'相关ISSUE
  2. 需要加上预处理器后缀名,原因是 loader 需要知道@import语句中文件的后缀,才能正确插入对应的<style>块中。例如'@import "~@/styles/other-variables.less";'就不会插入<style lang="styl">中。

参考资料

the-super-tiny-compiler vue-loader 相关 issue