如何使用 axios
- 创建实例
import axios from 'axios'
const service = axios.create({
baseURL: '/api',
timeout: 10000
})
- 加请求/响应拦截器:请求拦截器一般加 token,响应拦截器进行统一错误处理、获取数据
// 请求拦截器
service.interceptors.request.use(config => {
const token = localStorage.getItem('token')
if (token) {
config.headers.Authorization = `Bearer ${token}`
}
return config
})
// 响应拦截器
service.interceptors.response.use(
res => {
// 后端一般会有统一格式 { code, data, message }
if (res.data.code !== 0) {
return Promise.reject(res.data.message || 'Error')
}
return res.data.data
},
error => {
if (error.response?.status === 401) {
// token 过期,跳转登录
}
return Promise.reject(error)
}
)
- 导出通用方法
export const get = (url, params) => service.get(url, { params })
export default service
vite 与 webpack 区别
| 比较项 | vite | webpack |
|---|---|---|
| 构建 | 开发时利用 ESM 让浏览器解析 import,请求某个文件时才进行转换并提供源码 | 开发时先解析依赖、打包构建再启动服务器 |
| HMR | 只对这个文件进行替换 | 修改了 bundle 的一个子模块,需要重新构建整个 bundle |
| 配置 | 简单 | 复杂 |
| 生态 | 正在快速发展 | 较成熟 |
| 打包 | 生产环境基于 rollup 打包(不过最新的是 rust 写的 rolldown了),开发时基于 esbuild(go 写的,也要被 rolldown 干掉了) | 有自己的打包流程 |
webpack loader 与 plugin
loader
webpack 只能理解 JavaScript 和 JSON 文件,这是 webpack 开箱可用的自带能力。loader 让 webpack 能够去处理其他类型的文件,并将它们转换为有效模块,以供应用程序使用,以及被添加到依赖图中。
它有两个属性:
test属性,识别出哪些文件会被转换。use属性,定义出在进行转换时,应该使用哪个 loader。多个 loader,则从右到左执行。
当解析到与 test 属性相匹配的路径时,会使用相应的 user 转换,再进行打包。
- loader 可以是同步的,也可以是异步的。
- loader 运行在 Node.js 中,并且能够执行任何操作。
- loader 支持链式调用。链中的每个 loader 会将转换应用在已处理过的资源上。
plugin
插件目的在于解决 loader 无法实现的其他事。
webpack 插件是一个具有 apply 方法的 JavaScript 对象
Tree-shaking
它的核心原理是:
- 静态分析源码的 import/export。
- 找出哪些导出的东西实际没有被用到。
- 在打包时去掉这些未引用的代码。
vite 原理
简介
vite 是一个构建工具,主要由两部分构成:
- 一个开发服务器,它基于 原生 ES 模块 提供了丰富的内建功能,如 预构建、HMR、依赖强缓存、重写导入语句、转译 TS。
- 一套构建指令,它使用 Rollup 打包你的代码,并且它是预配置的,可输出用于生产环境的高度优化过的静态资源。
依赖预购建(开发模式)
首次启动 vite,将使用 ESBuild 进行依赖预购建。这个过程主要干两件事:
- 模块转换:在开发阶段中,Vite 的开发服务器将所有代码视为原生 ES 模块。因此,Vite 必须先将以 CommonJS 或 UMD 形式提供的依赖项转换为 ES 模块
- 合并模块:具有许多内部模块的 ESM 依赖项转换为单个模块。比如 lodash-es 有 600 多个内置模块,处理后只需要发送一个 HTTP 请求。
对于 monorepo 链接的本地包,Vite 不会把它当作依赖去打包,而是把它当作源码来看待。
预购建缓存
Vite 将预构建的依赖项缓存到 node_modules/.vite 中。在以下某项发生更改时,才需要重新运行预构建:
- 包管理器的锁文件内容,例如
package-lock.json,yarn.lock,pnpm-lock.yaml,或者bun.lock; - 补丁文件夹的修改时间;
vite.config.js中的相关字段;NODE_ENV的值。
如果没有找到现有的缓存,Vite 会扫描代码里的 bare import(一般都指向 node_modules 里的依赖),把这些依赖当作入口文件,先用 esbuild 预打包成单文件,避免浏览器直接去解析 node_modules 里成百上千的小模块。
已预构建的依赖请求使用 HTTP 头 max-age=31536000, immutable 进行强缓存,以提高开发期间页面重新加载的性能。一旦被缓存,这些请求将永远不会再次访问开发服务器。不同版本的依赖项会通过附加版本查询自动失效。
HMR
-
创建一个
websocket服务端和client文件,启动服务 -
通过
chokidar监听文件变更 -
当代码变更后,服务端进行判断并推送到客户端
-
客户端根据推送的信息执行不同操作的更新
只用对发生变更的模块重新加载,只需要精确的使相关模块与其临近的 HMR边界连接失效即可(不过通常只有自己)
Webpack 原理
核心概念
| 概念 | 作用 |
|---|---|
| Entry | 打包入口,Webpack 从这里开始分析依赖,一个 chunk 组的入口。可以有多个 |
| Module | 项目中每个 JS/CSS/图片等资源都被当作模块 |
| Loader | 模块转换器,把非 JS 资源转为 JS |
| Plugin | 扩展功能,修改打包流程或增强能力 |
| Chunk | 打包输出的代码块,一个 chunk 可能包含多个模块。有两种,initial(包含为入口起点指定的所有模块及其依赖项) 和 non-initial(动态加载导致的),每个 chunk 都有一个输出文件 |
| Dependency Graph | 模块依赖关系图,Webpack 的核心 |
| Runtime | 模块加载器,保证模块按需执行和缓存。功能:模块注册、加载、缓存、处理异步加载,使打包后的模块能在浏览器里按依赖顺序正确执行 |
流程
初始化:读取 webpack.config.js,根据 entry 确定打包起点
构建模块依赖图:
- 先解析入口文件:用 Loader 处理非 JS 资源
- 递归解析依赖:
import/require/import()等都会触发解析,每个模块会生成一个 module 对象,记录模块内容(转换后的代码)、模块依赖、模块 id - 构建依赖图:最终生成一个 完整的依赖图(Dependency Graph) ,表示所有模块之间的关系
编译:Webpack 将依赖图中每个模块进行 转换和封装,Loader 转换文件(如 Sass → CSS、TS → JS), Plugin 扩展功能(如打包优化、压缩、注入 HTML)
生成:根据依赖图生成最终 bundle,输出最终静态资源到 dist 或指定目录
优化
- Tree-shaking
- 代码分割
- 使用 contenthash 优化缓存
- 压缩:Terser 压缩 JS、CSS 压缩
PostCSS 原理
Tokenizer → parser → processer → stringifier
- tokenizer 负责将 CSS 字符转换为 Token,用来记录语法的某些组成,比如类名属于 word,左括号属于左括号,也可以包含位置信息。
- parser 负责根据 Token 生成抽象语法树。它与 Tokenizer 是流式的关系,出于性能考虑,postCSS 不会存储所有 Token,而是存储当前需要的部分 Token,当 parser 告诉 Tokenizer 它需要新的 token 时,token 的生成才会继续。
- processer 负责初始化插件和执行语法转换。
- stringifier 负责将修改后的 AST 转换为纯 CSS 字符串。
Babel 原理
解析(生成 Token 和 AST)、转换(插件进行工作)、生成(修改后的 AST 转字符串),和 postCSS 差不多。其他概念:
- 插件:是Babel转换功能的最小单位。一个插件通常只负责处理一种或一类语法(如转换箭头函数、解构赋值)。
- 预设:是一组插件的集合,目的是为了方便使用。
- Polyfill:Babel 默认只转换语法(Syntax)(如
let,const, 箭头函数、类),但无法转换新的 API(如Promise,Array.prototype.flat,Object.assign),需要引入 Polyfill 来模拟这些新的API,让它们在旧浏览器中可用。
PostCSS 与 Babel
- Babel 主要专注于 JavaScript 的语法转换和兼容性处理,确保新JS代码能在旧环境中运行。
- PostCSS 主要专注于 CSS 的处理、增强和优化,比如自动加前缀、转换新CSS语法、压缩。