Vue脚手架的Sass升级迁移案例

607 阅读3分钟

背景

总共有2种Vue 2项目构建工具场景
  1. 构建工具为Vue CLI 更新到"@vue/cli-service": "~5.0.8"
  • 具有sasssass-loader编译scss
  1. 构建工具为Webpack 更新到"webpack": "^5.95.0"
  • 具有sasssass-loadersass-resources-loader编译scss

目的

sass语法迁移到新版本

说明

以上2种Vue 2项目构建工具场景使用的scss语法是比较简单的,主要就是全局变量声明和引入,案例里需要配合vue.config.jswebpack.config.js进行协同配置和被使用文件通过将@import切换为@use,避免终端上出现webpack.config.js如下类似的warningerrorsuggestions

warning or error or suggestions
1.Sass @import rules are deprecated and will be removed in Dart Sass 3.0.0. More info and automated migrator: https://sass-lang.com/d/import

2.Module build failed (from ./node_modules/.pnpm/sass-loader@16.0.2_sass@1.80.3_webpack@5.95.0/node_modules/sass-loader/dist/cjs.js): Undefined variable.

3.There is no module with the namespace "color".

4.transparentize() is deprecated. Suggestions: color.scale($color, $alpha: -75%) color.adjust($color, $alpha: -0.75)

两种案例基于自己项目的一个参考,是尝试之后的一个直接的结果,在过程中遇到的问题没有提供具体的截图等相关信息

Vue CLI场景案例

  • 依赖项文件:package.json
  • 入口文件:main.js
  • 公共样式文件:common.scss
  • 变量声明文件:var.scss
  • vue配置文件:vue.config.js
  • SFC使用文件:App.vue
package.json
  "devDependencies": {
    ...
    "@vue/cli-service": "~5.0.8",
    "sass": "^1.80.6",
    "sass-loader": "^16.0.3",
    "vue-template-compiler": "^2.7.16"
    ...
  },

vue.config.js
  {
    ...
    css: {
    loaderOptions: {
      sass: {
        additionalData: `@use '@/assets/styles/var.scss' as *;@use 'sass:color' as color;`
        // 前面as为*可以直接使用定义变量,后面as为color,color.scale()可以使用color命名空间
      }
    }
  }
     ...
  }
var.scss
  {
    ...
    // 颜色
    $primary: #007fff;
    // 字体
    $fs12: 12px; // Caption
    // 行高 Line Height (Light Height = Font Size + 8)
    $lh12: 20px;
    ...
  }
common.scss
  {
    ...
    // 这里没有再次引入@use 'var.scss';@use 'sass:color';不然会与重复
    html,
    body {
      margin: 0px;
      padding: 0px;
    }
    ...
  }
main.js
  {
    ...
    import App from './App.vue';
    import './assets/styles/common.scss'; // 入口文件引入公共样式
    ...
  }
App.vue
  {
    ...
    <style lang="scss">
    #app {
      background-color: $primary;
      // 直接使用变量因为additionalData as *后不需要模块化var.$primary
      .truthly {
        color: $primary;
        background-color: color.scale($primary, $alpha: -90%);
        // 使用命名空间color因为additionalData as color,不能as *(因为这样会There is no module with the namespace "color".)
      }
    }
    </style>
    ...
  }

Webpack场景案例

  • 依赖项文件:package.json
  • 入口文件:main.js
  • 公共样式文件:common.scss
  • 变量声明文件:var.scss
  • 自定义字体文件:fonts.scss
  • 自定义图片文件:urls.scss
  • vue配置文件:webpack.config.js
  • SFC使用文件:App.vue
  • SFC使用引入字体:Fonts.vue
  • SFC使用引入图片:Urls.vue
package.json
  "devDependencies": {
    ...
    "sass": "^1.80.6",
    "sass-loader": "^16.0.3",
    "vue-template-compiler": "^2.7.16",
    "webpack": "^5.95.0",
    "webpack-bundle-analyzer": "^4.10.2",
    "webpack-cli": "^5.1.4",
    "webpack-dev-server": "^5.1.0"
    ...
  },

webpack.config.js
  {
    ...
      {
        test: /\.scss$/,
        use: [
          'style-loader',
          {
            loader: 'css-loader',
            options: {
              importLoaders: 2
            }
          },
          'sass-loader',
          'postcss-loader',
          {
            loader: 'sass-resources-loader',
            options: {
              hoistUseStatements: true,
              resources: './src/assets/styles/common.scss' // 共享scss
            }
          }
        ]
      },
     ...
  }
var.scss
  {
    ...
    // 颜色
    $primary: #007fff;
    // 字体
    $fs12: 12px; // Caption
    // 行高 Line Height (Light Height = Font Size + 8)
    $lh12: 20px;
    ...
  }
fonts.scss
  {
    ...
    @font-face {
      font-family: 'DigitalNumbers-Regular';
      src: url('@/assets/styles/fonts/DigitalNumbers-Regular.ttf')
        format('truetype');
    }
    @mixin digital-font($fallback: sans-serif) {
      font-family: 'DigitalNumbers-Regular', $fallback;
    }
    ...
  }
urls.scss
  {
    ...
    $imagePng: 'https://path/xx.png';
    $iconFont: 'https://path/xx.ttf';
    ...
  }
common.scss
  {
    ...
    // 不同:这里与上文vue.config.js不同,需要引入
    // 相同:as为*可以直接使用定义变量,后面as为color,color.scale()可以使用color命名空间
    @use 'var.scss' as *;
    @use 'sass:color' as color;
    @font-face {
      font-family: 'Material Icons';
      font-style: normal;
      font-weight: 400;
      src: local('material-design-icons'), local('MaterialIcons-Regular');
    }
    ...
  }
main.js
  {
    ...
    import App from './App.vue';
    import './assets/styles/common.scss'; // 入口文件引入公共样式
    ...
  }
App.vue
  {
    ...
    <style lang="scss">
    #app {
      background-color: $primary;
      // 直接使用变量因为additionalData as *后不需要模块化var.$primary
      .truthly {
        color: $primary;
        background-color: color.scale($primary, $alpha: -90%);
        // 使用命名空间color因为additionalData as color,不能as *(因为这样会There is no module with the namespace "color".)
      }
    }
    </style>
    ...
  }
Fonts.vue
  {
    ...
    <style lang="scss" scoped>
    @use '@/assets/styles/fonts/fonts' as *; // 使用as *
    .digital-font {
      @include digital-font();
      @include digital-font(sans-serif);
    }
    </style>
    ...
  }
Urls.vue
  {
    ...
    <style lang="scss" scoped>
    @use '@/assets/styles/urls/urls' as *; // 使用as *
    @font-face {
      font-family: YouSheBiaoTiHei-2;
      src: url($iconFont); // 使用定义的请求字体路径变量
    }
    .component {
      background: url($imagePng) no-repeat; // 使用定义的请求图片路径变量
    }
    </style>
    ...
  }

总结

  1. scss文件使用# Sass Migrator 自动转换
  2. Undefined variable在构建工具配置里使用或者scss声明为as *
  3. no module with the namespace "color"在构建工具配置里使用或者scss声明为as color
  4. transparentize() is deprecated遵循终端建议进行语法修改

参考

# Vue Tool Upgrade
# Automatically import SASS/SCSS into every Vue.js component
# Sass Migrator
# Vue-cli-css-loaderoptions
# webpack-sass-loader-options