【无标题】

Umi 入门实战:从零创建 Hello World 工程

Umi 入门实战:从零创建 Hello World 工程


目标

创建一个最简单的 Umi 工程,显示 "Hello World",理解每一步的意义。


第一步:创建项目目录

操作

bash 复制代码
# 创建项目目录
mkdir hello-umi

# 进入目录
cd hello-umi

意义

复制代码
hello-umi/          ← 项目根目录
                    ← 目前为空,接下来逐步填充

为什么需要单独的目录?

  • Node.js 项目需要独立的目录来管理依赖和配置
  • 目录名通常作为项目名称
  • 隔离不同项目的依赖,避免冲突

第二步:初始化 npm 项目

操作

bash 复制代码
npm init -y

输出结果

json 复制代码
{
  "name": "hello-umi",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {},
  "keywords": [],
  "author": "",
  "license": "ISC"
}

意义

生成 package.json 文件,这是 Node.js 项目的"身份证":

字段 含义
name 项目名称,发布 npm 包时必须唯一
version 版本号,遵循语义化版本规范
scripts 脚本命令,如 npm run dev
dependencies 运行时依赖
devDependencies 开发时依赖

为什么用 -y

  • 跳过交互式问答,使用默认值
  • 快速初始化,后续可手动修改

第三步:安装 Umi 依赖

操作

bash 复制代码
npm install umi @umijs/preset-umi --save-dev

等待安装完成后,package.json 变化

json 复制代码
{
  "devDependencies": {
    "umi": "^4.0.0",
    "@umijs/preset-umi": "^4.0.0"
  }
}

意义

包名 作用
umi Umi 核心包,提供 CLI 命令和 API
@umijs/preset-umi Umi 预设插件集,包含路由、构建等核心功能

为什么用 --save-dev

  • Umi 是构建工具,只在开发时使用
  • 生产环境只需要构建产物,不需要 Umi 本身
  • 区分 dependencies(运行时)和 devDependencies(开发时)

依赖安装到哪里了?

复制代码
hello-umi/
├── node_modules/        ← 依赖包存放位置
│   ├── umi/
│   ├── @umijs/
│   └── ...(数百个子依赖)
├── package.json
└── package-lock.json    ← 锁定依赖版本

第四步:创建源码目录结构

操作

bash 复制代码
# 创建 src 目录
mkdir src

# 创建 pages 目录
mkdir src/pages

# 创建首页文件

创建 src/pages/index.tsx

tsx 复制代码
// src/pages/index.tsx
export default function HomePage() {
  return (
    <div>
      <h1>Hello World</h1>
      <p>这是我的第一个 Umi 应用</p>
    </div>
  );
}

目录结构

复制代码
hello-umi/
├── node_modules/
├── src/
│   └── pages/
│       └── index.tsx    ← 首页组件
├── package.json
└── package-lock.json

意义

目录/文件 意义
src/ 源码目录,所有业务代码放这里
src/pages/ 页面目录,Umi 约定的路由目录
index.tsx 首页,文件名 index 对应路由 /

约定式路由规则:

复制代码
pages/index.tsx     →  路由 /
pages/users.tsx     →  路由 /users
pages/users/[id].tsx →  路由 /users/:id

第五步:添加 npm 脚本

操作

修改 package.json,添加 scripts

json 复制代码
{
  "name": "hello-umi",
  "version": "1.0.0",
  "scripts": {
    "dev": "umi dev",
    "build": "umi build",
    "preview": "umi preview"
  },
  "devDependencies": {
    "umi": "^4.0.0",
    "@umijs/preset-umi": "^4.0.0"
  }
}

意义

脚本 命令 作用
dev umi dev 启动开发服务器,支持热更新
build umi build 构建生产环境代码
preview umi preview 预览构建后的产物

为什么不直接运行 umi dev

  • 需要 npx umi dev./node_modules/.bin/umi dev
  • npm scripts 会自动将 node_modules/.bin 加入 PATH
  • 更简洁:npm run dev

第六步:启动开发服务器

操作

bash 复制代码
npm run dev

终端输出

复制代码
info  - Umi v4.0.0
info  - Preparing...
info  - Generate files
event - Start generating files
event - Generate files done
info  - Webpack compiling...
event - First compile done
Ready in 1234 ms

  ➜  Local:   http://localhost:8000/
  ➜  Network: http://192.168.1.100:8000/

此时发生了什么?

复制代码
┌─────────────────────────────────────────────────────────────┐
│  1. Umi 读取配置(无配置文件,使用默认值)                       │
│     ↓                                                       │
│  2. 扫描 src/pages/ 目录,生成路由配置                          │
│     发现 pages/index.tsx → 生成路由 { path: '/', component: ... }│
│     ↓                                                       │
│  3. 生成临时文件到 .umi/ 目录                                  │
│     ├── .umi/umi.ts         ← 入口文件                        │
│     ├── .umi/core/route.tsx ← 路由配置                        │
│     └── .umi/core/plugin.ts ← 插件系统                        │
│     ↓                                                       │
│  4. 启动 Webpack Dev Server                                  │
│     ├── 监听文件变化                                          │
│     ├── 编译 TypeScript                                      │
│     └── 提供 HMR(热更新)                                    │
│     ↓                                                       │
│  5. 打开浏览器 http://localhost:8000                          │
└─────────────────────────────────────────────────────────────┘

自动生成的 .umi 目录

复制代码
src/.umi/
├── core/
│   ├── route.tsx        ← 路由配置
│   ├── history.ts       ← 路由历史
│   └── plugin.ts        ← 插件运行时
├── umi.ts               ← 真正的入口文件
└── exports.ts           ← umi API 导出

查看生成的入口文件:

typescript 复制代码
// src/.umi/umi.ts(简化版)
import './core/polyfill';
import { renderClient } from 'umi';
import { routes } from './core/route';

renderClient({
  routes,
  rootElement: document.getElementById('root'),
});

查看生成的路由配置:

typescript 复制代码
// src/.umi/core/route.tsx(简化版)
export const routes = [
  {
    path: '/',
    element: require('@/pages/index').default,
  },
];

第七步:浏览器访问

操作

打开浏览器,访问 http://localhost:8000

页面显示

复制代码
┌─────────────────────────────────┐
│                                 │
│       Hello World               │
│                                 │
│   这是我的第一个 Umi 应用         │
│                                 │
└─────────────────────────────────┘

渲染流程

复制代码
┌─────────────────────────────────────────────────────────────┐
│  1. 浏览器加载 HTML                                           │
│     <div id="root"></div>                                    │
│     ↓                                                       │
│  2. 加载 umi.ts 入口文件                                      │
│     ↓                                                       │
│  3. 执行 renderClient()                                       │
│     ↓                                                       │
│  4. 根据当前 URL 匹配路由                                      │
│     URL: / → 匹配到 pages/index.tsx                           │
│     ↓                                                       │
│  5. 渲染组件到 #root                                          │
│     ReactDOM.render(<HomePage />, document.getElementById('root'))│
└─────────────────────────────────────────────────────────────┘

第八步:修改代码体验热更新

操作

修改 src/pages/index.tsx

tsx 复制代码
// src/pages/index.tsx
export default function HomePage() {
  return (
    <div>
      <h1>Hello Umi!</h1>
      <p>我修改了代码,页面自动更新了!</p>
      <p>当前时间:{new Date().toLocaleString()}</p>
    </div>
  );
}

观察

保存文件后,浏览器自动刷新,显示新内容。

热更新原理

复制代码
┌─────────────────────────────────────────────────────────────┐
│  1. Webpack 监听文件变化                                      │
│     ↓                                                       │
│  2. 检测到 index.tsx 变化                                     │
│     ↓                                                       │
│  3. 重新编译该模块                                            │
│     ↓                                                       │
│  4. 通过 WebSocket 通知浏览器                                  │
│     ↓                                                       │
│  5. 浏览器接收更新,执行 HMR                                   │
│     ↓                                                       │
│  6. 页面局部更新(无需完整刷新)                                │
└─────────────────────────────────────────────────────────────┘

第九步:添加第二个页面

操作

创建 src/pages/about.tsx

tsx 复制代码
// src/pages/about.tsx
export default function AboutPage() {
  return (
    <div>
      <h1>关于我们</h1>
      <p>这是关于页面</p>
    </div>
  );
}

访问

打开 http://localhost:8000/about

发生了什么?

复制代码
┌─────────────────────────────────────────────────────────────┐
│  1. Umi 检测到新文件 pages/about.tsx                          │
│     ↓                                                       │
│  2. 重新生成路由配置                                          │
│     routes = [                                               │
│       { path: '/', element: Index },                         │
│       { path: '/about', element: About },  ← 新增            │
│     ]                                                        │
│     ↓                                                       │
│  3. 浏览器访问 /about                                         │
│     ↓                                                       │
│  4. 路由匹配,渲染 AboutPage 组件                              │
└─────────────────────────────────────────────────────────────┘

无需任何配置,新页面自动生效! 这就是"约定优于配置"。


第十步:添加页面导航

操作

修改 src/pages/index.tsx

tsx 复制代码
// src/pages/index.tsx
import { Link } from 'umi';

export default function HomePage() {
  return (
    <div>
      <h1>Hello Umi!</h1>
      <p>这是首页</p>
      
      {/* 导航链接 */}
      <nav>
        <Link to="/">首页</Link>
        {' | '}
        <Link to="/about">关于</Link>
      </nav>
    </div>
  );
}

意义

tsx 复制代码
import { Link } from 'umi';
  • Link 是 Umi 提供的路由组件
  • 类似 HTML 的 <a> 标签,但不会触发页面刷新
  • 使用路由跳转,体验更流畅
tsx 复制代码
<Link to="/about">关于</Link>
  • 渲染为 <a href="/about">关于</a>
  • 点击时通过 JavaScript 路由跳转
  • 不重新加载页面,只更新组件

第十一步:添加全局样式

操作

创建 src/global.css

css 复制代码
/* src/global.css */
* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

body {
  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
  background: #f5f5f5;
  padding: 20px;
}

nav a {
  color: #3370ff;
  text-decoration: none;
  margin: 0 8px;
}

nav a:hover {
  text-decoration: underline;
}

意义

  • global.css 是 Umi 约定的全局样式文件
  • 自动在入口文件中引入
  • 影响所有页面

查看生成的入口文件:

typescript 复制代码
// src/.umi/umi.ts(简化版)
import '../global.css';  // ← 自动引入
import { renderClient } from 'umi';
// ...

第十二步:添加布局组件

操作

创建 src/layouts/index.tsx

tsx 复制代码
// src/layouts/index.tsx
import { Outlet, Link } from 'umi';

export default function Layout() {
  return (
    <div style={{ maxWidth: 800, margin: '0 auto' }}>
      {/* 顶部导航 */}
      <header style={{ 
        padding: '16px', 
        background: '#fff', 
        marginBottom: '16px',
        borderRadius: '8px'
      }}>
        <nav>
          <Link to="/">首页</Link>
          {' | '}
          <Link to="/about">关于</Link>
        </nav>
      </header>

      {/* 页面内容 */}
      <main style={{ 
        padding: '16px', 
        background: '#fff',
        borderRadius: '8px'
      }}>
        <Outlet />
      </main>

      {/* 底部 */}
      <footer style={{ 
        marginTop: '16px', 
        textAlign: 'center',
        color: '#999'
      }}>
        © 2024 Hello Umi
      </footer>
    </div>
  );
}

意义

复制代码
┌─────────────────────────────────────────────────────────────┐
│  layouts/index.tsx 是全局布局                                  │
│                                                             │
│  ┌─────────────────────────────────────┐                   │
│  │  header(导航)                      │                   │
│  ├─────────────────────────────────────┤                   │
│  │                                     │                   │
│  │  main                               │                   │
│  │  ┌─────────────────────────────┐   │                   │
│  │  │ <Outlet />                  │   │ ← 页面内容渲染这里  │
│  │  │                             │   │                   │
│  │  │ pages/index.tsx 或          │   │                   │
│  │  │ pages/about.tsx             │   │                   │
│  │  └─────────────────────────────┘   │                   │
│  │                                     │                   │
│  ├─────────────────────────────────────┤                   │
│  │  footer                             │                   │
│  └─────────────────────────────────────┘                   │
└─────────────────────────────────────────────────────────────┘

<Outlet /> 是什么?

  • React Router 提供的组件
  • 表示"子路由渲染的位置"
  • 所有页面内容都会显示在这里

第十三步:构建生产版本

操作

bash 复制代码
npm run build

终端输出

复制代码
info  - Umi v4.0.0
info  - Build for production
info  - Generate files
info  - Webpack compiling...
√ Webpack: Compiled successfully in 5.67s

info  - File sizes after gzip:

  12.34 kB  dist/umi.js
  1.23 kB   dist/index.html

event - Build index.html

生成的 dist 目录

复制代码
dist/
├── index.html           ← 入口 HTML
├── umi.[hash].js        ← 主 JS 包
├── umi.[hash].css       ← 主 CSS 包
└── static/              ← 静态资源

构建流程

复制代码
┌─────────────────────────────────────────────────────────────┐
│  1. 清理 dist/ 目录                                          │
│     ↓                                                       │
│  2. 生成 .umi-production/ 临时文件                            │
│     ↓                                                       │
│  3. Webpack 生产模式编译                                      │
│     ├── Tree Shaking(移除未使用代码)                         │
│     ├── 代码压缩(Terser)                                    │
│     ├── CSS 压缩(cssnano)                                  │
│     └── 文件名加 hash(缓存控制)                              │
│     ↓                                                       │
│  4. 生成 index.html                                         │
│     ↓                                                       │
│  5. 输出到 dist/                                            │
└─────────────────────────────────────────────────────────────┘

第十四步:预览生产版本

操作

bash 复制代码
npm run preview

访问

打开 http://localhost:8000

意义

  • 使用生产构建启动服务器
  • 验证构建产物是否正确
  • 模拟生产环境运行

完整项目结构

复制代码
hello-umi/
├── dist/                     ← 构建产物(git 忽略)
│   ├── index.html
│   ├── umi.[hash].js
│   └── umi.[hash].css
│
├── node_modules/             ← 依赖包(git 忽略)
│
├── src/
│   ├── .umi/                 ← 临时文件(自动生成,git 忽略)
│   │   ├── core/
│   │   │   ├── route.tsx
│   │   │   └── plugin.ts
│   │   └── umi.ts
│   │
│   ├── layouts/              ← 布局目录
│   │   └── index.tsx
│   │
│   ├── pages/                ← 页面目录
│   │   ├── index.tsx         ← 首页 /
│   │   └── about.tsx         ← 关于页 /about
│   │
│   └── global.css            ← 全局样式
│
├── package.json              ← 项目配置
├── package-lock.json         ← 依赖锁定
└── .gitignore                ← Git 忽略配置

核心概念总结

约定式路由

文件路径 生成的路由
pages/index.tsx /
pages/about.tsx /about
pages/users/[id].tsx /users/:id
pages/users/index.tsx /users

核心文件

文件 作用
pages/*.tsx 页面组件,自动生成路由
layouts/index.tsx 全局布局,包裹所有页面
global.css 全局样式,自动引入
.umi/umi.ts 入口文件,自动生成

npm scripts

命令 作用
npm run dev 开发模式,热更新
npm run build 生产构建
npm run preview 预览构建产物

下一步学习

  1. 添加配置文件 .umirc.ts - 自定义配置
  2. 添加运行时配置 app.tsx - 请求拦截、路由钩子
  3. 使用插件 - antd、request、model 等
  4. CSS Modules - 组件级样式隔离
  5. 数据流 - useModel 状态管理

文档生成时间:2026-06-04

相关推荐
yuananyun1 小时前
APP 图标规范与设计全攻略:iOS/Android/Web 一次设计多端合规,快速出图
android·前端·ios
李剑一1 小时前
面试问网络?问到我的软肋了。面试官:讲一下HTTP强缓存与协商缓存
前端·面试
小雨下雨的雨1 小时前
近视度数模拟器鸿蒙PC Electron框架技术实现详解
前端·javascript·electron
喜欢踢足球的老罗1 小时前
逆向 WhatsApp Web:前端 SDK 深度剖析与 Chrome 插件实战指南
前端·chrome
roseonly_h2 小时前
如何将钉钉微应用在浏览器打开
前端·钉钉
小雨下雨的雨2 小时前
鸿蒙PC用Electron框架——Canvas蜡笔抖动效果实现技术深度解析
前端·javascript·华为·electron·鸿蒙系统
ZC跨境爬虫2 小时前
跟着 MDN 学CSS day_49:定位实例练习从入门到精通
前端·css·学习
前端小万2 小时前
用AI两小时开发上架的小程序,单日新增用户173
前端·微信小程序
道友可好2 小时前
Spec Kit:GitHub 官方出品,规范即代码
前端·人工智能·后端