vite
es 模块
什么是 es 模块?它是 js 定义模块化的一种标准,让代码组织更加清晰,每个模块的命名都不会冲突。
模块的语法有:
// 导入
import xx from 'xx'
// 导出
export const a = 1
export default b = 2在 es6 之前,js 没有原生实现 es 模块化语法。但在 es6 及以后,js 已经原生实现了 es 模块化语法。
处理静态资源
webpack 项目肯定不会处理在 public 目录下或使用绝对路径引入的静态资源,而是直接将其复制到打包后的目录中。
旧版本也不会处理 static 目录下的资源,但会处理 assets 目录下的资源。但新版本不管是 static 还是 assets 目录,都会处理了。
默认情况下,TypeScript 不会将静态资源导入视为有效的模块
public
如果你有下列这些资源:
- 不会被源码引用(例如 robots.txt)
- 必须保持原有文件名(没有经过 hash)
- ...或者你压根不想引入该资源,只是想得到其 URL。
那么你可以将该资源放在指定的 public 目录中,它应位于你的项目根目录。该目录中的资源在开发时能直接通过 / 根路径访问到,并且打包时会被完整复制到目标目录的根目录下。
目录默认是 <root>/public,但可以通过 publicDir 选项 来配置。
请注意:
引入 public 中的资源永远应该使用根绝对路径 —— 举个例子,public/icon.png 应该在源码中被引用为 /icon.png。 public 中的资源不应该被 JavaScript 文件引用。
index.html 与项目根目录
在 vite 中,index.html 中的 URL 将被自动转换,因此不再需要像 webpack 项目使用 %PUBLIC_URL% 占位符了。
%PUBLIC_URL% 的作用是正确处理部署的路径。比如你部署到 /app/ 目录下,而不是根目录,使用了 %PUBLIC_URL% 路径才会找到。
%PUBLIC_URL% 会被替换为 /app/。
<link rel="icon" href="<%= BASE_URL %>favicon.ico">功能
对非常基础的使用来说,使用 Vite 开发和使用一个静态文件服务器并没有太大区别。
然而,Vite 提供了许多增强功能。
依赖解析与预构建
想象你用 express 启动了一个服务器并返回一个 index.html,script 标签设置 type="module",并引入一个入口文件。入口文件中像下面这样裸模块导入。
原生 ES 导入不支持下面这样的裸模块导入:
import { someMethod } from 'my-dep'上面的代码会在浏览器中抛出一个错误。
Vite 将会检测到所有被加载的源文件中的此类裸模块导入,并执行以下操作:
预构建 它们可以提高页面加载速度,并将 CommonJS / UMD 转换为 ESM 格式。预构建这一步由 esbuild 执行,这使得 Vite 的冷启动时间比任何基于 JavaScript 的打包器都要快得多。
重写导入为合法的 URL,例如 /node_modules/.vite/deps/my-dep.js?v=f3sf2ebd 以便浏览器能够正确导入它们。
依赖是强缓存的
Vite 通过 HTTP 头来缓存请求得到的依赖,所以如果你想要编辑或调试一个依赖,可以配置禁用强缓存:
optimizeDeps: {
force: true // 设置为 true 可以强制依赖预构建,而忽略之前已经缓存过的、已经优化过的依赖。
},天然支持 ts 文件
但仅转译,不会作类型检查。
在开发时,如果你需要更多的 IDE 提示,我们建议在一个单独的进程中运行 tsc --noEmit --watch。或者如果你喜欢在浏览器中直接看到上报的类型错误,可以使用 vite-plugin-checker。
使用仅含类型的导入导出可以避免一些不正确打包的问题。
import type { T } from 'only/types'
export type { T }TypeScript 编译器选项
tsconfig.json 中 compilerOptions 下的一些配置项需要特别注意。
isolatedModules
孤立模块。应该设置为 true。
下面是一个简单的示例,演示了开启和关闭 isolatedModules 配置的效果。
假设有两个 TypeScript 文件:foo.ts 和 bar.ts,它们的内容如下:
// foo.ts
const foo = 1;
// bar.ts
console.log(foo);在这个例子中,bar.ts 文件引用了 foo.ts 文件中定义的变量 foo,但是并没有显式地通过 import 和 export 来声明依赖关系。
如果使用默认的编译配置进行编译,即没有开启 isolatedModules 配置,那么编译器会将两个文件视为一个模块,并且会认为变量 foo 是在全局作用域下定义的。这样,bar.ts 文件可以成功地访问到变量 foo,并输出其值为 1。
但是,如果开启 isolatedModules 配置,那么编译器会将每个文件都视为独立的模块,并且会在编译 bar.ts 文件时发现变量 foo 来自于另外一个文件 foo.ts,但是没有通过 import 和 export 声明依赖关系。这样,编译器会报错,提示找不到变量 foo:
error TS2304: Cannot find name 'foo'.为了解决这个问题,我们需要显式地在 bar.ts 文件中引入 foo.ts 文件中定义的变量 foo,如下所示:
// bar.ts
import { foo } from './foo';
console.log(foo);这样,当开启 isolatedModules 配置时,编译器就能正确地识别依赖关系,并且可以成功地编译和运行代码。
useDefineForClassFields
类字段定义语法。默认为 true。
// 在这个例子中,count 属性会被定义为 Person 类的静态属性,因此我们可以通过类名来访问它。
// 而 name 和 age 属性会被定义为 Person 类的实例属性,在每个 Person 对象上都会有一份,因此我们可以通过实例来访问它们。
class Person {
static count = 0;
name: string = '';
age: number = 0;
}客户端类型
Vite 默认的类型定义是写给它的 Node.js API 的。要将其补充到一个 Vite 应用的客户端代码环境中,请添加一个 d.ts 声明文件:
比如 src/vite-env.d.ts 文件
/// <reference types="vite/client" />同时,你也可以将 vite/client 添加到 tsconfig 中的 compilerOptions.types 下:
{
"compilerOptions": {
"types": ["vite/client"]
}
}这将会提供以下类型定义补充:
- 资源导入 (例如:导入一个 .svg 文件)
- import.meta.env 上 Vite 注入的环境变量的类型定义
- import.meta.hot 上的 HMR API 类型定义
css
内联与 url 导入
Vite 通过 postcss-import,支持 css 文件的内联导入和 url 导入。(style 和 url('./xx'))
PostCSS 配置
自动加载 PostCSS 配置。(任何受 postcss-load-config 支持的格式,例如 postcss.config.js)
请注意,CSS 最小化压缩将在 PostCSS 之后运行,并会使用 build.cssTarget 选项。
CSS 预处理器
只需下载对应预处理器,然后 <style lang="sass"> 自动开启
# .scss and .sass
npm add -D sass静态资源处理
导入一个静态资源会返回解析后的 URL:
import imgUrl from './img.png'
document.getElementById('hero-img').src = imgUrl添加一些特殊的查询参数可以更改资源被引入的方式:
// 显式加载资源为一个 URL
import assetAsURL from './asset.js?url'// 以字符串形式加载资源
import assetAsString from './shader.glsl?raw'// 加载为 Web Worker
import Worker from './worker.js?worker'// 在构建时 Web Worker 内联为 base64 字符串
import InlineWorker from './worker.js?worker&inline'JSON
JSON 可以被直接导入 —— 同样支持具名导入:
// 导入整个对象
import json from './example.json'
// 对一个根字段使用具名导入 —— 有效帮助 treeshaking!
import { field } from './example.json'Glob 导入
Vite 支持使用特殊的 import.meta.glob 函数从文件系统导入多个模块:(其实是封装的 fast-glob 模块)
const modules = import.meta.glob('./dir/*.js')以上将会被转译为下面的样子:
// vite 生成的代码
const modules = {
'./dir/foo.js': () => import('./dir/foo.js'),
'./dir/bar.js': () => import('./dir/bar.js'),
}你可以遍历 modules 对象的 key 值来访问相应的模块:
for (const path in modules) {
modules[path]().then((mod) => {
console.log(path, mod)
})
}上面是懒加载的,在构建时会分离出 chunk。如果想要一次性全部加载出来,可以传入第二个参数 eager:
const modules = import.meta.glob('./dir/*.js', { eager: true })以上会被转译为下面的样子:
// vite 生成的代码
import * as __glob__0_0 from './dir/foo.js'
import * as __glob__0_1 from './dir/bar.js'
const modules = {
'./dir/foo.js': __glob__0_0,
'./dir/bar.js': __glob__0_1,
}插件
使用插件
若要使用一个插件,需要将它添加到项目的 devDependencies 并在 vite.config.js 配置文件中的 plugins 数组中引入它。例如,要想为传统浏览器提供支持,可以按下面这样使用官方插件 @vitejs/plugin-legacy:
npm add -D @vitejs/plugin-legacy// vite.config.js
import legacy from '@vitejs/plugin-legacy'
import { defineConfig } from 'vite'
export default defineConfig({
plugins: [
legacy({
targets: ['defaults', 'not IE 11'],
}),
],
})查找插件
https://cn.vitejs.dev/guide/using-plugins.html#finding-plugins
指明模式调用
默认情况下插件在开发 (serve) 和生产 (build) 模式中都会调用。如果插件在服务或构建期间按需使用,请使用 apply 属性指明它们仅在 'build' 或 'serve' 模式时调用:
// vite.config.js
import typescript2 from 'rollup-plugin-typescript2'
import { defineConfig } from 'vite'
export default defineConfig({
plugins: [
{
...typescript2(),
apply: 'build',
},
],
})创造插件
https://cn.vitejs.dev/guide/using-plugins.html#building-plugins
构建生成版本
当需要将应用部署到生产环境时,只需运行 vite build 命令。
处理浏览器兼容性
用于生产环境的构建包会假设目标浏览器支持现代 JavaScript 语法。默认情况下,Vite 的目标是能够 支持原生 ESM script 标签、支持原生 ESM 动态导入 和 import.meta 的浏览器:
Chrome >=87
Firefox >=78
Safari >=14
Edge >=88你也可以通过 build.target 配置项 指定构建目标,最低支持 es2015。
请注意,默认情况下 Vite 只处理语法转译,且 默认不包含任何 polyfill。
传统浏览器可以通过插件 @vitejs/plugin-legacy 来支持,它将自动生成传统版本的 chunk 及与其相对应 ES 语言特性方面的 polyfill。兼容版的 chunk 只会在不支持原生 ESM 的浏览器中进行按需加载。
公共基础路径
配置 base 选项。
库模式
部署静态站点
本地预览
首先确保有这两个脚本,先执行 build 脚本,打包产物会放在 dist 目录下。然后执行 preview 脚本,会在 dist 目录下起一个服务供浏览器预览。
{
"scripts": {
"build": "vite build",
"preview": "vite preview"
}
}GitHub Pages
如何部署。
在 GitHub 上创建一个新的仓库(Repository)。请注意,这个仓库的名称必须为“your_username.github.io”,其中“your_username”是你的 GitHub 用户名。这是因为 GitHub Pages 的网址是基于你的用户名的。
在仓库中添加一个 index.html 文件,这将是你网站的主页。你也可以添加其他的 HTML、CSS、JavaScript 文件和图片等内容。
- 在 vite.config.js 中设置正确的 base。
如果你的仓库名为 <USERNAME>.github.io(http 链接为 https://github.com/<USERNAME>/<USERNAME>.github.io),那么 github pages 将会被部署在 https://<USERNAME>.github.io/ 上,你可以省略 base 使其默认为 '/'。
如果你的仓库名不为 <USERNAME>.github.io(http 链接为 https://github.com/<USERNAME>/<REPO>),那么 github pages 将会被部署在 https://<USERNAME>.github.io/<REPO>/ 上,这时候设置 vite.config.js 的 base 为 '/<REPO>/'
- 进入仓库 settings,设置 github pages。可以设置选择部署的分支,部署的目录。部署目录只能选择根目录或 docs 目录。
环境变量和模式
在 vite.config.js 中,可以传入一个函数,返回配置对象。
函数参数是一个对象,有 command、mode 属性。
command 有两种值,serve、build,分别代表开发环境和生产环境。
mode 就是用户通过脚本 --mode 参数传递给 vite 的值。
在 Vite 的 API 中,在开发环境下 command 的值为 serve(在 CLI 中,vite dev 和 vite serve 是 vite 的别名),而在生产环境下为 build(vite build)