这是我参与「第四届青训营 」笔记创作活动的的第13天。
为什么要使用构建工具
构建工具用于解决模块化、编译高级语法、提高产物质量、提升开发效率等。
- 模块化:
- 提供模块加载方案
- 兼容不同模块规范
- 语法转译:
- 高级语法转译:如Sass、ts等
- 资源加载:如图片、字体等
- 产物质量:产物压缩、无用代码删除、语法降级
- 开发效率:热更新
Vite
概览
- 定位:新一代前端构建工具
- 组成:
- No-bundle开发服务,源文件无需打包
- 生产环境基于Roolup的Bundler
- 核心特征:
- 高性能,dev启动速度和热更新速度快
- 简单易用,开发者体验好
浏览器原生ESM的支持
两大要素:
- script标签添加
type="module"属性- 使用ESM模块导入导出语法
基于原生ESM的开发服务优势
- 无需打包项目源代码
- 天然的按需加载
- 利用文件级别的浏览器缓存
EsBuild具备如下能力
- 打包器
Bundler- 编译器
Transformer- 压缩器
Minifier
使用
项目初始化
# 提前安装pnmp
npm i -g pnpm
# 初始化
pnpm create vite
# 安装依赖
pnpm install
# 启动项目
npm run dev
生产环境Tree Shaking
优化原理:
- 基于ESM的
import/export语句依赖关系,与运行时状态无关- 在构建阶段将未使用到的代码删除
整体架构
预打包
为什么要使用预打包?
- 避免node_modules过多的文件请求
- 将CommonJS格式转为ESM格式
实现的原理
- 服务启动前扫描代码中用到的依赖
- 用Esbuild对依赖代码进行预打包
- 改写
import语句,指定依赖为预构建产物路径改写前:
import React from "react";改写后:
import React from "/node_modules/.vite/react.js"
单文件编译(用Esbuild编译TS/JSX)
- 优势:编译速度提升
- 局限性
- 不支持类型检查
- 不支持语法降级到ES5
代码压缩
进阶
插件开发(抽离核心逻辑、易于拓展)
- 服务启动阶段
graph LR
config --> configResolved --> options --> configureServer --> buildStart
- 请求响应阶段
graph LR
请求响应阶段 --> transformIndexHtml
请求响应阶段 --> resolveId --> load --> transfrom
- 热更新阶段
graph TD
handleHotUpdate
- 服务关闭阶段
graph LR
bulidEnd --> closeBundle
代码分割(拆包)
问题
- 无法进行并发请求
- 缓存复用率降低
Babel
原理图
Babel出现的原因
- JS语法标准繁多,浏览器支持程度不同
- 开发者需要使用高级语法
语法安全降级
graph LR
A[如何在构建产物中避免这类问题] --> B["上层解决方案:@vitejs/plugin-legacy"]
A --> C[底层原理] --> 借助Babel进行语法自动降级
C --> D["提前注入Ployfill实现,如core-js、regenerator-runtime"]
服务端渲染(SSR)
一种常见的渲染模式,用于提升首屏性能和SEO优化
构建阶段
graph LR
项目源码 --> 构建流程 --> 客户端参数 --- 运行在浏览器
构建流程 --> SSR产物 --- a["运行在服务端(Node.js)"]
代码执行阶段
graph LR
加载SSR入口 --> 数据预取 --> 组件渲染 --> HTML拼接