得益于 esbuild 的超高性能,vite 在诞生之初就备受关注,且始终放弃着沉闷的开发迭代。截至目前,vite 曾经迭代到了 2.7.10 版本,各方面也根本具备了在生产应用的条件。这段时间,我在我的项目中尝试了应用 vite 进行打包构建,本文就是这次构建的过程记录。

根底配置

首先应用vite 官网脚手架生成我的项目。

yarn create vite vite-demo --template react-ts
下面这行命令应用 react-ts 模板创立了一个叫 vite-demo 的我的项目。因为我在的团队日常应用 react 和 typescript 开发居多,因而抉择了 react-ts 这个模板,vite 官网反对的模板还有很多,能够在 create-vite 中查看。

我的项目初始化实现当前,目录构造如下:

.|____index.html|____.gitignore|____package.json|____tsconfig.json|____vite.config.ts|____src| |____App.tsx| |____main.tsx| |____App.css| |____index.css| |____vite-env.d.ts| |____logo.svg| |____favicon.svg

其中 vite.config.ts 内容如下:

import { defineConfig } from 'vite'import react from '@vitejs/plugin-react'// https://vitejs.dev/config/export default defineConfig({  plugins: [react()]})
能够看出,vite 官网曾经做了比较完善的封装,相较于之前版本,开发体验晋升了很多。

依照批示装置完依赖,启动利用当前,速度的确很快。当初咱们来做一些根本革新。

我通常应用 less 来写款式,vite 曾经做了很好的反对,在装置完依赖当前,只须要间接在代码中援用 xxx.less 即可。对于一个久经考验的开发者来说,款式还是要引入作用域的,通常应用 css modules。

装置 less 预处理器,

yarn add --dev less

而后批改 vite.config.ts 文件,增加 css modules 配置:

export default defineConfig({  ...  css: {    modules: {      localsConvention: 'camelCaseOnly', // 咱们应用驼峰模式    },  },  ...})

增加完配置当前,只有将原来的 xxx.less 改成 xxx.module.less 即可,这点与 create-react-app 是一样的。

这里举荐一个 vscode 插件 clinyong.vscode-css-modules 能够实现编码时款式类名的智能提醒,同时点击款式类名能够跳转到款式定义的中央,十分好用。如果在编写款式时应用的是中划线模式的命名形式,比方 .xxx-container,那么须要额定配置这个 vscode 插件,如下:

{  "cssModules.camelCase": true}

这样能够实现编写款式时应用中划线模式,在代码中应用的还是驼峰式的。

因为我开发的是一个中后盾我的项目,应用了 antd 和 lodash,大家都晓得,这两个是按需加载小户,以前咱们应用 babel-plugin-import 来解决,vite 生态里也有很多相似的计划。我选用了 vite-plugin-imp 这个插件,批改 vite.config.ts 如下:

import vitePluginImp from 'vite-plugin-imp';export default defineConfig({  ...  plugins: [    ...    vitePluginImp({      libList: [        {          libName: 'lodash',          libDirectory: '',          camel2DashComponentName: false,        },        {          libName: 'antd',          style(name) {              // use less              return `antd/es/${name}/style/index.js`;          },        },      ],    }),  ],  css: {    ...    preprocessorOptions: {      less: {        javascriptEnabled: true,      },    },  },});

antd 曾经默认反对了 Tree Shaking,下面的配置最终只会解决款式的按需加载。lodash 不反对 Tree Shaking,咱们也能够应用 ESM 版本 lodash-es,这样就能够不应用 vite-plugin-imp 了,配置如下:

export default defineConfig({  resolve: {    alias: [{      find: /^lodash$/,      replacement: 'lodash-es',    }],  },});

通常,咱们在开发前端我的项目时,须要一些代理来调用后端 API 接口,vite 配置如下:

export default defineConfig({    ...    server: {      proxy: {        '/api_path/': {          target: 'http://xxx.server.domain.com/',          changeOrigin: true,        },      },    },});
代理底层都是基于 http-proxy 实现,这里不做过多阐明了。

当初能够欢快的开发代码了。

反对微前端构建

因为咱们的中后盾利用是应用微前端(qiankun)来治理的,下面的配置,打包实现后不能被 qiankun 辨认,次要起因能够看看这里,咱们须要做一些额定解决。

咱们晓得,应用 webpack 构建微前端是,须要增加如下三个配置项:

{  output: {    libraryTarget: 'umd',    library: `${APP_NAME}-[name]`,    jsonpFunction: `webpackJsonp_${APP_NAME}`,  }}

在 vite 中,能够间接通过设置 build.rollupOptions.formatumd 来设置 UMD 标准,然而理论构建后果却不能被 qiankun 辨认,猜测是可能跟 vite 应用 html entry 有关系。

换一个思路,咱们把以后整个利用当做一个 library 来构建,输入为 UMD 标准,而后手动写入一个 html 文件,加载这个输入的 JS。

批改配置如下:

export default defineConfig({  ...  build: {    lib: {      name,      entry: path.resolve(__dirname, 'src/index.tsx'),      formats: ['umd'],    },  },  ...})

配置实现之后,执行 yarn build 提醒如下谬误:

UMD and IIFE output formats are not supported for code-splitting builds.

因为咱们的利用中有路由,应用了按需加载。咱们将 rollup 的 inlineDynamicImports 配置关上:

export default defineConfig({  ...  build: {    rollupOptions: {      output: {        inlineDynamicImports: true,      },    },  },  ...})

这样,构建实现之后,dist 目录下有两个文件 style.cssxxx.umd.js

当初咱们要生成 index.html 了。

因为 vite 在开发态间接应用 ES Modules,是不打包的,因而生成开发态的 index.html 和生产的 index.html 是不同的。

咱们批改我的项目根目录下的 index.html 为:

<!DOCTYPE html><html lang="en">  <head>    <meta charset="UTF-8" />    <link rel="icon" type="image/svg+xml" href="/src/favicon.svg" />    <meta name="viewport" content="width=device-width, initial-scale=1.0" />    <title>Vite App</title>    <!-- style placeholder -->  </head>  <body>    <div id="root"></div>    <!-- script placeholder -->  </body></html>

留神当中的两行正文,咱们会在开发态和生产构建做不同的解决。

vite 插件 API 中有一个 transformindexhtml 能够定制开发态的 html 内容,因而,咱们开发态的配置如下:

// https://vitejs.dev/config/export default defineConfig({  ...  plugins: [    ...    {      name: 'dev html',      apply: 'serve',      transformIndexHtml(indexHtml: string) {        return indexHtml          .replace('<!-- style placeholder -->', '')          .replace('<!-- script placeholder -->', '<script type="module" src="/src/index.tsx"></script>');      },    },    ...  ],});

生产构建须要借助于 @rollup/plugin-html 这个插件来实现定制 html 内容。

import html from '@rollup/plugin-html';import fs from 'fs';const entryHtml = fs.readFileSync('./index.html', { encoding: 'utf-8' });export default defineConfig({  ...  plugins: [    ...    {      name: 'build html',      apply: 'build',      ...html({        template: () => {          return entryHtml            .replace(              '<!-- style placeholder -->',              '<link rel="stylesheet" type="text/css" href="style.css" />',            )            .replace(              '<!-- script placeholder -->',              `<script type="text/javascript" src="${name}.umd.js"></script>`,            );        },      }),    },    ...  ],});

通过下面的配置,再次构建,qiankun 能够加载这个子利用了。

其余阐明

1. 老旧浏览器的反对

因为我这次的我的项目是中后盾我的项目,对老旧浏览器的反对诉求不强烈,就没有在我的项目中做解决。其实 vite 官网也是给了解决方案的,就是 @vitejs/plugin-legacy 这个插件。

原理也非常简单,就是通过 <script nomodule> 来实现在不反对 ES Modules 的浏览器执行相干脚本,同时应用 SystemJS 来加载模块。

2. 对于 TypeScript 的阐明

脚手架初始化实现当前就能够用 TypeScript 开发,这里分外阐明一点,就是须要开启编译器选项 isolatedModules:true,因为 vite 应用 esbuild 解决 ts 文件,只将 ts转换成 js 而不做类型查看(依赖编辑器解决类型查看,比方 vscode)。因而,当遇到一些纯类型的导入导出时,会出错,须要开启 isolatedModules:true 来防止这个问题。如果因为一些起因无奈开启这个选项,则能够应用 rollup-plugin-friendly-type-imports 这个包来解决,这个包的 README 里也阐明了为什么会有这样的问题。

3. 对接 CDN

基于下面的配置构建进去的后果,浏览器在加载资源的时候,都是应用的根门路(/)加载,如果应用 CDN 的话会呈现资源加载 404 的问题。

咱们能够配置 base 来设置根底门路,相似于 webpack 的 PUBLIC_PATH

export default defineConfig({  base: '/some/public/path',})

4. 构建出错

4.1 找不到包

报错信息为:

[plugin: vite:dep-scan] Failed to resolve entry for package "xxx"

通常是依赖包未在 package.json 正确配置 main、module 等字段,导致 vite 无奈找到包的入口。

能够设置通过设置别名的形式,将其映射到正确的文件上。

export default defineConfig({  resolve: {    alias: [{      find: /^SOME_PACKAGE_NAME$/,      replacement: 'SOME_PACKAGE_NAME/dist/xxx.es.js',    }],  },});

4.2 申请超时

报错信息为:

net::ERR_ABORTED 408 (Request Timeout)

启动开发服务器后,浏览器呈现申请超时谬误。是因为 vite 检测到对依赖包的申请,且该依赖尚未被 vite 解决过,这时候会会触发预构建,导致申请超时以及页面重载。

咱们能够多刷新几次等 vite 实现预构建,也能够将依赖退出 optimizeDeps.include 来提前解决。

4.3 导入模块出错

报错信息为:

Internal server error: Failed to resolve import "./chunk-7L3SPMWF.js" from "node_modules/.vite/antd.js?v=7bec0e27". Does the file exist?

可能是因为一些依赖包输入的格局 vite 还不反对,能够看看这个 issue。

这个谬误只在开发服务器运行处理过程中存在,待页面失常展现后就不呈现了,疏忽这个谬误之后,目前看也没产生什么影响。

小结

总体来说,vite 曾经根本具备了生产应用的条件。如果是惯例的利用开发,vite 的配置非常简单,能够说是开箱即用。如果须要增加额定的配置也十分不便。

目前比拟大的问题是周边生态还不是特地成熟,很多曾经成熟的包对于 vite(ES Modules)的反对比拟弱。同时,如果团队内基建气氛比拟浓重的话,本人开发的工具包也要思考这方面的问题。

常见面试知识点、技术计划剖析、教程,都能够扫码关注公众号“众里千寻”获取,或者来这里 https://everfind.github.io/po... 。