Vite 配置 - 深入理解 - 共享选项

1,502 阅读7分钟

Note:

此篇文章主要是对 Shared Options 中的几个比较难理解的配置选项的理解介绍:

  • define
  • css
    • modules
    • preprocessorOptions
    • devSourcemap
    • postcss
  • resolve
    • alias
    • dedupe
    • conditions
    • mainFields
    • browserField
    • extensions
    • preserveSymlinks

define:

定义全局常量替换方式。
其中每项在开发环境下会被定义在全局,如:window.<define.key>; 而在构建时被静态替换

  • String 值会以原始表达式形式使用,所以如果定义了一个字符串常量,它需要被显式地打引号。 (例如使用 JSON.stringify
  • 为了与 esbuild 的行为保持一致,表达式必须为一个 JSON 对象(null、boolean、number、string、数组或对象),亦或是一个单独的标识符。
  • 替换只会在匹配到周围不是其他字母、数字、_ 或 $ 时执行。
define: {
    __KEY__: value, // value 如果是字符串,需要 JSON.stringify(value)
    __KEY_A__: 11
}

// 客户端获取 常来那个的写法
console.log(__KEY__) // ${ JSON.stringify(value) }
console.log(__KEY_A__) // 11

css:

在vite.config.js中我们通过css属性去控制真个vite对于css的处理行为;

css.modules 配置:

modules 的配置最终会给到 postcss-modules, 进行处理; 可参考 postcss-modules 的配置;

  • localConvention: 修改生成的配置对象的key的展示形式(驼峰还是中划线形式)

  • scopeBehaviour: 配置当前的模块化行为是模块化还是全局化 (有hash就是开启了模块化的一个标志, 因为他可以保证产生不同的hash值来控制我们的样式类名不被覆盖)

  • generateScopedName: 生成的类名的规则(可以配置为函数, 也可以配置成字符串规则: interpolatename

  • hashPrefix: 生成hash会根据你的类名 + 一些其他的字符串(文件名 + 他内部随机生成一个字符串)去进行生成, 如果你想要你生成hash更加的独特一点, 你可以配置hashPrefix, 你配置的这个字符串会参与到最终的hash生成, (hash: 只要你的字符串有一个字不一样, 那么生成的hash就完全不一样, 但是只要你的字符串完全一样, 生成的hash就会一样)

  • globalModulePaths: 代表你不想参与到css模块化的路径.

DEMO:

css: { // 对 css 的行为进行配置

  // modules 的配置最终会给到 postcss-modules(https://github.com/css-modules/postcss-modules), 进行处理; 可参考 postcss-modules 的配置;
  modules: { // 配置 css modules 的行为;

    // scopeBehaviour:配置当前的模块化行为是模块化还是全局化 (有hash就是开启了模块化的一个标志, 因为他可以保证产生不同的hash值来控制我们的样式类名不被覆盖)
    scopeBehaviour: 'local', // 默认:local; 可选: global | local;

    // globalModulePaths: 为全局模块定义路径。它是一个用正则表达式定义路径的数组;// 代表你不想参与到css模块化的路径
    // globalModulePaths: ['./global/global.module.less'],
    globalModulePaths: [/./global/style//],

    // generateScopedName: 通过插值字符串的形式,配置参考:interpolatename(https://github.com/webpack/loader-utils#interpolatename)
    // generateScopedName: "[name]__[local]___[hash:base64:5]",
    // generateScopeName: 通过 callback 函数的形式自定义生成的类名;提供的参数:name(类名)、filename(文件名)、css(css 块)
    // generateScopedName: (name, filename, css) => {
    //   console.log('name -> ', name)
    //   console.log('filename -> ', filename)
    //   console.log('css -> ', css)
    //   const path = require("path");
    //   const i = css.indexOf("." + name);
    //   const line = css.substr(0, i).split(/[\r\n]/).length;
    //   const file = path.basename(filename, ".css");
    //   return "_" + file + "_" + line + "_" + name;
    // },

    // hashPrefix: 生成 hash 会根据你的类名 + 一些其他的字符串(文件名 + 它内部随机生成一个字符串)去进行生成, 如果你想要你生成 hash 更加的独特一点, 你可以配置 hashPrefix, 你配置的这个字符串会参与到最终的 hash 生成, (hash: 只要你的字符串有一个字不一样, 那么生成的 hash 就完全不一样, 但是只要你的字符串完全一样, 生成的 hash 就会一样)
    hashPrefix: 'prefix',

    // localsConvention: 设置导出的样式 classnames 的 json 对象的 key 的展示形式;(驼峰 | 仅驼峰 | 中划线 | 仅中划线);
    // 或者根据 originalClassName(原始类名)、generatedClassName(生成的唯一类名)、inputFile(输入类名的文件) 参数自定义类名;
    localsConvention: 'camelCaseOnly', // 默认:null; 可选:'camelCase' | 'camelCaseOnly' | 'dashes' | 'dashesOnly';
    // localsConvention: (originalClassName, generatedClassName, inputFile) => {
    //   console.log('originalClassName -> ', originalClassName)
    //   console.log('generatedClassName -> ', generatedClassName)
    //   console.log('inputFile -> ', inputFile)
    //   return 'test'
    // },
  },
}

css.preprocessorOptions 配置:

配置传递给对应的 css 预处理器的参数;

参数配置,参考各预处理的的配置项;如 less options ;

DEMO:

css: {
    // preprocessorOptions: 指定传递给 CSS 预处理器的选项; key + config, key 代表预处理器的名;
    preprocessorOptions: {

      // 整个的配置对象都会最终给到 less的执行参数(全局参数)中去,相当于 webpack 中给 less-loader 传递配置参数;
      less: {
        math: 'always', // 较少进行数学计算,兼容跟多数学计算的写法;
        globalVars: { // 配置 less 的全局变量
          mainColor: 'yellow'
        }
      }
    }
}

css.devSourcemap 配置:

在开发过程中是否启用 sourcemap。

DEMO:

css: {
    devSourcemap: true, // 开启 css 的sourceMap(文件索引)
}

css.postcss 配置:

官方文档记录:

类型:  string | (postcss.ProcessOptions & { plugins?: postcss.AcceptedPlugin[] })

  1. 内联的 PostCSS 配置(格式同 postcss.config.js), 或者一个(默认基于项目根目录的)自定义的 PostCSS 配置路径。

  2. 对内联的 POSTCSS 配置,它期望接收与 postcss.config.js 一致的格式。但对于 plugins 属性有些特别,只接收使用 数组格式

  3. 搜索是使用 postcss-load-config 完成的,只有被支持的文件名才会被加载。如:

    -> .postcssrc.js
    -> .postcssrc.mjs
    -> .postcssrc.cjs
    -> .postcssrc.ts
    -> postcss.config.js
    -> postcss.config.mjs
    -> postcss.config.cjs
    -> postcss.config.ts

  4. 【注意】:

  • 如果提供了该内联配置,Vite 将不会搜索其他 PostCSS 配置源。

  • vite 已经内置了 postcss, 一般无需再次安装 postcss, 直接使用,安装插件即可,不排除由于对版本的要求要重新安装 postcss

  • postcss 功能非常强大,如,css 语法降级、css 属性前缀补全 等功能, 这些功能 less/sass/stylus 等预处理器并没有实现,postcss 可以通过css 插件解决这些问题;而且它还可以通过各种 css 插件解决各种 css 处理问题;

DEMO:

// vite.config.js

import { defineConfig } from 'vite';
const path = require('path');
const postcssGlobalData = require('@csstools/postcss-global-data');
const postcssPresetEnv = require('postcss-preset-env');

export default defineConfig({
  css: { // 对 css 的行为进行配置
    // postcss: 配置postcss相关;使用此属性,postcss.config.js 文件会失效;所以只能二选一;
    postcss: {
      plugins: [
        postcssGlobalData({
          files: [
            path.resolve(__dirname, 'global/style/variable.css')
          ]
        }),
        postcssPresetEnv({
          features: {
            'custom-properties': { preserve: true }
          }
        })
      ]
    },
  }
})

一般我们会把 postcss 的配置放在 postcss.config.js 中单独设置,如下:

// postcss.config.js

const postcssPresetEnv = require('postcss-preset-env');
const postcssGlobalData = require('@csstools/postcss-global-data');
const path = require('path')

module.exports = {
 plugins: [
   postcssGlobalData({
     files: [
       path.resolve(__dirname, 'global/style/variable.css')
     ]
   }),
   postcssPresetEnv({
     features: {
       'custom-properties': { preserve: true }
     }
   })
 ]
}

resolve:

resolve.alias 配置:

官网摘录:

  1. 将会被传递到 @rollup/plugin-alias 作为 entries 的选项。也可以是一个对象,或一个 { find, replacement, customResolver } 的数组。
  2. 当使用文件系统路径的别名时,请始终使用绝对路径。相对路径的别名值会原封不动地被使用,因此无法被正常解析。

NOTE:

  1. 重命名的路径不应该以 ‘/’ 结尾

DEMO:

resolve: {
  alias: {
    '@': path.resolve(__dirname, './src'),
    '@assets': path.resolve(__dirname, './src/assets'),
  }
}

resolve.dedupe 配置:

官网摘录:

如果你在你的应用程序中有相同依赖的副本(比如 monorepos),请使用此选项强制 Vite 始终将列出的依赖项解析为同一副本(从项目根目录)。

理解:

将此 dedupe 设置中的库名,经过检索,只取一个版本的库(最外层的根库);

DEMO:

  resolve: {
     dedupe: ['@babel/core', '@babel/parser', '@x/a', '@x/b']
  }

  // 这样就强制使用 @babel  和 @x 库

resolve.conditions 配置:

解决程序包中 情景导出 时的其他允许条件。

一个带有情景导出的包可能在它的 package.json 中有以下 exports 字段:

 {
    "exports": {
      ".": {
        "import": "./index.esm.js",
        "require": "./index.cjs.js"
      }
    }
  }

vite 默认允许的情景:import, module, browser, default, 和基于当前的情景为 productiondevelopment;

resolve.conditions配置项可以指定其它允许的情景;

Demo:

项目 test-vite 里,安装了 foo 包,如图:

image.png

package.jsonexports 提供了几种情景引入的方式,如下:

  // package.json
  "exports": {
    ".": {
      "x": "./index-x.js",
      "y": "./index-y.js",
      "node": "./index-node.js",
      "import": "./index-import.js",
      "require": "./index-require.js",
      "default": "./index-import.js"
    },
    "./xx": {
      "x": "./index-x.js",
      "y": "./index-y.js"
    }
  }

项目的 test-vitevite.config.js 中设置 resolve.conditions, 如下:

  import { defineConfig } from 'vite';

  export default defineConfig(() => {
    return {
      resolve: {
        conditions: ['y']
      }
    }
  })

test-vite 中导入 foo 包:

  import foo from 'foo'; // 这时导入的就是 index-y.js
  
  imort foo from 'foo/xx'; // 这时导入的是 index-y.js

[NOTE]: 这在 monorepo 库的应用会更适合一点;

resolve.mainFields 配置:

官网摘录:

  • 类型:  string[]
  • 默认:  ['module', 'jsnext:main', 'jsnext']

package.json 中,在解析包的入口点时尝试的字段列表。注意:这比从 exports 字段解析的情景导出优先级低:如果一个入口点从 exports 成功解析,resolve.mainFields 将被忽略。

resolve.extensions 配置:

官网摘录:

  • 类型:  string[]
  • 默认:  ['.mjs', '.js', '.mts', '.ts', '.jsx', '.tsx', '.json']

导入时想要省略的扩展名列表。注意, 建议忽略自定义导入类型的扩展名(例如:.vue),因为它会影响 IDE 和类型支持。

resolve.preserveSymLinks 配置:

官网摘录:

  • 类型:  boolean
  • 默认:  false

启用此选项会使 Vite 通过原始文件路径(即不跟随符号链接的路径)而不是真正的文件路径(即跟随符号链接后的路径)确定文件身份。

DEMO:

// vite.config.js

resolve: {
  preserveSymlinks: true
}

test-vite 项目 npm link [my-test-module] , my-test-module 是自开发模块包,preserveSymLinkstruefalse 时,导入路径对比,如下:

// preserveSymlinks: false 时
import myTestModule from '/@fs/Users/xxx/xxx/.../my-test-module/index.js';

// preserveSymlinks: true 时
import myTestModule from '/node_modules/.vite/deps/my-test-module.js?v=b98ad576';