Vitejs开源项目实践指南(二)

1,146 阅读11分钟

注意:本文以vue-pure-adminvue-vben-admin为例,进行vite配置入门介绍

Vitejs开源项目实践指南系列文章:

本篇预告,Vitejs开源项目实践指南(二),内容包括:

  • esbuild字段配置
  • 预构建配置optimizeDeps
  • 全局变量配置define
  • css及其预处理器配置
  • 其他一般配置项
  • 重要字段的类型源码,都放在附录知识里面折叠隐藏了,可点击展开查看

vitejs字段解析(实例讲解)

esbuild

esbuild主要用于开发环境(npm run dev)(比如依赖预构建、文件编译等),而生产环境(npm run build)使用的是rollup(在build.rollupOptions字段中配置)进行代码构建的,出现此类缘故是esbuild的生态还不够完备。

对于非JSX项目来说,在使用vue3+vite的项目中,esbuild目前可用于在构建生产代码之前删除项目中的debugger和console,对于console来说,可全部清除,也可以特定删除console的部分api(比如console.log、console.error、console.info等),用法如下所示:

const esbuildOptions: ESBuildOptions = {
  // 全部删除代码中的console 和debugger语句
  drop: ['console', 'debugger']
}

const esbuildOptions2: ESBuildOptions = {
  // 仅删除debugger语句和console.log、console.info,其他console不进行删除
  drop: ['debugger'],
  pure: ['console.log', 'console.info']
}

// 最后将esbuildOptions对象添加到上述userConfig的esbuild的值的位置即可

同时,你想使用其他代码压缩功能,vite还集成了js压缩工具库terser,使用build.terserOptions字段进行配置,配置选项如下所示:

// vite.config.ts
import type { Terser, ConfigEnv, UserConfig } from 'vite'

const terserOptions: Terser.MinifyOptions = {
  compress: {
    // 防止将infinite被压缩成 1/0 ,1/0将导致chrome性能问题
    keep_infinity: true,
    // 删除所有的console语句和debugger语句
    // 若想删除特定console语句,则不能使用drop_console,应该使用pure_funcs
    drop_console: true,
    drop_debugger: true,
    // 删除特定的console
    pure_funcs: ['console.log', 'console.info']
  }
}

export default ({command, mode}: ConfigEnv): UserConfig => {
  return {
    build: {
      terserOptions: terserOptions
    }
  }
} 

依赖预构建:在vue项目启动之前,因为vite的开发服务器会将所有代码都视为原生ESM模块,因此vite必须先将用CommonJS、UMD模块发布的依赖项(devDependencies、dependencies)转为ESM模块;同时vite将含有大量的模块依赖关系(通过import进行导入)的模块(比如lodash-es库,内置了大量的常用函数模块)转成单个模块,减少http请求数量,提升页面加载性能。这个过程仅在开发环境下执行。

附录知识: ESBuildOptions类型说明

ESBuildOptions类型说明:

export declare interface ESBuildOptions extends EsbuildTransformOptions {
  include?: string | RegExp | string[] | RegExp[];
  exclude?: string | RegExp | string[] | RegExp[];
  jsxInject?: string;
  /**
   * This option is not respected. Use `build.minify` instead.
   */
  minify?: never;
}

export interface TransformOptions extends CommonOptions {
  tsconfigRaw?: string | {
    compilerOptions?: {
      alwaysStrict?: boolean,
      importsNotUsedAsValues?: 'remove' | 'preserve' | 'error',
      jsx?: 'react' | 'react-jsx' | 'react-jsxdev' | 'preserve',
      jsxFactory?: string,
      jsxFragmentFactory?: string,
      jsxImportSource?: string,
      preserveValueImports?: boolean,
      target?: string,
      useDefineForClassFields?: boolean,
    },
  };

  sourcefile?: string;
  loader?: Loader;
  banner?: string;
  footer?: string;
}

interface CommonOptions {
  /** Documentation: https://esbuild.github.io/api/#sourcemap */
  sourcemap?: boolean | 'linked' | 'inline' | 'external' | 'both';
  /** Documentation: https://esbuild.github.io/api/#legal-comments */
  legalComments?: 'none' | 'inline' | 'eof' | 'linked' | 'external';
  /** Documentation: https://esbuild.github.io/api/#source-root */
  sourceRoot?: string;
  /** Documentation: https://esbuild.github.io/api/#sources-content */
  sourcesContent?: boolean;

  /** Documentation: https://esbuild.github.io/api/#format */
  format?: Format;
  /** Documentation: https://esbuild.github.io/api/#global-name */
  globalName?: string;
  /** Documentation: https://esbuild.github.io/api/#target */
  target?: string | string[];
  /** Documentation: https://esbuild.github.io/api/#supported */
  supported?: Record<string, boolean>;
  /** Documentation: https://esbuild.github.io/api/#platform */
  platform?: Platform;

  /** Documentation: https://esbuild.github.io/api/#mangle-props */
  mangleProps?: RegExp;
  /** Documentation: https://esbuild.github.io/api/#mangle-props */
  reserveProps?: RegExp;
  /** Documentation: https://esbuild.github.io/api/#mangle-props */
  mangleQuoted?: boolean;
  /** Documentation: https://esbuild.github.io/api/#mangle-props */
  mangleCache?: Record<string, string | false>;
  /** Documentation: https://esbuild.github.io/api/#drop */
  drop?: Drop[];
  /** Documentation: https://esbuild.github.io/api/#minify */
  minify?: boolean;
  /** Documentation: https://esbuild.github.io/api/#minify */
  minifyWhitespace?: boolean;
  /** Documentation: https://esbuild.github.io/api/#minify */
  minifyIdentifiers?: boolean;
  /** Documentation: https://esbuild.github.io/api/#minify */
  minifySyntax?: boolean;
  /** Documentation: https://esbuild.github.io/api/#charset */
  charset?: Charset;
  /** Documentation: https://esbuild.github.io/api/#tree-shaking */
  treeShaking?: boolean;
  /** Documentation: https://esbuild.github.io/api/#ignore-annotations */
  ignoreAnnotations?: boolean;

  /** Documentation: https://esbuild.github.io/api/#jsx */
  jsx?: 'transform' | 'preserve' | 'automatic';
  /** Documentation: https://esbuild.github.io/api/#jsx-factory */
  jsxFactory?: string;
  /** Documentation: https://esbuild.github.io/api/#jsx-fragment */
  jsxFragment?: string;
  /** Documentation: https://esbuild.github.io/api/#jsx-import-source */
  jsxImportSource?: string;
  /** Documentation: https://esbuild.github.io/api/#jsx-development */
  jsxDev?: boolean;
  /** Documentation: https://esbuild.github.io/api/#jsx-side-effects */
  jsxSideEffects?: boolean;

  /** Documentation: https://esbuild.github.io/api/#define */
  define?: { [key: string]: string };
  /** Documentation: https://esbuild.github.io/api/#pure */
  pure?: string[];
  /** Documentation: https://esbuild.github.io/api/#keep-names */
  keepNames?: boolean;

  /** Documentation: https://esbuild.github.io/api/#color */
  color?: boolean;
  /** Documentation: https://esbuild.github.io/api/#log-level */
  logLevel?: LogLevel;
  /** Documentation: https://esbuild.github.io/api/#log-limit */
  logLimit?: number;
  /** Documentation: https://esbuild.github.io/api/#log-override */
  logOverride?: Record<string, LogLevel>;
}
附录知识: Terser.MinifyOptions类型说明

Terser.MinifyOptions类型说明:

export interface MinifyOptions {
  compress?: boolean | CompressOptions
  ecma?: ECMA
  ie8?: boolean
  keep_classnames?: boolean | RegExp
  keep_fnames?: boolean | RegExp
  mangle?: boolean | MangleOptions
  module?: boolean
  nameCache?: object
  format?: FormatOptions
  /** @deprecated use format instead */
  output?: FormatOptions
  parse?: ParseOptions
  safari10?: boolean
  sourceMap?: boolean | SourceMapOptions
  toplevel?: boolean
}

export interface CompressOptions {
  arguments?: boolean
  arrows?: boolean
  booleans_as_integers?: boolean
  booleans?: boolean
  collapse_vars?: boolean
  comparisons?: boolean
  computed_props?: boolean
  conditionals?: boolean
  dead_code?: boolean
  defaults?: boolean
  directives?: boolean
  drop_console?: boolean
  drop_debugger?: boolean
  ecma?: ECMA
  evaluate?: boolean
  expression?: boolean
  global_defs?: object
  hoist_funs?: boolean
  hoist_props?: boolean
  hoist_vars?: boolean
  ie8?: boolean
  if_return?: boolean
  inline?: boolean | InlineFunctions
  join_vars?: boolean
  keep_classnames?: boolean | RegExp
  keep_fargs?: boolean
  keep_fnames?: boolean | RegExp
  keep_infinity?: boolean
  loops?: boolean
  module?: boolean
  negate_iife?: boolean
  passes?: number
  properties?: boolean
  pure_funcs?: string[]
  pure_getters?: boolean | 'strict'
  reduce_funcs?: boolean
  reduce_vars?: boolean
  sequences?: boolean | number
  side_effects?: boolean
  switches?: boolean
  toplevel?: boolean
  top_retain?: null | string | string[] | RegExp
  typeofs?: boolean
  unsafe_arrows?: boolean
  unsafe?: boolean
  unsafe_comps?: boolean
  unsafe_Function?: boolean
  unsafe_math?: boolean
  unsafe_symbols?: boolean
  unsafe_methods?: boolean
  unsafe_proto?: boolean
  unsafe_regexp?: boolean
  unsafe_undefined?: boolean
  unused?: boolean
}

预构建配置optimizeDeps

optimizeDeps字段:用于配置依赖优化(依赖预构建)的选项。

vite预构建的项目依赖检测:默认情况下vite会抓取项目中的index.html文件检测需要预构建的项目依赖;若vite.config.ts中指定了build.rollupOptions.input字段,则从这里检测;若你想指定自定义的预构建依赖检测入口,可以通过optimizeDeps.entries字段进行配置。

使用optimizeDeps.exclude字段强制排除_一些依赖_进行预构建,注意,所有以 @iconify-icons/ 开头引入的的本地图标模块,都应该加入到下面的 exclude 里,因为平台推荐的使用方式是哪里需要哪里引入而且都是单个的引入,不需要预构建,直接让浏览器加载就好

使用optimizeDeps.include字段可以强制_一些依赖_必须进行预构建,vite 启动时会将include 里的模块,编译成 esm 格式并缓存到 node_modules/.vite 文件夹,页面加载到对应模块时如果浏览器有缓存就读取浏览器缓存,如果没有会读取本地缓存并按需加载。尤其当您禁用浏览器缓存时(这种情况只应该发生在调试阶段)必须将对应模块加入到 include里,否则会遇到开发环境切换页面卡顿的问题(vite 会认为它是一个新的依赖包会重新加载并强制刷新页面),因为它既无法使用浏览器缓存,又没有在本地 node_modules/.vite 里缓存。注意,如果您使用的第三方库是全局引入,也就是引入到 src/main.ts 文件里,就不需要再添加到 include 里了,因为 vite 会自动将它们缓存到 node_modules/.vite

注意,默认情况下node_modules, build.outDir文件夹会被忽略掉,所以可通过include字段对node_modules下的依赖进行强制预构建。

下面是依赖预构建的相关配置:

// optimize.ts
const include = [
  "qs",
  "mitt",
  "xlsx",
  "dayjs",
  "axios",
  "pinia",
  "echarts",
  // commonJs的依赖应该进行预构建优化,即使他们是嵌套在其他ESM中
  // 比如在esm-dep(esm依赖)用到了一个cjs-dep(commonjs依赖)
  "esm-dep > cjs-dep"
]

const exclude = [
  "@iconify-icons/ep",
  "@iconify-icons/ri",
  "@pureadmin/theme/dist/browser-utils"
]

// vite.config.ts
import { include, exclude } from './optimize.ts'
import type { Terser, ConfigEnv, UserConfig } from 'vite'

export default ({command, mode}: ConfigEnv): UserConfig => {
  return {
    optimizeDeps: {
      include: include,
      exclude: exclude,
      // 强制进行依赖预构建,即使依赖已经缓存过、优化过
      // 或者删除node_modules/.vite文件夹
      force: true
    }
  }
} 
附录知识: DepOptimizationOptions类型说明

DepOptimizationOptions类型说明:

export declare interface DepOptimizationOptions {
  /**
   * By default, Vite will crawl your `index.html` to detect dependencies that
   * need to be pre-bundled. If `build.rollupOptions.input` is specified, Vite
   * will crawl those entry points instead.
   *
   * If neither of these fit your needs, you can specify custom entries using
   * this option - the value should be a fast-glob pattern or array of patterns
   * (https://github.com/mrmlnc/fast-glob#basic-syntax) that are relative from
   * vite project root. This will overwrite default entries inference.
   */
  entries?: string | string[];
  /**
   * Force optimize listed dependencies (must be resolvable import paths,
   * cannot be globs).
   */
  include?: string[];
  /**
   * Do not optimize these dependencies (must be resolvable import paths,
   * cannot be globs).
   */
  exclude?: string[];
  /**
   * Options to pass to esbuild during the dep scanning and optimization
   *
   * Certain options are omitted since changing them would not be compatible
   * with Vite's dep optimization.
   *
   * - `external` is also omitted, use Vite's `optimizeDeps.exclude` option
   * - `plugins` are merged with Vite's dep plugin
   * - `keepNames` takes precedence over the deprecated `optimizeDeps.keepNames`
   *
   * https://esbuild.github.io/api
   */
  esbuildOptions?: Omit<BuildOptions_2, 'bundle' | 'entryPoints' | 'external' | 'write' | 'watch' | 'outdir' | 'outfile' | 'outbase' | 'outExtension' | 'metafile'>;
  /**
   * @deprecated use `esbuildOptions.keepNames`
   */
  keepNames?: boolean;
  /**
   * List of file extensions that can be optimized. A corresponding esbuild
   * plugin must exist to handle the specific extension.
   *
   * By default, Vite can optimize `.mjs`, `.js`, and `.ts` files. This option
   * allows specifying additional extensions.
   *
   * @experimental
   */
  extensions?: string[];
  /**
   * Disables dependencies optimizations
   * @default false
   * @experimental
   */
  disabled?: boolean;
}

全局变量配置define

define字段用于定义可在代码中使用的全局常量。该字段不会经过任何的语法分析,而是直接替换文本,故而应只对常量使用define。

如果定义了一个字符串常量,需要被显式的打上引号(比如通过JSON.stringify)。

若使用了typescript进行开发,应该给定义的全局常量在.d.ts文件下添加相应的类型声明,确保其能够获得类型检查和代码提示。

用法如下所示:

// vite.config.ts
import dayjs from 'dayjs'
import type { ConfigEnv, UserConfig } from 'vite'
import package from './package.json'

const { name, version, dependencies, devDependencies } = package
const __APP_INFO__ = {
  pkg: { name, version, dependencies, devDependencies },
  lastBuildTime: dayjs(new Date()).format('YYYY-MM-DD HH:mm:ss')
}
export default ({command, mode}: ConfigEnv): UserConfig => {
  return {
    define: {
      // 常量不需要使用
      __INTLIFY_PROD_DEVTOOLS__: false,
      // 对象形式需要使用json格式化
      __APP_INFO__: JSON.stringify(__APP_INFO__),
      
      // 下面的形式是不推荐的:
      // 使用对象简写
      __APP_INFO__
    }
  }
}

// 类型声明文件需要位于tsconfig.json文件的compilerOptions.typeRoots字段下声明的目录下进行定义才能被ts解析到,比如:
// compilerOptions.typeRoots = ['./types']
// 定义类型声明:./types/env.d.ts
declare global {
  const __APP_INFO__: {
    pkg: {
      name: string;
      version: string;
      dependencies: Recordable<string>;
      devDependencies: Recordable<string>;
    };
    lastBuildTime: string;
  };
  const __INTLIFY_PROD_DEVTOOLS__: boolean;
}

// 定义好之后,可在代码中直接使用该变量,比如在main.ts中输出
console.log('app info: ', __APP_INFO__)

常量和变量:常量是具有预定义值的命名数据项,而变量是在程序执行过程中其值可以更改的命名数据项。

css及其预处理器配置

css.preprocessorOptions字段:指定传递给css预处理器的选项,预处理器文件的扩展名作为选项的键名(比如scss, less, styl),键值为各自预处理器支持的选项。

在配置该字段时,需要安装相应的预处理器依赖,比如npm install -D [sass | less | stylus],但不需要想webpack那样安装对于的loader,因为vite提供了对这三者的内置支持。

css.preprocessorOptions字段可以结合css.modules字段一起使用,只需要将对应的.scss后缀改为.module.scss即可

所有预处理器的选项除了支持各自的选项(sass选项, less选项, stylus选项)外,还支持`additionalData选项,用于注入额外的代码(比如全局样式)。

用法如下:

// generateModifyVars.ts
import { generateAntColors, primaryColor } from '../config/themeConfig';
import { getThemeVariables } from 'ant-design-vue/dist/theme';
import { resolve } from 'path';

export function generateModifyVars(dark = false) {
  const palettes = generateAntColors(primaryColor);
  const primary = palettes[5];

  const primaryColorObj: Record<string, string> = {};

  for (let index = 0; index < 10; index++) {
    primaryColorObj[`primary-${index + 1}`] = palettes[index];
  }

  const modifyVars = getThemeVariables({ dark });
  // 定义less的全局变量
  return {
    ...modifyVars,
    // Used for global import to avoid the need to import each style file separately
    // reference:  Avoid repeated references
    // 全局导入一个文件config.less里面所有的样式,不需要像下面的单个写
    hack: `${modifyVars.hack} @import (reference) "${resolve('src/design/config.less')}";`,
    'primary-color': primary,
    ...primaryColorObj,
    'info-color': primary,
    'processing-color': primary,
    'success-color': '#55D187', //  Success color
    'error-color': '#ED6F6F', //  False color
    'warning-color': '#EFBD47', //   Warning color
    'warning-color12': 'red', //   Warning color
    //'border-color-base': '#EEEEEE',
    'font-size-base': '14px', //  Main font size
    'border-radius-base': '2px', //  Component/float fillet
    'link-color': primary, //   Link color
    'app-content-background': '#fafafa', //   Link color
  };
}

// vite.config.ts
import type { ConfigEnv, UserConfig } from 'vite'
import { generateModifyVars } from './generateModifyVars.ts'

export default ({command, mode}: ConfigEnv): UserConfig => {
  return {
    css: {
      preprocessorOptions: {
        scss: {
          // 允许在css文件中使用JavaScript语法
          javascriptEnabled: true,
          // 比如引入一个全局样式文件,另外添加一个全局变量
          adtionalData: `@import "./golbal.scss"; $primary-color: #eee;`
        },
        less: {
          javascriptEnabled: true,
          // 另一种添加全局变量的方式
          modifyVars: generateModifyVars()
        }
      }
    }
  }
}

// 使用,在一个功能模块中,比如./src/App.vue
<style lang="scss">
.app {
  &_main {
    color: $primary-color;
  }
}
</style>

注意:

  • 只能在scss文件里面使用additionalData里面导入的内容,即在main.ts导入的scss文件内,或者是*.vue文件下的<style lang="scss"></style>内使用additionalData里面的变量。
  • 同时建议additionalData里面导入的内容最好只写scss变量,不要写css变量(运行时属性),参考

提示: 如果官方文档中未对具体的选项做说明,假设css.preprocessorOptions下每个预处理器具体的选项配置没有给出上述所说的文档或出处,同时鼠标悬浮在css这个选项时,点进去看类型也没有具体的类型设置。这时可以查看不同的预处理器的配置选项对应的插件,比如less,可以查看1,以及在./node_modules/less/下搜索less源码对应的选项(比如javascriptEnabled),即可知道其他配置项还有什么

css.modules字段:该字段用于配置导入css模块时的一些行为,比如具名导入(import primaryColor from './variables.module.css)。

css.postcss字段:用于设置postcss配置源的路径。

附录知识: CSSOptions类型说明

CSSOptions类型说明:

export declare interface CSSOptions {
  /**
   * https://github.com/css-modules/postcss-modules
   */
  modules?: CSSModulesOptions | false;
  preprocessorOptions?: Record<string, any>;
  postcss?: string | (PostCSS.ProcessOptions & {
      plugins?: PostCSS.AcceptedPlugin[];
  });
  /**
   * Enables css sourcemaps during dev
   * @default false
   * @experimental
   */
  devSourcemap?: boolean;
}

export declare interface CSSModulesOptions {
  getJSON?: (cssFileName: string, json: Record<string, string>, outputFileName: string) => void;
  scopeBehaviour?: 'global' | 'local';
  globalModulePaths?: RegExp[];
  generateScopedName?: string | ((name: string, filename: string, css: string) => string);
  hashPrefix?: string;
  /**
   * default: undefined
   */
  localsConvention?: 'camelCase' | 'camelCaseOnly' | 'dashes' | 'dashesOnly' | ((originalClassName: string, generatedClassName: string, inputFile: string) => string);
}

export interface ProcessOptions {
  /**
   * The path of the CSS source file. You should always set `from`,
   * because it is used in source map generation and syntax error messages.
   */
  from?: string

  /**
   * The path where you'll put the output CSS file. You should always set `to`
   * to generate correct source maps.
   */
  to?: string

  /**
   * Function to generate AST by string.
   */
  parser?: Syntax | Parser

  /**
   * Class to generate string by AST.
   */
  stringifier?: Syntax | Stringifier

  /**
   * Object with parse and stringify.
   */
  syntax?: Syntax

  /**
   * Source map options
   */
  map?: SourceMapOptions | boolean
}

附录知识: less默认配置选项说明

less默认配置选项说明:

function default_1() {
  return {
    /* Inline Javascript - @plugin still allowed */
    javascriptEnabled: false,
    /* Outputs a makefile import dependency list to stdout. */
    depends: false,
    /* (DEPRECATED) Compress using less built-in compression.
      * This does an okay job but does not utilise all the tricks of
      * dedicated css compression. */
    compress: false,
    /* Runs the less parser and just reports errors without any output. */
    lint: false,
    /* Sets available include paths.
      * If the file in an @import rule does not exist at that exact location,
      * less will look for it at the location(s) passed to this option.
      * You might use this for instance to specify a path to a library which
      * you want to be referenced simply and relatively in the less files. */
    paths: [],
    /* color output in the terminal */
    color: true,
    /* The strictImports controls whether the compiler will allow an @import inside of either
      * @media blocks or (a later addition) other selector blocks.
      * See: https://github.com/less/less.js/issues/656 */
    strictImports: false,
    /* Allow Imports from Insecure HTTPS Hosts */
    insecure: false,
    /* Allows you to add a path to every generated import and url in your css.
      * This does not affect less import statements that are processed, just ones
      * that are left in the output css. */
    rootpath: '',
    /* By default URLs are kept as-is, so if you import a file in a sub-directory
      * that references an image, exactly the same URL will be output in the css.
      * This option allows you to re-write URL's in imported files so that the
      * URL is always relative to the base imported file */
    rewriteUrls: false,
    /* How to process math
      *   0 always           - eagerly try to solve all operations
      *   1 parens-division  - require parens for division "/"
      *   2 parens | strict  - require parens for all operations
      *   3 strict-legacy    - legacy strict behavior (super-strict)
      */
    math: 1,
    /* Without this option, less attempts to guess at the output unit when it does maths. */
    strictUnits: false,
    /* Effectively the declaration is put at the top of your base Less file,
      * meaning it can be used but it also can be overridden if this variable
      * is defined in the file. */
    globalVars: null,
    /* As opposed to the global variable option, this puts the declaration at the
      * end of your base file, meaning it will override anything defined in your Less file. */
    modifyVars: null,
    /* This option allows you to specify a argument to go on to every URL.  */
    urlArgs: ''
  };
}

其他配置项

// vite.config.ts
import type { ConfigEnv, UserConfig } from 'vite'

export default ({command, mode}: ConfigEnv): UserConfig => {
  return {
    // 用于加载.env文件的目录,可以是绝对路径,也可以是相对与项目根目录的路径,默认是root
    envDir: './envDirs',
    // 该字段开头的环境变量可以在代码其他位置通过import.meta.env.xxx读取到,默认是 VITE_
    envPrefix: 'SYing_',
    // 该字段配置的内容自动会作为静态资源进行处理,返回解析后的路径
    assetsInclude: ['**/*.gltf'],
    json: {
      // 支持按名导入json文件的字段,比如`import { name } from 'package.josn'
      namedExports: true,
      // 不支持按名导入,而是会将josn导入为默认导入,即`import pkg from 'package.json',开启此项,按名导入会被禁用
      stringift: false,
    },
    resolve: {
      // 设置导入时想要省略的扩展名,不建议自行设置,默认值如下:
      extensions: ['.mjs', '.js', '.mts', '.ts', '.jsx', '.tsx', '.json']
    },
    // 值为false时可以避免vite清屏而错过终端中(terminal)打印的某些信息,因为默认情况下每次vite重构建时,会删除之前的信息
    clearScreen: false,
  }
}

结尾

下篇预告,Vitejs开源项目实践指南(三),内容包括:

  • 插件plugins的引入和配置

一些对你有用的文章索引

参考文档