webpack {#webpack}
在webpack开发时构建时,默认会抓取并构建你的整个应用,然后才能提供服务,这就导致了你的项目中存在任何一个错误(即使当前错误不是首页引用的模块),他依然会影响到你的整个项目构建。所以你的项目越大,构建时间越长,项目启动速度也就越慢。
vite {#vite}
vite不会在一开始就构建你的整个项目,而是会将引用中的模块区分为依赖和源码(项目代码)两部分,
改进了开发服务器启动时间。依赖使用esbuild进行依赖预构建,源码就是我们代码中写的业务组件.vue,.ts文件等,是esmodule的形式,一方面浏览器可以直接解析esmodule,另一方面,我们可以通过动态导入,路由懒加载的方式,只有当路由跳转到对应页面才去加载该页面的资源。
对于源码部分,他会根据路由来拆分代码模块,只会去构建一开始就必须要构建的内容。
同时vite以原生 ESM的方式为浏览器提供源码,让浏览器接管了打包的部分工作。
vite服务热更新更快 {#vite%E6%9C%8D%E5%8A%A1%E7%83%AD%E6%9B%B4%E6%96%B0%E6%9B%B4%E5%BF%AB}
在 Vite 中,HMR 是在原生 ESM 上执行的。当编辑一个文件时,Vite 只需要精确地使已编辑的模块与其最近的 HMR 边界之间的链失活[1](大多数时候只是模块本身),使得无论应用大小如何,HMR 始终能保持快速更新。
Vite 同时利用 HTTP 头来加速整个页面的重新加载(再次让浏览器为我们做更多事情):源码模块的请求会根据 304 Not Modified 进行协商缓存,而依赖模块请求则会通过 Cache-Control: max-age=31536000,immutable
进行强缓存,因此一旦被缓存它们将不需要再次请求。
缓存 {#%E7%BC%93%E5%AD%98}
文件系统缓存 {#%E6%96%87%E4%BB%B6%E7%B3%BB%E7%BB%9F%E7%BC%93%E5%AD%98}
Vite 将预构建的依赖项缓存到 node_modules/.vite 中。它会基于以下几个来源来决定是否需要重新运行预构建步骤:
包管理器的锁文件内容,例如 package-lock.json,yarn.lock,pnpm-lock.yaml,或者 bun.lockb;
补丁文件夹的修改时间;
-vite.config.js 中的相关字段;
NODE_ENV 的值。
只有在上述其中一项发生更改时,才需要重新运行预构建。
如果出于某些原因你想要强制 Vite 重新构建依赖项,你可以在启动开发服务器时指定 --force 选项,或手动删除 node_modules/.vite 缓存目录。
浏览器缓存 {#%E6%B5%8F%E8%A7%88%E5%99%A8%E7%BC%93%E5%AD%98}
已预构建的依赖请求使用 HTTP 头 max-age=31536000, immutable 进行强缓存,以提高开发期间页面重新加载的性能。一旦被缓存,这些请求将永远不会再次访问开发服务器。
如果安装了不同版本的依赖项(这反映在包管理器的 lockfile 中),则会通过附加版本查询自动失效。如果你想通过本地编辑来调试依赖项,您可以:
通过浏览器开发工具的 Network 选项卡暂时禁用缓存;
重启 Vite 开发服务器指定 --force 选项,来重新构建依赖项;
重新载入页面。
vite一些处理 {#vite%E4%B8%80%E4%BA%9B%E5%A4%84%E7%90%86}
npm依赖解析和构建 {#npm%E4%BE%9D%E8%B5%96%E8%A7%A3%E6%9E%90%E5%92%8C%E6%9E%84%E5%BB%BA}
原生 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 头来缓存请求得到的依赖
,所以如果你想要编辑或调试一个依赖,请按照 这里 的步骤操作。
当你首次启动 vite 时,Vite 在本地加载你的站点之前预构建了项目依赖。默认情况下,它是自动且透明地完成的。
原因
这就是 Vite 执行时所做的"依赖预构建"。这个过程有两个目的:
- CommonJS 和 UMD 兼容性: 在开发阶段中,Vite 的开发服务器将所有代码视为原生 ES 模块。因此,Vite 必须先将以 CommonJS 或 UMD 形式提供的依赖项转换为 ES 模块。
在转换 CommonJS 依赖项时,Vite 会进行智能导入分析,这样即使模块的导出是动态分配的(例如 React),具名导入(named imports)也能正常工作:
// 符合预期
import React, { useState } from 'react'
性能: 为了提高后续页面的加载性能,Vite将那些具有许多内部模块的 ESM 依赖项转换为单个模块。
有些包将它们的 ES 模块构建为许多单独的文件,彼此导入。例如,lodash-es 有超过 600 个内置模块!当我们执行 import { debounce } from 'lodash-es' 时,浏览器同时发出 600 多个 HTTP 请求!即使服务器能够轻松处理它们,但大量请求会导致浏览器端的网络拥塞,使页面加载变得明显缓慢。
通过将lodash-es
预构建成单个模块,现在我们只需要一个HTTP请求!
注意
依赖预构建仅适用于开发模式,并使用 esbuild 将依赖项转换为 ES 模块。在生产构建中,将使用 @rollup/plugin-commonjs。
typescript {#typescript}
Vite 天然支持引入 .ts 文件。 请注意,Vite 仅执行 .ts 文件的转译工作,并不执行 任何类型检查。并假定类型检查已经被你的 IDE 或构建过程处理了。那怎么开启类型检查呢?
-
在构建生产版本时,你可以在 Vite 的构建命令之外运行
tsc --noEmit
。 -
在开发时,如果你需要更多的 IDE 提示,我们建议在一个单独的进程中运行 tsc --noEmit --watch,或者如果你喜欢在浏览器中直接看到上报的类型错误,可以使用 vite-plugin-checker。
客户端类型 Vite 默认的类型定义是写给它的 Node.js API 的。要将其补充到一个 Vite 应用的客户端代码环境中,请添加一个 d.ts 声明文件:
tsconfig.json中需要加入一下
或者官网提示可以这样做:
css {#css}
路径导入支持使用@import,eg: @import './base.css';
支持CSS Modules用法可以参考
- 支持css预处理器
由于 Vite 的目标仅为现代浏览器,因此建议使用原生 CSS 变量和实现 CSSWG 草案的 PostCSS 插件(例如 postcss-nesting)来编写简单的、符合未来标准的 CSS。
话虽如此,但 Vite 也同时提供了对 .scss, .sass, .less, .styl 和 .stylus 文件的内置支持。没有必要为它们安装特定的 Vite 插件,但必须安装相应的预处理器依赖:
# .scss and .sass
npm add -D sass
# .less
npm add -D less
# .styl and .stylus
npm add -D stylus
- 另外,vite.config.ts中需要增加如下配置:
css: {
// css预处理器
preprocessorOptions: {
scss: {
additionalData: '@import "@/assets/style/mixin.scss";@import "@/assets/style/variable.scss";' //引入全局scss样式
}
}
}
你还可以通过在文件扩展名前加上 .module 来结合使用 CSS modules 和预处理器,例如 style.module.scss。(react项目中这样用过)
- 禁用 CSS 注入页面
静态资源处理 {#%E9%9D%99%E6%80%81%E8%B5%84%E6%BA%90%E5%A4%84%E7%90%86}
- 引入静态资源的方式
import imgUrl from './img.png'
document.getElementById('hero-img').src = imgUrl
例如,imgUrl
在开发时会是/img.png
,在生产构建后会是 /assets/img.2d8efhg.png
。
- 常见的图像、媒体和字体文件类型被自动检测为资源。你可以使用 assetsInclude 选项 扩展内部列表。
- 较小的资源体积小于 assetsInlineLimit 选项值 则会被内联为 base64 data URL。
- 默认情况下,TypeScript 不会将静态资源导入视为有效的模块。要解决这个问题,需要添加 vite/client。(使用vue脚手架初始化项目,这些都会帮你配好的)
public 目录
如果你有下列这些资源:
- 不会被源码引用(例如 robots.txt)
- 必须保持原有文件名(没有经过 hash)
- ...或者你压根不想引入该资源,只是想得到其 URL。
- 那么你可以将该资源放在指定的 public 目录中,它应位于你的项目根目录。该目录中的资源在
开发时能直接通过 / 根路径访问到,并且打包时会被完整复制到目标目录的根目录下
。
目录默认是 /public,但可以通过 publicDir 选项 来配置。
请注意:
- 引入 public 中的资源永远应该使用根绝对路径 ------ 举个例子,
public/icon.png
应该在源码中被引用为/icon.png
。 - public 中的资源不应该被 JavaScript 文件引用。
vite快有什么问题? {#vite%E5%BF%AB%E6%9C%89%E4%BB%80%E4%B9%88%E9%97%AE%E9%A2%98%EF%BC%9F}
当源码中有commonjs
模块加载,那么将会出现模块加载失败的问题。通过依赖与构建的方式解决该问题。
例如axios库就有相关的issue
总结: {#%E6%80%BB%E7%BB%93%EF%BC%9A}
Webpack 和 Vite 存在以下显著区别:
1. 开发服务器启动速度
- Webpack:在开发阶段,它需要对整个项目的模块进行打包构建,这导致启动开发服务器的过程较为缓慢,特别是项目规模较大时,可能需要较长时间等待。
- Vite:充分利用现代浏览器对 ES Modules 的原生支持,在开发时无需打包,直接按需加载模块,因此启动速度非常快,几乎是瞬时启动。
2. 热更新(HMR)性能
- Webpack:当代码发生更改时,Webpack 可能需要重新打包和处理相关的模块及依赖,这可能导致热更新有一定的延迟,影响开发效率。
- Vite:基于浏览器对 ES Modules 的支持,能够实现真正的按需热更新,只更新修改的模块,极大地提高了热更新的效率,几乎能立即反映出代码的更改。
3. 构建方式
- Webpack:对所有模块进行打包处理,无论在开发还是生产环境。
- Vite:在开发环境采用即时编译,生产环境则会进行预构建,将依赖进行打包处理,以优化性能。
4. 配置复杂度
- Webpack:拥有丰富且复杂的配置选项,需要开发者深入了解各种插件和 loader 的使用,以满足不同的项目需求。
- Vite:配置相对简单直观,更容易上手和理解。
比如说,对于一个简单的前端应用原型开发,Vite 凭借其快速的启动和高效的热更新能显著提升开发体验。但对于一些大型的、具有复杂构建需求的企业级应用,Webpack 凭借其强大的扩展性和丰富的生态可能更能胜任。