一、浅谈构建工具
前端为什么需要构建工具?
1. 前端项目的组成部分
- HTML(超文本标记语言) :HTML 是构建网页内容的基础,它定义了页面的结构和内容。使用 HTML 标签,可以创建标题、段落、链接、图像等元素,从而构建页面的基本骨架。
- CSS(层叠样式表) :CSS 用于控制页面的外观和样式。通过定义样式规则,可以指定文本的字体、颜色、页面的布局、背景等。CSS 使页面变得美观并具有可读性。
- JavaScript:JavaScript 是一种编程语言,用于在用户的浏览器中添加交互性和动态功能。可以使用 JavaScript 操控 HTML 元素、处理表单数据、响应用户事件(如点击、滚动等),以及与后端服务器进行通信。
- 用户界面(UI)库/框架:UI 库(如React、Vue、Angular等)或框架为开发人员提供了组件化开发的能力。这些库/框架允许构建复杂的用户界面,将页面分解为可重用的组件,从而简化开发流程并提高代码的可维护性。
- 页面布局和设计:这包括确定页面上各个部分的排列方式,以及确保页面在不同设备上(如桌面、平板电脑、手机)上都有良好的布局和可用性。
- 响应式设计:现代前端项目通常需要支持多种不同大小和类型的设备。响应式设计是一种方法,通过适应不同的屏幕尺寸和方向,以确保页面在所有设备上都呈现出最佳效果。
- 浏览器兼容性处理:不同的浏览器可能对 HTML、CSS 和 JavaScript 的实现有所不同。为了确保在各种浏览器中都能正常工作,开发人员需要进行兼容性测试和修复。
- 性能优化:前端性能对用户体验至关重要。这涉及到优化页面加载速度、减少网络请求、缓存管理以及其他技术,以确保页面在各种情况下都能快速加载和流畅运行。
- 版本控制:使用工具如Git来管理项目的版本和变更,以便团队成员可以协同开发,追踪修改,解决冲突,并轻松地回滚到以前的版本。
- 构建工具:构建工具如Webpack、Parcel等帮助开发人员自动化构建过程,包括代码压缩、合并、转译新语法(如ES6到ES5)、资源管理等。
- 测试:前端项目需要进行单元测试、集成测试和端到端测试,以确保代码质量和功能的稳定性。
- 部署:将前端代码部署到服务器,以便用户可以通过互联网访问您的应用程序。这可能涉及设置服务器、配置域名和SSL证书等。
2. 前端工程化问题
- 模块化: 在前端项目中,将代码拆分为不同的模块可以提高代码的可维护性和复用性。模块化可以通过不同的模块规范来实现,如ESM(ES Modules)、CommonJS和UMD(Universal Module Definition)。ESM 是一种在现代浏览器和Node.js中原生支持的模块化规范,而CommonJS在Node.js中常用,UMD可以同时兼容浏览器和Node.js。
- 资源编译: 当使用较新的语法或特性时,为了在更旧的浏览器中运行,需要将代码进行编译和转换。这可以通过工具如Babel来实现,它可以将ES6+代码转换为更早版本的JavaScript,以确保兼容性。同时,还可以使用Sass、Less等预处理器将高级的CSS语法转换为浏览器可以理解的CSS。
- 产物质量: 在前端项目中,代码体积和性能都是重要的考虑因素。减小代码体积可以通过代码压缩、去除未使用的代码、按需加载等方式实现。性能优化可以涉及减少网络请求、使用适当的图像格式、延迟加载等方法,以确保用户在加载和使用应用时获得更好的体验。
- 开发效率: 开发效率对于前端工程也非常重要。热更新是一种开发工具,允许开发人员在修改代码时,不需要手动刷新浏览器,即可看到更改的效果。这可以通过工具如Webpack的热模块替换(HMR)功能来实现,以提高开发效率。
3. 前端构建工具的意义
- 模块化方案: 构建工具能够处理不同的模块化规范,如CommonJS、ES Modules、AMD等。它们可以将多个模块打包成一个或多个文件,减少了网络请求次数,提高了页面加载速度。同时,构建工具还能够解决模块加载顺序和依赖关系,确保代码按照正确的顺序加载和执行。
- 语法转译: 构建工具允许开发人员使用最新的语言特性和高级语法,而无需担心浏览器兼容性问题。构建工具能够优化资源加载,如图片、字体、Web Workers等。它们可以将图片压缩、转换为适当的格式,以及在需要时按需加载,减少页面加载时间。
- 产物质量: 构建工具可以通过压缩、混淆和删除无用代码来优化代码体积,提高应用程序的加载速度。这些工具还可以检测和移除未使用的代码,减少产物中的冗余内容。另外,它们还可以进行语法降级,将新语法转换为旧语法,以确保在更旧的浏览器中正常运行。
- 开发效率: 热更新允许开发人员在修改代码时,实时地在浏览器中查看变化,而无需手动刷新页面。
二、Vite 概要介绍
Vite 概览
-
Vite 的定位:新一代的前端构建工具。
-
Vite 的两大核心组成部分
-
No-bundle 开发服务,源文件无需打包
Vite 的开发服务器采用了「No-bundle」的开发方式,即在开发阶段,不需要像传统的打包工具那样将所有代码打包成一个或几个文件。Vite 利用了浏览器原生支持的 ES 模块系统,以及 HTTP/2 的多路复用特性,实现了即时的热模块替换(HMR)。
开发服务的特点包括:
- ES 模块系统:Vite 保留了原始的 ES 模块,当浏览器请求模块时,Vite 会将每个模块作为单独的文件提供。这有助于减少冗余加载和解析。
- 热模块替换(HMR) :Vite 支持即时的热模块替换,开发人员在修改代码时,可以实时地看到变化的效果,无需手动刷新页面。
- HTTP/2 多路复用:利用 HTTP/2 的多路复用特性,Vite 可以同时发送多个请求,从而减少网络请求的延迟,加速模块加载。
-
生产环境基于 Rollup 的 Bundler
Vite 基于 Rollup 的打包工具来处理生产构建的需求。这个部分包括:
- 产物优化:Vite 在生产环境下进行代码压缩、无用代码删除等优化,以减小产物体积,提高应用的加载速度。
- 代码分割:基于动态导入,Vite 实现了代码分割,将应用拆分成小块,按需加载,减少初始加载时间。
- ES 模块转换:在生产构建时,Vite 可以将现代 ES6+ 代码转换为浏览器可识别的 ES5 代码,确保在不支持 ES6 的浏览器中正常运行。
-
-
Vite 的核心特征
- 高性能,dev 启动速度和热更新速度非常快
- 快速的启动速度:Vite 利用了浏览器原生的 ES 模块系统,以及基于服务器的构建,在开发阶段实现了即时的热模块替换(HMR)。
- 热更新速度快:Vite 的热模块替换允许在修改代码时实时查看变化,无需手动刷新页面。由于 Vite 不需要重新打包整个应用,热更新的速度非常快,能够即时地看到代码变化的效果。
- 简单易用,开发者体验好
- 开箱即用:Vite 提供了预设的开发环境配置,支持多种前端框架(如Vue、React),以及原生 JavaScript。这使得项目初始化变得非常简单,可以迅速开始构建应用,而无需大量的配置。
- 无需额外的工具链:相比传统的前端工具链,Vite 更加集成化。无需额外的插件或工具,例如不需要单独配置 Babel,因为 Vite 自带了对现代 JavaScript 语法的支持。
- 本地依赖解析:Vite 支持本地依赖的 ES 模块解析,即在开发过程中,可以直接导入第三方库,而无需像传统的打包工具那样配置额外的别名或路径。
- 高性能,dev 启动速度和热更新速度非常快
-
当前前端构建工具存在的问题
- 传统构建工具存在的问题
- 缓慢的启动,导致项目编译等待成本高
- 缓慢的热更新,导致修改代码后不能实时更新
- Vite 的瓶颈
- bundle 带来的性能开销
- JavaScript 语言的性能瓶颈
- 传统构建工具存在的问题
-
浏览器原生 ESM 支持
两大要素:
- script 标签增加 type=”module” 属性:当在
script标签中使用type="module"时,浏览器会将脚本视为 ESM 模块,并自动启用严格模式。示例:
<script type="module" src="main.js"></script>- 使用 ESM 模块导入导出语法:ESM 支持使用类似于 Node.js 的模块导入和导出语法。这包括使用
import关键字导入其他模块,并使用export关键字从一个模块导出功能或变量。示例:
// 导入模块 import { someFunction } from './module.js'; // 导出功能 export function myFunction() { // ... } - script 标签增加 type=”module” 属性:当在
-
基于原生 ESM 的开发服务优势
- 无需打包项目源代码: 基于原生 ESM 的开发服务不需要将项目中的所有源代码打包成一个或几个文件,相反,每个模块都可以单独加载。这使得启动开发服务器的速度非常快,因为它不需要执行复杂的打包过程。开发人员可以立即开始编写和测试代码,无需长时间的等待。
- 天然的按需加载: ESM 支持的模块导入语法使得按需加载变得更加自然和直观。开发人员可以选择性地导入所需的模块,而不是一次性加载整个应用的代码。这种按需加载可以降低初始加载时间,提高应用的性能。
- 可以利用文件级浏览器缓存: 基于原生 ESM 的开发服务能够充分利用浏览器的缓存机制。由于每个模块都可以单独加载,并且在模块内容未更改的情况下可以从缓存中获取,因此开发过程中的模块加载速度得到了优化。这减少了对服务器的请求次数,提高了开发速度。
-
基于 Esbuild 的编译性能优化
Esbuild — 基于 Golang 开发的前端工具,具备如下能力:
- 打包器 Bundler: Esbuild 可以作为一个高效的打包工具,用于将前端项目中的多个模块打包成一个或多个输出文件。
- 编译器 Transformer 性能极高: Esbuild 在编译方面的性能极高,它可以将源代码从一种语言或格式转换为另一种。在前端开发中,Esbuild 主要用作 JavaScript 的编译器,将高级语法转换为浏览器可执行的 JavaScript。
- 压缩器 Minifier: Esbuild 也具备压缩代码的能力,它可以将 JavaScript、CSS 和其他前端资源进行压缩,以减小文件体积,提高应用的加载速度。
-
Vite 内置的 Web 构建能力
Vite 开箱即用的功能等价于:
- webpack: Vite 的开发服务器和生产构建均基于现代浏览器原生 ES 模块系统,不需要像 webpack 那样复杂的打包配置。
- webpage-dev-server: Vite 内置的开发服务器提供了快速的热模块替换(HMR),无需额外配置。
- css-loader 和 style-loader: Vite 支持在 JavaScript 中直接导入 CSS 文件,无需额外配置,这也是基于 ES 模块的优势。
- less-loader: 和 sass—loader: Vite 内置对 Less 和 Sass 的原生支持,可以在模块中直接导入 Less 和 Sass 文件。
- postcss-loader: Vite 内置了 PostCSS 的支持,您可以通过配置
postcss.config.js来自定义后处理样式。 - file-loader: Vite 能够在开发环境中直接将文件作为资源进行加载,无需使用特定的 loader。
- MiniCssExtractPlugin: Vite 在生产构建时自动将 CSS 提取为独立的文件,无需额外的插件。
- HTMLWebpackPlugin: Vite 会根据您的入口文件自动生成 HTML 文件,无需手动配置。
三、Vite 上手实践
1.项目初始化
# Vite 项目初始化
# 提前安装
pnpm npm i -g pnpm
# 初始化命令
pnpm create vite
# 安装依赖
pnpm install
#启动项目
npm run dev
2.使用 Sass / Scss & CSS Modules
在 Vite 项目中使用 Sass / Scss 和 CSS Modules 的步骤:
-
安装 Sass 依赖: 首先,需要在项目中安装 Sass 的开发依赖。可以使用以下命令来安装:
pnpm install sass -D -
创建样式文件: 在项目的源代码目录中,可以创建一个 Sass 或 Scss 样式文件,比如
styles.scss。 -
编写样式: 在创建的样式文件中,可以编写 Sass / Scss 样式代码。例如:
// styles.scss $primary-color: #007bff; .container { background-color: $primary-color; color: white; } -
使用 CSS Modules: Vite 默认支持 CSS Modules,无需额外配置。只需要在样式文件中使用
.module.scss或.module.css的文件命名模式,以启用 CSS Modules。例如,如果要创建一个启用了 CSS Modules 的样式文件,可以命名为styles.module.scss。 -
在组件中使用样式: 在 Vue 组件或 JavaScript 文件中,可以导入样式并应用到元素上。如果使用了 CSS Modules,可以通过模块对象访问类名。示例:
<template> <div class="container">Hello, Vite!</div> </template> <style lang="scss" module> .container { // 使用模块对象访问类名 background-color: $primary-color; color: white; } </style>
3.使用静态资源
在 Vite 项目中使用静态资源包括常见的图片格式以及其他类型的资源,如 JSON、Worker 和 WASM 资源。Vite 提供了内置的加载支持,使得在项目中使用这些资源变得更加方便。以下是使用不同类型的静态资源的步骤:
-
图片资源: 对于常见的图片格式(如 PNG、JPEG、GIF 等),可以直接在项目中引用它们。例如,在一个 Vue 组件中:
<template> <img src="./assets/image.png" alt="Image"> </template> -
JSON 资源: JSON 文件通常用于存储配置或数据。在 Vite 中,可以使用 ES 模块语法来导入 JSON 文件:
import jsonData from './assets/data.json'; // 使用 jsonData -
Worker 资源: 如果使用 Web Worker,在 Vite 中同样也很容易。可以直接导入 Worker 文件,并使用
new Worker()来创建一个 Worker 实例:import MyWorker from 'worker:./path/to/worker.js'; const worker = new MyWorker(); // 进一步操作Vite 的
worker:前缀用于标识 Worker 资源。 -
WASM 资源: 如果使用 WebAssembly(WASM)模块,Vite 同样支持。可以直接导入 WASM 文件,并通过 ES 模块加载:
import { add } from './path/to/wasm_module.wasm'; // 使用 add 函数Vite 会自动处理 WASM 模块的加载和使用。
4.使用 HMR
Vite 内置了热模块替换(HMR)功能,使得在开发过程中可以实时地查看代码变化的效果,无需额外的配置,自动启动。以下是使用 Vite 内置的 HMR 的步骤:
-
安装 Vite 项目依赖: 首先,确保已经初始化并安装了 Vite 项目的依赖。
-
创建组件和样式: 在 Vite 项目中,可以创建一个 Vue 组件,并附加一些样式。例如,创建一个
HelloWorld.vue组件:<template> <div class="hello"> <h1>{{ greeting }}</h1> </div> </template> <script> export default { data() { return { greeting: 'Hello, Vite!' }; } }; </script> <style> .hello { color: blue; } </style> -
启动开发服务器: 在项目根目录运行以下命令启动开发服务器:
npm run dev -
实时查看效果: 在开发服务器启动后,可以在浏览器中访问应用。然后,可以修改
HelloWorld.vue组件的内容或样式,并保存文件。不需要手动刷新页面,浏览器会自动更新,显示修改后的效果。 -
保存组件局部状态: Vite 的 HMR 不仅可以保持页面的状态,还可以保持组件的局部状态。即在编辑组件时,即使局部状态发生了变化,也可以在保存后保留之前的状态,而不会丢失。
5.生产环境 Tree Shaking
Vite 默认开启了生产环境下的 Tree Shaking,可以轻松优化项目中的代码,删除未使用的代码,以减小构建后的产物体积。
优化原理和操作:
-
基于 ESM 的依赖关系: Vite 利用 ES 模块的导入(
import)和导出(export)语句的静态性质。这些语句的依赖关系在构建时就能确定,与运行时状态无关。这使得 Vite 在构建阶段可以清楚地知道哪些代码是被使用的,哪些是没有使用的。 -
删除未使用的代码: 在构建阶段,Vite 会根据静态分析的结果,将未使用的代码从产物中删除,以减小生成的 JavaScript 文件的体积。通过构建工具自动删除无用的代码,提高应用的性能和加载速度。
-
Vite 中无需配置: 在 Vite 中,默认开启了 Tree Shaking 功能,无需额外的配置。Vite 的工作方式和开发体验都是基于原生 ES 模块的,这使得它更容易在构建时识别出未使用的代码,并对其进行删除。
四、Vite 整体架构
1.关键技术:依赖预打包
-
为什么要进行预打包?
- 避免 node_modules 过多的文件请求: Vite 通过预打包将这些依赖的模块预先打包为一个或多个文件,避免了过多的文件请求,从而减少了加载时间。
- 将 CommonJS 格式转换为 ESM 格式: 在传统的 CommonJS 模块规范中,模块加载方式是同步的,而在现代的前端开发中,更多使用的是 ES 模块(ESM)规范。预打包可以将 CommonJS 格式的模块转换为 ESM 格式,以利用浏览器原生的模块加载能力。
-
实现原理:
- 服务启动前扫描代码中用到的依赖: 在开发服务器启动之前,Vite 会分析项目中的源代码,识别出所有的依赖关系,包括第三方库和自己编写的模块。
- 用 Esbuild 对依赖代码进行预打包: Vite 使用 Esbuild 这个高性能的 JavaScript 构建工具,对依赖的代码进行预打包。Esbuild 可以将代码快速地从 CommonJS 转换为 ESM 格式,同时执行代码的压缩和优化。
- 改写 import 语句,指定依赖为预构建产物路径: 在预打包后,Vite 会对原始的
import语句进行改写,将依赖指向预构建产物的路径。这样在开发过程中,浏览器可以直接加载预构建的模块,而无需实时打包。
2.关键技术:单文件编译
Vite 采用了单文件编译架构。即在开发过程中,每个单独的文件都会被单独地编译和处理,而不是像传统的构建工具一样将所有代码合并在一起再进行处理。Vite 使用 Esbuild 作为默认的编译工具来处理 TypeScript(TS)和 JSX 文件。
-
优势:编译速度提升 10-100x
-
局限性:
- 不支持类型检查。
- 不支持语法降级到 ES5。
3.关键技术:代码压缩
Vite 使用 Esbuild 作为默认压缩工具,替换传统的 Terser、Uglify.js 等压缩工具。
4.关键技术:插件机制
-
开发阶段 - 模拟 Rollup 插件机制: 在开发阶段,Vite 使用了一种类似于 Rollup 的插件机制,用于处理源代码的转换、解析和预处理等操作。这个插件机制在开发过程中可以实现更快的热重载和构建速度。但是,与传统的 Rollup 插件不同,Vite 的插件在处理代码时是基于源码的 ES 模块语法的,而不是在构建时合并成一个捆绑包。
-
生产环境 - 直接使用 Rollup: 在生产环境中,Vite 切换到直接使用 Rollup 作为构建工具。Rollup 是一个优秀的 JavaScript 模块打包工具,专注于 ES 模块的捆绑。Vite 利用 Rollup 的强大能力来生成更小、更高效的生产构建输出。
本篇笔记为个人总结,学习交流使用,欢迎各位大佬评价指正,非常感谢!