构造模式
Vite 和 Webpack 是两种流行的前端构建工具,它们在构建模式、性能、开发体验等方面有显著差异。以下是它们的详细对比:
1. 构建模式的核心差异
1.1 Webpack
- 基于打包的构建模式:
- Webpack 是一个打包工具,它在开发和生产环境中都会将所有模块(如 JavaScript、CSS、图片等)打包成一个或多个文件。
- 开发环境下,Webpack 会将所有模块打包并启动一个开发服务器。
- 特点:
- 支持多种模块化规范(CommonJS、ES Module 等)。
CommonJS 模块是为 Node.js 打包 JavaScript 代码的原始方式。Node.js 还支持浏览器和其他 JavaScript 运行时使用的 ECMAScript 模块 标准。在 Node.js 中,每个文件都被视为一个单独的模块。
ES模块(ECMAScript Modules)是JavaScript官方的模块系统,它允许开发者将大型程序拆分为可重用的模块。这些模块可以导出和导入类、函数、对象或变量,以便在不同的文件或项目中使用。随着现代浏览器对ES模块的支持,开发者可以更高效地管理和维护代码。- 通过插件和加载器(Loader)支持丰富的功能(如代码分割、热更新、Tree Shaking 等)。
- 配置文件灵活,但可能较为复杂。
1.2 Vite
- 基于原生 ES Module 的构建模式:
- Vite 利用现代浏览器的原生 ES Module 支持,在开发环境下直接按需加载模块,无需打包。
- 生产环境下,Vite 使用 Rollup 进行打包。
Rollup 是一个 JavaScript 模块打包工具,主要用于将小块代码编译成大块复杂的代码(如库或应用程序)。它专注于 ES Module(ESM)的打包,支持 Tree Shaking(摇树优化)和代码分割等特性,适合构建高效、轻量的 JavaScript 库或应用。
以下是 Rollup 的详细介绍:Rollup 的核心特点
1.1 专注于 ES Module
- Rollup 是首批完全支持 ES Module 的打包工具之一。
- 它可以将多个 ES Module 打包成一个或多个文件,同时保留模块的静态结构。
1.2 Tree Shaking
- Rollup 通过静态分析移除未使用的代码(Dead Code),从而减小打包文件的体积。
- 这一特性特别适合构建库或工具包。
1.3 代码分割
- Rollup 支持将代码拆分成多个块(Chunk),实现按需加载。
1.4 轻量高效
- Rollup 生成的打包文件通常比其他工具(如 Webpack)更小,因为它专注于 ES Module 并优化了输出。
1.5 插件系统
- Rollup 提供了丰富的插件生态系统,支持扩展功能(如处理 CSS、TypeScript、Babel 等)。
Rollup 的适用场景
2.1 构建 JavaScript 库
- Rollup 非常适合构建 JavaScript 库(如 React、Vue 等),因为它生成的代码更小、更高效。
2.2 现代浏览器应用
- 如果你的项目主要面向现代浏览器(支持 ES Module),Rollup 是一个很好的选择。
2.3 工具链开发
- Rollup 常用于构建工具链或 CLI 工具,因为它可以生成轻量的、可复用的代码。
- 特点:
- 开发环境下启动速度极快,因为不需要打包。
- 支持热模块替换(HMR),且性能优于 Webpack。
- 配置文件简单,开箱即用。
2. 开发环境对比
2.1 Webpack
- 启动速度:
- 在开发环境下,Webpack 需要先打包所有模块,然后启动开发服务器。对于大型项目,启动时间可能较长。
- 热更新(HMR):
- Webpack 支持热更新,但在大型项目中,热更新速度可能较慢。
- 开发体验:
- 配置复杂,尤其是对于初学者。
- 需要安装和配置大量插件和加载器。
2.2 Vite
- 启动速度:
- Vite 在开发环境下直接按需加载模块,无需打包,因此启动速度极快。
- 热更新(HMR):
- Vite 的热更新性能优于 Webpack,尤其是在大型项目中。
- 开发体验:
- 配置简单,开箱即用。
- 支持 TypeScript、CSS 预处理器等,无需额外配置。
3. 生产环境对比
3.1 Webpack
- 打包性能:
- Webpack 的打包性能较好,支持代码分割、Tree Shaking 等优化。
- 输出文件:
- Webpack 生成的打包文件通常较大,但可以通过配置优化。
- 插件生态:
- Webpack 有丰富的插件生态,支持各种复杂的构建需求。
3.2 Vite
- 打包性能:
- Vite 在生产环境下使用 Rollup 进行打包,性能优于 Webpack。
- 输出文件:
- Vite 生成的打包文件通常较小,且支持 Tree Shaking 和代码分割。
- 插件生态:
- Vite 的插件生态相对较新,但正在快速发展。
4. 适用场景
4.1 Webpack
- 适合场景:
- 大型复杂项目,需要高度定制化的构建流程。
- 需要兼容旧版浏览器(如 IE11)。
- 需要使用 Webpack 特有的插件或功能。
4.2 Vite
- 适合场景:
- 现代浏览器项目,利用原生 ES Module 的优势。
- 中小型项目,追求极快的开发体验。
- 使用 Vue 3、React 等现代框架的项目。
5. 配置文件对比
5.1 Webpack
- Webpack 的配置文件通常较为复杂,需要手动配置入口、输出、加载器、插件等。
- 示例:
javascriptconst path = require('path'); module.exports = { entry: './src/index.js', output: { filename: 'bundle.js', path: path.resolve(__dirname, 'dist'), }, module: { rules: [ { test: /\.js$/, use: 'babel-loader', }, { test: /\.css$/, use: ['style-loader', 'css-loader'], }, ], }, plugins: [ new HtmlWebpackPlugin({ template: './src/index.html', }), ], };
5.2 Vite
- Vite 的配置文件简单,通常只需几行代码即可完成基本配置。
- 示例:
javascript
复制import { defineConfig } from 'vite'; import vue from '@vitejs/plugin-vue'; export default defineConfig({ plugins: [vue()], });
6. 性能对比
| 特性 | Webpack | Vite |
|---|---|---|
| 开发启动速度 | 较慢(需要打包所有模块) | 极快(按需加载模块) |
| 热更新速度 | 较慢(尤其是大型项目) | 极快 |
| 生产打包速度 | 较慢 | 较快(使用 Rollup) |
| 输出文件大小 | 较大(可通过配置优化) | 较小 |
| 配置复杂度 | 复杂 | 简单 |
7. 总结
- Webpack:
- 适合大型复杂项目,功能强大但配置复杂。
- 开发环境下启动速度较慢,但生产环境下打包性能较好。
- Vite:
- 适合现代浏览器项目,开发体验极佳。
- 开发环境下启动速度极快,生产环境下打包性能优于 Webpack。
如果你的项目需要快速启动和开发,且主要面向现代浏览器,Vite 是更好的选择。如果你的项目需要兼容旧版浏览器或需要高度定制化的构建流程,Webpack 可能更适合。
npm客户端
npm、cnpm、tnpm、yarn 和 pnpm 都是 JavaScript 生态中常用的包管理工具,它们的主要功能是管理项目的依赖包。以下是它们的区别和特点:
1. npm
- 全称:Node Package Manager
- 开发者:Node.js 官方团队
- 特点:
- Node.js 的默认包管理工具。
- 拥有最大的包生态系统(npm registry)。
- 支持脚本命令(如
npm run)。 - 支持
package-lock.json文件,用于锁定依赖版本。
- 缺点:
- 安装速度较慢。
- 依赖嵌套结构可能导致
node_modules体积庞大。
- 常用命令:
bash
复制npm install npm install <package> npm run <script>
2. cnpm
- 全称:China npm
- 开发者:阿里巴巴
- 特点:
- npm 的国内镜像,专为中国开发者优化。
- 安装速度快(使用国内服务器)。
- 支持 npm 的所有命令。
- 缺点:
- 依赖镜像服务器,可能存在同步延迟。
- 安装时默认使用软链接,可能导致某些工具(如 Webpack)无法正确解析依赖。
- 常用命令:
bash
复制cnpm install cnpm install <package>
3. tnpm
- 全称:Taobao npm
- 开发者:阿里巴巴
- 特点:
- 专为阿里巴巴内部开发的 npm 客户端。
- 支持私有 npm 仓库。
- 安装速度快,优化了依赖解析和下载。
- 缺点:
- 主要用于阿里巴巴内部,普通开发者使用较少。
- 常用命令:
bash
复制tnpm install tnpm install <package>
4. yarn
- 全称:Yarn Package Manager
- 开发者:Facebook、Google、Tilde 等
- 特点:
- 比 npm 更快的安装速度(并行下载依赖)。
- 支持离线模式(缓存依赖包)。
- 支持
yarn.lock文件,确保依赖版本一致性。 - 支持工作区(Workspaces),适合管理多包项目。
- 缺点:
- 依赖解析算法复杂,可能导致某些场景下的兼容性问题。
- 常用命令:
bash
复制yarn install yarn add <package> yarn run <script>
5. pnpm
- 全称:Performant npm
- 开发者:Zoltan Kochan
- 特点:
- 使用硬链接和符号链接,减少磁盘空间占用。
- 安装速度快,依赖解析效率高。
- 支持
pnpm-lock.yaml文件,确保依赖版本一致性。 - 支持工作区(Workspaces)。
- 缺点:
- 某些工具(如 Webpack)可能不兼容 pnpm 的依赖结构。
- 常用命令:
bash
复制pnpm install pnpm add <package> pnpm run <script>
6. 对比总结
| 特性 | npm | cnpm | tnpm | yarn | pnpm |
|---|---|---|---|---|---|
| 安装速度 | 较慢 | 快(国内镜像) | 快(内部优化) | 快(并行下载) | 快(硬链接优化) |
| 磁盘空间占用 | 高(嵌套依赖) | 高(嵌套依赖) | 高(嵌套依赖) | 高(嵌套依赖) | 低(硬链接共享依赖) |
| 依赖锁定文件 | package-lock.json | package-lock.json | package-lock.json | yarn.lock | pnpm-lock.yaml |
| 工作区支持 | 支持 | 不支持 | 不支持 | 支持 | 支持 |
| 离线模式 | 不支持 | 不支持 | 不支持 | 支持 | 支持 |
| 适用场景 | 通用 | 国内开发者 | 阿里巴巴内部 | 大型项目 | 磁盘空间有限的项目 |
7. 如何选择?
- npm:适合大多数项目,尤其是小型项目或初学者。
- cnpm:适合国内开发者,解决 npm 安装速度慢的问题。
- tnpm:主要用于阿里巴巴内部项目。
- yarn:适合大型项目,尤其是需要工作区支持的项目。
- pnpm:适合磁盘空间有限的项目,或需要高效依赖管理的场景。
根据你的项目需求和环境选择合适的工具即可!
包管理仓库:
npm registry 和 taobao registry 是 JavaScript 生态中两个常用的包管理仓库。它们的主要区别在于服务器位置、同步机制和使用场景。以下是它们的详细对比:
1. npm registry
- 官方地址:https://registry.npmjs.org/
- 开发者:Node.js 官方团队
- 特点:
- 是 npm 的官方包管理仓库,拥有最大的包生态系统。
- 所有 npm 包都会首先发布到 npm registry。
- 支持私有包发布和管理。
- 缺点:
- 服务器位于国外,国内开发者访问速度较慢。
- 在某些地区可能受到网络限制。
2. taobao registry
- 官方地址:https://registry.npmmirror.com/
- 开发者:阿里巴巴
- 特点:
- 是 npm registry 的国内镜像,专为中国开发者优化。
- 服务器位于国内,访问速度快。
- 定期与 npm registry 同步,确保包的最新性。
- 支持 npm 的所有功能。
- 缺点:
- 由于是镜像,可能存在同步延迟(通常几分钟到几小时)。
- 不支持私有包发布(私有包需要切换到 npm registry)。
3. 主要区别
| 特性 | npm registry | taobao registry |
|---|---|---|
| 服务器位置 | 国外 | 国内 |
| 访问速度 | 较慢(国内用户) | 快(国内用户) |
| 同步机制 | 官方源 | 定期与 npm registry 同步 |
| 私有包支持 | 支持 | 不支持 |
| 适用场景 | 全球用户 | 国内用户 |
4. 如何使用 taobao registry
4.1 临时使用
- 在安装包时指定 registry:
bash
复制npm install <package> --registry=https://registry.npmmirror.com
4.2 永久切换
- 通过 npm 配置命令切换 registry:
bash
复制npm config set registry https://registry.npmmirror.com
4.3 恢复默认 registry
- 如果需要恢复默认的 npm registry,可以运行:
bash
复制npm config set registry https://registry.npmjs.org
5. 总结
- npm registry 是官方的包管理仓库,适合全球用户,但国内访问速度较慢。
- taobao registry 是 npm registry 的国内镜像,适合国内用户,访问速度快,但不支持私有包发布。
根据你的网络环境和需求选择合适的 registry 即可!
注:使用 bun 初始化项目会更快,需要 bun >= 0.4.0 版本。
国内建议选 pnpm + taobao 源,速度提升明显。这一步会自动安装依赖,同时安装成功后会自动执行 umi setup 做一些文件预处理等工作。
部署发布
执行 pnpm build 命令,
> umi build
event - compiled successfully in 1179 ms (567 modules)
event - build index.html
产物默认会生成到 ./dist 目录下,
Prettier
如果需要用 prettier 做项目代码的自动格式化,执行 pnpm umi g
使用 Prettier 来自动格式化项目代码有很多优点,尤其是在团队开发和大规模项目中。下面是一些主要的优点:
1. 统一的代码风格
- 消除代码风格争议:Prettier 自动格式化代码,使得所有开发者的代码风格统一,避免了团队内部关于空格、缩进、行长度等细节的争论。
- 可配置性:Prettier 提供了很多配置选项,允许你根据项目的需要调整格式(例如行宽、缩进方式等)。这样可以根据团队的偏好进行统一配置。
2. 提高代码可读性
- 代码格式统一后,不同开发者写的代码会呈现出一致的结构,增强了代码的可读性和可维护性,尤其是在多人协作时,代码的可读性显得尤为重要。
3. 减少手动格式化工作
- 使用 Prettier 后,开发者不再需要花时间手动调整代码格式,例如调整缩进、对齐等。Prettier 会自动完成这些工作,让开发者可以更专注于功能实现和逻辑编写。
4. 自动修复格式问题
- Prettier 会自动格式化所有不符合标准的代码,不仅仅是新写的代码,还包括已有的代码。只要运行 Prettier,它会修复格式问题,保持代码库的一致性。
5. 减少合并冲突
- 在团队合作时,由于格式化规则不统一,可能会出现大量的无意义的合并冲突(例如空格或换行不同)。Prettier 自动格式化的机制能够减少这种冲突,因为它确保所有开发者使用相同的格式规则,减少因格式差异引发的冲突。
6. 提高开发效率
- 团队成员不需要花时间去讨论和审查代码格式问题,Prettier 会自动统一,代码审查可以集中在代码逻辑和功能上,提升开发效率和代码质量。
7. 与编辑器集成
- Prettier 可以与常用的代码编辑器(如 VSCode、WebStorm 等)集成,使得开发者在保存文件时自动格式化代码。通过这种方式,你无需手动运行格式化工具,Prettier 会在每次保存时自动修复格式问题。
8. 支持多种语言
- Prettier 支持多种语言和文件类型(如 JavaScript、TypeScript、HTML、CSS、JSON、Markdown、YAML 等),因此在全栈项目中,它能够保持各个语言之间的格式一致性。
9. 减轻代码审查的负担
- 代码审查时,Prettier 的使用让审查者能够专注于业务逻辑和代码质量,而不是纠结于代码风格问题。减少了代码审查过程中的冗余讨论,提高了审查效率。
10. 可与其他工具协同工作
- Prettier 可以与其他静态分析工具(如 ESLint、TSLint 等)一起使用。比如,Prettier 可以专注于格式化,而 ESLint 可以专注于代码质量检查。两者协同工作能够全面提升代码质量。
目录结构
这里罗列了 Umi 项目中约定(或推荐)的目录结构,在项目开发中,请遵照这个目录结构组织代码。
.
├── config
│ └── config.ts
├── dist
├── mock //mock数据
│ └── app.ts|tsx
├── src
│ ├── .umi //编译后自动生成的文件
│ ├── .umi-production
│ ├── layouts
│ │ ├── BasicLayout.tsx
│ │ ├── index.less
│ ├── models
│ │ ├── global.ts
│ │ └── index.ts
│ ├── pages //业务组件文件夹(页面)
│ │ ├── index.less
│ │ └── index.tsx //业务组件
│ ├── utils // 推荐目录
│ │ └── index.ts
│ ├── services // 推荐目录
│ │ └── api.ts
│ ├── app.(ts|tsx)
│ ├── global.ts
│ ├── global.(css|less|sass|scss)
│ ├── overrides.(css|less|sass|scss)
│ ├── favicon.(ico|gif|png|jpg|jpeg|svg|avif|webp)
│ └── loading.(tsx|jsx)
├── node_modules
│ └── .cache
│ ├── bundler-webpack
│ ├── mfsu
│ └── mfsu-deps
├── .env //环境参数文件
├── plugin.ts
├── .umirc.ts // 与 config/config 文件 2 选一 核心配置文件
├── package.json //项目基本信息,依赖信息
├── tsconfig.json
└── typings.d.ts
根目录
package.json
与 Umi 3 不同,Umi 4 不会自动注册 package.json 中以 @umijs/preset-、@umijs/plugin-、umi-preset- 和 umi-plugin- 开头的插件、预设,若你需要自定义额外的插件、预设,需要手动配置到 plugins 。
.env
环境变量,比如:
PORT=8888
COMPRESS=none
.umirc.ts
与
config/config.ts文件功能相同,2 选 1 。.umirc.ts文件优先级较高
配置文件,包含 Umi 所有非运行时配置(运行时配置一般定义于 app.ts)。
若你需要在不同环境中加载不同配置,这在 Umi 中是根据 UMI_ENV 来实现的,一个不同环境启动的例子:
// package.json
{
"scripts": {
"dev": "umi dev",
"dev:pre": "cross-env UMI_ENV=pre umi dev"
}
}
config/config.ts
与
.umirc.ts文件功能相同,2 选 1 。.umirc.ts文件优先级较高
与 .umirc.ts 相同,区别是你可以单独在一个 config 文件夹下集中管理所有的配置,保持项目根目录整洁。
dist 目录
执行 umi build 后产物的默认输出文件夹。可通过 outputPath 配置修改产物输出文件夹。
mock 目录
存放 mock 文件,此目录下所有 .ts / .js 文件会被 mock 服务加载,从而提供模拟数据,使用方法详见 Mock 。
public 目录
存放固定的静态资源,如存放 public/image.png ,则开发时可以通过 /image.png 访问到,构建后会被拷贝到输出文件夹。
注:
- 对于 svg 资源,Umi 支持 svgr ,可以直接导入作为组件使用:
import SmileUrl, { ReactComponent as SvgSmile } from './smile.svg';
// <SvgSmile />
- 对于图片等资源,Umi 支持直接导入获取资源路径:
import imgUrl from './image.png'
// <img src={imgUrl} />>
src 目录
.umi 目录
🛎️
不要提交 .umi 临时文件到 git 仓库,默认已在 .gitignore 被忽略。
dev 时的临时文件目录,比如入口文件、路由等,都会被临时生成到这里。
.umi-production 目录
🛎️
不要提交 .umi-production 临时文件到 git 仓库,默认已在 .gitignore 被忽略。
build 时的临时文件目录,比如入口文件、路由等,都会被临时生成到这里。
app.ts|tsx
运行时配置 文件,可以在这里扩展运行时的能力,比如修改路由、修改 render 方法等。
运行时配置带来的逻辑会在浏览器中运行,因此当有远程配置、动态内容时,这些我们在本地开发时还不确定,不能写死,所以需要在浏览器实际运行项目时动态获取他们。
layouts/index.tsx
全局布局,默认会在所有路由下生效,比如有以下路由关系:
[
{ path: '/', component: '@/pages/index' },
{ path: '/users', component: '@/pages/users' },
]
输出为:
<Layout>
<Page>index</Page>
<Page>users</Page>
</Layout>
当你需要关闭 layout 时可以使用 layout: false ,当你需要更多层 layout 时,可以考虑使用 wrappers ,仅在配置式路由可用:
routes: [
{ path: '/', component: './index', layout: false },
{
path: '/users',
component: './users',
wrappers: ['@/wrappers/auth']
}
]
pages 目录
约定式路由默认以 pages/* 文件夹的文件层级结构来生成路由表。
在配置式路由中,component 若写为相对路径,将从该文件夹为起点开始寻找文件:
routes: [
// `./index` === `@/pages/index`
{ path: '/', component: './index' }
]
基础路由
假设 pages 目录结构如下:
+ pages/
+ users/
- index.tsx
- index.tsx
那么,会自动生成路由配置如下:
[
{ path: '/', component: '@/pages/index.tsx' },
{ path: '/users/', component: '@/pages/users/index.tsx' },
]
动态路由
约定带 $ 前缀的目录或文件为动态路由。若 $ 后不指定参数名,则代表 * 通配,比如以下目录结构:
+ pages/
+ foo/
- $slug.tsx
+ $bar/
- $.tsx
- index.tsx
会生成路由配置如下:
[
{ path: '/', component: '@/pages/index.tsx' },
{ path: '/foo/:slug', component: '@/pages/foo/$slug.tsx' },
{ path: '/:bar/*', component: '@/pages/$bar/$.tsx' },
]
pages/404.tsx
在使用约定式路由时,该文件会自动被注册为全局 404 的 fallback 页面。若你使用配置式路由,需要自行配置兜底路由到路由表最后一个:
routes: [
// other routes ...
{ path: '/*', component: '@/pages/404.tsx' }
]
global.(j|t)sx?
全局前置脚本文件。
Umi 区别于其他前端框架,没有显式的程序主入口(如 src/index.ts),所以当你有需要在应用前置、全局运行的逻辑时,优先考虑写入 global.ts 。
当你需要添加全局 Context 、修改应用运行时,请使用 app.tsx 。
global.(css|less|sass|scss)
全局样式文件。
当你有需要全局使用的样式时,请考虑加入此文件。
💡
需要注意的是,此文件的优先级在第三方组件库的样式之后,所以当你有覆盖第三方库样式的需求时,请使用 overrides.css 。
overrides.(css|less|sass|scss)
高优先级全局样式文件。
该文件一般专用于覆盖第三方库样式,其中所有 CSS 选择器都会附加 body 前缀以抬高优先级。
loading.(tsx|jsx)
全局加载组件。
Umi 4 默认 按页分包 ,从而在页面切换时存在加载过程,通过该文件来配置加载动画。
plugin.ts
项目级 Umi 插件。
当你有 Umi 定制需求时,往往会用到 插件 API (比如 修改产物 html),此时可创建该文件进行自定义:
import type { IApi } from 'umi';
export default (api: IApi) => { api.onDevCompileDone((opts) => { opts; // console.log('> onDevCompileDone', opts.isFirstCompile); }); api.modifyHTML(($) => { $; }); api.chainWebpack((memo) => { memo; });};
favicon
站点 favicon 图标文件。
当存在 src/favicon.(ico|gif|png|jpg|jpeg|svg|avif|webp) 文件时,将会自动在产物中添加站点 favicon :
<link rel="shortcut icon" href="/favicon.png">
若使用外部资源等,可以使用 favicons 手动配置站点图标,配置值优先于约定。
路由
约定式路由
除配置式路由外,Umi 也支持约定式路由。约定式路由也叫文件路由,就是不需要手写配置,文件系统即路由,通过目录和文件及其命名分析出路由配置。
如果没有 routes 配置,Umi 会进入约定式路由模式,然后分析 src/pages 目录拿到路由配置。
比如以下文件结构:
.
└── pages
├── index.tsx
└── users.tsx
会得到以下路由配置,
[
{ path: '/', component: '@/pages/index' },
{ path: '/users', component: '@/pages/users' },
]
路由动态参数
// 路由配置 /comp/:id// 当前 location /comp/paramId
const params = useParams();// params{ "id": "paramId"}
query 信息
// 当前 location /comp?a=b;const [searchParams, setSearchParams] = useSearchParams();searchParams.get('a') // bsearchParams.toString() // a=b
setSearchParams({a:'c',d:'e'}) // location 变成 /comp?a=c&d=e
searchParams的 api 参考
路由数据加载
Umi 提供了开箱即用的数据预加载方案,能够解决在多层嵌套路由下,页面组件和数据依赖的瀑布流请求。Umi 会自动根据当前路由或准备跳转的路由,并行地发起他们的数据请求,因此当路由组件加载完成后,已经有马上可以使用的数据了。
启用方式
配置开启:
// .umirc.ts
export default { clientLoader: {}}
使用方式
在路由文件中,除了默认导出的页面组件外,再导出一个 clientLoader 函数,并且在该函数内完成路由数据加载的逻辑。
// pages/.../some_page.tsx
import { useClientLoaderData } from 'umi';
export default function SomePage() { const { data } = useClientLoaderData(); return <div>{data}</div>;}
export async function clientLoader() { const data = await fetch('/api/data'); return data;}
如上代码,在 clientLoader 函数返回的数据,可以在组件内调用 useClientLoaderData 获取。
优化效果
考虑一个三层嵌套路由的场景:
- 我们需要先等第一层路由的组件加载完成,然后第一层路由的组件发起数据请求
- 第一层路由的数据请求完成后,开始请求第二层路由的组件,第二层路由的组件加载好以后请求第二层路由需要的数据
- 第二层路由的数据请求完成后,开始请求第三层路由的组件,第三层路由的组件加载好以后请求第三层路由需要的数据
- 第三层路由的数据请求完成后,整个页面才完成渲染
这样的瀑布流请求会严重影响用户的体验,如下图所示:

如果将组件请求数据的程序提取到 clientLoader 中,则 Umi 可以并行地请求这些数据:

插件
使用插件
在普通的 Umi 应用中,默认 不附带任何插件 ,如需使用 Max 的功能(如 数据流、antd 等),需要手动安装插件并开启他们:
pnpm add -D @umijs/plugins
如开启 antd 插件:
// .umirc.ts
export default {
plugins: ['@umijs/plugins/dist/antd'],
antd: {}
}
Umi 与 Max 的区别是 Max 已经内置了大部分插件,如 数据流( initial-state 、 model )、antd 等,这些插件都可以在 @umijs/plugins/dist/* 加载并且开启。