本质上来说,Vite和静态文件服务器在开发使用上并没有太大差别。然而Vite在原生ESM imports的基础上做了很多的提升,提供了多种多样的典型见于基于bundler打包设置的特性。
NPM依赖的解析和预打包
原生ES imports不支持纯模块引入,例如我们经常在 webpack-based 项目中使用的方法:
import { someMethod } from 'my-dep' // 官方例子
import React, { useState } from 'react' // 个人例子
这种引入方式不加转义直接运行会在浏览器中报错。Vite会在所有文件中检测这类纯模块引入,然后做以下处理:
- 预打包(Pre-bundle) 这些纯模块以提高页面加载速度,还要把 CommonJS/UMD 标准定义的模块转为ESM标准。预打包是由 esbuild 完成的,这使得Vite的冷启动时间明显快于任何基于JS的打包工具。
- 把引入模块的可用路径重写,改成类似于
/node_modules/.vite/my-dep.js?v=f3sf2ebd
,让浏览器能够正确的引入这些纯模块。
依赖将被强缓存
Vite把依赖的请求通过HTTP header缓存起来,如果你想本地的 编辑/debug 某一依赖,操作如 下。
模块热替换(Hot Module Replacement)
Vite基于ESM提供了一个 HMR API。HMR(Hot Module Replacement)是利用API提供即时、精确地更新,这一操作不会导致页面重加载或者应用状态丢失(使用状态管理时 // 个人理解)。Vite为Vue的单文件组件和React的快速刷新提供了第一方HMR集成库支持。也有为Preact提供的官方集成库( @prefresh/vite)。
值得一提的是你不再需要手动配置模块热替换——使用@vitejs/create-app
指令创建应用时,这一项功能已经帮你预设好了。
TS支持
Vite支持在项目中开箱即用的使用.ts
文件。
Vite仅对.ts
文件执行转译,不执行类型检查。Vite假定类型检查由你的IDE和构建过程(你可以在构建脚本中使用tsc --noEmit
指令)完成。
Vite使用esbuild对ts进行转译,这一过程比使用vanilla的tsc
指令快20-30倍。HRM更新在浏览器中的表现是小于50ms。
值得注意的是,因为esbuild
仅执行不带类型信息的转义,因此它不支持某些功能例如:const enum
和隐式的type-only
导入(TS3.8)。如此一来,你必须在tsconfig.json
文件下,compilerOptions
属性下配置"isolateModules": true
。以便于TS本身提醒你隔离式转译的功能不会生效。
客户端类型
Vite的默认类型是适用于它的Nodejs API。来调整一个Vite应用中客户端代码的环境,需要在你的tsconfig.json
文件中加入以下代码
{
"compilerOptions": {
"types": ["vite/client"]
}
}
这会提供以下的类型支持:
- 静态资源的导入(例如导入一个
.svg
文件) - Vite注入的环境变量的类型
import.meta.env
- HMR API类型
import.meta.hot
VUE
Vite提供一流的Vue支持:
- @vitejs/plugin-vue提供Vue3 SFC支持
- @vitejs/plugin-vue-jsx提供Vue3 JSX支持
- underfin/vite-plugin-vue2提供Vue2支持
JSX
Vite提供开箱即用的.jsx
和.tsx
文件支持。JSX同样由 esbuild 负责转译,默认支持React16特性。React17的esbuild支持请点击这里。
Vue的开发者可以使用官方插件@vitejs/plugin-vue-jsx,该插件提供了Vue3特有的特性,包括HMR,全局组件解析,vue指令(directives)和插槽(slots)。
如果不想在React或Vue项目中使用JSX,可以使用esbuild
选项配置自定义的可选项jsxFactory
和jsxFragment
。例如为Preact项目配置如下:
// vite.config.js
export default {
esbuild: {
jsxFactory: 'h',
jsxFragment: 'Fragment'
}
}
更多细节查看ESBuild文档。
你可以使用可选项jsxInject
全局注入JSX语法支持来避免在每一个文件中手动声明引入。这一特性为Vite独有配置:
// vite.config.js
export default {
esbuild: {
jsxInject: `import React from 'react'`
}
}
CSS
引入.css
文件将通过具有HMR支持的<style>
标签将样式表内容注入页面。你还可以将处理后的CSS字符串作为模块的默认导出。
@import
内联样式和重构
Vite默认支持通过postcss-import
使用@import
内联的引入CSS。Vite别名也适用于@import
。另外,即使导入的文件位于不同的文件夹下,所有的CSSurl()
引用都会自动重构以保证正确性。
@import
别名和URL重构同样支持Sass和Less文件。
PostCSS
如果项目包含有效的PostCSS配置(postcss-load-config支持的任何格式,例如postcss.config.js
),它将自动应用于所有导入的CSS。
CSS 模块
任何以.module.css
结尾的CSS文件都会被当做一个CSS模块文件。导入这样的文件将返回相应的模块对象:
/* example.module.css */
.red {
color: red;
}
import classes from './example.module.css'
document.getElementById('foo').className = classes.red
可以通过css.modules
选项配置CSS模块的行为。
如果将css.modules.localsConvention
设置为启用驼峰命名法(设置localsConvention:'camelCaseOnly'
),则还可以使用命名导入:
// .apply-color -> applyColor
import { applyColor } from './example.module.css'
document.getElementById('foo').className = applyColor
CSS 预处理器
因为Vite仅面向现代浏览器,我们建议将原生CSS变量与PostCSS插件一起使用。PostCSS插件实行CSSWG草案(例如postcss-nesting)并支持符合未来标准的普通CSS。
也就是说,Vite内置了对.scss
, .sass
, .less
, .styl
和 .stylus
文件的支持。因此不用再为这些文件额外安装适配Vite的插件,但还是要安装相应的预处理器本身:
# .scss and .sass
npm install -D sass
# .less
npm install -D less
# .styl and .stylus
npm install -D stylus
如果是使用Vue单文件组件,也会自动启用<style lang="sass">
等。
Vite改进了@import
解析Sass和Less的方式,因此Vite同样支持别名引入。而且,与根文件位于不同文件路径下被导入的Sass / Less文件,其相对路径url()
的引用也将自动重构以确保正确性。
Stylus因其API限制并不支持@import
别名和url重构。
你也可以联合使用CSS模块和预处理器。使用方法是在文件拓展名中缀加入.module
,例如style.module.scss
。
静态资源
导入一个静态资源时会返回给使用者一个解析过的公共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 Workers
import Worker from './worker.js?worker'
// 创建时Web Workers作为base64字符串行内引入
import InlineWorker from './worker.js?worker&inline'
更多细节查看静态资源打包。
JSON
JSON文件支持直接引入和命名引入:
// import the entire object
import json from './example.json'
// import a root field as named exports - helps with treeshaking!
import { field } from './example.json'
批量引入(通配引入)(glob import)
Vite支持批量引入模块。方法是只需要通过import.meta.glob
函数:
const modules = import.meta.glob('./dir/*.js)`
上述写法实际上是以下写法的变形:
// code produced by 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)
})
}
匹配的文件默认通过动态引入实现懒加载。项目打包时会拆成多块。如果你想要直接引入所有模块(例如:依赖于这些模块的副作用需要先被应用),则可以使用import.meta.globEager
函数:
const modules = import.meta.globEager('./dir/*.js')
上述写法实际上是以下写法的变形:
// code produced by 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
}
值得注意的是:
- 这只是Vite提供的特性而非web或ES标准
- 通配模式与
import
语法使用规则相同,引入路径必须是相对路径(以./
开头)或绝对路径(以/
开头,被解释为项目根路径)。不支持在依赖中使用通配引入。 - 通配匹配由
fast-glob
完成——查看文档通配特性支持。
Web Assembly
预编译的.wasm
文件可以直接引入。文件的默认导出是一个初始化函数,函数返回一个wasm实例的导出对象的Promise:
import init from './example.wasm'
init().then((exports) => {
exports.test()
})
这个初始化函数也可以接受一个传给WebAssembly.instantiate
的imports
对象作为第二参数:
init({
imports: {
someFunc: () => {
/* ... */
}
}
}).then(() => {
/* ... */
})
产品打包过程中,小于assetInlineLimit
的.wasm
文件将作为base64字符串内联。否则,它们将作为静态资源直接复制到dist目录并按需获取。
Web Workers
一个web worker脚本可以通过添加引入参数?worker
的方式直接引入。默认导出是一个自定义的worker构造函数:
import MyWorker from './worker?worker'
const worker = new MyWorker()
worker脚本也可以直接使用import
而不是imnportScripts()
引入。但是请注意,开发环境下这种方式依靠浏览器的原生支持且仅在谷歌浏览器下可用。但是生产环境打包后会被编译为通用格式。
默认情况打包下,worker脚本会被分块导出。如果你希望worker作为base64字符串内联,请添加内联参数:
import MyWorker from './worker?worker&inline'
打包优化
动态引入Polyfill
Vite使用ES动态导入作为代码拆分点。生成的代码还将使用动态导入来加载异步块。 但是,原生ESM通过script标签提供的动态导入支持比ESM加载要慢,并且在浏览器支持上两个功能存在差异。Vite会自动注入轻量级的动态导入Polyfill,以缓解这种差异。
如果你只使用具有原生动态导入功能支持的浏览器,则可以通过build.polyfillDynamicImport
显式禁用此功能。
CSS代码拆分
Vite会自动提取模块使用到的CSS到一个异步块中,然后为此生成一个分隔文件。加载关联的异步块时,会通过<link>
标签自动加载CSS文件,并确保仅在加载CSS之后解析异步块,以避免FOUC的情况。
如果您希望将所有CSS提取到一个文件中,则可以通过将build.cssCodeSplit
设置为false
来禁用CSS代码拆分。
预载指令生成
Vite自动为入口块文件和构建的HTML中直接引入这些文件的地方生成<link rel =“ modulepreload”>
指令。
异步块加载优化
在真实的程序中,Rollup通常会生成"common"块,"common"块中的代码会在其他两三个块中共享。结合动态导入,通常会出现以下情况:
在非优化方案中,当导入异步块A
时,浏览器必须先请求并解析A,然后才能确定它还需要公共块C
。这将导致额外的网络往返:
Entry ---> A ---> C
Vite会使用预加载步骤自动重写代码拆分的动态导入调用,以便在请求A
时并行获取C
:
Entry ---> (A + C)
C
可能会进一步导入,这将导致会比未优化的情况下产生更大的网络往返。 Vite的优化将跟踪所有直接导入,以完全消除往返,无论导入深度如何。
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!