拥抱 Vite2.0 系列(二)

2021-03-16 15:21:03 浏览数 (1)

特征

在最基本的层次上,使用Vite进行开发与使用静态文件服务器没有太大区别。但是,Vite对本机ESM导入提供了许多增强功能,以支持通常在基于捆绑程序的设置中常见的各种功能。

NPM依赖关系解析和预捆绑

原生ES导入不支持如下所示的裸模块导入:

代码语言:javascript复制
import { someMethod } from 'my-dep'

上面的操作将在浏览器中抛出一个错误。Vite将在所有服务的源文件中检测此类裸模块导入,并执行以下操作:

  • 预捆绑它们以提高页面加载速度,并将CommonJS / UMD模块转换为ESM。预绑定步骤是用esbuild执行的,这使得Vite的冷启动时间比任何基于javascript的绑定程序都要快得多。
  • 重写导入到有效的url,如/node_modules/.vite/my- depj .js?v=f3sf2ebd,以便浏览器能正确导入。

依赖项被强缓存

Vite通过HTTP头缓存依赖请求,所以如果你想在本地编辑/调试依赖,请遵循这里的步骤。

热模块替换

Vite通过本地ESM提供了HMR API。具有HMR功能的框架可以利用API提供即时、准确的更新,而无需重新加载页面或删除应用程序状态。Vite为Vue单文件组件提供第一方HMR集成,并快速响应刷新。还有通过@prefresh/vite对Preact的官方集成。

注意,您不需要手动设置这些-当您通过@vitejs/create-app创建应用程序时,所选模板将为您预先配置这些。

TypeScript

Vite支持直接导入.ts文件。

Vite只对.ts文件执行翻译,不执行类型检查。它假设类型检查由IDE和构建过程负责(可以在构建脚本中运行tsc——noEmit)。

Vite使用esbuild将TypeScript转换为JavaScript,比普通tsc快20~30倍,HMR更新可以在50毫秒内反映到浏览器中。

请注意,因为esbuild只执行不带类型信息的转换,所以它不支持某些特性,如const enum和隐式的纯类型导入。你必须在tsconfig中设置"isolatedModules": true。这样TS就会对那些不能与单独的翻译一起工作的特性发出警告。

客户端类型

Vite的默认类型是Node.js API。要在Vite应用程序中缓冲客户端代码环境,请添加Vite/client到compilerOptions.tsconfig的类型:

代码语言:javascript复制
{
  "compilerOptions": {
    "types": ["vite/client"]
  }
}

这将提供以下类型的垫片:

  • 资产导入(例如导入.svg文件)
  • import.meta.env上导入的env变量的类型
  • import.meta.hot上的HMR API的类型

Vue

Vite提供一流的Vue支持:

  • 通过@vitejs/plugin-vue支持Vue 3 SFC
  • 通过@vitejs/plugin-vue-jsx支持Vue 3 JSX
  • 通过underfin/vite-plugin-vue2支持Vue 2

JSX

.jsx和.tsx文件也支持开箱即用。JSX编译也通过ESBuild处理,默认使用React 16风格。这里跟踪ESBuild中React 17风格的JSX支持。

Vue用户应该使用官方的@vitejs/plugin- Vue -jsx插件,该插件提供了Vue 3特有的特性,包括HMR、全局组件解析、指令和插槽。

如果没有将JSX与React或Vue一起使用,可以使用esbuild选项配置自定义jsxFactory和jsxFragment。例如Preact:

代码语言:javascript复制
// vite.config.js
export default {
  esbuild: {
    jsxFactory: 'h',
    jsxFragment: 'Fragment'
  }
}

更多细节在ESBuild文档中。

你可以使用jsxInject(这是唯一的vite选项)注入JSX helper,以避免手动导入:

代码语言:javascript复制
// vite.config.js
export default {
  esbuild: {
    jsxInject: `import React from 'react'`
  }
}

CSS

导入.css文件将通过带有HMR支持的<style>标签将其内容注入到页面。您还可以以字符串的形式检索已处理的CSS,作为模块的默认导出。

@import Inlining and Rebasing

Vite是预先配置的,通过postcss-import支持CSS @import内联。在CSS @import中,Vite别名也受到尊重。此外,所有CSS url()引用,即使导入的文件在不同的目录中,也总是自动重基,以确保正确性。

@import别名和URL重基也支持Sass和Less文件(参见CSS Pre-processors)。

PostCSS

如果项目包含有效的PostCSS配置(PostCSS load-config支持的任何格式,例如PostCSS .config.js),它将自动应用于所有导入的CSS。

CSS Modules

任何以.module. CSS结尾的CSS文件都被认为是一个CSS模块文件。导入这样的文件将返回相应的模块对象:

代码语言:javascript复制
/* example.module.css */
.red {
  color: red;
}
代码语言:javascript复制
import classes from './example.module.css'
document.getElementById('foo').className = classes.red

CSS模块可以通过CSS模块选项来配置。

如果css.modules.localsConvention被设置为启用驼色本地化(例如localsConvention: 'camelCaseOnly'),你也可以使用命名导入:

代码语言:javascript复制
// .apply-color -> applyColor
import { applyColor } from './example.module.css'
document.getElementById('foo').className = applyColor

CSS Pre-processors

因为Vite只针对现代浏览器,所以建议使用原生CSS变量和实现CSSWG草案的PostCSS插件(例如PostCSS嵌套),并编写简单的、未来标准兼容的CSS。

也就是说,Vite确实提供了对.scss、.sass、.less、.styl和.stylus文件的内置支持。不需要为他们安装特定的插件,但相应的预处理器本身必须安装:

代码语言:javascript复制
# .scss and .sass
npm install -D sass

# .less
npm install -D less

# .styl and .stylus
npm install -D stylus

如果使用Vue单文件组件,也会自动启用等功能。

Vite改进了Sass和Less的@import解析,因此Vite别名也得到了尊重。此外,在与根文件不同的目录中,导入的Sass/Less文件中的相对url()引用也会自动重基,以确保正确性。

由于Stylus的API约束,不支持@import别名和url重基。

您还可以通过在文件扩展名前加上.module来结合使用CSS模块和预处理器,例如style.module.scss。

Static Assets

导入静态资产时,将返回解析后的公共URL:

代码语言:javascript复制
import imgUrl from './img.png'
document.getElementById('hero-img').src = imgUrl

特殊查询可以修改资产的加载方式:

代码语言:javascript复制
// Explicitly load assets as URL
import assetAsURL from './asset.js?url'
代码语言:javascript复制
// Load assets as strings
import assetAsString from './shader.glsl?raw'
代码语言:javascript复制
// Load Web Workers
import Worker from './worker.js?worker'
代码语言:javascript复制
// Web Workers inlined as base64 strings at build time
import InlineWorker from './worker.js?worker&inline'

JSON

JSON文件可以直接导入-命名导入也支持:

代码语言:javascript复制
// 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从文件系统中导入多个模块:

代码语言:javascript复制
const modules = import.meta.glob('./dir/*.js')

以上将转化为以下内容:

代码语言:javascript复制
// code produced by vite
const modules = {
  './dir/foo.js': () => import('./dir/foo.js'),
  './dir/bar.js': () => import('./dir/bar.js')
}

然后你可以遍历modules对象的键来访问相应的模块:

代码语言:javascript复制
for (const path in modules) {
  modules[path]().then((mod) => {
    console.log(path, mod)
  })
}

匹配的文件默认情况下是通过动态导入延迟加载的,并将在构建过程中分割为单独的块。如果你宁愿直接导入所有的模块(例如,依赖于这些模块中的副作用首先被应用),你可以使用import.meta.globEager相反:

代码语言:javascript复制
const modules = import.meta.globEager('./dir/*.js')

以上将转化为以下内容:

代码语言:javascript复制
// 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标准。

glob模式被视为类似于导入说明符:它们必须是相对的(以。/开始)或绝对的(以/开始,相对于项目根目录解析)。不支持对依赖项进行通配。

glob匹配是通过fast-glob完成的——请查看它的文档以获取支持的glob模式。

Web Assembly

预编译的.wasm文件可以直接导入——默认的导出将是一个初始化函数,它返回wasm实例的exports对象的承诺:

代码语言:javascript复制
import init from './example.wasm'

init().then((exports) => {
  exports.test()
})

init函数也可以接收传入WebAssembly的imports对象。作为它的第二个参数实例化:

代码语言:javascript复制
init({
  imports: {
    someFunc: () => {
      /* ... */
    }
  }
}).then(() => {
  /* ... */
})

在生产版本中,小于assetInlineLimit的.wasm文件将作为base64字符串内联。否则,它们将作为资产复制到dist目录中,并按需获取。

Web Workers

通过在导入请求中附加?worker,可以直接导入web worker脚本。默认的导出将是一个自定义的worker构造函数:

代码语言:javascript复制
import MyWorker from './worker?worker'

const worker = new MyWorker()

worker脚本也可以使用import语句来代替importScripts()——注意,在开发过程中,这依赖于浏览器本地支持,目前只在Chrome中工作,但在生产版本中,它被编译掉了。

默认情况下,worker脚本将在生产构建中作为单独的块发出。如果你想将worker内联为base64字符串,添加内联查询:

代码语言:javascript复制
import MyWorker from './worker?worker&inline'

打包优化

下面列出的特性将作为构建过程的一部分自动应用,除非您想禁用它们,否则不需要显式配置。

动态导入Polyfill

Vite使用ES动态导入作为代码分割点。生成的代码还将使用动态导入来加载异步块。然而,本机ESM动态导入支持是在ESM之后通过脚本标记实现的,并且这两个特性在浏览器支持方面存在差异。Vite会自动注入一个轻量级的动态导入填充来消除这种差异。

如果你知道你的目标浏览器只支持本机动态导入,你可以通过build.polyfillDynamicImport显式禁用此特性。

CSS 代码分离

Vite自动提取模块在一个异步块中使用的CSS,并为它生成一个单独的文件。当相关的异步块被加载时,CSS文件通过标签自动加载,并且异步块保证只在CSS加载后才被计算,以避免FOUC。

如果您希望将所有CSS提取到一个文件中,可以通过设置build禁用CSS代码分割,通过设置build.cssCodeSplit为假。

生成预加载指令

Vite自动生成<link rel="modulepreload"> 指令,用于条目块和它们在构建的HTML中直接导入。

异步块加载优化

在真实的应用程序中,Rollup经常生成“公共”块——在两个或多个块之间共享的代码。与动态导入相结合,下面的场景很常见:

在未优化的场景中,当异步块A被导入时,浏览器将不得不请求并解析A,然后才能确定它也需要普通块c。这导致了额外的网络往返:

代码语言:javascript复制
Entry ---> A ---> C

Vite使用预加载步骤自动重写代码分割动态导入调用,这样当a请求时,C被并行获取:

代码语言:javascript复制
Entry ---> (A   C)

C可能有进一步的导入,这将在未优化的场景中导致更多的往返。Vite的优化将跟踪所有的直接导入,从而完全消除无论导入深度如何的往返。

0 人点赞