vue项目中scss、less、stylus预编译语言全局变量注入

5,439 阅读5分钟

在项目中,我们常会用到css预处理器 ,如sass,less, stylus,书写css变得非常便捷;项目中一般会建立公共样式文件,存放公共样式、公共变量、项目主题、基础样式混合方法,但是在项目中使用这些变量的时候通常都要在每个页面style标签内用@import引入,繁琐,所以需要使用webpack的相关配置全局注入公共文件

sass 全局变量注入

为了使用sass,我们需要安装sass的依赖包

npm install --save-dev sass-loader
npm install --save-dev node-sass  //sass-loader依赖于node-sass

1、使用sass-resources-loader工具引入

  • 添加依赖
npm install sass-resources-loader --save-dev
  • 在项目build文件夹里找到utils.js ,定位到下边代码
return {
    css: generateLoaders(),
    postcss: generateLoaders(),
    less: generateLoaders('less'),
    sass: generateLoaders('sass', { indentedSyntax: true }),
    scss: generateLoaders('sass'),
    stylus: generateLoaders('stylus'),
    styl: generateLoaders('stylus')
}

将scss: generateLoaders('sass')进行修改

sass: generateLoaders('sass', {
    indentedSyntax: true,
}),
scss: generateLoaders('sass').concat(
    {
        loader: 'sass-resources-loader',
        options: {
            //这里按照你的文件路径填写;多个文件时用数组的形式传入,如resources: [path.resolve(__dirname, '../src/styles/base/_variables.scss')]
            resources: path.resolve(__dirname, '../src/styles/base/_variables.scss')
        }
    }),

当然也可以直接修改generateLoaders方法

function generateLoaders(loader, loaderOptions) {
    const loaders = []

    // Extract CSS when that option is specified
    // (which is the case during production build)
    if (options.extract) {
        // loaders.push(MiniCssExtractPlugin.loader)
        loaders.push({
            loader: MiniCssExtractPlugin.loader,
            options: {
                publicPath: '../../'
            }
        })
    } else {
        loaders.push('vue-style-loader')
    }

    loaders.push(cssLoader)

    if (options.usePostCSS) {
        loaders.push(postcssLoader)
    }

    if (loader) {
        // 修改这一块,当使用sass-resources时也需要引入'sass-loader'
        if (loader === 'sass-resources') {
            loaders.push({
                loader: 'sass-loader'
            })
        }
        loaders.push({
            loader: loader + '-loader',
            options: Object.assign({}, loaderOptions, {
                sourceMap: options.sourceMap
            })
        })
    }
    return loaders
}
// 全局文件引入 当然只想编译一个文件的话可以省去这个函数
function resolveResource(name) {
    return path.resolve(__dirname, '../src/styles/base/' + name);
}

return {
    css: generateLoaders(),
    postcss: generateLoaders(),
    less: generateLoaders('less'),
    sass: generateLoaders('sass-resources', {
        resources: [resolveResource('_variables.scss')]
    }),
    scss: generateLoaders('sass-resources', {
        resources: [resolveResource('_variables.scss')]
    }),
    stylus: generateLoaders('stylus'),
    styl: generateLoaders('stylus')
}

2、向预处理器 Loader 传递选项实现全局变量注入

// vue.config.js;这个方法我没有实践过,哈哈,但是官方文档应该还是很可信的
module.exports = {
  css: {
    loaderOptions: {
      // 给 sass-loader 传递选项
      sass: {
        // @/ 是 src/ 的别名
        // 所以这里假设你有 `src/variables.sass` 这个文件
        // 注意:在 sass-loader v7 中,这个选项名是 "data"
        prependData: `@import "~@/variables.sass"`
      },
      // 默认情况下 `sass` 选项会同时对 `sass` 和 `scss` 语法同时生效
      // 因为 `scss` 语法在内部也是由 sass-loader 处理的
      // 但是在配置 `data` 选项的时候
      // `scss` 语法会要求语句结尾必须有分号,`sass` 则要求必须没有分号
      // 在这种情况下,我们可以使用 `scss` 选项,对 `scss` 语法进行单独配置
      scss: {
        prependData: `@import "~@/variables.scss";`
      },
      // 给 less-loader 传递 Less.js 相关选项
      less:{
        // http://lesscss.org/usage/#less-options-strict-units `Global Variables`
        // `primary` is global variables fields name
        globalVars: {
          primary: '#fff'
        }
      }
    }
  }
}

也可以直接在对应Loader 中的 loaderOptions 配置

//在项目build文件夹里找到utils.js
return {
    css: generateLoaders(),
    postcss: generateLoaders(),
    less: generateLoaders('less'),
    
    // @/ 是 src/ 的别名,使用的时候要加上~
    // 注意:在 sass-loader v7 中,prependData这个选项名要改成 "data",我用的是v7,所以使用的data,要导入多个文件时,就直接import多个就行,如 : data: `
        @import "~@/styles/base/_variables.scss";
        @import "~@/styles/base/_mixins.scss"
        `
    // 默认情况下 `sass` 选项会同时对 `sass` 和 `scss` 语法同时生效,因为 `scss` 语法在内部也是由 sass-loader 处理的,但是在配置 `data` 选项的时候,`scss` 语法会要求语句结尾必须有分号,`sass` 则要求必须没有分号,在这种情况下,我们可以使用 `scss` 选项,对 `scss` 语法进行单独配置
 

    sass: generateLoaders('sass', {
      indentedSyntax: true,
      data: `
        @import "~@/styles/base/_variables.scss"`
    }),
     scss: generateLoaders('sass',{
        data: `
            @import "~@/styles/base/_variables.scss";`
     }),
    stylus: generateLoaders('stylus'),
    styl: generateLoaders('stylus')
}

less 全局变量注入

为了使用less,我们需要安装less的依赖包

npm install less less-loader --save-dev

1、使用sass-resources-loader工具引入

方法同sass引入方法,将sass-loader 改为 less-loader即可

2、使用style-resources-loader工具引入

安装依赖

npm i style-resources-loader -D

在项目build文件夹里找到utils.js

return {
    css: generateLoaders(),
    postcss: generateLoaders(),
    less: generateLoaders('less').concat({
      loader: 'style-resources-loader',
      options: {
        patterns: path.resolve(__dirname, '../src/assets/styles/variables.less'),
        injector: 'append'
      }
    }),
    sass: generateLoaders('sass', { indentedSyntax: true }),
    scss: generateLoaders('sass'),
    stylus: generateLoaders('stylus'),
    styl: generateLoaders('stylus')
}

3、可以为less-loader在加载时使用globalVars注入全局变量。

此选项定义文件可以引用的变量。实际上,该声明放置在基本Less文件的顶部,这意味着可以使用该声明,但是如果在文件中定义了此变量,也可以覆盖该声明。

return {
    css: generateLoaders(),
    postcss: generateLoaders(),
    less: generateLoaders('less',{
        globalVars : {
            @primary : #F97A73
        }
    }),
    sass: generateLoaders('sass', { indentedSyntax: true }),
    scss: generateLoaders('sass'),
    stylus: generateLoaders('stylus'),
    styl: generateLoaders('stylus')
}

或者处理对应less文件,获取所有的变量值;但是如果变量文件中出现引用关系的时候就会报错,例如 @primary : #F97A73;@button-primary-background-color: @primary;

//在项目build文件夹里找到utils.js
const fs = require('fs');  //使用时需要导入
// 读取less全局变量文件
function getLessVariables(file) {
    var themeContent = fs.readFileSync(file, 'utf-8')
    var variables = {}
    themeContent.split('\n').forEach(function (item) {
      if (item.indexOf('//') > -1 || item.indexOf('/*') > -1) { return }
      var _pair = item.split(':')
      if (_pair.length < 2) return;
      var key = _pair[0].replace('\r', '').replace('@', '')
      if (!key) return;
      var value = _pair[1].replace(';', '').replace('\r', '').replace(/^\s+|\s+$/g, '')
      variables[key] = value
    })
    console.info(variables);
    return variables
}
return {
    css: generateLoaders(),
    postcss: generateLoaders(),
    less: generateLoaders('less', {
      globalVars: getLessVariables(path.join(__dirname, "../src/assets/styles/variables.less"))// 读取less全局变量文件
    }),
    sass: generateLoaders('sass', { indentedSyntax: true }),
    scss: generateLoaders('sass'),
    stylus: generateLoaders('stylus'),
    styl: generateLoaders('stylus')
  }
}

4、可以为less-loader在加载时使用modifyVars注入全局变量。

与全局变量选项相反,这会将声明放在基本文件的末尾,这意味着它将覆盖Less文件中定义的所有内容。

//在项目build文件夹里找到utils.js
return {
    css: generateLoaders(),
    postcss: generateLoaders(),
    less: generateLoaders('less',{
      modifyVars: {
        // 直接覆盖变量
        'text-color': '#333',
        'hack': `true;
        // 或者可以通过 less 文件覆盖(文件路径为绝对路径)
        @import "${path.join(__dirname,'../src/assets/styles/variables')}";`
      }
    }),
    sass: generateLoaders('sass', { indentedSyntax: true }),
    scss: generateLoaders('sass'),
    stylus: generateLoaders('stylus'),
    styl: generateLoaders('stylus')
}

stylus全局变量注入

为了使用stylus的安装包,我们需要安装stylus的依赖

npm install stylus-loader stylus --save-dev

1、使用style-resources-loader工具引入

方法同less引入方法一致

2、可以为stylus-loader的传递选项实现全局变量注入

//在项目build文件夹里找到utils.js中的cssLoaders函数中
const stylusOptions = {
    import: [
      path.join(__dirname, "../src/assets/style/mk_variables.styl")
    ],
    paths: [
      path.join(__dirname, '../src/assets'),
      path.join(__dirname, '../')
    ]
}

return {
    css: generateLoaders(),
    postcss: generateLoaders(),
    less: generateLoaders('less'),
    sass: generateLoaders('sass', { indentedSyntax: true }),
    scss: generateLoaders('sass'),
    stylus: generateLoaders('stylus',stylusOptions),
    styl: generateLoaders('stylus',stylusOptions)
}