├── packages
├── umi
│ ├── src
│ │ ├── test.md
│ │ ├── scripts
│ │ │ ├── dev.md
│ │ │ ├── help.md
│ │ │ ├── test.md
│ │ │ ├── generate.md
│ │ │ ├── realDev.md
│ │ │ └── build.md
│ │ ├── dev.md
│ │ ├── generate.md
│ │ ├── buildDevOpts.md
│ │ ├── build.md
│ │ ├── help.md
│ │ ├── cli.md
│ │ └── generators
│ │ │ └── page.md
│ └── bin
│ │ └── umi.md
└── umi-build-dev
│ └── src
│ └── plugins
│ └── 404
│ └── index.md
├── README.md
└── docs
├── zh
├── guide
│ ├── navigate-between-pages.md
│ ├── load-on-demand.md
│ ├── create-umi-app.md
│ ├── config.md
│ ├── html-template.md
│ ├── examples.md
│ ├── README.md
│ ├── env-variables.md
│ ├── migration.md
│ ├── deploy.md
│ ├── mock-data.md
│ ├── app-structure.md
│ ├── getting-started.md
│ ├── with-dva.md
│ ├── faq.md
│ └── router.md
├── plugin
│ ├── README.md
│ ├── umi-plugin-react.md
│ └── develop.md
├── README.md
├── api
│ └── README.md
└── config
│ └── README.md
├── guide
├── navigate-between-pages.md
├── load-on-demand.md
├── create-umi-app.md
├── config.md
├── html-template.md
├── examples.md
├── README.md
├── env-variables.md
├── migration.md
├── getting-started.md
├── deploy.md
├── mock-data.md
├── app-structure.md
├── with-dva.md
├── faq.md
└── router.md
├── plugin
├── README.md
├── umi-plugin-react.md
└── develop.md
├── README.md
├── api
└── README.md
└── config
└── README.md
/packages/umi/src/test.md:
--------------------------------------------------------------------------------
1 | ```js
2 | export default from 'umi-test';
3 | ```
--------------------------------------------------------------------------------
/packages/umi/src/scripts/dev.md:
--------------------------------------------------------------------------------
1 | ```js
2 | import fork from 'umi-build-dev/lib/fork';
3 |
4 | fork(require.resolve('./realDev.js'));
5 | ```
6 | 从其他文件引入
7 | 此处的fork来自child_process
8 |
--------------------------------------------------------------------------------
/packages/umi/src/scripts/help.md:
--------------------------------------------------------------------------------
1 | ```js
2 | import yParser from 'yargs-parser';
3 | import help from '../help';
4 |
5 | const argv = yParser(process.argv.slice(2));
6 | const [type] = argv._;
7 |
8 | help({
9 | type,
10 | });
11 | ```
12 | 从别的文件中引入help方法
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # 源码共读计划-UMI
2 | 突然发现自己的博客好久没有更新了,不知道写点什么,正好最近在学习UMI框架。
3 | 所以干脆把学习笔记整理出来。
4 | 项目目录是根据UMI项目的目录设置的。
5 | 希望对大家有所帮助。
6 |
7 | ## change log
8 | 请查看[Releases](https://github.com/xiaohuoni/source-code-co-reading-umi/releases)
9 | 你们可以使用Releases Only来关注这个项目,这样就收不到issues中的相关消息了。
10 |
--------------------------------------------------------------------------------
/packages/umi/src/scripts/test.md:
--------------------------------------------------------------------------------
1 | ```js
2 | import test from '../test';
3 |
4 | const args = process.argv.slice(2);
5 |
6 | const watch = args.indexOf('-w') > -1 || args.indexOf('--watch') > -1;
7 | const coverage = args.indexOf('--coverage') > -1;
8 |
9 | test({
10 | watch,
11 | coverage,
12 | });
13 | ```
14 | 从umi-test中引入test模块,然后执行。
--------------------------------------------------------------------------------
/packages/umi/src/dev.md:
--------------------------------------------------------------------------------
1 | ```js
2 | import buildDevOpts from './buildDevOpts';
3 |
4 | process.env.NODE_ENV = 'development';
5 |
6 | export default function(opts = {}) {
7 | return require('umi-build-dev/lib/dev').default(buildDevOpts(opts));
8 | }
9 |
10 | export { fork } from 'umi-build-dev/lib/dev';
11 | ```
12 | 调用umi-build-dev模块的方法
13 |
--------------------------------------------------------------------------------
/packages/umi/src/scripts/generate.md:
--------------------------------------------------------------------------------
1 | ```js
2 | import yParser from 'yargs-parser';
3 | import generate from '../generate';
4 |
5 | const argv = yParser(process.argv.slice(2));
6 | const [type, file] = argv._;
7 |
8 | generate({
9 | type,
10 | file,
11 | useClass: argv.c || argv.class || false,
12 | isDirectory: argv.d || argv.directory || false,
13 | });
14 | ```
15 | 取出参数调用generate
--------------------------------------------------------------------------------
/packages/umi/src/scripts/realDev.md:
--------------------------------------------------------------------------------
1 | ```js
2 | import yParser from 'yargs-parser';
3 | import dev from '../dev';
4 |
5 | const argv = yParser(process.argv.slice(2));
6 |
7 | // 修复 Ctrl+C 时 dev server 没有正常退出的问题
8 | process.on('SIGINT', () => {
9 | process.exit(1);
10 | });
11 |
12 | dev({
13 | plugins: argv.plugins ? argv.plugins.split(',') : [],
14 | });
15 | ```
16 | 从命令行中去除参数,调用dev方法
--------------------------------------------------------------------------------
/docs/zh/guide/navigate-between-pages.md:
--------------------------------------------------------------------------------
1 | # 在页面间跳转
2 |
3 | 在 umi 里,页面之间跳转有两种方式:声明式和命令式。
4 |
5 | ## 声明式
6 |
7 | 基于 `umi/link`,通常作为 React 组件使用。
8 |
9 | ```bash
10 | import Link from 'umi/link';
11 |
12 | export default () => (
13 | Go to list page
14 | );
15 | ```
16 |
17 | ## 命令式
18 |
19 | 基于 `umi/router`,通常在事件处理中被调用。
20 |
21 | ```js
22 | import router from 'umi/router';
23 |
24 | function goToListPage() {
25 | router.push('/list');
26 | }
27 | ```
28 |
29 | 更多命令式的跳转方法,详见 [api#umi/router](/zh/api/#umi-router)。
30 |
--------------------------------------------------------------------------------
/docs/zh/guide/load-on-demand.md:
--------------------------------------------------------------------------------
1 | # 按需加载
2 |
3 | 出于性能的考虑,我们会对模块和组件进行按需加载。
4 |
5 | ## 按需加载组件
6 |
7 | 通过 `umi/dynamic` 接口实现,比如:
8 |
9 | ```js
10 | import dynamic from 'umi/dynamic';
11 |
12 | const delay = (timeout) => new Promise(resolve => setTimeout(resolve, timeout));
13 | const App = dynamic({
14 | loader: async function() {
15 | await delay(/* 1s */1000);
16 | return () =>
I will render after 1s
;
17 | },
18 | });
19 | ```
20 |
21 | ## 按需加载模块
22 |
23 | 通过 `import()` 实现,比如:
24 |
25 | ```js
26 | import('g2').then(() => {
27 | // do something with g2
28 | });
29 | ```
30 |
--------------------------------------------------------------------------------
/packages/umi/src/generate.md:
--------------------------------------------------------------------------------
1 | ```js
2 | import assert from 'assert';
3 | import page from './generators/page';
4 |
5 | const generators = {
6 | page,
7 | };
8 | ```
9 | 这里应该是为了后续扩展使用的,这里暂时只有一个page
10 | ```js
11 | export default function(opts = {}) {
12 | const { type, file } = opts;
13 | assert(type, 'opts.type should be supplied');
14 | assert(typeof type === 'string', 'opts.file should be string');
15 | assert(file, 'opts.file should be supplied');
16 | assert(typeof file === 'string', 'opts.file should be string');
17 | assert(generators[type], `generator of type (${type}) not found`);
18 |
19 | delete opts.type;
20 | generators[type](opts);
21 | }
22 | ```
--------------------------------------------------------------------------------
/docs/guide/navigate-between-pages.md:
--------------------------------------------------------------------------------
1 | # Navigate between pages
2 |
3 | In umi, there are two ways to navigate between pages: declarative and imperative.
4 |
5 | ## Declarative
6 |
7 | Based on `umi/link`, it is usually used as a React component.
8 |
9 | ```bash
10 | import Link from 'umi/link';
11 |
12 | export default () => (
13 | Go to list page
14 | );
15 | ```
16 |
17 | ## Command
18 |
19 | Based on `umi/router`, it is usually called in event processing.
20 |
21 | ```js
22 | import router from 'umi/router';
23 |
24 | function goToListPage() {
25 | router.push('/list');
26 | }
27 | ```
28 |
29 | For more command-style jump methods, see [api#umi/router](/api/#umi-router).
30 |
--------------------------------------------------------------------------------
/docs/guide/load-on-demand.md:
--------------------------------------------------------------------------------
1 | # Load on demand
2 |
3 | For performance reasons, we load modules and components on demand.
4 |
5 | ## Loading Components on Demand
6 |
7 | Implemented through the `umi/dynamic` interface, such as:
8 |
9 | ```js
10 | import dynamic from 'umi/dynamic';
11 |
12 | const delay = (timeout) => new Promise(resolve => setTimeout(resolve, timeout));
13 | const App = dynamic({
14 | loader: async function() {
15 | await delay(/* 1s */1000);
16 | return () => I will render after 1s
;
17 | },
18 | });
19 | ```
20 |
21 | ## Loading Modules on Demand
22 |
23 | Implemented by `import()`, such as:
24 |
25 | ```js
26 | import('g2').then(() => {
27 | // do something with g2
28 | });
29 | ```
30 |
--------------------------------------------------------------------------------
/packages/umi/src/scripts/build.md:
--------------------------------------------------------------------------------
1 | ```js
2 | import chalk from 'chalk';
3 | import yParser from 'yargs-parser';
4 | import build from '../build';
5 | const argv = yParser(process.argv.slice(2));
6 | ```
7 | ```js
8 | //回顾
9 | [require.resolve(`../lib/scripts/${script}`)].concat(args),
10 | ```
11 | yargs-parser取出命令行参数,如
12 | ```base
13 | umi build abc --xiaohu=haha --bcd=123
14 | ```
15 | ```json
16 | argv = { _: [ 'abc' ], xiaohu: 'haha', bcd: 123 }
17 | ```
18 | ```js
19 | build({
20 | plugins: argv.plugins ? argv.plugins.split(',') : [],
21 | }).catch(e => {
22 | console.error(chalk.red(`Build failed: ${e.message}`));
23 | console.log(e);
24 | });
25 | ```
26 | 执行build。
27 | 注,这里取得是argv.plugins的值,但是我执行了很多种情况的命令,都没有plugins这个值。
28 |
--------------------------------------------------------------------------------
/docs/zh/plugin/README.md:
--------------------------------------------------------------------------------
1 | ---
2 | sidebarDepth: 2
3 | ---
4 |
5 | # 插件
6 |
7 | umi 区别于其他前端开发框架和工具的核心就是它的插件机制,基于 umi 的插件机制,你可以获得扩展项目的编译时和运行时的能力。通过插件支持的功能也会变得更强大,我们针对功能的需要可以去使用修改代码打包配置,修改启动代码,约定目录结构,修改 HTML 等更丰富接口。
8 |
9 | ## 插件使用
10 |
11 | 插件可以是一个 npm 包,也可以是路径直接引向一个 JS 的模块。用户通过配置 `plugins` 来使用插件。如下所示:
12 |
13 | ```js
14 | // .umirc.js
15 | export default {
16 | plugins: [
17 | ['umi-plugin-dva', {
18 | immer: true,
19 | }],
20 | ['./src/plugins/customPlugin.js', {
21 | // plugin config
22 | }]
23 | ],
24 | };
25 | ```
26 |
27 | ## 插件列表
28 |
29 | ### 官方插件
30 |
31 | - [umi-plugin-react](/zh/plugin/umi-plugin-react.html)(插件集)
32 | - umi-plugin-dva
33 | - umi-plugin-locale
34 | - umi-plugin-dll
35 | - umi-plugin-routes
36 | - umi-plugin-polyfills
37 |
38 | ### 社区插件
39 |
40 | - [umi-plugin-*](https://www.npmjs.com/search?q=umi-plugin-)
41 |
--------------------------------------------------------------------------------
/docs/zh/guide/create-umi-app.md:
--------------------------------------------------------------------------------
1 | # 通过脚手架创建项目
2 |
3 | umi 通过 [create-umi](https://github.com/umijs/create-umi) 提供脚手架,包含一定的定制化能力。推荐使用 `yarn create` 命令,因为能确保每次使用最新的脚手架。
4 |
5 | 首先,在新目录下使用 `yarn create umi`,
6 |
7 | ```bash
8 | $ mkdir myapp && cd myapp
9 | $ yarn create umi
10 | ```
11 |
12 | 然后,选择你需要的功能,功能介绍详见 [plugin/umi-plugin-react](../plugin/umi-plugin-react.html),
13 |
14 |
15 |
16 | 确定后,会根据你的选择自动创建好目录和文件,
17 |
18 |
19 |
20 | 然后手动安装依赖,
21 |
22 | ```bash
23 | $ yarn
24 | ```
25 |
26 | 最后通过 `yarn start` 启动本地开发,
27 |
28 | ```bash
29 | $ yarn start
30 | ```
31 |
32 | 如果顺利,在浏览器打开 [http://localhost:8000](http://localhost:8000) 可看到以下界面,
33 |
34 |
35 |
--------------------------------------------------------------------------------
/docs/zh/guide/config.md:
--------------------------------------------------------------------------------
1 | # 配置
2 |
3 | ## 配置文件
4 |
5 | umi 允许在 `.umirc.js` 或 `config/config.js` (二选一,`.umirc.js` 优先)中进行配置,支持 ES6 语法。
6 |
7 | > 为简化说明,后续文档里只会出现 `.umirc.js`。
8 |
9 | 比如:
10 |
11 | ```js
12 | export default {
13 | base: '/admin/',
14 | publicPath: 'http://cdn.com/foo',
15 | plugins: [
16 | ['umi-plugin-react', {
17 | dva: true,
18 | }],
19 | ],
20 | };
21 | ```
22 |
23 | 具体配置项详见[配置](/zh/config/)。
24 |
25 | ## .umirc.local.js
26 |
27 | `.umirc.local.js` 是本地的配置文件,**不要提交到 git**,所以通常需要配置到 `.gitignore`。如果存在,会和 `.umirc.js` 合并后再返回。
28 |
29 | ## UMI_ENV
30 |
31 | 可以通过环境变量 `UMI_ENV` 区分不同环境来指定配置。
32 |
33 | 举个例子,
34 |
35 | ```js
36 | // .umirc.js
37 | export default { a: 1, b: 2 };
38 |
39 | // .umirc.cloud.js
40 | export default { b: 'cloud', c: 'cloud' };
41 |
42 | // .umirc.local.js
43 | export default { c: 'local' };
44 | ```
45 |
46 | 不指定 `UMI_ENV` 时,拿到的配置是:
47 |
48 | ```js
49 | {
50 | a: 1,
51 | b: 2,
52 | c: 'local',
53 | }
54 | ```
55 |
56 | 指定 `UMI_ENV=cloud` 时,拿到的配置是:
57 |
58 | ```js
59 | {
60 | a: 1,
61 | b: 'cloud',
62 | c: 'local',
63 | }
64 | ```
65 |
--------------------------------------------------------------------------------
/docs/zh/README.md:
--------------------------------------------------------------------------------
1 | ---
2 | home: true
3 | actionText: 快速上手 →
4 | actionLink: /zh/guide/
5 | features:
6 | - title: 插件化
7 | details: umi 的整个生命周期都是插件化的,甚至其内部实现就是由大量插件组成,比如 pwa、按需加载、一键切换 preact、一键兼容 ie9 等等,都是由插件实现。
8 | - title: 开箱即用
9 | details: 你只需一个 umi 依赖就可启动开发,无需安装 react、preact、webpack、react-router、babel、jest 等等。
10 | - title: 约定式路由
11 | details: 类 next.js 的约定式路由,无需再维护一份冗余的路由配置,支持权限、动态路由、嵌套路由等等。
12 | footer: MIT Licensed | Copyright © 2017-present
13 | ---
14 |
15 | ### 入门非常简单
16 |
17 | ```bash
18 | # 安装
19 | $ yarn global add umi # 或者 npm install -g umi
20 |
21 | # 新建应用
22 | $ mkdir myapp && cd myapp
23 |
24 | # 新建页面
25 | $ umi generate page index
26 |
27 | # 本地开发
28 | $ umi dev
29 |
30 | # 构建上线
31 | $ umi build
32 | ```
33 |
34 | [10 分钟入门 umi 视频版](https://youtu.be/vkAUGUlYm24)
35 |
36 | ### 社区
37 |
38 | #### 钉钉群
39 |
40 |
41 |
42 | #### 微信群
43 |
44 | 群满 100 人,请加 `sorryccpro` 好友备注 `umi` 邀请加入。
45 |
46 | #### Telegram
47 |
48 | [https://t.me/joinchat/G0DdHw-44FO7Izt4K1lLFQ](https://t.me/joinchat/G0DdHw-44FO7Izt4K1lLFQ)
49 |
--------------------------------------------------------------------------------
/packages/umi/bin/umi.md:
--------------------------------------------------------------------------------
1 | ```base
2 | #!/usr/bin/env node
3 | ```
4 | 声明文件执行环境 node
5 | ```js
6 | const resolveCwd = require('resolve-cwd');
7 | ```
8 | resolve-cwd是指从当前工作目录解析像[require.resolve()](https://nodejs.org/api/globals.html#globals_require_resolve)这样的模块的路径.
9 | 这里有个小例子,可以看明白它的功能。
10 | ```js
11 | const resolveCwd = require('resolve-cwd');
12 |
13 | console.log(__dirname);
14 | //=> '/Users/sindresorhus/rainbow'
15 |
16 | console.log(process.cwd());
17 | //=> '/Users/sindresorhus/unicorn'
18 |
19 | resolveCwd('./foo');
20 | //=> '/Users/sindresorhus/unicorn/foo.js'
21 | ```
22 | 下面的就比较没有阅读难度了,用于调试本地的umi
23 | ```js
24 | const localCLI = resolveCwd.silent('umi/bin/umi');
25 | if (localCLI && localCLI !== __filename) {
26 | const debug = require('debug')('umi');
27 | debug('Using local install of umi');
28 | require(localCLI);
29 | } else {
30 | require('../lib/cli');
31 | }
32 | ```
33 | 以下代码是指,开启了debug之后,打印日志。
34 | ```js
35 | const debug = require('debug')('umi');
36 | debug('Using local install of umi');
37 | ```
38 | > 关于引用路径说明:因为umi里面的src目录都会被编译到lib目录,所以在代码中引用的都是类似 **../lib/cli** 这样的路径,但是实际上我们要查看的是 **../src/cli**
--------------------------------------------------------------------------------
/packages/umi/src/buildDevOpts.md:
--------------------------------------------------------------------------------
1 | ```js
2 | import { resolve } from 'path';
3 |
4 | const debug = require('debug')('umi:devDevOpts');
5 | ```
6 | ```js
7 | export default function(opts = {}) {
8 | const { extraResolveModules, hash } = opts;
9 | debug(`opts: ${JSON.stringify(opts)}`);
10 | delete opts.extraResolveModules;
11 |
12 | return {
13 | cwd: process.env.APP_ROOT,
14 | // eslint-disable-line
15 | babel: resolve(__dirname, './babel'),
16 | extraResolveModules: [
17 | ...(extraResolveModules || []),
18 | resolve(__dirname, '../../node_modules'),
19 | ],
20 | libraryAlias: {
21 | dynamic: require.resolve('./dynamic'),
22 | link: require.resolve('./link'),
23 | navlink: require.resolve('./navlink'),
24 | redirect: require.resolve('./redirect'),
25 | router: require.resolve('./router'),
26 | withRouter: require.resolve('./withRouter'),
27 | _renderRoutes: require.resolve('./renderRoutes'),
28 | _createHistory: require.resolve('./createHistory'),
29 | },
30 | hash,
31 | ...opts,
32 | };
33 | }
34 | ```
35 | 当执行umi build时,这里opts={plugins: [],hash: true}
36 | 在这里组装成开发环境中需要的option
37 |
--------------------------------------------------------------------------------
/docs/guide/create-umi-app.md:
--------------------------------------------------------------------------------
1 | # Create a Project With create-umi
2 |
3 | Umi provides scaffolding through [create-umi](https://github.com/umijs/create-umi), which includes some customization capabilities. The `yarn create` command is recommended because it ensures that every time you use the latest scaffolding.
4 |
5 | First, use `yarn create umi` in the new directory.
6 |
7 | ```bash
8 | $ mkdir myapp && cd myapp
9 | $ yarn create umi
10 | ```
11 |
12 | Then, select the function you need, checkout [plugin/umi-plugin-react](../plugin/umi-plugin-react.html) for the detailed description.
13 |
14 |
15 |
16 | Once determined, the directories and files will be automatically created based on your selection.
17 |
18 |
19 |
20 | Then install the dependencies manually,
21 |
22 | ```bash
23 | $ yarn
24 | ```
25 |
26 | Finally, start local development server with `yarn start`.
27 |
28 | ```bash
29 | $ yarn start
30 | ```
31 |
32 | If it goes well, open [http://localhost:8000](http://localhost:8000) in the browser and you will see the following ui.
33 |
34 |
35 |
--------------------------------------------------------------------------------
/docs/plugin/README.md:
--------------------------------------------------------------------------------
1 | ---
2 | sidebarDepth: 2
3 | ---
4 |
5 | # Plugin
6 |
7 | The key of umi that distinguishes it from other front-end development frameworks and tools is its plugin system. Based on the umi plugin system, you can get the compile-time and runtime capabilities of the extension project. The feature supported by the plugin will also become more powerful. For the needs of the feature, we can use the modified code package configuration, modify the bootstrap code, stipulate the directory structure, modify the HTML and other rich interfaces.
8 |
9 | ## Plugin usage
10 |
11 | The plugin can be an npm package or a JS module that located with a path. You can register a plugin by configuring `plugins`. As follows:
12 |
13 | ```js
14 | // .umirc.js
15 | export default {
16 | plugins: [
17 | ['umi-plugin-dva', {
18 | immer: true,
19 | }],
20 | ['./src/plugins/customPlugin.js', {
21 | // plugin config
22 | }]
23 | ],
24 | };
25 | ```
26 |
27 | ## Plugin list
28 |
29 | ### Official plugins
30 |
31 | - [umi-plugin-react](/plugin/umi-plugin-react.html) (Plugin set)
32 | - umi-plugin-dva
33 | - umi-plugin-locale
34 | - umi-plugin-dll
35 | - umi-plugin-routes
36 | - umi-plugin-polyfills
37 |
38 | ### Community plugins
39 |
40 | - [umi-plugin-*](https://www.npmjs.com/search?q=umi-plugin-)
41 |
--------------------------------------------------------------------------------
/docs/zh/guide/html-template.md:
--------------------------------------------------------------------------------
1 | # HTML 模板
2 |
3 | ## 修改默认模板
4 |
5 | 新建 `src/pages/document.ejs`,umi 约定如果这个文件存在,会作为默认模板,内容上需要保证有 `
`,比如:
6 |
7 | ```html
8 |
9 |
10 |
11 |
12 | Your App
13 |
14 |
15 |
16 |
17 |
18 | ```
19 |
20 | ## 配置模板
21 |
22 | 模板里可通过 `context` 来获取到 umi 提供的变量,context 包含:
23 |
24 | * `route`,路由对象,包含 path、component 等
25 | * `config`,用户配置信息
26 | * `publicPath` ,webpack 的 `output.publicPath` 配置
27 | * `env`,环境变量,值为 development 或 production
28 | * 其他在路由上通过 context 扩展的配置信息
29 |
30 | 模板基于 ejs 渲染,可以参考 [https://github.com/mde/ejs](https://github.com/mde/ejs) 查看具体使用。
31 |
32 | 比如输出变量,
33 |
34 | ```html
35 |
36 | ```
37 |
38 | 比如条件判断,
39 |
40 | ```html
41 | <% if(context.env === 'production') { %>
42 | 生产环境
43 | <% } else {%>
44 | 开发环境
45 | <% } %>
46 | ```
47 |
48 | ## 针对特定页面指定模板
49 |
50 | ::: warning
51 | 此功能需开启 `exportStatic` 配置,否则只会输出一个 html 文件。
52 | :::
53 |
54 | ::: tip
55 | 优先级是:路由的 document 属性 > src/pages/document.ejs > umi 内置模板
56 | :::
57 |
58 | 配置路由的 document 属性。
59 |
60 | 比如约定式路由可通过注释扩展 `document` 属性,路径从项目根目录开始找,
61 |
62 | ```js
63 | /**
64 | * document: ./src/documents/404.ejs
65 | */
66 | ```
67 |
68 | 然后这个路由就会以 `./src/documents/404.ejs` 为模板输出 HTML。
69 |
--------------------------------------------------------------------------------
/docs/guide/config.md:
--------------------------------------------------------------------------------
1 | # Configuration
2 |
3 | ## Configuration File
4 |
5 | Umi can be configured in `.umirc.js` or `config/config.js` (choose one, `.umirc.js` has priority), ES6 syntax is supported.
6 |
7 | > To simplify the description, only `.umirc.js` will appear in subsequent documents.
8 |
9 | Such as:
10 |
11 | ```js
12 | export default {
13 | base: '/admin/',
14 | publicPath: 'http://cdn.com/foo',
15 | plugins: [
16 | ['umi-plugin-react', {
17 | dva: true,
18 | }],
19 | ],
20 | };
21 | ```
22 |
23 | For details, see [Configuration](/config/).
24 |
25 | ## .umirc.local.js
26 |
27 | `.umirc.local.js` is a local configuration file, **don't commit to git**, so it usually needs to be configured to `.gitignore`. If it exists, it will be merged with `.umirc.js` and then returned.
28 |
29 | ## UMI_ENV
30 |
31 | The configuration can be specified by the environment variable `UMI_ENV` to distinguish between different environments.
32 |
33 | For a example,
34 |
35 | ```js
36 | // .umirc.js
37 | export default { a: 1, b: 2 };
38 |
39 | // .umirc.cloud.js
40 | export default { b: 'cloud', c: 'cloud' };
41 |
42 | // .umirc.local.js
43 | export default { c: 'local' };
44 | ```
45 |
46 | When `UMI_ENV` is not specified, the configuration is:
47 |
48 | ```js
49 | {
50 | a: 1,
51 | b: 2,
52 | c: 'local',
53 | }
54 | ```
55 |
56 | When `UMI_ENV=cloud` is specified, the configuration is:
57 |
58 | ```js
59 | {
60 | a: 1,
61 | b: 'cloud',
62 | c: 'local',
63 | }
64 | ```
65 |
--------------------------------------------------------------------------------
/docs/README.md:
--------------------------------------------------------------------------------
1 | ---
2 | home: true
3 | actionText: Get Started →
4 | actionLink: /guide/
5 | features:
6 | - title: Pluggable
7 | details: The entire lifecycle of umi is composed of plugins. Features such as pwa, on-demand loading, one-click switching preact, one-button compatibility ie9, etc., are all implemented by plugins.
8 | - title: Out Of Box
9 | details: You only need an umi dependency to start development without having to install react, preact, webpack, react-router, babel, jest, and more.
10 | - title: Conventional Routing
11 | details: Next.js like and full featured routing conventions, support permissions, dynamic routing, nested routing, and more.
12 | footer: MIT Licensed | Copyright © 2017-present
13 | ---
14 |
15 | ### Getting started is very simple
16 |
17 | ```bash
18 | # Install deps
19 | $ yarn global add umi # or npm install -g umi
20 |
21 | # Create application
22 | $ mkdir myapp && cd myapp
23 |
24 | # Create page
25 | $ umi generate page index
26 |
27 | # Start dev server
28 | $ umi dev
29 |
30 | # Build and deploy
31 | $ umi build
32 | ```
33 |
34 | [Getting started with a 10 minutes video](https://youtu.be/vkAUGUlYm24)
35 |
36 | ## Community
37 |
38 | ### Telegram
39 |
40 | [https://t.me/joinchat/G0DdHw-44FO7Izt4K1lLFQ](https://t.me/joinchat/G0DdHw-44FO7Izt4K1lLFQ)
41 |
42 | ### 钉钉群
43 |
44 |
45 |
46 | ### WeChat Group
47 |
48 | Group of 100 people, please add `sorryccpro` friend note `umi` invite to join.
49 |
--------------------------------------------------------------------------------
/packages/umi/src/build.md:
--------------------------------------------------------------------------------
1 | ```js
2 | import buildDevOpts from './buildDevOpts';
3 | ```
4 | 引入buildDevOpts,用于配置开发环境所需要的option。
5 | ```js
6 | process.env.NODE_ENV = 'production';
7 | ```
8 | 设置环境变量
9 | ```js
10 | export default function(opts = {}) {
11 | return require('umi-build-dev/lib/build').default(
12 | buildDevOpts({
13 | ...opts,
14 | hash: true,
15 | }),
16 | );
17 | }
18 | ```
19 | 这里传入的opts={ plugins: [] }
20 | buildDevOpts将会返回如下对象
21 | ```json
22 | {
23 | cwd: undefined,
24 | babel: 'C:\\Users\\admin\\AppData\\Roaming\\npm\\node_modules\\umi\\lib\\babel',
25 | extraResolveModules:
26 | [ 'C:\\Users\\admin\\AppData\\Roaming\\npm\\node_modules\\node_modules' ],
27 | libraryAlias:
28 | { dynamic: 'C:\\Users\\admin\\AppData\\Roaming\\npm\\node_modules\\umi\\lib\\dynamic.js',
29 | link: 'C:\\Users\\admin\\AppData\\Roaming\\npm\\node_modules\\umi\\lib\\link.js',
30 | navlink: 'C:\\Users\\admin\\AppData\\Roaming\\npm\\node_modules\\umi\\lib\\navlink.js',
31 | redirect: 'C:\\Users\\admin\\AppData\\Roaming\\npm\\node_modules\\umi\\lib\\redirect.js',
32 | router: 'C:\\Users\\admin\\AppData\\Roaming\\npm\\node_modules\\umi\\lib\\router.js',
33 | withRouter: 'C:\\Users\\admin\\AppData\\Roaming\\npm\\node_modules\\umi\\lib\\withRouter.js',
34 | _renderRoutes: 'C:\\Users\\admin\\AppData\\Roaming\\npm\\node_modules\\umi\\lib\\renderRoutes.js',
35 | _createHistory: 'C:\\Users\\admin\\AppData\\Roaming\\npm\\node_modules\\umi\\lib\\createHistory.js' },
36 | hash: true,
37 | plugins: [] }
38 | ```
39 |
--------------------------------------------------------------------------------
/docs/zh/guide/examples.md:
--------------------------------------------------------------------------------
1 | # 例子
2 |
3 | ## 成品
4 |
5 | * [Ant Design Pro](https://github.com/ant-design/ant-design-pro),Use Ant Design like a Pro!
6 | * [Antd Admin](https://github.com/zuiidea/antd-admin),A admin dashboard application demo built upon Ant Design and Dva.js.
7 |
8 | ## 官方
9 |
10 | * [with-dva](https://github.com/umijs/umi-examples/tree/master/with-dva),umi + dva 的例子
11 | * [umi-dva-user-dashboard](https://github.com/umijs/umi-dva-user-dashboard),umi + dva 的 dashboard 例子
12 | * [routes](https://github.com/umijs/umi-examples/tree/master/routes),约定式路由的例子
13 | * [routes-via-config](https://github.com/umijs/umi-examples/blob/master/routes-via-config),配置式路由的例子
14 | * [typescript](https://github.com/umijs/umi-examples/blob/master/typescript),使用 TypeScript 的例子
15 | * [umi-example-electron](https://github.com/umijs/umi-example-electron),umi + electron 的例子
16 | * [with-unstated](https://github.com/umijs/umi-examples/tree/master/with-unstated),使用 unstated 的例子
17 | * [with-nav-and-sidebar](https://github.com/umijs/umi-examples/tree/master/with-nav-and-sidebar),包含 antd-pro 的头和侧边栏的例子
18 |
19 | ## 社区
20 |
21 | ::: warning 警告
22 | 以下例子使用 umi@1.x,尚未升级到 umi@2。
23 | :::
24 |
25 | * [umi-antd-pro](https://github.com/xiaohuoni/umi-antd-pro),来自 @xiaohuni 的 umi + antd-pro 的例子,antd-pro 官方版本计划在 2.0 之后切换到 umi,还需等待一些时间
26 | * [dva-umi](https://github.com/xiaohuoni/dva-umi),来自 @xiaohuni 的 umi + dva 的脚手架
27 | * [dva-umi-mobile](https://github.com/xiaohuoni/dva-umi-mobile),来自 @xiaohuni 的 umi + dva 的 mobile 版本脚手架
28 | * [umi-pro](https://github.com/boxcc/umi-pro),来自 @boxcc 的 antd-pro 例子
29 |
30 |
--------------------------------------------------------------------------------
/docs/guide/html-template.md:
--------------------------------------------------------------------------------
1 | # HTML Template
2 |
3 | ::: warning
4 | This article has not been translated yet. Wan't to help us out? Click the `Edit this page on GitHub` at the end of the page.
5 | :::
6 |
7 | ## Modify the default template
8 |
9 | Create a new `src/pages/document.ejs`, umi stipulates that if this file exists, it will be used as the default template. You need to ensure that `
` appears.
10 |
11 | ```html
12 |
13 |
14 |
15 |
16 | Your App
17 |
18 |
19 |
20 |
21 |
22 | ```
23 |
24 | ## Configure the template
25 |
26 | 模板里可通过 `context` 来获取到 umi 提供的变量,context 包含:
27 |
28 | * `route`,路由对象,包含 path、component 等
29 | * `config`,用户配置信息
30 | * `publicPath` ,webpack 的 `output.publicPath` 配置
31 | * `env`,环境变量,值为 development 或 production
32 | * 其他在路由上通过 context 扩展的配置信息
33 |
34 | 模板基于 ejs 渲染,可以参考 [https://github.com/mde/ejs](https://github.com/mde/ejs) 查看具体使用。
35 |
36 | 比如输出变量,
37 |
38 | ```html
39 |
40 | ```
41 |
42 | 比如条件判断,
43 |
44 | ```html
45 | <% if(context.env === 'production') { %>
46 | 生产环境
47 | <% } else {%>
48 | 开发环境
49 | <% } %>
50 | ```
51 |
52 | ## 针对特定页面指定模板
53 |
54 | ::: warning
55 | 此功能需开启 `exportStatic` 配置,否则只会输出一个 html 文件。
56 | :::
57 |
58 | ::: tip
59 | 优先级是:路由的 document 属性 > src/pages/document.ejs > umi 内置模板
60 | :::
61 |
62 | 配置路由的 document 属性。
63 |
64 | 比如约定式路由可通过注释扩展 `document` 属性,路径从项目根目录开始找,
65 |
66 | ```js
67 | /**
68 | * document: ./src/documents/404.ejs
69 | */
70 | ```
71 |
72 | 然后这个路由就会以 `./src/documents/404.ejs` 为模板输出 HTML。
73 |
--------------------------------------------------------------------------------
/packages/umi/src/help.md:
--------------------------------------------------------------------------------
1 | ```js
2 | import chalk from 'chalk';
3 | ```
4 | 把现有的支持的命令都罗列出来,名字,简介,别名
5 | ```js
6 | const commands = {
7 | build: {
8 | name: 'build',
9 | description: 'Create a production build',
10 | },
11 | dev: {
12 | name: 'dev',
13 | description: 'Start a development server',
14 | },
15 | test: {
16 | name: 'test',
17 | description: 'Start a development server',
18 | },
19 | help: {
20 | name: 'help',
21 | description: 'show help',
22 | aliases: ['h'],
23 | },
24 | version: {
25 | name: 'version',
26 | description: 'Outputs Umi version.',
27 | aliases: ['v'],
28 | },
29 | };
30 | ```
31 | 统一调用的打印方法,其实这个应该放别的地方,做util工具使用
32 | ```js
33 | class Logger {
34 | info = message => {
35 | console.log(`${message}`);
36 | };
37 |
38 | error = message => {
39 | console.error(chalk.red(message));
40 | };
41 |
42 | success = message => {
43 | console.error(chalk.green(message));
44 | };
45 | }
46 | ```
47 | 对现有支持的数组做一个遍历,打印出所有的使用方法
48 | ```js
49 | export default function(opts = {}) {
50 | const { type } = opts;
51 | const logger = new Logger();
52 | logger.info(`\nUsage: umi \n`);
53 | if (!commands[type]) {
54 | logger.error(`Unknown script : ${chalk.cyan(type)}.`);
55 | }
56 | logger.info(`Available Commands:`);
57 | for (const key in commands) {
58 | if (commands.hasOwnProperty(key)) {
59 | const cmd = commands[key];
60 | logger.info(` ${chalk.cyan(cmd.name)} ${cmd.description}`);
61 | }
62 | }
63 | // 这里应该是留做后续接口扩展说明的,如使用umi dev --help,应该要打印出dev的说明,还有所支持的环境变量等等。
64 | // Support for subsequent extensions
65 | // logger.info(`\nFor more detailed help run "umi [command name] --help"`);
66 | }
67 | ```
68 | 文中注释可扩展的地方是因为现在umi版本还不是那么稳定,这一块的功能我没想好怎么处理。应该要支持多语言。
--------------------------------------------------------------------------------
/docs/guide/examples.md:
--------------------------------------------------------------------------------
1 | # Examples
2 |
3 | ## Finished Products
4 |
5 | * [Ant Design Pro](https://github.com/ant-design/ant-design-pro), Use Ant Design like a Pro!
6 | * [Antd Admin](https://github.com/zuiidea/antd-admin), An admin dashboard application demo built upon Ant Design and Dva.js.
7 |
8 | ## Official
9 |
10 | * [with-dva](https://github.com/umijs/umi-examples/tree/master/with-dva), Example of umi + dva
11 | * [umi-dva-user-dashboard](https://github.com/umijs/umi-dva-user-dashboard), Example of dashboard with umi + dva
12 | * [routes](https://github.com/umijs/umi-examples/tree/master/routes), Example for convensional routing
13 | * [routes-via-config](https://github.com/umijs/umi-examples/blob/master/routes-via-config), Example for configurable routing
14 | * [typescript](https://github.com/umijs/umi-examples/blob/master/typescript), Example of using TypeScript
15 | * [umi-example-electron](https://github.com/umijs/umi-example-electron), Example of umi + electron
16 | * [with-unstated](https://github.com/umijs/umi-examples/tree/master/with-unstated), Example of using unstated
17 | * [with-nav-and-sidebar](https://github.com/umijs/umi-examples/tree/master/with-nav-and-sidebar), Example containing the header and sidebar of antd-pro
18 |
19 | ## Community
20 |
21 | ::: warning
22 | The following example uses umi@1.x and has not been upgraded to umi@2.
23 | :::
24 |
25 | * [umi-antd-pro](https://github.com/xiaohuoni/umi-antd-pro), an example of umi + antd-pro from @xiaohuni, the official version of antd-pro is scheduled to switch to umi after 2.0 Still have to wait for some time
26 | * [dva-umi](https://github.com/xiaohuoni/dva-umi), umi + dva scaffolding from @xiaohuni
27 | * [dva-umi-mobile](https://github.com/xiaohuoni/dva-umi-mobile), umi + dva mobile version scaffolding from @xiaohuni
28 | * [umi-pro](https://github.com/boxcc/umi-pro), an antd-pro example from @boxcc
29 |
30 |
--------------------------------------------------------------------------------
/docs/zh/guide/README.md:
--------------------------------------------------------------------------------
1 |
2 | # 介绍
3 |
4 | umi,中文可发音为乌米,是一个可插拔的企业级 react 应用框架。umi 以路由为基础的,支持[类 next.js 的约定式路由](https://umijs.org/zh/guide/router.html),以及各种进阶的路由功能,并以此进行功能扩展,比如[支持路由级的按需加载](https://umijs.org/zh/plugin/umi-plugin-react.html#dynamicimport)。然后配以完善的[插件体系](https://umijs.org/zh/plugin/),覆盖从源码到构建产物的每个生命周期,支持各种功能扩展和业务需求,目前内外部加起来已有 50+ 的插件。
5 |
6 | umi 是蚂蚁金服的底层前端框架,已直接或间接地服务了 600+ 应用,包括 java、node、H5 无线、离线(Hybrid)应用、纯前端 assets 应用、CMS 应用等。他已经很好地服务了我们的内部用户,同时希望他也能服务好外部用户。
7 |
8 | ## 特性
9 |
10 | * 📦 **开箱即用**,内置 react、react-router 等
11 | * 🏈 **类 next.js 且[功能完备](./router.html)的路由约定**,同时支持配置的路由方式
12 | * 🎉 **完善的插件体系**,覆盖从源码到构建产物的每个生命周期
13 | * 🚀 **高性能**,通过插件支持 PWA、以路由为单元的 code splitting 等
14 | * 💈 **支持静态页面导出**,适配各种环境,比如中台业务、无线业务、[egg](https://github.com/eggjs/egg)、支付宝钱包、云凤蝶等
15 | * 🚄 **开发启动快**,支持一键开启 [dll](../plugin/umi-plugin-react.html#dll) 和 [hard-source-webpack-plugin](../plugin/umi-plugin-react.html#hardSource) 等
16 | * 🐠 **一键兼容到 IE9**,基于 [umi-plugin-polyfills](../plugin/umi-plugin-react.html#polyfills)
17 | * 🍁 **完善的 TypeScript 支持**,包括 d.ts 定义和 umi test
18 | * 🌴 **与 [dva](https://dvajs.com/) 数据流的深入融合**,支持 duck directory、model 的自动加载、code splitting 等等
19 |
20 | ## 架构
21 |
22 | 下图是 umi 的架构图。
23 |
24 |
25 |
26 | ## 从源码到上线的生命周期管理
27 |
28 | 市面上的框架基本都是从源码到构建产物,很少会考虑到各种发布流程,而 umi 则多走了这一步。
29 |
30 | 下图是 umi 从源码到上线的一个流程。
31 |
32 |
33 |
34 | umi 首先会加载用户的配置和插件,然后基于配置或者目录,生成一份路由配置,再基于此路由配置,把 JS/CSS 源码和 HTML 完整地串联起来。用户配置的参数和插件会影响流程里的每个环节。
35 |
36 | ## 他和 dva、roadhog 是什么关系?
37 |
38 | 简单来说,
39 |
40 | * roadhog 是基于 webpack 的封装工具,目的是简化 webpack 的配置
41 | * umi 可以简单地理解为 roadhog + 路由,思路类似 next.js/nuxt.js,辅以一套插件机制,目的是通过框架的方式简化 React 开发
42 | * dva 目前是纯粹的数据流,和 umi 以及 roadhog 之间并没有相互的依赖关系,可以分开使用也可以一起使用,个人觉得 [umi + dva 是比较搭的](https://github.com/sorrycc/blog/issues/66)
43 |
44 | ## 为什么不是...?
45 |
46 | ### next.js
47 |
48 | next.js 的功能相对比较简单,比如他的路由配置并不支持一些高级的用法,比如布局、嵌套路由、权限路由等等,而这些在企业级的应用中是很常见的。相比 next.js,umi 在约定式路由的功能层面会更像 nuxt.js 一些。
49 |
50 | ### roadhog
51 |
52 | roadhog 是比较纯粹的 webpack 封装工具,作为一个工具,他能做的就比较有限(限于 webpack 层)。而 umi 则等于 roadhog + 路由 + HTML 生成 + 完善的插件机制,所以能在提升开发者效率方面发挥出更大的价值。
53 |
--------------------------------------------------------------------------------
/docs/guide/README.md:
--------------------------------------------------------------------------------
1 | # Introduction
2 |
3 | umi is a routing-based framework that supports [next.js-like conventional routing](https://umijs.org/guide/router.html) and various advanced routing functions, such as [routing-level on-demand loading](https://umijs.org/en/plugin/umi-plugin-react.html#dynamicimport). With a complete [plugin system](https://umijs.org/plugin/) that covers every life cycle from source code to build product, umi is able to support various functional extensions and business needs. Currently umi has almost 50+ plugins in both community and inside company.
4 |
5 | umi is the basic front-end framework of [Ant Financial](https://www.antfin.com/), and has served 600+ applications directly or indirectly, including Java, node, mobile apps, Hybrid apps, pure front-end assets apps, CMS apps, and more. umi has served our internal users very well and we hope that it can also serve external users well.
6 |
7 | ## Features
8 |
9 | * 📦 **Out of box**, with built-in support for react, react-router, etc.
10 | * 🏈 **Next.js like and [full featured](./router.html) routing conventions**, which also supports configured routing
11 | * 🎉 **Complete plugin system**, covering every lifecycle from source code to production
12 | * 🚀 **High performance**, with support for PWA, route-level code splitting, etc. via plugins
13 | * 💈 **Support for static export**, adapt to various environments, such as console app, mobile app, [egg](https://github.com/eggjs/egg), Alipay wallet, etc
14 | * 🚄 **Fast dev startup**, support enable [dll](../plugin/umi-plugin-react.html#dll) and [hard-source-webpack-plugin](../plugin/umi-plugin-react.html#hardSource) with config
15 | * 🐠 **Compatible with IE9**, based on [umi-plugin-polyfills](../plugin/umi-plugin-react.html#polyfills)
16 | * 🍁 **Support TypeScript**, including d.ts definition and `umi test`
17 | * 🌴 **Deep integration with [dva](https://dvajs.com/)**, support duck directory, automatic loading of model, code splitting, etc
18 |
19 | ## Architecture
20 |
21 | The figure below is the architecture of umi.
22 |
23 |
24 |
25 | ## Why not...?
26 |
27 | ### next.js
28 |
29 | The routing of next.js is relatively simple. For example, its routing configuration does not support some advanced usages such as layout, nested routing, permission routing, etc., which are common in enterprise applications. Compared to next.js, umi is more like nuxt.js at the functional level of contracted routing.
30 |
31 |
--------------------------------------------------------------------------------
/docs/zh/guide/env-variables.md:
--------------------------------------------------------------------------------
1 | ---
2 | sidebarDepth: 3
3 | ---
4 |
5 | # .env 和环境变量
6 |
7 | ## 如何配置
8 |
9 | 比如要
10 |
11 | ```
12 | # OS X, Linux
13 | $ PORT=3000 umi dev
14 |
15 | # Windows (cmd.exe)
16 | $ set PORT=3000&&umi dev
17 |
18 | # Or use cross-env for all platforms
19 | $ yarn add cross-env --dev
20 | $ cross-env PORT=3000 umi dev
21 |
22 | # .env
23 | $ echo PORT=3000 > .env
24 | ```
25 |
26 | ## 环境变量
27 |
28 | ### UMI_ENV
29 |
30 | 指定覆盖默认配置的配置文件。比如 `UMI_ENV=prod umi build`,那么则会用 `.umirc.prod.js` 覆盖 `.umirc.js`。或者是 `config/config.prod.js` 覆盖 `config/config.js`。注意是覆盖而不是替换,`.umirc.prod.js` 中没有的配置者会使用 `.umirc.js` 中的配置。
31 |
32 | 另外,开发模式下 `.umirc.local.js` 或者 `config/config.local.js` 中的配置永远是优先级最高的。
33 |
34 | ### PORT
35 |
36 | 指定端口号,默认是 `8000`。比如:
37 |
38 | ```bash
39 | $ PORT=8001 umi dev
40 | ```
41 |
42 | ### HOST
43 |
44 | 默认是 `0.0.0.0`。
45 |
46 | ### APP_ROOT
47 |
48 | ::: warning
49 | APP_ROOT 不能配在 .env 里。
50 | :::
51 |
52 | 指定项目根目录。比如:
53 |
54 | ```bash
55 | $ APP_ROOT=src/renderer umi dev
56 | ```
57 |
58 | ### ANALYZE
59 |
60 | 默认关闭。分析 bundle 构成,build 时有效。比如:
61 |
62 | ```bash
63 | $ ANALYZE=1 umi build
64 | ```
65 |
66 | ### ANALYZE_PORT
67 |
68 | ANALYZE 服务器端口,默认 8888。
69 |
70 | ### BABEL_POLYFILL
71 |
72 | 默认引入 `@babel/polyfill`,值为 none 时不引入。比如:
73 |
74 | ```bash
75 | $ BABEL_POLYFILL=none umi build
76 | ```
77 |
78 | ### COMPRESS
79 |
80 | 默认压缩 CSS 和 JS,值为 none 时不压缩,build 时有效。比如:
81 |
82 | ```bash
83 | $ COMPRESS=none umi build
84 | ```
85 |
86 | ### CSS_COMPRESS
87 |
88 | 默认压缩,值为 none 时不压缩,build 时有效。因为 css 压缩有时是会有问题的,而且压缩并不能减少多少尺寸,所以有时可以压 JS 而不压 CSS。
89 |
90 | ### BROWSER
91 |
92 | 默认自动开浏览器,值为 none 时不自动打开,dev 时有效。比如:
93 |
94 | ```bash
95 | $ BROWSER=none umi dev
96 | ```
97 |
98 | ### CLEAR_CONSOLE
99 |
100 | 默认清屏,值为 none 时不清屏。
101 |
102 | ### HMR
103 |
104 | 默认开启 HMR,值为 none 时禁用,值为 reload 时文件有变化时刷新浏览器。
105 |
106 | ### BABELRC
107 |
108 | 开启 `.babelrc` 解析,默认不解析。
109 |
110 | ### BABEL_CACHE
111 |
112 | 默认开启 babel cache,值为 none 时禁用。比如:
113 |
114 | ```bash
115 | $ BABEL_CACHE=none umi dev
116 | ```
117 |
118 | ### MOCK
119 |
120 | 默认开启 mock,值为 none 时禁用。比如:
121 |
122 | ```bash
123 | $ MOCK=none umi dev
124 | ```
125 |
126 | ### HTML
127 |
128 | 默认打包 HTML 文件,值为 none 时不打包 HTML 文件。比如:
129 |
130 | ```bash
131 | $ HTML=none umi build
132 | ```
133 |
134 | ### WATCH_FILES
135 |
136 | ### RM_TMPDIR
137 |
138 | ### FORK_TS_CHECKER
139 | 默认不开启TypeScript检查,值为1时启用。比如:
140 |
141 | ```bash
142 | $ FORK_TS_CHECKER=1 umi dev
143 | ```
144 |
--------------------------------------------------------------------------------
/packages/umi/src/cli.md:
--------------------------------------------------------------------------------
1 | ```js
2 | import { dirname } from 'path';
3 | import yParser from 'yargs-parser';
4 | import signale from 'signale';
5 | import semver from 'semver';
6 | import buildDevOpts from './buildDevOpts';
7 | ```
8 | ```js
9 | let script = process.argv[2];
10 | const args = yParser(process.argv.slice(3));
11 | ```
12 | process模块用来与当前进程互动,可以通过全局变量process访问,不必使用require命令加载。它是一个EventEmitter对象的实例。
13 |
14 | process对象提供一系列属性,用于返回系统信息。
15 | - process.pid:当前进程的进程号。
16 | - process.version:Node的版本,比如v0.10.18。
17 | - process.platform:当前系统平台,比如Linux。
18 | - process.title:默认值为“node”,可以自定义该值。
19 | - process.argv:当前进程的命令行参数数组。
20 | - process.env:指向当前shell的环境变量,比如process.env.HOME。
21 | - process.execPath:运行当前进程的可执行文件的绝对路径。
22 | - process.stdout:指向标准输出。
23 | - process.stdin:指向标准输入。
24 | - process.stderr:指向标准错误。
25 |
26 | yParser 用于取出执行命令时携带的参数。
27 | 比如执行 umi dev haha xixi --me=xiaohuoni
28 | ```base
29 | // process.argv
30 | [
31 | 'C:\\Program Files\\nodejs\\node.exe',
32 | 'C:\\Users\\Administrator\\AppData\\Roaming\\npm\\node_modules\\umi\\bin\\umi.js',
33 | 'dev',
34 | 'haha',
35 | 'xixi'
36 | ]
37 | ```
38 | 那么此时
39 |
40 | script = dev
41 |
42 | args = { _: [], haha: true, xixi: true, me:'xiaohuoni' }
43 |
44 | ```js
45 | // Node version check
46 | const nodeVersion = process.versions.node;
47 | if (semver.satisfies(nodeVersion, '<6.5')) {
48 | signale.error(`Node version must >= 6.5, but got ${nodeVersion}`);
49 | process.exit(1);
50 | }
51 | ```
52 | 判断当前node的版本大于v6.5
53 | - process.exit(0)表示成功完成,回调函数中,err将为null;
54 | - process.exit(非0)表示执行失败,回调函数中,err不为null,err.code就是我们传给exit的数字。
55 | ```js
56 | // Notify update when process exits
57 | const updater = require('update-notifier');
58 | const pkg = require('../package.json');
59 | updater({ pkg }).notify({ defer: true });
60 | ```
61 | 进程退出时通知更新,其中defer:true,表示在进程退出后显示通知。
62 | ```js
63 | process.env.UMI_DIR = dirname(require.resolve('../package'));
64 | process.env.UMI_VERSION = pkg.version;
65 | ```
66 | 定义了两个环境变量,用于后续功能使用吧。
67 | ```js
68 | const aliasMap = {
69 | '-v': 'version',
70 | '--version': 'version',
71 | '-h': 'help',
72 | '--help': 'help',
73 | };
74 | ```
75 | 给命令取别名,比如这里给version取了个别名叫做-v
76 | 当执行umi -v 时,相当于执行umi version
77 | ```js
78 | switch (script) {
79 | case 'build':
80 | case 'dev':
81 | case 'test':
82 | case 'inspect':
83 | require(`./scripts/${script}`);
84 | break;
85 | default: {
86 | const Service = require('umi-build-dev/lib/Service').default;
87 | new Service(buildDevOpts(args)).run(aliasMap[script] || script, args);
88 | break;
89 | }
90 | }
91 | ```
92 |
93 | defaule中使用service启动命令,是为了执行那些使用```api.registerCommand```注册的命令行,比如内置的umi help就是这么执行的。
94 |
--------------------------------------------------------------------------------
/packages/umi-build-dev/src/plugins/404/index.md:
--------------------------------------------------------------------------------
1 | ```js
2 | import { join, basename, extname } from 'path';
3 | ```
4 | # join
5 | 对于以/开始的路径片段,path.join只是简单的将该路径片段进行拼接
6 | ```js
7 | path.join('/a','/b') // 'a/b'
8 | ```
9 | # basename
10 | 提取出用 '/' 隔开的path的最后一部分
11 | ```js
12 | path.basename('/a/b/c/d/e.html') // 'e.html'
13 | ```
14 | # extname
15 | 返回path路径文件扩展名,如果path以 ‘.' 为结尾,将返回 ‘.',如果无扩展名 又 不以'.'结尾,将返回空值
16 | ```js
17 | path.extname('/a/b/c/d/e.html') // '.html'
18 | path.extname('/a/b/c/d/e.') // '.'
19 | path.extname('/a/b/c/d/e') // ''
20 | ```
21 | ```import { readFileSync } from 'fs';```
22 | readFileSync 同步读取
23 | ```js
24 | /**
25 | **
26 | **/
27 | export function patchRoutes(routes) {
28 | let index = null;
29 | for (const [i, value] of routes.entries()) {
30 | const { component } = value;
31 | if (basename(component, extname(component)) === '404') {
32 | index = i;
33 | }
34 | if (value.routes) {
35 | value.routes = patchRoutes(value.routes);
36 | }
37 | }
38 | if (index !== null) {
39 | const route = routes.splice(index, 1)[0];
40 | routes = routes.concat({
41 | component: route.component,
42 | });
43 | }
44 | return routes;
45 | }
46 | ```
47 | export default function(api) {
48 | const { paths, config } = api.service;
49 |
50 | if (process.env.NODE_ENV === 'production' && !config.exportStatic) {
51 | api.register('modifyRoutes', ({ memo }) => {
52 | return patchRoutes(memo);
53 | });
54 | }
55 |
56 | api.register('beforeServer', ({ args: { devServer } }) => {
57 | function UMI_PLUGIN_404(req, res, next) {
58 | if (req.accepts('html')) {
59 | let pageContent = readFileSync(
60 | join(__dirname, '../../../template/404.html'),
61 | 'utf-8',
62 | );
63 | const routes = [...api.service.routes];
64 | const rootRoute = routes.filter(route => route.path === '/')[0];
65 | if (rootRoute) {
66 | routes.unshift({
67 | ...rootRoute,
68 | path: '/index.html',
69 | });
70 | }
71 | pageContent = pageContent
72 | .replace('<%= PAGES_PATH %>', paths.pagesPath)
73 | .replace(
74 | '<%= PAGES_LIST %>',
75 | routes
76 | .map(route => {
77 | return `${route.path} `;
78 | })
79 | .join('\r\n'),
80 | );
81 | res.writeHead(404, { 'Content-Type': 'text/html' });
82 | res.write(pageContent);
83 | res.end();
84 | } else {
85 | next();
86 | }
87 | }
88 | devServer.use(UMI_PLUGIN_404);
89 | });
90 | }
91 |
--------------------------------------------------------------------------------
/docs/zh/guide/migration.md:
--------------------------------------------------------------------------------
1 | # 从 umi 1.x 迁移
2 |
3 | > 更喜欢观看视频?可以[点此观看](https://youtu.be/1mvKzFLLBck)。
4 |
5 | 下面以 [antd-admin](https://github.com/zuiidea/antd-admin/pull/877) 为例,介绍如何从 umi@1 升级到 umi@2 。
6 |
7 | ## npm 依赖
8 |
9 | 升级 umi 到 `^2.0.0-0`,并使用 umi-plugin-react 代替以前的众多插件,包含 umi-plugin-dva、umi-plugin-dll、umi-plugin-routes、umi-plugin-polyfill 和 umi-plugin-locale。
10 |
11 | ```diff
12 | - "umi": "^1.3.17",
13 | + "umi": "^2.0.0-beta.16",
14 |
15 | - "umi-plugin-dll": "^0.2.1",
16 | - "umi-plugin-dva": "^0.9.1",
17 | - "umi-plugin-routes": "^0.1.5"
18 | + "umi-plugin-react": "^1.0.0-beta.16",
19 | ```
20 |
21 | umi-plugin-react 是一个包含了十多个插件的集合,详见 [umi-plugin-react 介绍](/zh/plugin/umi-plugin-react.html)。
22 |
23 | ## 环境变量
24 |
25 | umi@2 支持在 `.env` 里配置环境变量,所以之前写在 package.json scripts 里的环境变量可以切到这里。
26 |
27 | ```diff
28 | - "start": "cross-env COMPILE_ON_DEMAND=none BROWSER=none HOST=0.0.0.0 umi dev",
29 | + "start": "cross-env BROWSER=none HOST=0.0.0.0 umi dev",
30 | ```
31 |
32 | 然后新建 `.env`,(其中 `COMPILE_ON_DEMAND` 已不再支持)
33 |
34 | ```
35 | BROWSER=none
36 | HOST=0.0.0.0
37 | ```
38 |
39 | 另外,有些环境变量有变化或不再支持:
40 |
41 | * 不再支持 `PUBLIC_PATH`,通过配置 `publicPath` 实现
42 | * 不再支持 `BASE_URL`,通过配置 `base` 实现
43 | * 不再支持 `COMPILE_ON_DEMAND`,umi@2 里没有这个功能了
44 | * 不再支持 `TSLINT`,umi@2 里没有这个功能了
45 | * 不再支持 `ESLINT`,umi@2 里没有这个功能了
46 |
47 | ## 配置
48 |
49 | ### 插件配置
50 |
51 | 由于前面我们把很多插件改成通过 umi-plugin-react 实现,所以需要修改 `.umirc.js`,
52 |
53 | ```diff
54 | export default {
55 | plugins: [
56 | - 'umi-plugin-dva',
57 | + ['umi-plugin-react', {
58 | + dva: true,
59 | + antd: true, // antd 默认不开启,如有使用需自行配置
60 | + }],
61 | ],
62 | };
63 | ```
64 |
65 | 更多 dll、hardSource、polyfilles、locale、title 等,参考 [umi-plugin-react 文档](/zh/plugin/umi-plugin-react.html)。
66 |
67 | ### webpackrc.js
68 |
69 | umi@2 不再支持 `webpackrc.js`,把里面的配置原样复制到 `.umirc.js` 即可。
70 |
71 | ### webpack.config.js
72 |
73 | umi@2 不再支持 `webpack.config.js`,改为通过配置 [chainWebpack](/zh/config/#chainwebpack) 实现。
74 |
75 | ### 详细的配置项变更
76 |
77 | * 不再支持 `hd`,如需开启,装载插件 `umi-plugin-react` 并配置 `hd: {}`
78 | * 不再支持 `disableServiceWorker`,默认不开启,如需开启,装载插件 `umi-plugin-react` 并配置 `pwa: {}`
79 | * 不再支持 `preact`,如需配置,装载插件 `umi-plugin-react` 并配置 `library: 'preact'`
80 | * 不再支持 `loading`,如需配置,装载插件 `umi-plugin-react` 并配置 `dynamicImport.loadingComponent`
81 | * `hashHistory: true` 变更为 `history: 'hash'`
82 | * 不再支持 `disableDynamicImport`,默认不开启,如需开启,装载插件 `umi-plugin-react` 并配置 `dynamicImport: {}`
83 | * 不再支持 `disableFastClick`,默认不开启,如需开启,装载插件 `umi-plugin-react` 并配置 `fastClick: {}`
84 | * 不再支持 `pages`,改为直接配在路由上
85 | * 不再支持 `disableHash`,默认不开启,如需开启,配置 `hash: true`
86 |
87 | ## 约定式路由
88 |
89 | 路由层不再支持 `page.js` 的目录级路由。之前如果有用,需要把不需要的路由通过 umi-plugin-react 的 routes.exclude 排除掉。
90 |
91 | ## umi/dynamic
92 |
93 | 接口变更,umi@2 是基于 [react-loadable](https://github.com/jamiebuilds/react-loadable) 实现的。
94 |
95 | ```diff
96 | - dynamic(async () => {})
97 | + dynamic({ loader: async () => {}})
98 | ```
99 |
100 | 详见 [umi/dynamic 接口说明](/zh/api/#umi-dynamic)。
101 |
--------------------------------------------------------------------------------
/docs/zh/guide/deploy.md:
--------------------------------------------------------------------------------
1 | # 部署
2 |
3 | ## 默认方案
4 |
5 | umi@2 默认对新手友好,所以默认不做按需加载处理,`umi build` 后输出 `index.html`、`umi.js` 和 `umi.css` 三个文件。
6 |
7 | ## 不输出 html 文件
8 |
9 | 某些场景 html 文件交给后端输出,前端构建并不需要输出 html 文件,可配置环境变量 `HTML=none` 实现。
10 |
11 | ```bash
12 | $ HTML=none umi build
13 | ```
14 |
15 | ## 部署 html 到非根目录
16 |
17 | 经常有同学问这个问题:
18 |
19 | > 为什么我本地开发是好的,部署后就没反应了,而且没有报错?
20 |
21 | **没有报错!** 这是应用部署在非根路径的典型现象。为啥会有这个问题?因为路由没有匹配上,比如你把应用部署在 `/xxx/` 下,然后访问 `/xxx/hello`,而代码里匹配的是 `/hello`,那就匹配不上了,而又没有定义 fallback 的路由,比如 404,那就会显示空白页。
22 |
23 | 怎么解决?
24 |
25 | 可通过配置 [base](/zh/config/#base) 解决。
26 |
27 | ```bash
28 | export default {
29 | base: '/path/to/your/app/root',
30 | };
31 | ```
32 |
33 | ## 使用 hashHistory
34 |
35 | 可通过配置 [history](/zh/config/#history) 为 `hash` 为解决。
36 |
37 | ```bash
38 | export default {
39 | history: 'hash',
40 | };
41 | ```
42 |
43 | ## 按需加载
44 |
45 | 要实现按需加载,需装载 umi-plugin-react 插件并配置 [dynamicImport](/zh/plugin/umi-plugin-react.html#dynamicimport)。
46 |
47 | ```js
48 | export default {
49 | plugins: [
50 | ['umi-plugin-react', {
51 | dynamicImport: true,
52 | }],
53 | ],
54 | };
55 | ```
56 |
57 | 参数详见:[umi-plugin-react#dynamicImport](/zh/plugin/umi-plugin-react.html#dynamicimport)。
58 |
59 | ## 静态资源在非根目录或 cdn
60 |
61 | 这时,就需要配置 [publicPath](/zh/config/#publicPath)。至于 publicPath 是啥?具体看 [webpack 文档](https://webpack.js.org/configuration/output/#output-publicpath),把他指向静态资源(js、css、图片、字体等)所在的路径。
62 |
63 | ```js
64 | export default {
65 | publicPath: "http://yourcdn/path/to/static/"
66 | }
67 | ```
68 |
69 | ## 使用 runtime 的 publicPath
70 |
71 | 对于需要在 html 里管理 publicPath 的场景,比如在 html 里判断环境做不同的输出,可通过配置 [runtimePublicPath](/zh/config/#history) 为解决。
72 |
73 | ```bash
74 | export default {
75 | runtimePublicPath: true,
76 | };
77 | ```
78 |
79 | 然后在 html 里输出:
80 |
81 | ```html
82 |
85 | ```
86 |
87 | ## 静态化
88 |
89 | 在一些场景中,无法做服务端的 html fallback,即让每个路由都输出 index.html 的内容,那么就要做静态化。
90 |
91 | 比如上面的例子,我们在 .umirc.js 里配置:
92 |
93 | ```js
94 | export default {
95 | exportStatic: {},
96 | }
97 | ```
98 |
99 | 然后执行 umi build,会为每个路由输出一个 html 文件。
100 |
101 | ```
102 | ./dist
103 | ├── index.html
104 | ├── list
105 | │ └── index.html
106 | └── static
107 | ├── pages__index.5c0f5f51.async.js
108 | ├── pages__list.f940b099.async.js
109 | ├── umi.2eaebd79.js
110 | └── umi.f4cb51da.css
111 | ```
112 |
113 | > 注意:静态化暂不支持有变量路由的场景。
114 |
115 | ## HTML 后缀
116 |
117 | 有些静态化的场景里,是不会自动读索引文件的,比如支付宝的容器环境,那么就不能生成这种 html 文件,
118 |
119 | ```
120 | ├── index.html
121 | ├── list
122 | │ └── index.html
123 | ```
124 |
125 | 而是生成,
126 |
127 | ```
128 | ├── index.html
129 | └── list.html
130 | ```
131 |
132 | 配置方式是在 .umirc.js 里,
133 |
134 | ```js
135 | export default {
136 | exportStatic: {
137 | htmlSuffix: true,
138 | },
139 | }
140 | ```
141 |
142 | umi build 会生成,
143 |
144 | ```
145 | ./dist
146 | ├── index.html
147 | ├── list.html
148 | └── static
149 | ├── pages__index.5c0f5f51.async.js
150 | ├── pages__list.f940b099.async.js
151 | ├── umi.2924fdb7.js
152 | └── umi.cfe3ffab.css
153 | ```
154 |
155 | ## 静态化后输出到任意路径
156 |
157 | ```js
158 | export default {
159 | exportStatic: {
160 | htmlSuffix: true,
161 | dynamicRoot: true,
162 | },
163 | }
164 | ```
165 |
--------------------------------------------------------------------------------
/docs/zh/guide/mock-data.md:
--------------------------------------------------------------------------------
1 | # Mock 数据
2 |
3 | Mock 数据是前端开发过程中必不可少的一环,是分离前后端开发的关键链路。通过预先跟服务器端约定好的接口,模拟请求数据甚至逻辑,能够让前端开发独立自主,不会被服务端的开发所阻塞。
4 |
5 | ## 使用 umi 的 mock 功能
6 |
7 | umi 里约定 mock 文件夹下的文件即 mock 文件,文件导出接口定义,支持基于 `require` 动态分析的实时刷新,支持 ES6 语法,以及友好的出错提示,详情参看 [mock-data](https://umijs.org/zh/guide/mock-data.html)。
8 |
9 | ```js
10 | export default {
11 | // 支持值为 Object 和 Array
12 | 'GET /api/users': { users: [1, 2] },
13 |
14 | // GET POST 可省略
15 | '/api/users/1': { id: 1 },
16 |
17 | // 支持自定义函数,API 参考 express@4
18 | 'POST /api/users/create': (req, res) => { res.end('OK'); },
19 | };
20 | ```
21 |
22 | 当客户端(浏览器)发送请求,如:`GET /api/users`,那么本地启动的 `umi dev` 会跟此配置文件匹配请求路径以及方法,如果匹配到了,就会将请求通过配置处理,就可以像样例一样,你可以直接返回数据,也可以通过函数处理以及重定向到另一个服务器。
23 |
24 | 比如定义如下映射规则:
25 |
26 | ```
27 | 'GET /api/currentUser': {
28 | name: 'momo.zxy',
29 | avatar: imgMap.user,
30 | userid: '00000001',
31 | notifyCount: 12,
32 | },
33 | ```
34 |
35 | 访问的本地 `/api/users` 接口:
36 |
37 | 请求头
38 |
39 |
40 |
41 | 返回的数据
42 |
43 |
44 |
45 | ### 引入 Mock.js
46 |
47 | [Mock.js](http://mockjs.com/) 是常用的辅助生成模拟数据的第三方库,当然你可以用你喜欢的任意库来结合 roadhog 构建数据模拟功能。
48 |
49 | ```js
50 | import mockjs from 'mockjs';
51 |
52 | export default {
53 | // 使用 mockjs 等三方库
54 | 'GET /api/tags': mockjs.mock({
55 | 'list|100': [{ name: '@city', 'value|1-100': 50, 'type|0-2': 1 }],
56 | }),
57 | };
58 | ```
59 |
60 | ### 添加跨域请求头
61 |
62 | 设置 `response` 的请求头即可:
63 |
64 | ```
65 | 'POST /api/users/create': (req, res) => {
66 | ...
67 | res.setHeader('Access-Control-Allow-Origin', '*');
68 | ...
69 | },
70 | ```
71 |
72 | ## 合理的拆分你的 mock 文件
73 |
74 | 对于整个系统来说,请求接口是复杂并且繁多的,为了处理大量模拟请求的场景,我们通常把每一个数据模型抽象成一个文件,统一放在 `mock` 的文件夹中,然后他们会自动被引入。
75 |
76 |
77 |
78 | ## 如何模拟延迟
79 |
80 | 为了更加真实的模拟网络数据请求,往往需要模拟网络延迟时间。
81 |
82 | ### 手动添加 setTimeout 模拟延迟
83 |
84 | 你可以在重写请求的代理方法,在其中添加模拟延迟的处理,如:
85 |
86 | ```js
87 | 'POST /api/forms': (req, res) => {
88 | setTimeout(() => {
89 | res.send('Ok');
90 | }, 1000);
91 | },
92 | ```
93 |
94 | ### 使用插件模拟延迟
95 |
96 | 上面的方法虽然简便,但是当你需要添加所有的请求延迟的时候,可能就麻烦了,不过可以通过第三方插件来简化这个问题,如:[roadhog-api-doc#delay](https://github.com/nikogu/roadhog-api-doc/blob/master/lib/utils.js#L5)。
97 |
98 | ```js
99 | import { delay } from 'roadhog-api-doc';
100 |
101 | const proxy = {
102 | 'GET /api/project/notice': getNotice,
103 | 'GET /api/activities': getActivities,
104 | 'GET /api/rule': getRule,
105 | 'GET /api/tags': mockjs.mock({
106 | 'list|100': [{ name: '@city', 'value|1-100': 50, 'type|0-2': 1 }]
107 | }),
108 | 'GET /api/fake_list': getFakeList,
109 | 'GET /api/fake_chart_data': getFakeChartData,
110 | 'GET /api/profile/basic': getProfileBasicData,
111 | 'GET /api/profile/advanced': getProfileAdvancedData,
112 | 'POST /api/register': (req, res) => {
113 | res.send({ status: 'ok' });
114 | },
115 | 'GET /api/notices': getNotices,
116 | };
117 |
118 | // 调用 delay 函数,统一处理
119 | export default delay(proxy, 1000);
120 | ```
121 |
122 | ## 联调
123 |
124 | 当本地开发完毕之后,如果服务器的接口满足之前的约定,那么你只需要不开本地代理或者重定向代理到目标服务器就可以访问真实的服务端数据,非常方便。
125 |
126 |
--------------------------------------------------------------------------------
/packages/umi/src/generators/page.md:
--------------------------------------------------------------------------------
1 | ```js
2 | import assert from 'assert';
3 | ```
4 | 该模块用于编写应用程序的单元测试
5 | ```js
6 | import ejs from 'ejs';
7 | ```
8 | 嵌入式JavaScript模板
9 | ```js
10 | import uppercamelcase from 'uppercamelcase';
11 | ```
12 | 首字母大写转换 如 foo-bar => FooBar
13 | ```js
14 | import { join, basename } from 'path';
15 | import { existsSync, statSync, readFileSync, writeFileSync } from 'fs';
16 | ```
17 | 属性 | 说明|
18 | -------- | ------|
19 | existsSync|测试某个路径下的文件是否存在
20 | statSync|获取文件信息
21 | readFileSync|读取文件
22 | writeFileSync|写文件
23 |
24 | ```js
25 | //目录存在
26 | function directoryExists(path) {
27 | return existsSync(path) && statSync(path).isDirectory();
28 | }
29 | ```
30 | ```js
31 | //文件存在
32 | function fileExists(path) {
33 | return existsSync(path) && statSync(path).isFile();
34 | }
35 | ```
36 | ```js
37 | //去除空行
38 | function stripEmptyLine(content) {
39 | const ret = content
40 | .trim()
41 | // 两行 -> 一行
42 | .replace(/\n\n/g, '\n');
43 |
44 | // 结尾空行
45 | return `${ret}\n`;
46 | }
47 | ```
48 | ```js
49 | //看一下代码时,可先忽略assert
50 | export default function(opts = {}) {
51 | const { file } = opts;
52 | //断言
53 | assert(
54 | !('isDirectory' in opts) || typeof opts.isDirectory === 'boolean',
55 | 'opts.isDirectory should be boolean',
56 | );
57 | assert(
58 | !('useClass' in opts) || typeof opts.useClass === 'boolean',
59 | 'opts.useClass should be boolean',
60 | );
61 | //目录
62 | const isDirectory = opts.isDirectory || false;
63 | //当前执行路径
64 | const cwd = opts.cwd || process.cwd();
65 |
66 | console.log(`[DEBUG] generate page ${file} with isDirectory ${isDirectory}`);
67 |
68 | let cssTargetPath;
69 | let jsTargetPath;
70 | //是目录的时候,在file目录下新建page文件
71 | //不是目录的时候,新建file文件
72 | if (isDirectory) {
73 | assert(
74 | !directoryExists(join(cwd, 'src', 'page', file)),
75 | `directory src/page/${file} exists`,
76 | );
77 | jsTargetPath = join(cwd, 'src', 'page', file, 'page.js');
78 | cssTargetPath = join(cwd, 'src', 'page', file, 'page.css');
79 | } else {
80 | jsTargetPath = join(cwd, 'src', 'page', `${file}.js`);
81 | cssTargetPath = join(cwd, 'src', 'page', `${file}.css`);
82 | }
83 |
84 | assert(!fileExists(jsTargetPath), `file src/page/${file} exists`);
85 | assert(!fileExists(cssTargetPath), `file src/page/${file} exists`);
86 |
87 | //从模板中读取文件
88 | const jsTpl = readFileSync(
89 | join(__dirname, '../../template/page.js'),
90 | 'utf-8',
91 | );
92 | const cssTpl = readFileSync(
93 | join(__dirname, '../../template/page.css'),
94 | 'utf-8',
95 | );
96 |
97 |
98 | const fileName = basename(file);
99 | const componentName = uppercamelcase(fileName);
100 | //使用ejs render文件
101 | //ejs.render(str, data, options);
102 | //options https://www.npmjs.com/package/ejs#options
103 | const jsContent = ejs.render(
104 | jsTpl,
105 | {
106 | useClass: opts.useClass,
107 | fileName,
108 | componentName,
109 | },
110 | {
111 | _with: false,
112 | localsName: 'umi',
113 | },
114 | );
115 |
116 | const cssContent = ejs.render(
117 | cssTpl,
118 | {},
119 | {
120 | _with: false,
121 | localsName: 'umi',
122 | },
123 | );
124 |
125 | //写入文件
126 | writeFileSync(jsTargetPath, stripEmptyLine(jsContent), 'utf-8');
127 | writeFileSync(cssTargetPath, stripEmptyLine(cssContent), 'utf-8');
128 | }
129 | ```
--------------------------------------------------------------------------------
/docs/zh/api/README.md:
--------------------------------------------------------------------------------
1 | ---
2 | sidebarDepth: 2
3 | ---
4 |
5 | # API
6 |
7 | ## 路由
8 |
9 | ### umi/link
10 |
11 | 通过声明的方式做路由跳转。
12 |
13 | 例子:
14 |
15 | ```markup
16 | import Link from 'umi/link';
17 |
18 | export default () => {
19 |
20 | /* 普通使用 */
21 | Go to list page
22 |
23 | /* 带参数 */
24 | Go to list page
25 |
26 | /* 包含子组件 */
27 | Go to list page
28 |
29 | }
30 | ```
31 |
32 | ### umi/router
33 |
34 | 通过编程的方式做路由切换,包含以下 4 个 API 。
35 |
36 | #### router.push(path)
37 |
38 | 推一个新的页面到 history 里。
39 |
40 | 例子:
41 |
42 | ```js
43 | import router from 'umi/router';
44 |
45 | // 普通跳转,不带参数
46 | router.push('/list');
47 |
48 | // 带参数
49 | router.push('/list?a=b');
50 | router.push({
51 | pathname: '/list',
52 | query: {
53 | a: 'b',
54 | },
55 | });
56 | # 对象且不包含 pathname 会报错
57 | router.push({
58 | query: {}
59 | });
60 | ```
61 |
62 | #### router.replace(path)
63 |
64 | 替换当前页面,参数和 [router.push()](#router.push\(path\)) 相同。
65 |
66 | #### router.go(n)
67 |
68 | 往前或往后跳指定页数。
69 |
70 | 例子:
71 |
72 | ```js
73 | import router from 'umi/router';
74 |
75 | router.go(-1);
76 | router.go(2);
77 | ```
78 |
79 | #### router.goBack()
80 |
81 | 后退一页。
82 |
83 | 例子:
84 |
85 | ```js
86 | import router from 'umi/router';
87 | router.goBack();
88 | ```
89 |
90 | ### umi/navlink
91 |
92 | 详见:[https://reacttraining.com/react-router/web/api/NavLink](https://reacttraining.com/react-router/web/api/NavLink)
93 |
94 | ### umi/redirect
95 |
96 | 重定向用。
97 |
98 | 例子:
99 |
100 | ```js
101 | import Redirect from 'umi/redirect';
102 |
103 | ```
104 |
105 | 详见:[https://reacttraining.com/react-router/web/api/Redirect](https://reacttraining.com/react-router/web/api/Redirect)
106 |
107 | ### umi/prompt
108 |
109 | 例子:
110 |
111 | ```js
112 | import Prompt from 'umi/prompt';
113 |
114 | export default () => {
115 | return (
116 | <>
117 | Prompt
118 | {
121 | return window.confirm(`confirm to leave to ${location.pathname}?`);
122 | }}
123 | />
124 | >
125 | );
126 | }
127 | ```
128 |
129 | 详见:[https://reacttraining.com/react-router/web/api/Prompt](https://reacttraining.com/react-router/web/api/Prompt)
130 |
131 | ### umi/withRouter
132 |
133 | 详见:[https://reacttraining.com/react-router/web/api/withRouter](https://reacttraining.com/react-router/web/api/withRouter)
134 |
135 | ## 性能
136 |
137 | ### umi/dynamic
138 |
139 | 动态加载组件,基于 [react-loadable](https://github.com/jamiebuilds/react-loadable) 实现。
140 |
141 | #### dynamic(options)
142 |
143 | 例子:
144 |
145 | ```js
146 | import dynamic from 'umi/dynamic';
147 |
148 | // 延时 1s 渲染的组件。
149 | const App = dynamic({
150 | loader: () => {
151 | return new Promise((resolve) => {
152 | setTimeout(() => {
153 | resolve(() => I will render after 1s
);
154 | }, /* 1s */1000);
155 | }));
156 | },
157 | });
158 |
159 | // 或者用 async 语法
160 | const delay = (timeout) => new Promise(resolve => setTimeout(resolve, timeout));
161 | const App = dynamic({
162 | loader: async function() {
163 | await delay(/* 1s */1000);
164 | return () => I will render after 1s
;
165 | },
166 | });
167 | ```
168 |
169 | ## 构建
170 |
171 | ### umi/babel
172 |
173 | 让用户可基于 umi 的 babel 配置进行扩展。
174 |
--------------------------------------------------------------------------------
/docs/zh/guide/app-structure.md:
--------------------------------------------------------------------------------
1 | # 目录及约定
2 |
3 | 在文件和目录的组织上,umi 尽量选择了约定的方式。
4 |
5 | 一个复杂应用的目录结构如下:
6 |
7 | ```
8 | .
9 | ├── dist/ // 默认的 build 输出目录
10 | ├── mock/ // mock 文件所在目录,基于 express
11 | ├── config/
12 | ├── config.js // umi 配置,同 .umirc.js,二选一
13 | └── src/ // 源码目录,可选
14 | ├── layouts/index.js // 全局布局
15 | ├── pages/ // 页面目录,里面的文件即路由
16 | ├── .umi/ // dev 临时目录,需添加到 .gitignore
17 | ├── .umi-production/ // build 临时目录,会自动删除
18 | ├── document.ejs // HTML 模板
19 | ├── 404.js // 404 页面
20 | ├── page1.js // 页面 1,任意命名,导出 react 组件
21 | ├── page1.test.js // 用例文件,umi test 会匹配所有 .test.js 和 .e2e.js 结尾的文件
22 | └── page2.js // 页面 2,任意命名
23 | ├── global.css // 约定的全局样式文件,自动引入,也可以用 global.less
24 | ├── global.js // 可以在这里加入 polyfill
25 | ├── .umirc.js // umi 配置,同 config/config.js,二选一
26 | ├── .env // 环境变量
27 | └── package.json
28 | ```
29 |
30 | ## ES6 语法
31 |
32 | 配置文件、mock 文件等都有通过 `@babel/register` 注册实时编译,所以可以和 src 里的文件一样,使用 ES6 的语法和 es modules 。
33 |
34 | ## dist
35 |
36 | 默认输出路径,可通过配置 outputPath 修改。
37 |
38 | ## mock
39 |
40 | 约定 mock 目录里所有的 `.js` 文件会被解析为 mock 文件。
41 |
42 | 比如,新建 `mock/users.js`,内容如下:
43 |
44 | ```js
45 | export default {
46 | '/api/users': ['a', 'b'],
47 | }
48 | ```
49 |
50 | 然后在浏览器里访问 [http://localhost:8000/api/users](http://localhost:8000/api/users) 就可以看到 `['a', 'b']` 了。
51 |
52 | ## src
53 |
54 | 约定 `src` 为源码目录,但是可选,简单项目可以不加 `src` 这层目录。
55 |
56 | 比如:下面两种目录结构的效果是一致的。
57 |
58 | ```
59 | + src
60 | + pages
61 | - index.js
62 | + layouts
63 | - index.js
64 | - .umirc.js
65 | ```
66 |
67 | ```
68 | + pages
69 | - index.js
70 | + layouts
71 | - index.js
72 | - .umirc.js
73 | ```
74 |
75 | ## src/layouts/index.js
76 |
77 | 全局布局,实际上是在路由外面套了一层。
78 |
79 | 比如,你的路由是:
80 |
81 | ```
82 | [
83 | { path: '/', component: './pages/index' },
84 | { path: '/users', component: './pages/users' },
85 | ]
86 | ```
87 |
88 | 如果有 `layouts/index.js`,那么路由则变为:
89 |
90 | ```
91 | [
92 | { path: '/', component: './layouts/index', routes: [
93 | { path: '/', component: './pages/index' },
94 | { path: '/users', component: './pages/users' },
95 | ] }
96 | ]
97 | ```
98 |
99 | ## src/pages
100 |
101 | 约定 pages 下所有的 `(j|t)sx?` 文件即路由。关于更多关于约定式路由的介绍,请前往路由章节。
102 |
103 | ## src/pages/404.js
104 |
105 | 404 页面。注意开发模式下有内置 umi 提供的 404 提示页面,所以只有显式访问 `/404` 才能访问到这个页面。
106 |
107 | ## src/pages/document.ejs
108 |
109 | 有这个文件时,会覆盖默认的 HTML 模板。需至少包含以下代码,
110 |
111 | ```html
112 |
113 | ```
114 |
115 | ## src/pages/.umi
116 |
117 | 这是 umi dev 时生产的临时目录,默认包含 `umi.js` 和 `router.js`,有些插件也会在这里生成一些其他临时文件。可以在这里做一些验证,**但请不要直接在这里修改代码,umi 重启或者 pages 下的文件修改都会重新生成这个文件夹下的文件。**
118 |
119 | ## src/pages/.umi-production
120 |
121 | 同 `src/pagers/.umi`,但是是在 `umi build` 时生成的,会在 `umi build` 执行完自动删除。
122 |
123 | ## .test.js 和 .e2e.js
124 |
125 | 测试文件,`umi test` 会查找所有的 .(test|e2e).(j|t)s 文件跑测试。
126 |
127 | ## src/global.(j|t)sx?
128 |
129 | 在入口文件最前面被自动引入,可以考虑在此加入 polyfill。
130 |
131 | ## src/global.(css|less|sass|scss)
132 |
133 | 这个文件不走 css modules,自动被引入,可以写一些全局样式,或者做一些样式覆盖。
134 |
135 | ## .umirc.js 和 config/config.js
136 |
137 | umi 的配置文件,二选一。
138 |
139 | ## .env
140 |
141 | 环境变量,比如:
142 |
143 | ```
144 | CLEAR_CONSOLE=none
145 | BROWSER=none
146 | ```
147 |
--------------------------------------------------------------------------------
/docs/guide/env-variables.md:
--------------------------------------------------------------------------------
1 | ---
2 | sidebarDepth: 3
3 | ---
4 |
5 | # .env and Environment Variables
6 |
7 | ## How to Configure
8 |
9 | For example
10 |
11 | ```
12 | # OS X, Linux
13 | $ PORT=3000 umi dev
14 |
15 | # Windows (cmd.exe)
16 | $ set PORT=3000&&umi dev
17 |
18 | # Or use cross-env for all platforms
19 | $ yarn add cross-env --dev
20 | $ cross-env PORT=3000 umi dev
21 |
22 | # .env
23 | $ echo PORT=3000 > .env
24 | ```
25 |
26 | ## Environment Variables
27 |
28 | ### UMI_ENV
29 |
30 | Specifies a profile that overrides the default configuration. For example, `UMI_ENV=prod umi build`, then `.umirc.js` will be overwritten with `.umirc.prod.js`. Or `config/config.prod.js` overrides `config/config.js`. Note that overriding instead of replacing, configurators not in `.umirc.prod.js` will use the configuration in `.umirc.js`.
31 |
32 | In addition, the configuration in `.umirc.local.js` or `config/config.local.js` in development mode is always the highest priority.
33 |
34 | ### PORT
35 |
36 | Specify the port number. The default is `8000`. such as:
37 |
38 | ```bash
39 | $ PORT=8001 umi dev
40 | ```
41 |
42 | ### HOST
43 |
44 | The default is `0.0.0.0`.
45 |
46 | ### APP_ROOT
47 |
48 | ::: warning
49 | APP_ROOT cannot be included in .env.
50 | :::
51 |
52 | Specify the project root directory. such as:
53 |
54 | ```bash
55 | $ APP_ROOT=src/renderer umi dev
56 | ```
57 |
58 | ### ANALYZE
59 |
60 | It is off by default. Analyze the bundle composition, valid when building. such as:
61 |
62 | ```bash
63 | $ ANALYZE=1 umi build
64 | ```
65 |
66 | ### ANALYZE_PORT
67 |
68 | ANALYZE server port, default 8888.
69 |
70 | ### BABEL_POLYFILL
71 |
72 | 默认引入 `@babel/polyfill`,值为 none 时不引入。比如:
73 |
74 | `@babel/polyfill` is included by default, set the value to `none` if you don't want it.
75 |
76 | e.g.
77 |
78 | ```bash
79 | $ BABEL_POLYFILL=none umi build
80 | ```
81 |
82 | ### COMPRESS
83 |
84 | The default compression CSS and JS, the value is none when it is none, and it is valid when building. such as:
85 |
86 | ```bash
87 | $ COMPRESS=none umi build
88 | ```
89 |
90 | ### CSS_COMPRESS
91 |
92 | The default compression, the value is none without compression, and is valid at build time. Because css compression is sometimes problematic, and compression does not reduce the size, sometimes you can suppress JS without pressing CSS.
93 |
94 | ### BROWSER
95 |
96 | The browser is automatically opened by default. If the value is none, it will not be automatically opened. It is valid when dev. such as:
97 |
98 | ```bash
99 | $ BROWSER=none umi dev
100 | ```
101 |
102 | ### CLEAR_CONSOLE
103 |
104 | The default is cleared. If the value is none, the screen is not cleared.
105 |
106 | ### HMR
107 |
108 | The HMR is enabled by default, the value is disabled when none, and the value is refreshed when the file changes when reload.
109 |
110 | ### BABELRC
111 |
112 | Turn on `.babelrc` parsing, which is not resolved by default.
113 |
114 | ### BABEL_CACHE
115 |
116 | The babel cache is enabled by default, and is disabled when the value is none. such as:
117 |
118 | ```bash
119 | $ BABEL_CACHE=none umi dev
120 | ```
121 |
122 | ### MOCK
123 |
124 | The mock is enabled by default, and is disabled when the value is none. such as:
125 |
126 | ```bash
127 | $ MOCK=none umi dev
128 | ```
129 |
130 | ### HTML
131 |
132 | The HTML file is packaged by default, and the HTML file is not packaged when the value is none. such as:
133 |
134 | ```bash
135 | $ HTML=none umi build
136 | ```
137 |
138 | ### WATCH_FILES
139 |
140 | ### RM_TMPDIR
141 | ### FORK_TS_CHECKER
142 | 默认不开启TypeScript检查,值为1时启用。比如:
143 | ```bash
144 | $ FORK_TS_CHECKER=1 umi dev
145 | ```
146 |
--------------------------------------------------------------------------------
/docs/zh/guide/getting-started.md:
--------------------------------------------------------------------------------
1 | # 快速上手
2 |
3 | > 更喜欢观看视频?可以[点此观看](https://www.youtube.com/watch?v=vkAUGUlYm24&list=PLzu0PBqV2jld2q5gCADxX17NE3gF3FvYq)
4 |
5 | ## 环境准备
6 |
7 | 首先得有 [node](https://nodejs.org/en/),并确保 node 版本是 8.10 或以上。(mac 下推荐使用 [nvm](https://github.com/creationix/nvm) 来管理 node 版本)
8 |
9 | ```bash
10 | $ node -v
11 | 8.1x
12 | ```
13 |
14 | 推荐使用 yarn 管理 npm 依赖,并[使用国内源](https://github.com/yiminghe/tyarn)(阿里用户使用内网源)。
15 |
16 | ```bash
17 | # 国内源
18 | $ npm i yarn tyarn -g
19 | # 后面文档里的 yarn 换成 tyarn
20 | $ tyarn -v
21 |
22 | # 阿里内网源
23 | $ tnpm i yarn @alipay/yarn -g
24 | # 后面文档里的 yarn 换成 ayarn
25 | $ ayarn -v
26 | ```
27 |
28 | 然后全局安装 umi,并确保版本是 2.0.0 或以上。
29 |
30 | ```bash
31 | $ yarn global add umi
32 | $ umi -v
33 | 2.0.0
34 | ```
35 |
36 | ## 脚手架
37 |
38 | 先找个地方建个空目录。
39 |
40 | ```bash
41 | $ mkdir myapp && cd myapp
42 | ```
43 |
44 | 然后通过 `umi g` 创建一些页面,
45 |
46 | ```bash
47 | $ umi g page index
48 | $ umi g page users
49 | ```
50 |
51 | > `umi g` 是 `umi generate` 的别名,可用于快速生成 component、page、layout 等,并且可在插件里被扩展,比如 umi-plugin-dva 里扩展了 dva:model,然后就可以通过 `umi g dva:model foo` 快速 dva 的 model。
52 |
53 | 然后通过 tree 查看下目录,(windows 用户可跳过此步)
54 |
55 | ```bash
56 | $ tree
57 | .
58 | └── pages
59 | ├── index.css
60 | ├── index.js
61 | ├── users.css
62 | └── users.js
63 | ```
64 |
65 | 这里的 pages 目录是页面所在的目录,umi 里约定默认情况下 pages 下所有的 js 文件即路由,如果有 [next.js](https://github.com/zeit/next.js) 或 [nuxt.js](https://nuxtjs.org/) 的使用经验,应该会有点眼熟吧。
66 |
67 | 然后启动本地服务器,
68 |
69 | ```bash
70 | $ umi dev
71 | ```
72 |
73 |
74 |
75 | ## 约定式路由
76 |
77 | 启动 `umi dev` 后,大家会发现 pages 下多了个 `.umi` 的目录。这是啥?这是 umi 的临时目录,可以在这里做一些验证,但请不要直接在这里修改代码,umi 重启或者 pages 下的文件修改都会重新生成这个文件夹下的文件。
78 |
79 | 然后我们在 index 和 users 直接加一些路由跳转逻辑。
80 |
81 | 先修改 `pages/index.js`,
82 |
83 | ```diff
84 | + import Link from 'umi/link';
85 | import styles from './index.css';
86 |
87 | export default function() {
88 | return (
89 |
90 |
Page index
91 | + go to /users
92 |
93 | );
94 | }
95 | ```
96 |
97 | 再修改 `pages/users.js`,
98 |
99 | ```diff
100 | + import router from 'umi/router';
101 | import styles from './index.css';
102 |
103 | export default function() {
104 | return (
105 |
106 |
Page index
107 | + { router.goBack(); }}>go back
108 |
109 | );
110 | }
111 | ```
112 |
113 | 然后浏览器验证,应该已经可以在 index 和 users 两个页面之间通过路由跳转了。
114 |
115 | ## 部署发布
116 |
117 | ### 构建
118 |
119 | 执行 `umi build`,
120 |
121 | ```bash
122 | $ umi build
123 |
124 | DONE Compiled successfully in 1729ms
125 |
126 | File sizes after gzip:
127 |
128 | 68.04 KB dist/umi.js
129 | 83 B dist/umi.css
130 | ```
131 |
132 | 构建产物默认生成到 `./dist` 下,然后通过 tree 命令查看,(windows 用户可忽略此步)
133 |
134 | ```bash
135 | $ tree ./dist
136 | ./dist
137 | ├── index.html
138 | ├── umi.css
139 | └── umi.js
140 | ```
141 |
142 | ### 本地验证
143 |
144 | 发布之前,可以通过 `serve` 做本地验证,
145 |
146 | ```bash
147 | $ yarn global add serve
148 | $ serve ./dist
149 |
150 | Serving!
151 |
152 | - Local: http://localhost:5000
153 | - On Your Network: http://{Your IP}:5000
154 |
155 | Copied local address to clipboard!
156 | ```
157 |
158 | 访问 http://localhost:5000,正常情况下应该是和 `umi dev` 一致的。
159 |
160 | ### 部署
161 |
162 | 本地验证完,就可以部署了,这里通过 [now](http://now.sh/) 来做演示。
163 |
164 | ```bash
165 | $ yarn global add now
166 | $ now ./dist
167 |
168 | > Deploying /private/tmp/sorrycc-1KVCmK/dist under chencheng
169 | > Synced 3 files (301.93KB) [2s]
170 | > https://dist-jtckzjjatx.now.sh [in clipboard] [1s]
171 | > Deployment complete!
172 | ```
173 |
174 | 然后打开相应的地址就能访问到线上的地址了。
175 |
--------------------------------------------------------------------------------
/docs/api/README.md:
--------------------------------------------------------------------------------
1 | ---
2 | sidebarDepth: 2
3 | ---
4 |
5 | # API
6 |
7 | ## Route
8 |
9 | ### umi/link
10 |
11 | Navigation via route declaration.
12 |
13 | Example:
14 |
15 | ```markup
16 | import Link from 'umi/link';
17 |
18 | export default () => {
19 |
20 | /* Normal use */
21 | Go to list page
22 |
23 | /* With query string */
24 | Go to list page
25 |
26 | /* Include child component */
27 | Go to list page
28 |
29 | }
30 | ```
31 |
32 | ### umi/router
33 |
34 | Programmatic navigation via four router methods
35 |
36 | #### router.push(path)
37 |
38 | Add one entry to the browser's history.
39 |
40 | Example:
41 |
42 | ```js
43 | import router from 'umi/router';
44 |
45 | // Normal navigation without query string
46 | router.push('/list');
47 |
48 | // With query string
49 | router.push('/list?a=b');
50 | router.push({
51 | pathname: '/list',
52 | query: {
53 | a: 'b',
54 | },
55 | });
56 | # Object without property `pathname` will throw an error
57 | router.push({
58 | query: {}
59 | });
60 | ```
61 |
62 | #### router.replace(path)
63 |
64 | Replace current page. Accept same parameter as [router.push()](#router.push\(path\))
65 |
66 | #### router.go(n)
67 |
68 | Move back or forward through history.
69 |
70 | Example:
71 |
72 | ```js
73 | import router from 'umi/router';
74 |
75 | router.go(-1);
76 | router.go(2);
77 | ```
78 |
79 | #### router.goBack()
80 |
81 | Move backward.
82 |
83 | Example:
84 |
85 | ```js
86 | import router from 'umi/router';
87 | router.goBack();
88 | ```
89 |
90 | ### umi/navlink
91 |
92 | See: [https://reacttraining.com/react-router/web/api/NavLink](https://reacttraining.com/react-router/web/api/NavLink)
93 |
94 | ### umi/redirect
95 |
96 | Redirection.
97 |
98 | Example:
99 |
100 | ```js
101 | import Redirect from 'umi/redirect';
102 |
103 | ```
104 |
105 | See: [https://reacttraining.com/react-router/web/api/Redirect](https://reacttraining.com/react-router/web/api/Redirect)
106 |
107 | ### umi/prompt
108 |
109 | Example.
110 |
111 | ```js
112 | import Prompt from 'umi/prompt';
113 |
114 | export default () => {
115 | return (
116 | <>
117 | Prompt
118 | {
121 | return window.confirm(`confirm to leave to ${location.pathname}?`);
122 | }}
123 | />
124 | >
125 | );
126 | }
127 | ```
128 |
129 | See:[https://reacttraining.com/react-router/web/api/Prompt](https://reacttraining.com/react-router/web/api/Prompt)
130 |
131 | ### umi/withRouter
132 |
133 | See: [https://reacttraining.com/react-router/web/api/withRouter](https://reacttraining.com/react-router/web/api/withRouter)
134 |
135 | ## Performance
136 |
137 | ### umi/dynamic
138 |
139 | Dynamically loading components based on [react-loadable](https://github.com/jamiebuilds/react-loadable).
140 |
141 | #### dynamic(options)
142 |
143 | Example:
144 |
145 | ```js
146 | import dynamic from 'umi/dynamic';
147 |
148 | // Render component with 1s delay
149 | const App = dynamic({
150 | loader: () => {
151 | return new Promise((resolve) => {
152 | setTimeout(() => {
153 | resolve(() => I will render after 1s
);
154 | }, /* 1s */1000);
155 | }));
156 | },
157 | });
158 |
159 | // Or use `async function`
160 | const delay = (timeout) => new Promise(resolve => setTimeout(resolve, timeout));
161 | const App = dynamic({
162 | loader: async function() {
163 | await delay(/* 1s */1000);
164 | return () => I will render after 1s
;
165 | },
166 | });
167 | ```
168 |
169 | ## Build
170 |
171 | ### umi/babel
172 |
173 | Make umi's babel configuration extensible.
174 |
--------------------------------------------------------------------------------
/docs/zh/guide/with-dva.md:
--------------------------------------------------------------------------------
1 | # Use umi with dva
2 |
3 | ::: warning
4 | This article has not been translated yet. Wan't to help us out? Click the `Edit this page on GitHub` at the end of the page.
5 | :::
6 |
7 | 自`>= umi@2`起,`dva`的整合可以直接通过 [umi-plugin-react](https://github.com/umijs/umi/tree/master/packages/umi-plugin-react) 来配置。
8 |
9 | ## 特性
10 |
11 | * **按目录约定注册 model**,无需手动 `app.model`
12 | * **文件名即 namespace**,可以省去 model 导出的 `namespace` key
13 | * **无需手写 router.js**,交给 umi 处理,支持 model 和 component 的按需加载
14 | * **内置 query-string 处理**,无需再手动解码和编码
15 | * **内置 dva-loading 和 dva-immer**,其中 dva-immer 需通过配置开启
16 | * **开箱即用**,无需安装额外依赖,比如 dva、dva-loading、dva-immer、path-to-regexp、object-assign、react、react-dom 等
17 |
18 | ## 使用
19 |
20 | 用 yarn 安装依赖,
21 |
22 | ```bash
23 | $ yarn add umi-plugin-react
24 | ```
25 |
26 | 如果你用 npm,执行 `npm install --save umi-plugin-react`。
27 |
28 | 然后在 `.umirc.js` 里配置插件:
29 |
30 | ```js
31 | export default {
32 | plugins: [
33 | [
34 | 'umi-plugin-react',
35 | {
36 | dva: true,
37 | },
38 | ]
39 | ],
40 | };
41 | ```
42 |
43 | 推荐开启 dva-immer 以简化 reducer 编写,
44 |
45 | ```js
46 | export default {
47 | plugins: [
48 | [
49 | 'umi-plugin-react',
50 | {
51 | dva: {
52 | immer: true
53 | }
54 | }
55 | ],
56 | ],
57 | };
58 | ```
59 |
60 | ## model 注册
61 |
62 | model 分两类,一是全局 model,二是页面 model。全局 model 存于 `/src/models/` 目录,所有页面都可引用;**页面 model 不能被其他页面所引用**。
63 |
64 | 规则如下:
65 |
66 | * `src/models/**/*.js` 为 global model
67 | * `src/pages/**/models/**/*.js` 为 page model
68 | * global model 全量载入,page model 在 production 时按需载入,在 development 时全量载入
69 | * page model 为 page js 所在路径下 `models/**/*.js` 的文件
70 | * page model 会向上查找,比如 page js 为 `pages/a/b.js`,他的 page model 为 `pages/a/b/models/**/*.js` + `pages/a/models/**/*.js`,依次类推
71 | * 约定 model.js 为单文件 model,解决只有一个 model 时不需要建 models 目录的问题,有 model.js 则不去找 `models/**/*.js`
72 |
73 | 举个例子,
74 |
75 | ```
76 | + src
77 | + models
78 | - g.js
79 | + pages
80 | + a
81 | + models
82 | - a.js
83 | - b.js
84 | + ss
85 | - s.js
86 | - page.js
87 | + c
88 | - model.js
89 | + d
90 | + models
91 | - d.js
92 | - page.js
93 | - page.js
94 | ```
95 |
96 | 如上目录:
97 |
98 | * global model 为 `src/models/g.js`
99 | * `/a` 的 page model 为 `src/pages/a/models/{a,b,ss/s}.js`
100 | * `/c` 的 page model 为 `src/pages/c/model.js`
101 | * `/c/d` 的 page model 为 `src/pages/c/model.js, src/pages/c/d/models/d.js`
102 |
103 | ## 配置及插件
104 |
105 | > 之前在 `src/dva.js` 下进行配置的方式已 deprecated,下个大版本会移除支持。
106 |
107 | 在 `src` 目录下新建 `app.js`,内容如下:
108 |
109 | ```js
110 | export const dva = {
111 | config: {
112 | onError(e) {
113 | e.preventDefault();
114 | console.error(e.message);
115 | },
116 | },
117 | plugins: [
118 | require('dva-logger')(),
119 | ],
120 | };
121 | ```
122 |
123 | ## FAQ
124 |
125 | ### url 变化了,但页面组件不刷新,是什么原因?
126 |
127 | `layouts/index.js` 里如果用了 connect 传数据,需要用 `umi/withRouter` 高阶一下。
128 |
129 | ```js
130 | import withRouter from 'umi/withRouter';
131 |
132 | export default withRouter(connect(mapStateToProps)(LayoutComponent));
133 | ```
134 |
135 | ### 如何访问到 store 或 dispatch 方法?
136 |
137 | ```js
138 | window.g_app._store
139 | window.g_app._store.dispatch
140 | ```
141 |
142 | ### 如何禁用包括 component 和 models 的按需加载?
143 |
144 | 在 .umirc.js 里配置:
145 |
146 | ```js
147 | export default {
148 | plugins: [
149 | [
150 | 'umi-plugin-react',
151 | {
152 | dva: {
153 | dynamicImport: undefined // 配置在dva里
154 | },
155 | dynamicImport: undefined // 或者直接写在react插件的根配置,写在这里也会被继承到上面的dva配置里
156 | }
157 | ],
158 | ],
159 | };
160 | ```
161 |
162 | ### 全局 layout 使用 connect 后路由切换后没有刷新?
163 |
164 | 需用 withRouter 包一下导出的 react 组件,注意顺序。
165 |
166 | ```js
167 | import withRouter from 'umi/withRouter';
168 | export default withRouter(connect()(Layout));
169 | ```
170 |
171 | ## 参考
172 |
173 | * [使用 umi 改进 dva 项目开发](https://github.com/sorrycc/blog/issues/66)
174 | * [umi + dva,完成用户管理的 CURD 应用](https://github.com/sorrycc/blog/issues/62)
175 |
--------------------------------------------------------------------------------
/docs/guide/migration.md:
--------------------------------------------------------------------------------
1 | # Migrate from umi 1.x
2 |
3 | > More like watching videos? You can [click here to watch](https://youtu.be/1mvKzFLLBck).
4 |
5 | Let's take an example of [antd-admin](https://github.com/zuiidea/antd-admin/pull/877) to update from umi@1 to umi@2.
6 |
7 | ## npm Dependency
8 |
9 | Upgrade umi to `^2.0.0-0` and use umi-plugin-react instead of the previous plugins, including umi-plugin-dva, umi-plugin-dll, umi-plugin-routes, umi-plugin-polyfill and Umi-plugin-locale.
10 |
11 | ```diff
12 | - "umi": "^1.3.17",
13 | + "umi": "^2.0.0-beta.16",
14 |
15 | - "umi-plugin-dll": "^0.2.1",
16 | - "umi-plugin-dva": "^0.9.1",
17 | - "umi-plugin-routes": "^0.1.5"
18 | + "umi-plugin-react": "^1.0.0-beta.16",
19 | ```
20 |
21 | Umi-plugin-react is a collection of more than a dozen plugins, as described in [Introduction to umi-plugin-react](/plugin/umi-plugin-react.html).
22 |
23 | ## Environment Variables
24 |
25 | Umi@2 supports configuring environment variables in `.env`, so the environment variables previously written in package.json scripts can be cut here.
26 |
27 | ```diff
28 | - "start": "cross-env COMPILE_ON_DEMAND=none BROWSER=none HOST=0.0.0.0 umi dev",
29 | + "start": "cross-env BROWSER=none HOST=0.0.0.0 umi dev",
30 | ```
31 |
32 | Then create a new `.env`, (where `COMPILE_ON_DEMAND` is no longer supported)
33 |
34 | ```
35 | BROWSER=none
36 | HOST=0.0.0.0
37 | ```
38 |
39 | In addition, some environment variables have changed or are no longer supported:
40 |
41 | * `PUBLIC_PATH` is no longer supported, configured by `publicPath`
42 | * `BASE_URL` is no longer supported, configured by `base`
43 | * `COMPILE_ON_DEMAND` is no longer supported, and this function is not available in umi@2.
44 | * `TSLINT` is no longer supported, and this function is not available in umi@2.
45 | * `ESLINT` is no longer supported, and this function is not available in umi@2.
46 |
47 | ## Configuration
48 |
49 | ### Plugin Configuration
50 |
51 | Since we changed a lot of plugins to umi-plugin-react, we need to modify `.umirc.js`.
52 |
53 | ```diff
54 | export default {
55 | plugins: [
56 | - 'umi-plugin-dva',
57 | + ['umi-plugin-react', {
58 | + dva: true,
59 | + antd: true, // antd is not enabled by default, if you need to use it yourself
60 | + }],
61 | ],
62 | };
63 | ```
64 |
65 | For more dll, hardSource, polyfilles, locale, title, etc., refer to [umi-plugin-react documentation](/plugin/umi-plugin-react.html).
66 |
67 | ### webpackrc.js
68 |
69 | Umi@2 no longer supports `webpackrc.js`, copy the configuration inside it to `.umirc.js`.
70 |
71 | ### webpack.config.js
72 |
73 | Umi@2 no longer supports `webpack.config.js`, instead it is implemented by configuring [chainWebpack](/config/#chainwebpack).
74 |
75 | ### Detailed Configuration Item Changes
76 |
77 | * `hd` is no longer supported. To enable it, load the plugin `umi-plugin-react` and configure `hd: {}`
78 | * `disableServiceWorker` is no longer supported, it is not enabled by default. To enable it, load the plugin `umi-plugin-react` and configure `pwa: {}`
79 | * `preact` is no longer supported. To configure, load the plugin `umi-plugin-react` and configure `library: 'preact'.
80 | * `loading` is no longer supported. To configure, load the plugin `umi-plugin-react` and configure `dynamicImport.loadingComponent`
81 | * `hashHistory: true` changed to `history: 'hash'`
82 | * `disableDynamicImport` is no longer supported, it is not enabled by default. To enable it, load the plugin `umi-plugin-react` and configure `dynamicImport: {}`
83 | * `disableFastClick` is no longer supported, it is not enabled by default. To enable it, load the plugin `umi-plugin-react` and configure `fastClick: {}`
84 | * No longer supports `pages`, instead of directly on the route
85 | * `disableHash` is no longer supported, it is not enabled by default. To enable it, configure `hash: true`
86 |
87 | ## Conventional Routing
88 |
89 | The routing layer no longer supports directory-level routing for `page.js`. Previously useful, you need to exclude unwanted routes through umi-plugin-react's routes.exclude.
90 |
91 | ## umi/dynamic
92 |
93 | Interface changes, umi@2 is based on [react-loadable](https://github.com/jamiebuilds/react-loadable).
94 |
95 | ```diff
96 | - dynamic(async () => {})
97 | + dynamic({ loader: async () => {}})
98 | ```
99 |
100 | See [umi/dynamic Interface Description](/api/#umi-dynamic) for details.
101 |
--------------------------------------------------------------------------------
/docs/guide/getting-started.md:
--------------------------------------------------------------------------------
1 | # Getting Started
2 |
3 | > There's also a [video version](https://www.youtube.com/watch?v=vkAUGUlYm24&list=PLzu0PBqV2jld2q5gCADxX17NE3gF3FvYq) of this.
4 |
5 | ## Environmental preparation
6 |
7 | First you should have [node](https://nodejs.org/en/), and make sure it's version 8.10 or above.
8 |
9 | ```bash
10 | $ node -v
11 | 8.1x
12 | ```
13 |
14 | Recommended to use `yarn` to management npm dependency.
15 |
16 | Then install `umi` globally, and make sure it's 2.0.0 or above.
17 |
18 | ```bash
19 | $ yarn global add umi
20 | $ umi -v
21 | 2.0.0
22 | ```
23 |
24 | ## Boilerplate
25 |
26 | First create an empty directory.
27 |
28 | ```bash
29 | $ mkdir myapp && cd myapp
30 | ```
31 |
32 | Then create some pages with `umi g`,
33 |
34 | ```bash
35 | $ umi g page index
36 | $ umi g page users
37 | ```
38 |
39 | > `umi g` is the alias of `umi generate`, used for generate `component`, `page`, `layout` quickly. And it can be extended in plugins, such as uni-plugin-dva extended `dva:model`, then you can generate dva's model via `umi g dva:model foo`.
40 |
41 | Then view the directory with `tree`, (windows users can skip this step)
42 |
43 | ```bash
44 | $ tree
45 | .
46 | └── pages
47 | ├── index.css
48 | ├── index.js
49 | ├── users.css
50 | └── users.js
51 | ```
52 |
53 | The pages directory here is the directory where the page is located. In umi, all the js files under the pages are routes. It's like [next.js](https://github.com/zeit/next.js) or [nuxt The experience of .js](https://nuxtjs.org/).
54 |
55 | Then start the local dev server,
56 |
57 | ```bash
58 | $ umi dev
59 | ```
60 |
61 |
62 |
63 | ## Convensional Routing
64 |
65 | After starting `umi dev`, you will find a directory of `.umi` under pages. What is this? This is the temporary directory of umi, you can do some verification here, but please do not modify the code directly here, umi restart or file modification under pages will regenerate the files in this folder.
66 |
67 | Then we add some route jump code to `index.js` and `users.js`.
68 |
69 | First modify `pages/index.js`,
70 |
71 | ```diff
72 | + import Link from 'umi/link';
73 | import styles from './index.css';
74 |
75 | export default function() {
76 | return (
77 |
78 |
Page index
79 | + go to /users
80 |
81 | );
82 | }
83 | ```
84 |
85 | Then modify `pages/users.js`,
86 |
87 | ```diff
88 | + import router from 'umi/router';
89 | import styles from './index.css';
90 |
91 | export default function() {
92 | return (
93 |
94 |
Page index
95 | + { router.goBack(); }}>go back
96 |
97 | );
98 | }
99 | ```
100 |
101 | Then verify in the browser, and it should already be able to jump between the index page and the users pages.
102 |
103 | ## Build and Deploy
104 |
105 | ### Build
106 |
107 | Run `umi build`,
108 |
109 | ```bash
110 | $ umi build
111 |
112 | DONE Compiled successfully in 1729ms
113 |
114 | File sizes after gzip:
115 |
116 | 68.04 KB dist/umi.js
117 | 83 B dist/umi.css
118 | ```
119 |
120 | The files is generated to `./dist` by default. You could view the files by the `tree` command (Windows users can skip this step)
121 |
122 | ```bash
123 | $ tree ./dist
124 | ./dist
125 | ├── index.html
126 | ├── umi.css
127 | └── umi.js
128 | ```
129 |
130 | ### Local Verification
131 |
132 | Local verification can be done via `serve` before publishing.
133 |
134 | ```bash
135 | $ yarn global add serve
136 | $ serve ./dist
137 |
138 | Serving!
139 |
140 | - Local: http://localhost:5000
141 | - On Your Network: http://{Your IP}:5000
142 |
143 | Copied local address to clipboard!
144 | ```
145 |
146 | Visit http://localhost:5000, which should be same as `umi dev`.
147 |
148 | ### Deploy
149 |
150 | Once verified, you can deploy it. Here is a demonstration with [now](http://now.sh/).
151 |
152 | ```bash
153 | $ yarn global add now
154 | $ now ./dist
155 |
156 | > Deploying /private/tmp/sorrycc-1KVCmK/dist under chencheng
157 | > Synced 3 files (301.93KB) [2s]
158 | > https://dist-jtckzjjatx.now.sh [in clipboard] [1s]
159 | > Deployment complete!
160 | ```
161 |
162 | Then open the url to view it online.
163 |
--------------------------------------------------------------------------------
/docs/zh/plugin/umi-plugin-react.md:
--------------------------------------------------------------------------------
1 | ---
2 | sidebarDepth: 3
3 | ---
4 |
5 | # umi-plugin-react
6 |
7 | 这是官方封装的一个插件集,包含 13 个常用的进阶功能。
8 |
9 | ## 安装
10 |
11 | ```bash
12 | $ yarn add umi-plugin-react --dev
13 | ```
14 |
15 | ## 使用
16 |
17 | 在 `.umirc.js` 里配置:
18 |
19 | ```js
20 | export default {
21 | plugins: [
22 | ['umi-plugin-react', {
23 | dva: {
24 | immer: true,
25 | },
26 | antd: true,
27 | routes: {
28 | exclude: [/models\//],
29 | },
30 | polyfills: ['ie9'],
31 | locale: {},
32 | library: 'react',
33 | dynamicImport: {
34 | webpackChunkName: true,
35 | loadingComponent: './components/Loading.js',
36 | },
37 | dll: {
38 | exclude: [],
39 | },
40 | hardSource: true,
41 | pwa: true,
42 | hd: true,
43 | fastClick: true,
44 | title: 'default title',
45 | }],
46 | ],
47 | };
48 | ```
49 |
50 | ## 配置项
51 |
52 | 所有功能默认关闭,有真值配置才会开启。
53 |
54 | ### dva
55 |
56 | * 类型:`Object`
57 |
58 | 基于 [umi-plugin-dva](https://github.com/umijs/umi/tree/master/packages/umi-plugin-dva) 实现,功能详见 [和 dva 一起用](/zh/guide/with-dva.html)。
59 |
60 | 配置项包含:
61 |
62 | * `immer`,是否启用 [dva-immer](https://github.com/dvajs/dva/tree/master/packages/dva-immer)
63 | * `dynamicImport`,是否启用按需加载,配置项同 [#dynamicImport](#dynamicImport),并且如果在 [#dynamicImport](#dynamicImport) 有配置,配置项会继承到 dva 中
64 | * `hmr`,是否启用 dva 的 hmr
65 |
66 | ::: warning
67 | 如果项目中有 dva 依赖,则优先使用项目中的依赖。
68 | :::
69 |
70 | ### antd
71 |
72 | * 类型:`Boolean`
73 |
74 | 启用后自动配置 [babel-plugin-import](https://github.com/ant-design/babel-plugin-import) 实现 antd 和 antd-mobile 的按需编译,并且内置 antd 和 antd-mobile 依赖,无需手动在项目中安装。
75 |
76 | ::: warning
77 | 如果项目中有 antd 或者 antd-mobile 依赖,则优先使用项目中的依赖。
78 | :::
79 |
80 | ### routes
81 |
82 | * 类型:`Object`
83 |
84 | 基于 [umi-plugin-routes](https://github.com/umijs/umi/tree/master/packages/umi-plugin-routes) 实现,用于批量修改路由。
85 |
86 | 配置项包含:
87 |
88 | * `exclude`,值为 `Array(RegExp)`,用于忽略某些路由,比如使用 dva 后,通常需要忽略 models、components、services 等目录
89 | * `update`, 值为 `Function`,用于更新路由
90 |
91 | ### polyfills
92 |
93 | * 类型:`Array(String)`
94 |
95 | 基于 [umi-plugin-polyfills](https://github.com/umijs/umi/tree/master/packages/umi-plugin-polyfills) 实现,用于加各种补丁。
96 |
97 | 目前支持配置 `['ie9']`、`['ie10']` 或 `['ie11']`,实现一键兼容。
98 |
99 | ### locale
100 |
101 | * 类型:`Object`
102 |
103 | 基于 [umi-plugin-locale](https://github.com/umijs/umi/tree/master/packages/umi-plugin-locale) 和 [react-intl](https://github.com/yahoo/react-intl) 实现,用于解决 i18n 问题。
104 |
105 | 配置项包含:
106 |
107 | * `default: 'zh-CN'`, // default zh-CN
108 | * `baseNavigator: true`, // default true, when it is true, will use `navigator.language` overwrite default
109 | * `antd: true`, // use antd, default is true
110 |
111 | ### library
112 |
113 | * 类型:`String`
114 |
115 | 可能切换底层库为 preact 或 react。
116 |
117 | ### dynamicImport
118 |
119 | * 类型:`Object`
120 |
121 | 实现路由级的动态加载(code splitting),可按需指定哪一级的按需加载。
122 |
123 | 配置项包含:
124 |
125 | * `webpackChunkName`,是否通过 webpackChunkName 实现有意义的异步文件名
126 | * `loadingComponent`,指定加载时的组件路径
127 | * `level`,指定按需加载的路由等级
128 |
129 | ### dll
130 |
131 | * 类型:`Object`
132 |
133 | 通过 webpack 的 dll 插件预打包一份 dll 文件来达到二次启动提速的目的。
134 |
135 | 配置项包含:
136 |
137 | * `include`
138 | * `exclude`
139 |
140 | ### hardSource
141 |
142 | * 类型:`Boolean`
143 |
144 | 通过 [hard-source-webpack-plugin](https://github.com/mzgoddard/hard-source-webpack-plugin) 开启 webpack 缓存,二次启动时间减少 80%。推荐非 windows 电脑使用,windows 下由于大文件 IO 比较慢,可自行决定是否启用。
145 |
146 | ### pwa
147 |
148 | * 类型:`Object`
149 |
150 | 开启 pwa 。
151 |
152 | ### hd
153 |
154 | * 类型:`Boolean`
155 |
156 | 开启高清方案。
157 |
158 | ### fastClick
159 |
160 | * 类型:`Boolean`
161 |
162 | 启用 fastClick。
163 |
164 | ### title
165 |
166 | * 类型:`String` 或者 `Object`
167 |
168 | 开启 title 插件,设置 HTML title:
169 |
170 | 配置项包含:
171 |
172 | * `defaultTitle: '默认标题'`, // 必填,当配置项为 String 时直接配置项作为 defaultTitle
173 | * `format: '{parent}{separator}{current}'`, // default {parent}{separator}{current}, title format
174 | * `separator: ' - '`, // default ' - '
175 |
176 | 当 title 插件开启后你可以在 routes 配置或者 pages 下的页面组件中配置 title。
177 |
178 | 比如使用配置式路由的时候如下配置:
179 |
180 | ```js
181 | // .umirc.js or config/config.js
182 | export default {
183 | routes: [{
184 | path: '/testpage',
185 | component: './testpage',
186 | title: 'test page',
187 | }],
188 | }
189 | ```
190 |
191 | 使用约定式路由的时候则直接在页面组件中配置:
192 |
193 | ```jsx
194 | /**
195 | * title: test page
196 | */
197 | export default () => {
198 | return testpage
;
199 | }
200 | ```
201 |
--------------------------------------------------------------------------------
/docs/guide/deploy.md:
--------------------------------------------------------------------------------
1 | # Deploy
2 |
3 | ## Default Scheme
4 |
5 | Umi@2 is friendly to newbies by default, so it does not load on-demand by default. After `umi build`, it outputs three files: `index.html`, `umi.js` and `umi.css`.
6 |
7 | ## Do Not Output HTML Files
8 |
9 | Some scene html files are handed to the backend output. The frontend build does not need to output html files. The environment variable `HTML=none` is configurable.
10 |
11 | ```bash
12 | $ HTML=none umi build
13 | ```
14 |
15 | ## Deploy HTML to a Non-Root Directory
16 |
17 | I often have students asking this question:
18 |
19 | > Why is my local development good, no response after deployment, and no error?
20 |
21 | **No error!** This is a typical phenomenon where an application is deployed on a non-root path. Why do you have this problem? Because the route does not match, for example, if you deploy the application under `/xxx/` and then access `/xxx/hello`, and the code matches `/hello`, then it will not match, but there is no definition. A fallback route, such as 404, will display a blank page.
22 |
23 | How to deal with it?
24 |
25 | Can be solved by configuring [base](/config/#base).
26 |
27 | ```bash
28 | export default {
29 | base: '/path/to/your/app/root',
30 | };
31 | ```
32 |
33 | ## Use hashHistory
34 |
35 | This can be solved by configuring [history](/config/#history) for `hash`.
36 |
37 | ```bash
38 | export default {
39 | history: 'hash',
40 | };
41 | ```
42 |
43 | ## Load on Demand
44 |
45 | To implement on-demand loading, load the umi-plugin-react plugin and configure [dynamicImport](/plugin/umi-plugin-react.html#dynamicimport).
46 |
47 | ```js
48 | export default {
49 | plugins: [
50 | ['umi-plugin-react', {
51 | dynamicImport: true,
52 | }],
53 | ],
54 | };
55 | ```
56 |
57 | See the parameter [umi-plugin-react#dynamicImport](/plugin/umi-plugin-react.html#dynamicimport) for details.
58 |
59 | ## Static Resources in Non-Root Directory or CDN
60 |
61 | At this point, you need to configure [publicPath](/config/#publicPath). As for publicPath, what? Look at the [webpack documentation](https://webpack.js.org/configuration/output/#output-publicpath) and point it to the path where the static resources (js, css, images, fonts, etc.) are located.
62 |
63 | ```js
64 | export default {
65 | publicPath: "http://yourcdn/path/to/static/"
66 | }
67 | ```
68 |
69 | ## Using the publicPath of Runtime
70 |
71 | For scenes that need to manage publicPath in html, such as judging the environment to make different output in html, you can solve it by configuring [runtimePublicPath](/config/#history).
72 |
73 | ```bash
74 | export default {
75 | runtimePublicPath: true,
76 | };
77 | ```
78 |
79 | Then output in html:
80 |
81 | ```html
82 |
85 | ```
86 |
87 | ## Static
88 |
89 | In some scenarios, you can't do html fallback on the server side, that is, let each route output the contents of index.html, then it needs to be static.
90 |
91 | For example, in the above example, we configured in .umirc.js:
92 |
93 | ```js
94 | export default {
95 | exportStatic: {},
96 | }
97 | ```
98 |
99 | Then execute the umi build and output an html file for each route.
100 |
101 | ```
102 | ./dist
103 | ├── index.html
104 | ├── list
105 | │ └── index.html
106 | └── static
107 | ├── pages__index.5c0f5f51.async.js
108 | ├── pages__list.f940b099.async.js
109 | ├── umi.2eaebd79.js
110 | └── umi.f4cb51da.css
111 | ```
112 |
113 | > Note: Statics does not support scenarios with variable routing.
114 |
115 | ## HTML Suffix
116 |
117 | In some static scenarios, the index file is not automatically read, such as Alipay's container environment, then this html file cannot be generated.
118 |
119 | ```
120 | ├── index.html
121 | ├── list
122 | │ └── index.html
123 | ```
124 |
125 | But generate,
126 |
127 | ```
128 | ├── index.html
129 | └── list.html
130 | ```
131 |
132 | The configuration is in .umirc.js,
133 |
134 | ```js
135 | export default {
136 | exportStatic: {
137 | htmlSuffix: true,
138 | },
139 | }
140 | ```
141 |
142 | Umi build will generate,
143 |
144 | ```
145 | ./dist
146 | ├── index.html
147 | ├── list.html
148 | └── static
149 | ├── pages__index.5c0f5f51.async.js
150 | ├── pages__list.f940b099.async.js
151 | ├── umi.2924fdb7.js
152 | └── umi.cfe3ffab.css
153 | ```
154 |
155 | ## Statically Output to Any Path
156 |
157 | ```js
158 | export default {
159 | exportStatic: {
160 | htmlSuffix: true,
161 | dynamicRoot: true,
162 | },
163 | }
164 | ```
165 |
--------------------------------------------------------------------------------
/docs/zh/guide/faq.md:
--------------------------------------------------------------------------------
1 | ---
2 | sidebarDepth: 3
3 | ---
4 |
5 | # FAQ
6 |
7 | ## General
8 |
9 | ### 是否可用于生产环境?
10 |
11 | umi 是蚂蚁金服的底层前端框架,已直接或间接地服务了 600+ 应用,包括 java、node、H5 无线、离线(Hybrid)应用、纯前端 assets 应用、CMS 应用等。
12 |
13 | ### 如何查看 react、react-dom、react-router 等版本号?
14 |
15 | ```bash
16 | $ umi -v --verbose
17 |
18 | umi@2.0.0
19 | darwin x64
20 | node@v10.6.0
21 | umi-build-dev@1.0.0
22 | af-webpack@1.0.0
23 | babel-preset-umi@1.0.0
24 | umi-test@1.0.0
25 | react@16.4.2 (/Users/chencheng/code/github.com/ant-design/ant-design-pro/node_modules/react)
26 | react-dom@16.4.2 (/Users/chencheng/code/github.com/ant-design/ant-design-pro/node_modules/react-dom)
27 | react-router@4.3.1 (/Users/chencheng/code/github.com/umijs/umi/packages/umi-build-dev/node_modules/react-router)
28 | react-router-dom@4.3.1 (/Users/chencheng/code/github.com/ant-design/ant-design-pro/node_modules/react-router-dom)
29 | dva@2.4.0 (/Users/chencheng/code/github.com/ant-design/ant-design-pro/node_modules/dva)
30 | dva-loading@2.0.5
31 | dva-immer@0.2.3
32 | path-to-regexp@1.7.0
33 | ```
34 |
35 | ### 如何引入 @babel/polyfill ?
36 |
37 | 先安装依赖,
38 |
39 | ```bash
40 | $ yarn add @babel/polyfill
41 | ```
42 |
43 | 然后新建 `src/global.js`,内容如下:
44 |
45 | ```js
46 | import '@babel/polyfill';
47 | ```
48 |
49 | ### 如何动态修改 title ?
50 |
51 | 可以通过 [react-helmet](https://github.com/nfl/react-helmet) 动态修改 title 。
52 | > 注意:在混合应用中,ios端web容器内,使用react-helmet失效的话,可以尝试使用[react-document-title](https://github.com/gaearon/react-document-title)。
53 |
54 | ## 报错
55 |
56 | ### `Object.values` is not a function
57 |
58 | e.g.
59 |
60 |
61 |
62 | 升级 node 版本,并确保版本是 8.10 或以上。
63 |
64 | ### `exports is not defined`
65 |
66 | e.g.
67 |
68 |
69 |
70 | 检查 babel 配置,删除不必要的 preset 和 plugin 。
71 |
72 | ### `Plugin umi-plugin-react:pwa initialize failed`
73 |
74 | e.g.
75 |
76 |
77 |
78 | 确保有 package.json 并配置 `name` 属性。
79 |
80 | ### `Conflicting order between [mini-css-extract-plugin]`
81 |
82 | e.g.
83 |
84 |
85 |
86 | 这是 [webpack 插件的问题](https://github.com/webpack-contrib/mini-css-extract-plugin/issues/250),不会影响 CSS 文件的正常生产,可暂时忽略。
87 |
88 | ### `umi` 不是内部或外部命令
89 |
90 | e.g.
91 |
92 |
93 |
94 | 需配置 NODE_PATH 环境变量,如使用 yarn,可通过执行 `yarn global bin` 拿到 bin 路径。
95 |
96 | ## webpack
97 |
98 | ### 如何配置额外的 loader ?
99 |
100 | 比如 svg 我希望不走 base64,而是全部产生 svg 文件,可以这样配:
101 |
102 | ```js
103 | export default {
104 | // 添加 url-loader 的 exclude
105 | urlLoaderExcludes: [/.svg$/],
106 | // 添加 loader
107 | chainWebpack(config) {
108 | config.module.rule('svg-with-file')
109 | .test(/.svg$/)
110 | .use('svg-with-file-loader')
111 | .loader('file-loader')
112 | },
113 | }
114 | ```
115 |
116 | ## CSS
117 |
118 | ### 为啥我 import 的 css 文件不生效?
119 |
120 | umi 默认是开启 css modules 的,请按照 css modules 的方式进行书写。
121 |
122 | 参考:
123 |
124 | * [css-modules/css-modules](https://github.com/css-modules/css-modules)
125 | * [CSS Modules 用法教程](http://www.ruanyifeng.com/blog/2016/06/css_modules.html)
126 |
127 | ### 如何禁用 css modules ?
128 |
129 | 修改 `.umirc.js`:
130 |
131 | ```json
132 | {
133 | "disableCSSModules": true
134 | }
135 | ```
136 |
137 | 但没有特殊的理由时,不建议关闭 css modules。
138 |
139 | ### 如何使用 sass ?
140 |
141 | 先安装额外的依赖,
142 |
143 | ```bash
144 | $ npm i node-sass sass-loader --save
145 | ```
146 |
147 | 然后修改 `.umirc.js`:
148 |
149 | ```json
150 | {
151 | "sass": {}
152 | }
153 | ```
154 |
155 | ## Test
156 |
157 | ### 如何断点调试
158 |
159 | 确保 node 在 8.10 以上,然后执行:
160 |
161 | ```bash
162 | $ node --inspect-brk ./node_modules/.bin/umi test
163 | ```
164 |
165 | 然后在浏览器里打开 chrome://inspect/#devices 进行 inspect 和断点。
166 |
167 | ## 部署
168 |
169 | ### build 后访问路由刷新后 404?
170 |
171 | 几个方案供选择:
172 |
173 | * 改用 hashHistory,在 `.umirc.js` 里配 `history: 'hash'`
174 | * 静态化,在 `.umirc.js` 里配 `exportStatic: true`
175 | * 服务端配置路由 fallback 到 index.html
176 |
177 | ### build之后图片丢失?
178 |
179 | 可能是图片没有正确引用,可以参考一下代码,正确引入图片。
180 |
181 | ```js
182 | import React from 'react';
183 | import logo from './logo.png'; // 告诉WebPACK这个JS文件使用这个图像
184 |
185 | console.log(logo); // logo.84287d09.png
186 |
187 | function Header() {
188 | // 导入图片
189 | return ;
190 | }
191 |
192 | export default Header;
193 |
194 | ```
195 | 在css中使用,注意不要使用绝对路径
196 | ```css
197 | .Logo {
198 | background-image: url(./logo.png);
199 | }
200 | ```
201 |
202 | > 注意:图片大小小于 10 k 时会走 base64。即不会被拷贝到 public 文件夹下,而是以 base64 的资源存在。
203 |
--------------------------------------------------------------------------------
/docs/guide/mock-data.md:
--------------------------------------------------------------------------------
1 | # Mock Data
2 |
3 | Mock data is indispensable in front-end development process and it is the key link to separate the front-end from the back-end. Through the pre-agreed interface with the server-side, simulation request data and even logic, can make the front-end development independent, will not be blocked by the development of the server-side.
4 |
5 | ## Using the mock feature of umi
6 |
7 | Umi agreed that the files under the mock folder are mock files, files export interface definitions, support for real-time refresh based on 'require' dynamic analysis, support for ES6 syntax, and with friendly error messages, see [mock-data](https://umijs.org/guide/mock-data.html) for more detail.
8 |
9 | ```js
10 | export default {
11 | // supported values are Object and Array
12 | 'GET /api/users': { users: [1, 2] },
13 |
14 | // GET and POST can be omitted
15 | '/api/users/1': { id: 1 },
16 |
17 | // support for custom functions, APIs refer to express@4
18 | 'POST /api/users/create': (req, res) => { res.end('OK'); },
19 | };
20 | ```
21 |
22 | When a client(browser) sends a request, such as `GET /api/users`, the locally launched `umi dev` will match the request path and method with this configuration file, if it find a match, the request will be processed through configuration, just like the sample, you can directly return the data, or process and redirect it to another server through a function.
23 |
24 | For example, define the following mapping rules as below:
25 |
26 | ```
27 | 'GET /api/currentUser': {
28 | name: 'momo.zxy',
29 | avatar: imgMap.user,
30 | userid: '00000001',
31 | notifyCount: 12,
32 | },
33 | ```
34 |
35 | Request local interface `/api/users`:
36 |
37 | Request header
38 |
39 |
40 |
41 | Response data
42 |
43 |
44 |
45 | ### Introduce Mock.js
46 |
47 | [Mock.js](http://mockjs.com/) is a commonly used third-party library to help generate mock data. Of course, you can use any library you like working with roadhog to build data simulation functions.
48 |
49 | ```js
50 | import mockjs from 'mockjs';
51 |
52 | export default {
53 | // Use third-party library such as mockjs
54 | 'GET /api/tags': mockjs.mock({
55 | 'list|100': [{ name: '@city', 'value|1-100': 50, 'type|0-2': 1 }],
56 | }),
57 | };
58 | ```
59 |
60 | ### Add a cross-domain request header
61 |
62 | Just set the header of `response`:
63 |
64 | ```
65 | 'POST /api/users/create': (req, res) => {
66 | ...
67 | res.setHeader('Access-Control-Allow-Origin', '*');
68 | ...
69 | },
70 | ```
71 |
72 | ## Properly split your mock file
73 |
74 | For the entire system, the request interface is complex and numerous, in order to handle a large number of mock request scenarios, we usually abstract each data model into a file, and put them all in the `mock` folder. And then they will be automatically introduced.
75 |
76 |
77 |
78 | ## How to simulate delay
79 |
80 | In order to simulate the network data request more realistically, it is necessary to simulate network delay time in most cases.
81 |
82 | ### Add setTimeout manually to simulate delay
83 |
84 | You can rewrite the proxy method of the request and add the processing of simulation delay to it, like:
85 |
86 | ```js
87 | 'POST /api/forms': (req, res) => {
88 | setTimeout(() => {
89 | res.send('Ok');
90 | }, 1000);
91 | },
92 | ```
93 |
94 | ### Use plugins to simulate delay
95 |
96 | Although the method above is simple, it may be troublesome when you need to add delays for all request, it can be simplified by a third-party plugin,such as [roadhog-api-doc#delay](https://github.com/nikogu/roadhog-api-doc/blob/master/lib/utils.js#L5).
97 |
98 | ```js
99 | import { delay } from 'roadhog-api-doc';
100 |
101 | const proxy = {
102 | 'GET /api/project/notice': getNotice,
103 | 'GET /api/activities': getActivities,
104 | 'GET /api/rule': getRule,
105 | 'GET /api/tags': mockjs.mock({
106 | 'list|100': [{ name: '@city', 'value|1-100': 50, 'type|0-2': 1 }]
107 | }),
108 | 'GET /api/fake_list': getFakeList,
109 | 'GET /api/fake_chart_data': getFakeChartData,
110 | 'GET /api/profile/basic': getProfileBasicData,
111 | 'GET /api/profile/advanced': getProfileAdvancedData,
112 | 'POST /api/register': (req, res) => {
113 | res.send({ status: 'ok' });
114 | },
115 | 'GET /api/notices': getNotices,
116 | };
117 |
118 | // Calling the delay function, unified processing
119 | export default delay(proxy, 1000);
120 | ```
121 |
122 | ## Joint debugging
123 |
124 | After finishing the local development, if the interface of server-side meets the previous convention, you only need to open the local proxy or redirect the proxy to the target server to access the real server data, which is very convenient.
125 |
--------------------------------------------------------------------------------
/docs/guide/app-structure.md:
--------------------------------------------------------------------------------
1 | # Directory and Convention
2 |
3 | In the organization of files and directories, umi tries to choose the agreed upon way.
4 |
5 | The directory structure of a complex application is as follows:
6 |
7 | ```
8 | .
9 | ├── dist/ // default build output directory
10 | ├── mock/ // The directory where the mock file is located, based on express
11 | ├── config/
12 | ├── config.js // umi configuration, same as .umirc.js, choose one
13 | └── src/ // source directory, optional
14 | ├──layouts/index.js // global layout
15 | ├── pages/ // page directory, the file inside is the route
16 | ├── .umi/ // dev temp directory, need to be added to .gitignore
17 | ├── .umi-production/ // build temporary directory, will be deleted automatically
18 | ├── document.ejs // HTML template
19 | ├── 404.js // 404 page
20 | ├── page1.js // page 1, arbitrarily named, export react component
21 | ├── page1.test.js // Use case file, umi test will match all files ending in .test.js and .e2e.js
22 | └── page2.js // page 2, arbitrarily named
23 | ├── global.css // Conventional global style files, imported automatically, or global.less
24 | ├── global.js // can add polyfill here
25 | ├── .umirc.js // umi configuration, same as config/config.js, choose one
26 | ├── .env // environment variable
27 | └── package.json
28 | ```
29 |
30 | ## ES6 Grammar
31 |
32 | Configuration files, mock files, etc. are registered in real time with `@babel/register`, so you can use ES6 syntax and es modules just like files in src.
33 |
34 | ## dist
35 |
36 | The default output path can be modified by configuring `outputPath`.
37 |
38 | ## mock
39 |
40 | It is agreed that all `.js` files in the mock directory will be parsed as mock files.
41 |
42 | For example, create a new `mock/users.js` with the following contents:
43 |
44 | ```js
45 | export default {
46 | '/api/users': ['a', 'b'],
47 | }
48 | ```
49 |
50 | Then visit [http://localhost:8000/api/users](http://localhost:8000/api/users) in your browser to see `['a', 'b']`.
51 |
52 | ## src
53 |
54 | By convention, `src` is the source directory. But optional, simple items can be added without the `src` directory.
55 |
56 | For example: the effect of the following two directory structures is the same.
57 |
58 | ```
59 | + src
60 | + pages
61 | - index.js
62 | + layouts
63 | - index.js
64 | - .umirc.js
65 | ```
66 |
67 | ```
68 | + pages
69 | - index.js
70 | + layouts
71 | - index.js
72 | - .umirc.js
73 | ```
74 |
75 | ## src/layouts/index.js
76 |
77 | The global layout is actually a layer outside the route.
78 |
79 | For example, your route is:
80 |
81 | ```
82 | [
83 | { path: '/', component: './pages/index' },
84 | { path: '/users', component: './pages/users' },
85 | ]
86 | ```
87 |
88 | If there is `layouts/index.js`, then the route becomes:
89 |
90 | ```
91 | [
92 | { path: '/', component: './layouts/index', routes: [
93 | { path: '/', component: './pages/index' },
94 | { path: '/users', component: './pages/users' },
95 | ] }
96 | ]
97 | ```
98 |
99 | ## src/pages
100 |
101 | All the `(j|t)sx?` files under the pages are the routes. For more information on contracted routing, go to the Routing chapter.
102 |
103 | ## src/pages/404.js
104 |
105 | 404 page. Note that there is a 404 prompt page provided by the built-in umi in development mode, so you can access this page only by explicitly accessing `/404`.
106 |
107 | ## src/pages/document.ejs
108 |
109 | When this file is available, it overrides the default HTML template. Needs to include at least the following code:
110 |
111 | ```html
112 |
113 | ```
114 |
115 | ## src/pages/.umi
116 |
117 | This is a temporary directory produced by umi dev. It contains `umi.js` and `router.js` by default, and some plugins will generate some other temporary files here. You can do some validation here, **but please don't modify the code directly here, umi restart or file modification under pages will regenerate the files in this folder.**
118 |
119 | ## src/pages/.umi-production
120 |
121 | Same as `src/pagers/.umi`, but generated in `umi build`, it will be automatically deleted after `umi build`.
122 |
123 | ## .test.js and .e2e.js
124 |
125 | The test file, `umi test` will find all the .(test|e2e).(j|t)s files to run the test.
126 |
127 | ## src/global.(j|t)sx?
128 |
129 | At the beginning of the entry file is automatically introduced, you can consider adding polyfill here.
130 |
131 | ## src/global.(css|less|sass|scss)
132 |
133 | This file does not go css modules, is automatically introduced, you can write some global styles, or do some style coverage.
134 |
135 | ## .umirc.js and config/config.js
136 |
137 | Umi's configuration file, choose one.
138 |
139 | ## .env
140 |
141 | Environment variables, such as:
142 |
143 | ```
144 | CLEAR_CONSOLE=none
145 | BROWSER=none
146 | ```
147 |
--------------------------------------------------------------------------------
/docs/guide/with-dva.md:
--------------------------------------------------------------------------------
1 | # Use umi with dva
2 |
3 | As of `>= umi@2`, we recommend using [umi-plugin-react](https://github.com/umijs/umi/tree/master/packages/umi-plugin-react) for `dva` integration.
4 |
5 | ## Features
6 |
7 | * **Model loading by directory**, getting rid of `app.model`
8 | * **File name as namespace**, `namespace` as model key will be exported by `umi`
9 | * **No manually defined router.js**, `umi` will take over the router stuff, and both `model`s and `component`s can be loaded on demand
10 | * **Built-in query-string handler**, manually encoding and decoding URL are not required any more
11 | * **Built-in dva-loading and dva-immer support**, of which `dva-immer` can be enabled via configuration
12 | * **Out of box**, dependencies such as: `dva`, `dva-loading`, `dva-immer`, `path-to-regexp`, `object-assign`, `react`, `react-dom` are built in, so that you don't have to worry about them
13 |
14 | ## Usage
15 |
16 | Install via `yarn`,
17 |
18 | ```bash
19 | $ yarn add umi-plugin-react
20 | ```
21 |
22 | Install via `npm`, using the command `npm install --save umi-plugin-react`.
23 |
24 | Add configuration in `.umirc.js`:
25 |
26 | ```js
27 | export default {
28 | plugins: [
29 | [
30 | 'umi-plugin-react',
31 | {
32 | dva: true,
33 | },.
34 | ]
35 | ],
36 | };
37 | ```
38 |
39 | Enable `dva-immer` for elegant reducer writing experience
40 |
41 | ```js
42 | export default {
43 | plugins: [
44 | [
45 | 'umi-plugin-react',
46 | {
47 | dva: {
48 | immer: true
49 | }
50 | }
51 | ],
52 | ],
53 | };
54 | ```
55 |
56 | ## Registering models
57 |
58 | There are two types of models: the globally registered (global) model, and the page-level model.
59 |
60 | The global model should be defined in `/src/models/`, and can be referenced in all other pages.
61 |
62 | The page-level model should not be used in any other page.
63 |
64 |
65 | Model loading rules:
66 |
67 | * `src/models/**/*.js` are defined as global models
68 | * `src/pages/**/models/**/*.js` are defined as page-level models
69 | * global models will be loaded along with the application; page-level models are loaded on demand while in `production` build (both will always be loaded in `development` build)
70 | * page-level models can be `.js` files in `models/**/*.js` pattern
71 | * page-level models can be scanned upward to app structure, For example: if you have page `.js` like `pages/a/b.js`, its page-level model shall be `pages/a/b/models/**/*.js` + `pages/a/models/**/*.js`...
72 | * if `model.js` is defined, the page should be a single-file-model, which means you don't have to create `modles` directory if you have only one model. So if you have `model.js` defined, all `.js` files defined in `models/**/*.js` will be ignored
73 |
74 | Example:
75 |
76 | ```
77 | + src
78 | + models
79 | - g.js
80 | + pages
81 | + a
82 | + models
83 | - a.js
84 | - b.js
85 | + ss
86 | - s.js
87 | - page.js
88 | + c
89 | - model.js
90 | + d
91 | + models
92 | - d.js
93 | - page.js
94 | - page.js
95 | ```
96 |
97 | With the above file structure:
98 |
99 | * the global model is `src/models/g.js`
100 | * the page-level models for `/a` is `src/pages/a/models/{a,b,ss/s}.js`
101 | * the page-level model for `/c` is `src/pages/c/model.js`
102 | * the page-level models for `/c/d` are `src/pages/c/model.js, src/pages/c/d/models/d.js`
103 |
104 | ## Configuration and plugins
105 |
106 | > The previous configuration in `src/dva.js` has been deprecated, and will remove support in next major release.
107 |
108 | Create a new `app.js` in the `src` directory with the following contents:
109 |
110 | ```js
111 | export const dva = {
112 | config: {
113 | onError(e) {
114 | e.preventDefault();
115 | console.error(e.message);
116 | },
117 | },
118 | plugins: [
119 | require('dva-logger')(),
120 | ],
121 | };
122 | ```
123 |
124 | ## FAQ
125 |
126 | ### Page component is not re-rendered whenever url changed?
127 |
128 | If you have `connect` data in `layouts/index.js`, `umi/withRouter` is required
129 |
130 | ```js
131 | import withRouter from 'umi/withRouter';
132 |
133 | export default withRouter(connect(mapStateToProps)(LayoutComponent));
134 | ```
135 |
136 | ### How to access `store` or `dispatch`?
137 |
138 | ```js
139 | window.g_app._store
140 | window.g_app._store.dispatch
141 | ```
142 |
143 | ### How to disable load on demand for `component` and `models`?
144 |
145 | Add config to `.umirc.js`:
146 |
147 | ```js
148 | export default {
149 | plugins: [
150 | [
151 | 'umi-plugin-react',
152 | {
153 | dva: {
154 | dynamicImport: undefined // config in dva
155 | },
156 | dynamicImport: undefined // root config will be inherited as well
157 | }
158 | ],
159 | ],
160 | };
161 | ```
162 |
163 | ### Page component is not re-rendered whenever url is changed while `connect` data in `layout`
164 |
165 | Check the order of `connect`, `withRouter` usage
166 |
167 | ```js
168 | import withRouter from 'umi/withRouter';
169 | export default withRouter(connect()(Layout));
170 | ```
171 |
172 | ## References
173 |
174 | * [Improve dva project with umi](https://github.com/sorrycc/blog/issues/66)
175 | * [umi + dva, write your own user-management CURD app](https://github.com/sorrycc/blog/issues/62)
176 |
--------------------------------------------------------------------------------
/docs/plugin/umi-plugin-react.md:
--------------------------------------------------------------------------------
1 | ---
2 | sidebarDepth: 3
3 | ---
4 |
5 | # umi-plugin-react
6 |
7 | This is a collection of officially packaged plugins with 13 commonly used advanced features.
8 |
9 | ## Install
10 |
11 | ```bash
12 | $ yarn add umi-plugin-react --dev
13 | ```
14 |
15 | ## Usage
16 |
17 | Configured in `.umirc.js`:
18 |
19 | ```js
20 | export default {
21 | plugins: [
22 | ['umi-plugin-react', {
23 | dva: {
24 | immer: true,
25 | },
26 | antd: true,
27 | routes: {
28 | exclude: [/models\//],
29 | },
30 | polyfills: ['ie9'],
31 | locale: {},
32 | library: 'react',
33 | dynamicImport: {
34 | webpackChunkName: true,
35 | loadingComponent: './components/Loading.js',
36 | },
37 | dll: {
38 | exclude: [],
39 | },
40 | hardSource: true,
41 | pwa: true,
42 | hd: true,
43 | fastClick: true,
44 | title: 'default title',
45 | }],
46 | ],
47 | };
48 | ```
49 |
50 | ## Configuration items
51 |
52 | All features are turned off by default and will be enabled if there is a true value.
53 |
54 | ### dva
55 |
56 | * Type: `Object`
57 |
58 | Based on [umi-plugin-dva](https://github.com/umijs/umi/tree/master/packages/umi-plugin-dva), see the details at [Use with dva](/guide/with-dva.html)。
59 |
60 | Configuration items includes:
61 |
62 | * `immer`, Whether to enable [dva-immer](https://github.com/dvajs/dva/tree/master/packages/dva-immer)
63 | * `dynamicImport`, Whether to enable dynamic import, options same as [#dynamicImport](#dynamicImport), and if you configure it in [#dynamicImport](#dynamicImport), the options items will be inherited into dva
64 | * `hmr`, Whether to enable dva hmr
65 |
66 | ::: warning
67 | If there is a dva dependency in the project, the dependencies in the project are prioritized.
68 | :::
69 |
70 | ### antd
71 |
72 | * Type: `Boolean`
73 |
74 | Automatically configure [babel-plugin-import](https://github.com/ant-design/babel-plugin-import) to enable on-demand compilation of antd and antd-mobile, with built-in antd and antd-mobile dependencies, There is no need to manually install in the project.
75 |
76 | ::: warning
77 | If there is an ant or antd-mobile dependency in the project, the dependencies in the project are prioritized.
78 | :::
79 |
80 | ### routes
81 |
82 | * Type: `Object`
83 |
84 | based on [umi-plugin-routes](https://github.com/umijs/umi/tree/master/packages/umi-plugin-routes), used to modify routes in batches.
85 |
86 | options include:
87 |
88 | * `exclude`, type is `Array(RegExp)`, used to ignore certain routes, such as using dva, usually need to ignore the models, components, services, etc.
89 | * `update`, type is `Function`, for update routes.
90 |
91 | ### polyfills
92 |
93 | * Type: `Array(String)`
94 |
95 | Based on [umi-plugin-polyfills](https://github.com/umijs/umi/tree/master/packages/umi-plugin-polyfills), used to add polyfills.
96 |
97 | Currently supports configuration of `['ie9']`, `['ie10']` or `['ie11']` for quickly compatibility.
98 |
99 | ### locale
100 |
101 | * Type `Object`
102 |
103 | Based on [umi-plugin-locale](https://github.com/umijs/umi/tree/master/packages/umi-plugin-locale) and [react-intl](https://github.com/yahoo/react-intl), used to resolve internationalization.
104 |
105 | options include:
106 |
107 | * `default`: 'zh-CN', // default zh-CN
108 | * `baseNavigator`: true, // default true, when it is true, will use `navigator.language` overwrite default
109 | * `antd`: true, // use antd, default is true
110 |
111 | ### library
112 |
113 | * Type: `String`
114 |
115 | It is possible to switch the underlying library to either preact or react.
116 |
117 | ### dynamicImport
118 |
119 | * Type: `Object`
120 |
121 | Implement routing-level code splitting, which specifies which level of on-demand loading is required.
122 |
123 | options include:
124 |
125 | * `webpackChunkName`, Whether to add a meaningful file name
126 | * `loadingComponent`, Specify the component path at load time
127 | * `level`, specifying the route level to code splitting
128 |
129 | ### dll
130 |
131 | * Type: `Object`
132 |
133 | Increase the second startup speed by webpack dll plugin.
134 |
135 | options include:
136 |
137 | * `include`
138 | * `exclude`
139 |
140 | ### hardSource
141 |
142 | * Type: `Boolean`
143 |
144 | Open webpack cache with [hard-source-webpack-plugin](https://github.com/mzgoddard/hard-source-webpack-plugin), 80% increase in speed of the second start. It is recommended to use non-windows computers. Due to the slowness of large file IO under Windows, it is up to you to decide whether to enable it.
145 |
146 | ### pwa
147 |
148 | * Type `Object`
149 |
150 | Enable pwa 。
151 |
152 | ### hd
153 |
154 | * Type `Boolean`
155 |
156 | Turn on the HD solution.
157 |
158 | ### fastClick
159 |
160 | * Type `Boolean`
161 |
162 | Enable fastClick.
163 |
164 | ### title
165 |
166 | * Type `String` or `Object`
167 |
168 | Enable title plugin for set HTML title:
169 |
170 | options include:
171 |
172 | * `defaultTitle`: 'default tile', // required, when option type is String, will use option as the default title
173 | * `format`: '{parent}{separator}{current}', // default {parent}{separator}{current}, title format
174 | * `separator`: ' - ', // default ' - '
175 |
176 | When the title plugin is enabled you can configure the title in the route configuration or in the page component in pages folder.
177 |
178 | For example:
179 |
180 | ```js
181 | // .umirc.js or config/config.js
182 | export default {
183 | routes: [{
184 | path: '/testpage',
185 | component: './testpage',
186 | title: 'test page',
187 | }],
188 | }
189 | ```
190 |
191 | or
192 |
193 | ```jsx
194 | /**
195 | * title: test page
196 | */
197 | export default () => {
198 | return testpage
;
199 | }
200 | ```
201 |
--------------------------------------------------------------------------------
/docs/guide/faq.md:
--------------------------------------------------------------------------------
1 | ---
2 | sidebarDepth: 3
3 | ---
4 |
5 | # FAQ
6 |
7 | ## General
8 |
9 | ### Can it be used in a production environment?
10 |
11 | Umi is the underlying front-end framework of Ant Financial, which has directly or indirectly served 600+ applications, including java, node, H5 wireless, Hybrid applications, pure front-end assets applications, CMS applications, and more.
12 |
13 | ### How do I view the version numbers such as react, react-dom, and react-router?
14 |
15 | ```bash
16 | $ umi -v --verbose
17 |
18 | umi@2.0.0
19 | darwin x64
20 | node@v10.6.0
21 | umi-build-dev@1.0.0
22 | af-webpack@1.0.0
23 | babel-preset-umi@1.0.0
24 | umi-test@1.0.0
25 | react@16.4.2 (/Users/chencheng/code/github.com/ant-design/ant-design-pro/node_modules/react)
26 | react-dom@16.4.2 (/Users/chencheng/code/github.com/ant-design/ant-design-pro/node_modules/react-dom)
27 | react-router@4.3.1 (/Users/chencheng/code/github.com/umijs/umi/packages/umi-build-dev/node_modules/react-router)
28 | react-router-dom@4.3.1 (/Users/chencheng/code/github.com/ant-design/ant-design-pro/node_modules/react-router-dom)
29 | dva@2.4.0 (/Users/chencheng/code/github.com/ant-design/ant-design-pro/node_modules/dva)
30 | dva-loading@2.0.5
31 | dva-immer@0.2.3
32 | path-to-regexp@1.7.0
33 | ```
34 |
35 | ### How to introduce @babel/polyfill?
36 |
37 | Install dependencies first,
38 |
39 | ```bash
40 | $ yarn add @babel/polyfill
41 | ```
42 |
43 | Then create a new `src/global.js` with the following contents:
44 |
45 | ```js
46 | import '@babel/polyfill';
47 | ```
48 |
49 | ### How to dynamically modify the title?
50 |
51 | The title can be dynamically modified via [react-helmet](https://github.com/nfl/react-helmet).
52 | > Note: In a hybrid application, if you use react-helmet in the ios web container, you can try [react-document-title](https://github.com/gaearon/react-document-title).
53 |
54 | ## Reporting Error
55 |
56 | ### `Object.values` is not a function
57 |
58 | E.g.
59 |
60 |
61 |
62 | Upgrade the node version and make sure the version is 8.10 or greater.
63 |
64 | ### `exports is not defined`
65 |
66 | E.g.
67 |
68 |
69 |
70 | Check the babel configuration to remove unnecessary presets and plugins.
71 |
72 | ### `Plugin umi-plugin-react:pwa initialize failed`
73 |
74 | E.g.
75 |
76 |
77 |
78 | Make sure you have package.json and have configured the `name` attribute.
79 |
80 | ### `Conflicting order between [mini-css-extract-plugin]`
81 |
82 | E.g.
83 |
84 |
85 |
86 | This is [a problem with the webpack plugin](https://github.com/webpack-contrib/mini-css-extract-plugin/issues/250), which does not affect the normal production of CSS files and can be ignored for now.
87 |
88 | ### `umi` is not an internal or external command
89 |
90 | E.g.
91 |
92 |
93 |
94 | You need to configure the NODE_PATH environment variable. If you use yarn, you can get the bin path by executing `yarn global bin`.
95 |
96 | ## webpack
97 |
98 | ### How to configure additional loader?
99 |
100 | For example, I hope .svg not to produce base64, but to generate svg files, which can be configured like this:
101 |
102 | ```js
103 | export default {
104 | // Add exclude for url-loader
105 | urlLoaderExcludes: [/.svg$/],
106 | // Add loader
107 | chainWebpack(config) {
108 | config.module.rule('svg-with-file')
109 | .test(/.svg$/)
110 | .use('svg-with-file-loader')
111 | .loader('file-loader')
112 | },
113 | }
114 | ```
115 |
116 | ## CSS
117 |
118 | ### Why don't my imported CSS files take effect?
119 |
120 | umi use css modules by default, please write your css as css modules.
121 |
122 | Ref:
123 |
124 | * [css-modules/css-modules](https://github.com/css-modules/css-modules)
125 | * [CSS Modules usage tutorial](http://www.ruanyifeng.com/blog/2016/06/css_modules.html)
126 |
127 | ### How to disable CSS modules?
128 |
129 | Modify `.umirc.js`:
130 |
131 | ```json
132 | {
133 | "disableCSSModules": true
134 | }
135 | ```
136 |
137 | However, it is not recommended to turn off css modules for no particular reason.
138 |
139 | ### How to use sass?
140 |
141 | Install additional dependencies first,
142 |
143 | ```bash
144 | $ npm i node-sass sass-loader --save
145 | ```
146 |
147 | Then modify `.umirc.js`:
148 |
149 | ```json
150 | {
151 | "sass": {}
152 | }
153 | ```
154 |
155 | ## Test
156 |
157 | ### How to do breakpoint debugging?
158 |
159 | Make sure node version is above 8.10 and then execute:
160 |
161 | ```bash
162 | $ node --inspect-brk ./node_modules/.bin/umi test
163 | ```
164 |
165 | Then open chrome://inspect/#devices in the browser for inspect and breakpoints.
166 |
167 | ## Deployment
168 |
169 | ### After the build access route is refreshed 404?
170 |
171 | Several options are available:
172 |
173 | * Use `hashHistory` instead of `history: 'hash' in `.umirc.js`
174 | * Static, with `exportStatic: true` in `.umirc.js`
175 | * The server configures the route fallback to index.html
176 |
177 | ### After the build, the picture is lost?
178 |
179 | It may be that the picture is not correctly quoted. You can refer to the code and import the picture correctly.
180 |
181 | ```js
182 | import React from 'react';
183 | import logo from './logo.png'; // Tell Webpack this JS file to use this image
184 |
185 | console.log(logo); // logo.84287d09.png
186 |
187 | function header() {
188 | // import image
189 | return ;
190 | }
191 |
192 | export default Header;
193 |
194 | ```
195 | Use in css, be careful not to use absolute paths
196 | ```css
197 | .Logo {
198 | background-image: url(./logo.png);
199 | }
200 | ```
201 |
202 | > Note: base64 will be taken when the image size is less than 10 k. That is, it will not be copied to the public folder, but will be stored as a base64 resource.
203 |
--------------------------------------------------------------------------------
/docs/zh/config/README.md:
--------------------------------------------------------------------------------
1 | ---
2 | sidebarDepth: 2
3 | ---
4 |
5 | # 配置
6 |
7 | ## 基本配置
8 |
9 | ### plugins
10 |
11 | * 类型:`Array`
12 | * 默认值:`[]`
13 |
14 | 指定插件。
15 |
16 | 比如:
17 |
18 | ```js
19 | export default {
20 | plugins: [
21 | 'umi-plugin-react',
22 | // 插件有参数时为数组,数组的第二项是参数,类似 babel 插件
23 | ['umi-plugin-react', {
24 | dva: true,
25 | }],
26 | ],
27 | };
28 | ```
29 |
30 | ### routes
31 |
32 | * 类型:`Array`
33 | * 默认值:`null`
34 |
35 | 配置路由。
36 |
37 | ::: tip 提醒
38 | 如果配置了 `routes`,则约定式路由会不生效。
39 | :::
40 |
41 | ### disableRedirectHoist
42 |
43 | * 类型:`Boolean`
44 | * 默认值:`false`
45 |
46 | 禁用 redirect 上提。
47 |
48 | 出于一些原因的考虑,我们在处理路由时把所有 redirect 声明提到路由最前面进行匹配,但这导致了一些问题,所以添加了这个配置项,禁用 redirect 上提。
49 |
50 | ### history
51 |
52 | * 类型:`String`
53 | * 默认值:`browser`
54 |
55 | 如需切换 history 方式为 hash(默认是 browser history),配置 `history: 'hash'`。
56 |
57 | ### outputPath
58 |
59 | * 类型:`String`
60 | * 默认值:`./dist`
61 |
62 | 指定输出路径。
63 |
64 | ### base
65 |
66 | * 类型:`String`
67 | * 默认值:`/`
68 |
69 | 指定 react-router 的 base,部署到非根目录时需要配置。
70 |
71 | ### publicPath
72 |
73 | * 类型:`String`
74 | * 默认值:`/`
75 |
76 | 指定 webpack 的 publicPath,指向静态资源文件所在的路径。
77 |
78 | ### runtimePublicPath
79 |
80 | * 类型:`Boolean`
81 | * 默认值:`false`
82 |
83 | 值为 `true` 时使用 HTML 里指定的 `window.publicPath`。
84 |
85 | ### mountElementId
86 |
87 | * 类型:`String`
88 | * 默认值:`root`
89 |
90 | 指定 react app 渲染到的 HTML 元素 id。
91 |
92 | ### hash
93 |
94 | * Type: `Boolean`
95 | * Default: `false`
96 |
97 | 是否开启 hash 文件后缀。
98 |
99 | ### targets
100 |
101 | * Type: `Object`
102 | * Default: `{ chrome: 49, firefox: 45, safari: 10, edge: 13, ios: 10 }`
103 |
104 | 配置浏览器最低版本,会自动引入 polyfill 和做语法转换,配置的 targets 会和合并到默认值,所以不需要重复配置。
105 |
106 | 比如要兼容 ie11,需配置:
107 |
108 | ```js
109 | export default {
110 | targets: {
111 | ie: 11,
112 | },
113 | };
114 | ```
115 |
116 | ### context
117 |
118 | * 类型:`Object`
119 | * 默认值:`{}`
120 |
121 | 配置全局 context,会覆盖到每个 pages 里的 context。
122 |
123 | ### exportStatic
124 |
125 | * 类型:`Boolean | Object`
126 | * 默认值:`false`
127 |
128 | 如果设为 `true` 或 `Object`,则导出全部路由为静态页面,否则默认只输出一个 index.html。
129 |
130 | 比如:
131 |
132 | ```
133 | "exportStatic": {}
134 | ```
135 |
136 | ### exportStatic.htmlSuffix
137 |
138 | * 类型:`Boolean`
139 | * 默认值:`false`
140 |
141 | 启用 `.html` 后缀。
142 |
143 | ### exportStatic.dynamicRoot
144 |
145 | * 类型:`Boolean`
146 | * 默认值:`false`
147 |
148 | 部署到任意路径。
149 |
150 | ### singular
151 |
152 | * 类型:`Boolean`
153 | * 默认值:`false`
154 |
155 | 如果设为 `true`,启用单数模式的目录。
156 |
157 | * src/layout/index.js
158 | * src/page
159 | * model(如果有开启 umi-plugin-dva 插件的话)
160 |
161 | ## webpack
162 |
163 | ### chainWebpack
164 |
165 | 通过 [webpack-chain](https://github.com/mozilla-neutrino/webpack-chain) 的 API 扩展或修改 webpack 配置。
166 |
167 | 比如:
168 |
169 | ```js
170 | chainWebpack(config, { webpack }) {
171 | // 设置 alias
172 | config.resolve.alias.set('a', 'path/to/a');
173 |
174 | // 删除进度条插件
175 | config.plugins.delete('progress');
176 | }
177 | ```
178 |
179 | ### theme
180 |
181 | 配置主题,实际上是配 less 变量。支持对象和字符串两种类型,字符串需要指向一个返回配置的文件。
182 | 比如:
183 |
184 | ```
185 | "theme": {
186 | "@primary-color": "#1DA57A"
187 | }
188 | ```
189 |
190 | 或者,
191 |
192 | ```
193 | "theme": "./theme-config.js"
194 | ```
195 |
196 | ### define
197 |
198 | 通过 webpack 的 DefinePlugin 传递给代码,值会自动做 `JSON.stringify` 处理。
199 | 比如:
200 |
201 | ```js
202 | "define": {
203 | "process.env.TEST": 1,
204 | "USE_COMMA": 2,
205 | }
206 | ```
207 |
208 | ### externals
209 |
210 | 配置 webpack 的?[externals](https://webpack.js.org/configuration/externals/)?属性。
211 | 比如:
212 |
213 | ```js
214 | // 配置 react 和 react-dom 不打入代码
215 | "externals": {
216 | "react": "window.React",
217 | "react-dom": "window.ReactDOM"
218 | }
219 | ```
220 |
221 | ### alias
222 |
223 | 配置 webpack 的 [resolve.alias](https://webpack.js.org/configuration/resolve/#resolve-alias) 属性。
224 |
225 | ### browserslist
226 |
227 | 配置 [browserslist](https://github.com/ai/browserslist),同时作用于 babel-preset-env 和 autoprefixer。
228 | 比如:
229 |
230 | ```js
231 | "browserslist": [
232 | "> 1%",
233 | "last 2 versions"
234 | ]
235 | ```
236 |
237 | ### devtool
238 |
239 | 配置 webpack 的 [devtool](https://webpack.js.org/configuration/devtool/) 属性。
240 |
241 | ### disableCSSModules
242 |
243 | 禁用 [CSS Modules](https://github.com/css-modules/css-modules)。
244 |
245 | ### disableCSSSourceMap
246 |
247 | 禁用 CSS 的 SourceMap 生成。
248 |
249 | ### extraBabelPresets
250 |
251 | 定义额外的 babel preset 列表,格式为数组。
252 |
253 | ### extraBabelPlugins
254 |
255 | 定义额外的 babel plugin 列表,格式为数组。
256 |
257 | ### extraBabelIncludes
258 |
259 | 定义额外需要做 babel 转换的文件匹配列表,格式为数组,数组项是 [webpack#Condition](https://webpack.js.org/configuration/module/#condition)。
260 |
261 | ### extraPostCSSPlugins
262 |
263 | 定义额外的 PostCSS 插件,格式为数组。
264 |
265 | ### cssModulesExcludes
266 |
267 | 指定项目目录下的文件不走 css modules,格式为数组,项必须是 css 或 less 文件。
268 |
269 | ### copy
270 |
271 | 定义需要单纯做复制的文件列表,格式为数组,项的格式参考 [copy-webpack-plugin](https://github.com/webpack-contrib/copy-webpack-plugin) 的配置。
272 |
273 | 比如:
274 |
275 | ```markup
276 | "copy": [
277 | {
278 | "from": "",
279 | "to": ""
280 | }
281 | ]
282 | ```
283 |
284 | ### proxy
285 |
286 | 配置 webpack-dev-server 的 [proxy](https://webpack.js.org/configuration/dev-server/#devserver-proxy) 属性。
287 | 如果要代理请求到其他服务器,可以这样配:
288 |
289 | ```markup
290 | "proxy": {
291 | "/api": {
292 | "target": "http://jsonplaceholder.typicode.com/",
293 | "changeOrigin": true,
294 | "pathRewrite": { "^/api" : "" }
295 | }
296 | }
297 | ```
298 |
299 | 然后访问?`/api/users`?就能访问到?[http://jsonplaceholder.typicode.com/users](http://jsonplaceholder.typicode.com/users)?的数据。
300 |
301 | ### sass
302 |
303 | 配置 [node-sass](https://github.com/sass/node-sass#options) 的选项。注意:使用 sass 时需在项目目录安装 node-sass 和 sass-loader 依赖。
304 |
305 | ### manifest
306 |
307 | 配置后会生成 manifest.json,option 传给 [https://www.npmjs.com/package/webpack-manifest-plugin](https://www.npmjs.com/package/webpack-manifest-plugin)。
308 | 比如:
309 |
310 | ```markup
311 | "manifest": {
312 | "basePath": "/app/"
313 | }
314 | ```
315 |
316 | ### ignoreMomentLocale
317 |
318 | 忽略 moment 的 locale 文件,用于减少尺寸。
319 |
320 | ### lessLoaderOptions
321 |
322 | 给 [less-loader](https://github.com/webpack-contrib/less-loader) 的额外配置项。
323 |
324 | ### cssLoaderOptions
325 |
326 | 给 [css-loader](https://github.com/webpack-contrib/css-loader) 的额外配置项。
327 |
--------------------------------------------------------------------------------
/docs/zh/guide/router.md:
--------------------------------------------------------------------------------
1 | ---
2 | sidebarDepth: 3
3 | ---
4 |
5 | # 路由
6 |
7 | ::: tip 提示
8 | 下文介绍的路由使用可以在 [umi-examples/routes](https://github.com/umijs/umi-examples/tree/master/routes) 和 [umi-examples/routes-via-config](https://github.com/umijs/umi-examples/tree/master/routes-via-config) 里找到示例代码。
9 | :::
10 |
11 | umi 会根据 `pages` 目录自动生成路由配置。
12 |
13 | ## 约定式路由
14 |
15 | ### 基础路由
16 |
17 | 假设 `pages` 目录结构如下:
18 |
19 | ```
20 | + pages/
21 | + users/
22 | - index.js
23 | - list.js
24 | - index.js
25 | ```
26 |
27 | 那么,umi 会自动生成路由配置如下:
28 |
29 | ```js
30 | [
31 | { path: '/', component: './pages/index.js' },
32 | { path: '/users/', component: './pages/users/index.js' },
33 | { path: '/users/list', component: './pages/users/list.js' },
34 | ]
35 | ```
36 |
37 | ### 动态路由
38 |
39 | umi 里约定,带 `$` 前缀的目录或文件为动态路由。
40 |
41 | 比如以下目录结构:
42 |
43 | ```
44 | + pages/
45 | + $post/
46 | - index.js
47 | - comments.js
48 | + users/
49 | $id.js
50 | - index.js
51 | ```
52 |
53 | 会生成路由配置如下:
54 |
55 | ```js
56 | [
57 | { path: '/', component: './pages/index.js' },
58 | { path: '/users/:id', component: './pages/users/$id.js' },
59 | { path: '/:post/', component: './pages/$post/index.js' },
60 | { path: '/:post/comments', component: './pages/$post/comments.js' },
61 | ]
62 | ```
63 |
64 | ### 可选的动态路由
65 |
66 | umi 里约定动态路由如果带 `$` 后缀,则为可选动态路由。
67 |
68 | 比如以下结构:
69 |
70 | ```
71 | + pages/
72 | + users/
73 | - $id$.js
74 | - index.js
75 | ```
76 |
77 | 会生成路由配置如下:
78 |
79 | ```js
80 | [
81 | { path: '/': component: './pages/index.js' },
82 | { path: '/users/:id?': component: './pages/users/$id$.js' },
83 | ]
84 | ```
85 |
86 | ### 嵌套路由
87 |
88 | umi 里约定目录下有 `_layout.js` 时会生成嵌套路由,以 `_layout.js` 为该目录的 layout 。
89 |
90 | 比如以下目录结构:
91 |
92 | ```
93 | + pages/
94 | + users/
95 | - _layout.js
96 | - $id.js
97 | - index.js
98 | ```
99 |
100 | 会生成路由配置如下:
101 |
102 | ```js
103 | [
104 | { path: '/users': component: './pages/users/_layout.js'
105 | routes: [
106 | { path: '/users/', component: './pages/users/index.js' },
107 | { path: '/users/:id', component: './pages/users/$id.js' },
108 | ],
109 | },
110 | ]
111 | ```
112 |
113 | ### 全局 layout
114 |
115 | 约定 `src/layouts/index.js` 为全局路由,返回一个 React 组件,通过 `props.children` 渲染子组件。
116 |
117 | 比如:
118 |
119 | ```js
120 | export default function(props) {
121 | return (
122 | <>
123 |
124 | { props.children }
125 |
126 | >
127 | );
128 | }
129 | ```
130 |
131 | ### 不同的全局 layout
132 |
133 | 你可能需要针对不同路由输出不同的全局 layout,umi 不支持这样的配置,但你仍可以在 `layouts/index.js` 对 location.path 做区分,渲染不同的 layout 。
134 |
135 | 比如想要针对 /login 输出简单布局,
136 |
137 | ```js
138 | export default function(props) {
139 | if (props.location.pathname === '/login') {
140 | return { props.children }
141 | }
142 |
143 | return (
144 | <>
145 |
146 | { props.children }
147 |
148 | >
149 | );
150 | }
151 | ```
152 |
153 | ### 404 路由
154 |
155 | 约定 `pages/404.js` 为 404 页面,需返回 React 组件。
156 |
157 | 比如:
158 |
159 | ```js
160 | export default () => {
161 | return (
162 | I am a customized 404 page
163 | );
164 | };
165 | ```
166 |
167 | > 注意:开发模式下,umi 会添加一个默认的 404 页面来辅助开发,但你仍然可通过精确地访问 `/404` 来验证 404 页面。
168 |
169 | ### 通过注释扩展路由
170 |
171 | 约定路由文件的首个注释如果包含 **yaml** 格式的配置,则会被用于扩展路由。
172 |
173 | 比如:
174 |
175 | ```
176 | + pages/
177 | - index.js
178 | ```
179 |
180 | 如果 `pages/index.js` 里包含:
181 |
182 | ```js
183 | /**
184 | * title: Index Page
185 | * Routes:
186 | * - ./src/routes/a.js
187 | * - ./src/routes/b.js
188 | */
189 | ```
190 |
191 | 则会生成路由配置:
192 |
193 | ```js
194 | [
195 | { path: '/', component: './index.js',
196 | title: 'Index Page',
197 | Routes: [ './src/routes/a.js', './src/routes/b.js' ],
198 | },
199 | ]
200 | ```
201 |
202 | ## 配置式路由
203 |
204 | 如果你倾向于使用配置式的路由,可以配置 `routes` ,**此配置项存在时则不会对 `src/pages` 目录做约定式的解析**。
205 |
206 | 比如:
207 |
208 | ```js
209 | export default {
210 | routes: [
211 | { path: '/', component: './a' },
212 | { path: '/list', component: './b', Routes: ['./routes/PrivateRoute.js'] },
213 | { path: '/users', component: './users/_layout',
214 | routes: [
215 | { path: '/users/detail', component: './users/detail' },
216 | { path: '/users/:id', component: './users/id' }
217 | ]
218 | },
219 | ],
220 | };
221 | ```
222 |
223 | 注意:
224 |
225 | 1. component 是相对于 `src/pages` 目录的
226 |
227 | ## 权限路由
228 |
229 | umi 的权限路由是通过配置路由的 `Routes` 属性来实现。约定式的通过 yaml 注释添加,配置式的直接配上即可。
230 |
231 | 比如有以下配置:
232 |
233 | ```js
234 | [
235 | { path: '/', component: './pages/index.js' },
236 | { path: '/list', component: './pages/list.js', Routes: ['./routes/PrivateRoute.js'] },
237 | ]
238 | ```
239 |
240 | 然后 umi 会用 `./routes/PrivateRoute.js` 来渲染 `/list`。
241 |
242 | `./routes/PrivateRoute.js` 文件示例:
243 |
244 | ```js
245 | export default (props) => {
246 | return (
247 |
248 |
PrivateRoute (routes/PrivateRoute.js)
249 | { props.children }
250 |
251 | );
252 | }
253 | ```
254 |
255 | ## 路由动效
256 |
257 | 路由动效应该是有多种实现方式,这里举 [react-transition-group](https://github.com/reactjs/react-transition-group) 的例子。
258 |
259 | 先安装依赖,
260 |
261 | ```bash
262 | $ yarn add react-transition-group
263 | ```
264 |
265 | 在 layout 组件(`layouts/index.js` 或者 pages 子目录下的 `_layout.js`)里在渲染子组件时用 TransitionGroup 和 CSSTransition 包裹一层,并以 `location.key` 为 key,
266 |
267 | ```js
268 | import withRouter from 'umi/withRouter';
269 | import { TransitionGroup, CSSTransition } from "react-transition-group";
270 |
271 | export default withRouter(
272 | ({ location }) =>
273 |
274 |
275 | { children }
276 |
277 |
278 | )
279 | ```
280 |
281 | 上面用到的 `fade` 样式,可以在 `src` 下的 `global.css` 里定义:
282 |
283 | ```css
284 | .fade-enter {
285 | opacity: 0;
286 | z-index: 1;
287 | }
288 |
289 | .fade-enter.fade-enter-active {
290 | opacity: 1;
291 | transition: opacity 250ms ease-in;
292 | }
293 | ```
294 |
295 | ## 面包屑
296 |
297 | 面包屑也是有多种实现方式,这里举 [react-router-breadcrumbs-hoc](https://github.com/icd2k3/react-router-breadcrumbs-hoc) 的例子。
298 |
299 | 先安装依赖,
300 |
301 | ```bash
302 | $ yarn add react-router-breadcrumbs-hoc
303 | ```
304 |
305 | 然后实现一个 `Breakcrumbs.js`,比如:
306 |
307 | ```js
308 | import NavLink from 'umi/navlink';
309 | import withBreadcrumbs from 'react-router-breadcrumbs-hoc';
310 |
311 | // 更多配置请移步 https://github.com/icd2k3/react-router-breadcrumbs-hoc
312 | const routes = [
313 | { path: '/', breadcrumb: '首页' },
314 | { path: '/list', breadcrumb: 'List Page' },
315 | ];
316 |
317 | export default withBreadcrumbs(routes)(({ breadcrumbs }) => (
318 |
319 | {breadcrumbs.map((breadcrumb, index) => (
320 |
321 |
322 | {breadcrumb}
323 |
324 | {(index < breadcrumbs.length - 1) && / }
325 |
326 | ))}
327 |
328 | ));
329 | ```
330 |
331 | 然后在需要的地方引入此 React 组件即可。
332 |
333 | ## 启用 Hash 路由
334 |
335 | umi 默认是用的 Browser History,如果要用 Hash History,需配置:
336 |
337 | ```js
338 | export default {
339 | history: 'hash',
340 | }
341 | ```
342 |
343 | ## Scroll to top
344 |
345 | 在 layout 组件(`layouts/index.js` 或者 pages 子目录下的 `_layout.js`)的 componentDidUpdate 里决定是否 scroll to top,比如:
346 |
347 | ```js
348 | import { Component } from 'react';
349 | import withRouter from 'umi/withRouter';
350 |
351 | class Layout extends Component {
352 | componentDidUpdate(prevProps) {
353 | if (this.props.location !== prevProps.location) {
354 | window.scrollTo(0, 0);
355 | }
356 | }
357 | render() {
358 | return this.props.children;
359 | }
360 | }
361 |
362 | export default withRouter(Layout);
363 | ```
364 |
365 | ## 参考
366 |
367 | * [https://reacttraining.com/react-router/](https://reacttraining.com/react-router/)
368 |
--------------------------------------------------------------------------------
/docs/guide/router.md:
--------------------------------------------------------------------------------
1 | ---
2 | sidebarDepth: 3
3 | ---
4 |
5 | # Router
6 |
7 | ::: tip
8 | The routing usage described below can be found in [umi-examples/routes](https://github.com/umijs/umi-examples/tree/master/routes) and find the sample code in [umi-examples/routes-via-config](https://github.com/umijs/umi-examples/tree/master/routes-via-config).
9 | :::
10 |
11 | Umi automatically generates routing configurations based on the `pages` directory.
12 |
13 | ## Conventional Routing
14 |
15 | ### Basic Routing
16 |
17 | Assume that the `pages` directory structure is as follows:
18 |
19 | ```
20 | + pages/
21 | + users/
22 | - index.js
23 | - list.js
24 | - index.js
25 | ```
26 |
27 | Then, umi will automatically generate the routing configuration as follows:
28 |
29 | ```js
30 | [
31 | { path: '/', component: './pages/index.js' },
32 | { path: '/users/', component: './pages/users/index.js' },
33 | { path: '/users/list', component: './pages/users/list.js' },
34 | ]
35 | ```
36 |
37 | ### Dynamic Routing
38 |
39 | As agreed in umi, directories or files with the `$` prefix are dynamic routes.
40 |
41 | For example, the following directory structure:
42 |
43 | ```
44 | + pages/
45 | + $post/
46 | - index.js
47 | - comments.js
48 | + users/
49 | $id.js
50 | - index.js
51 | ```
52 |
53 | The routing configuration will be generated as follows:
54 |
55 | ```js
56 | [
57 | { path: '/', component: './pages/index.js' },
58 | { path: '/users/:id', component: './pages/users/$id.js' },
59 | { path: '/:post/', component: './pages/$post/index.js' },
60 | { path: '/:post/comments', component: './pages/$post/comments.js' },
61 | ]
62 | ```
63 |
64 | ### Optional Dynamic Routing
65 |
66 | In umi, dynamic routing is an optional dynamic route if it has a `$` suffix.
67 |
68 | For example, the following structure:
69 |
70 | ```
71 | + pages/
72 | + users/
73 | - $id$.js
74 | - index.js
75 | ```
76 |
77 | The routing configuration will be generated as follows:
78 |
79 | ```js
80 | [
81 | { path: '/': component: './pages/index.js' },
82 | { path: '/users/:id?': component: './pages/users/$id$.js' },
83 | ]
84 | ```
85 |
86 | ### Nested Routing
87 |
88 | When there is `_layout.js` in the umi directory, a nested route will be generated, with `_layout.js` as the layout of the directory.
89 |
90 | For example, the following directory structure:
91 |
92 | ```
93 | + pages/
94 | + users/
95 | - _layout.js
96 | - $id.js
97 | - index.js
98 | ```
99 |
100 | The routing configuration will be generated as follows:
101 |
102 | ```js
103 | [
104 | { path: '/users': component: './pages/users/_layout.js'
105 | routes: [
106 | { path: '/users/', component: './pages/users/index.js' },
107 | { path: '/users/:id', component: './pages/users/$id.js' },
108 | ],
109 | },
110 | ]
111 | ```
112 |
113 | ### Global Layout
114 |
115 | The convention `src/layouts/index.js` is a global route, returning a React component, and rendering the child components via `props.children`.
116 |
117 | Example:
118 |
119 | ```js
120 | export default function(props) {
121 | return (
122 | <>
123 |
124 | { props.children }
125 |
126 | >
127 | );
128 | }
129 | ```
130 |
131 | ### Different Global Layout
132 |
133 | You may need to output a different global layout for different routes. umi does not support such a configuration, but you can still distinguish between location.path and render different layouts in `layouts/index.js`.
134 |
135 | For example, if you want to output a simple layout for /login,
136 |
137 | ```js
138 | export default function(props) {
139 | if (props.location.pathname === '/login') {
140 | return { props.children }
141 | }
142 |
143 | return (
144 | <>
145 |
146 | { props.children }
147 |
148 | >
149 | );
150 | }
151 | ```
152 |
153 | ### 404 Routing
154 |
155 | The convention `pages/404.js` is a 404 page and needs to return a React component.
156 |
157 | Example:
158 |
159 | ```js
160 | export default () => {
161 | return (
162 | I am a customized 404 page
163 | );
164 | };
165 | ```
166 |
167 | > Note: In development mode, umi will add a default 404 page to aid development, but you can still verify the 404 page by precisely accessing `/404`.
168 |
169 | ### Extending Routing by Annotation
170 |
171 | The first comment of the contracted routing file is used to extend the route if it contains a configuration in the **yaml** format.
172 |
173 | Example:
174 |
175 | ```
176 | + pages/
177 | - index.js
178 | ```
179 |
180 | If `pages/index.js` contains:
181 |
182 | ```js
183 | /**
184 | * title: Index Page
185 | * Routes:
186 | * - ./src/routes/a.js
187 | * - ./src/routes/b.js
188 | */
189 | ```
190 |
191 | A route configuration is generated:
192 |
193 | ```js
194 | [
195 | { path: '/', component: './index.js',
196 | title: 'Index Page',
197 | Routes: [ './src/routes/a.js', './src/routes/b.js' ],
198 | },
199 | ]
200 | ```
201 |
202 | ## Configuration Routing
203 |
204 | If you prefer to use a configured route, you can configure `routes`, **this configuration item will not be parsed for the `src/pages` directory**.
205 |
206 | Example:
207 |
208 | ```js
209 | export default {
210 | routes: [
211 | { path: '/', component: './a' },
212 | { path: '/list', component: './b', Routes: ['./routes/PrivateRoute.js'] },
213 | { path: '/users', component: './users/_layout',
214 | routes: [
215 | { path: '/users/detail', component: './users/detail' },
216 | { path: '/users/:id', component: './users/id' }
217 | ]
218 | },
219 | ],
220 | };
221 | ```
222 |
223 | note:
224 |
225 | 1. component is relative to the `src/pages` directory
226 |
227 | ## Permission Routing
228 |
229 | The permission routing of umi is implemented by configuring the `Routes` attribute of the route. The convention is added by the yaml annotation, and the configuration formula can be directly matched.
230 |
231 | For example, the following configuration:
232 |
233 | ```js
234 | [
235 | { path: '/', component: './pages/index.js' },
236 | { path: '/list', component: './pages/list.js', Routes: ['./routes/PrivateRoute.js'] },
237 | ]
238 | ```
239 |
240 | Then umi will render `/list` with `./routes/PrivateRoute.js`.
241 |
242 | Example of `./routes/PrivateRoute.js` file:
243 |
244 | ```js
245 | export default (props) => {
246 | return (
247 |
248 |
PrivateRoute (routes/PrivateRoute.js)
249 | { props.children }
250 |
251 | );
252 | }
253 | ```
254 |
255 | ## Route Transition Effects
256 |
257 | There are several ways to implement route transition effects. Here is an example of [react-transition-group](https://github.com/reactjs/react-transition-group).
258 |
259 | Install dependencies first,
260 |
261 | ```bash
262 | $ yarn add react-transition-group
263 | ```
264 |
265 | In the layout component (`layouts/index.js` or `_layout.js` in the pages subdirectory), wrap a subassembly with `TransitionGroup` and `CSSTransition` and use `location.key` as the key.
266 |
267 | ```js
268 | import withRouter from 'umi/withRouter';
269 | import { TransitionGroup, CSSTransition } from "react-transition-group";
270 |
271 | export default withRouter(
272 | ({ location }) =>
273 |
274 |
275 | { children }
276 |
277 |
278 | )
279 | ```
280 |
281 | The `fade` style used above can be defined in `global.css` under `src`:
282 |
283 | ```css
284 | .fade-enter {
285 | opacity: 0;
286 | z-index: 1;
287 | }
288 |
289 | .fade-enter.fade-enter-active {
290 | opacity: 1;
291 | transition: opacity 250ms ease-in;
292 | }
293 | ```
294 |
295 | ## Bread Crumbs
296 |
297 | There are many ways to implement breadcrumbs. Here is an example of [react-router-breadcrumbs-hoc](https://github.com/icd2k3/react-router-breadcrumbs-hoc).
298 |
299 | Install dependencies first,
300 |
301 | ```bash
302 | $ yarn add react-router-breadcrumbs-hoc
303 | ```
304 |
305 | Then implement a `Breakcrumbs.js`, such as:
306 |
307 | ```js
308 | import NavLink from 'umi/navlink';
309 | import withBreadcrumbs from 'react-router-breadcrumbs-hoc';
310 |
311 | // More configuration please go to https://github.com/icd2k3/react-router-breadcrumbs-hoc
312 | const routes = [
313 | { path: '/', breadcrumb: 'home' },
314 | { path: '/list', breadcrumb: 'List Page' },
315 | ];
316 |
317 | export default withBreadcrumbs(routes)(({ breadcrumbs }) => (
318 |
319 | {breadcrumbs.map((breadcrumb, index) => (
320 |
321 |
322 | {breadcrumb}
323 |
324 | {(index < breadcrumbs.length - 1) && / }
325 |
326 | ))}
327 |
328 | ));
329 | ```
330 |
331 | Then introduce this React component where you need it.
332 |
333 | ## Enable Hash Routing
334 |
335 | Umi defaults to the Browser History. If you want to use Hash History, you need to configure:
336 |
337 | ```js
338 | export default {
339 | history: 'hash',
340 | }
341 | ```
342 |
343 | ## Scroll to Top
344 |
345 | Decide whether to scroll to top in the `componentDidUpdate` of the layout component (`layouts/index.js` or the `_layout.js` in the pages subdirectory), for example:
346 |
347 | ```js
348 | import { Component } from 'react';
349 | import withRouter from 'umi/withRouter';
350 |
351 | class Layout extends Component {
352 | componentDidUpdate(prevProps) {
353 | if (this.props.location !== prevProps.location) {
354 | window.scrollTo(0, 0);
355 | }
356 | }
357 | render() {
358 | return this.props.children;
359 | }
360 | }
361 |
362 | export default withRouter(Layout);
363 | ```
364 |
365 | ## Reference
366 |
367 | * [https://reacttraining.com/react-router/](https://reacttraining.com/react-router/)
368 |
--------------------------------------------------------------------------------
/docs/config/README.md:
--------------------------------------------------------------------------------
1 | ---
2 | sidebarDepth: 2
3 | ---
4 |
5 | # Configuration
6 |
7 | ## Basic
8 |
9 | ### plugins
10 |
11 | * Type: `Array`
12 | * Default: `[]`
13 |
14 | Specify the plugin.
15 |
16 | such as:
17 |
18 | ```js
19 | export default {
20 | plugins: [
21 | 'umi-plugin-react',
22 | // When the plugin has parameters, it is an array, and the second item of the array is a parameter, similar to the babel plugin.
23 | ['umi-plugin-react', {
24 | dva: true,
25 | }],
26 | ],
27 | };
28 | ```
29 |
30 | ### routes
31 |
32 | * Type: `Array`
33 | * Default: `null`
34 |
35 | Configure routing.
36 |
37 | ::: tip reminder
38 | If `routes` is configured, the negotiated route will not take effect.
39 | :::
40 |
41 | ### disableRedirectHoist
42 |
43 | * 类型:`Boolean`
44 | * 默认值:`false`
45 |
46 | For some reason, we hoist all redirect when parsing the route config, but this caused some problems, so add this configuration to disable redirect hoist.
47 |
48 | ### history
49 |
50 | * Type: `String`
51 | * Default: `browser`
52 |
53 | To switch the history mode to hash (the default is browser history), configure `history: 'hash'`.
54 |
55 | ### outputPath
56 |
57 | * Type: `String`
58 | * Default: `./dist`
59 |
60 | Specifies the output path.
61 |
62 | ### base
63 |
64 | * Type: `String`
65 | * Default: `/`
66 |
67 | Specify the base of the react-router to be configured when deploying to a non-root directory.
68 |
69 | ### publicPath
70 |
71 | * Type: `String`
72 | * Default: `/`
73 |
74 | Specifies the publicPath of the webpack, pointing to the path where the static resource file is located.
75 |
76 | ### runtimePublicPath
77 |
78 | * Type: `Boolean`
79 | * Default: `false`
80 |
81 | Use the `window.publicPath` specified in the HTML when the value is `true`.
82 |
83 | ### mountElementId
84 |
85 | * Type: `String`
86 | * Default: `root`
87 |
88 | Specifies the mount point id which the react app will mount to.
89 |
90 | ### hash
91 |
92 | * Type: `Boolean`
93 | * Default: `false`
94 |
95 | Whether to enable the hash file suffix.
96 |
97 | ### targets
98 |
99 | * Type: `Object`
100 | * Default: `{ chrome: 49, firefox: 45, safari: 10, edge: 13, ios: 10 }`
101 |
102 | 配置浏览器最低版本,会自动引入 polyfill 和做语法转换,配置的 targets 会和合并到默认值,所以不需要重复配置。
103 |
104 | Configuring the minimum version of browsers you want to compatible with.
105 |
106 | e.g. Compatible with ie 11,
107 |
108 | ```js
109 | export default {
110 | targets: {
111 | ie: 11,
112 | },
113 | };
114 | ```
115 |
116 | ### context
117 |
118 | * Type: `Object`
119 | * Default: `{}`
120 |
121 | Configuring a global context will override the context in each page.
122 |
123 | ### exportStatic
124 |
125 | * Type: `Boolean | Object`
126 | * Default: `false`
127 |
128 | If set to `true` or `Object`, all routes are exported as static pages, otherwise only one index.html is output by default.
129 |
130 | such as:
131 |
132 | ```
133 | "exportStatic": {}
134 | ```
135 |
136 | ### exportStatic.htmlSuffix
137 |
138 | * Type: `Boolean`
139 | * Default: `false`
140 |
141 | Enable the `.html` suffix.
142 |
143 | ### exportStatic.dynamicRoot
144 |
145 | * Type: `Boolean`
146 | * Default: `false`
147 |
148 | Deploy to any path.
149 |
150 | ### singular
151 |
152 | * Type: `Boolean`
153 | * Default: `false`
154 |
155 | If set to `true`, enable the directory for singular mode.
156 |
157 | * src/layout/index.js
158 | * src/page
159 | * model (if umi-plugin-dva plugin is enabled)
160 |
161 | ## webpack
162 |
163 | ### chainWebpack
164 |
165 | Extend or modify the webpack configuration via the API of [webpack-chain](https://github.com/mozilla-neutrino/webpack-chain).
166 |
167 | such as:
168 |
169 | ```js
170 | chainWebpack(config, { webpack }) {
171 | // Set alias
172 | config.resolve.alias.set('a', 'path/to/a');
173 |
174 | // Delete progress bar plugin
175 | config.plugins.delete('progress');
176 | }
177 | ```
178 |
179 | ### theme
180 |
181 | The configuration theme is actually equipped with the less variable. Support for both object and string types, the string needs to point to a file that returns the configuration.
182 | such as:
183 |
184 | ```
185 | "theme": {
186 | "@primary-color": "#1DA57A"
187 | }
188 | ```
189 |
190 | or,
191 |
192 | ```
193 | "theme": "./theme-config.js"
194 | ```
195 |
196 | ### define
197 |
198 | Passed to the code via the webP's DefinePlugin , the value is automatically handled by `JSON.stringify`.
199 | such as:
200 |
201 | ```js
202 | "define": {
203 | "process.env.TEST": 1,
204 | "USE_COMMA": 2,
205 | }
206 | ```
207 |
208 | ### externals
209 |
210 | Configure the [externals](https://webpack.js.org/configuration/externals/) property of webpack.
211 | such as:
212 |
213 | ```js
214 | // Configure react and react-dom do not enter the code
215 | "externals": {
216 | "react": "window.React",
217 | "react-dom": "window.ReactDOM"
218 | }
219 | ```
220 |
221 | ### alias
222 |
223 | Configure the [resolve.alias](https://webpack.js.org/configuration/resolve/#resolve-alias) property of webpack.
224 |
225 | ### browserslist
226 |
227 | Configure [browserslist](https://github.com/ai/browserslist) to work with babel-preset-env and autoprefixer.
228 | such as:
229 |
230 | ```js
231 | "browserslist": [
232 | "> 1%",
233 | "last 2 versions"
234 | ]
235 | ```
236 |
237 | ### devtool
238 |
239 | Configure the [devtool](https://webpack.js.org/configuration/devtool/) property of webpack.
240 |
241 | ### disableCSSModules
242 |
243 | Disable [CSS Modules](https://github.com/css-modules/css-modules).
244 |
245 | ### disableCSSSourceMap
246 |
247 | Disable SourceMap generation for CSS.
248 |
249 | ### extraBabelPresets
250 |
251 | Define an additional babel preset list in the form of an array.
252 |
253 | ### extraBabelPlugins
254 |
255 | Define an additional babel plugin list in the form of an array.
256 |
257 | ### extraBabelIncludes
258 |
259 | Define a list of additional files that need to be babel converted, in the form of an array, and the array item is [webpack#Condition](https://webpack.js.org/configuration/module/#condition).
260 |
261 | ### extraPostCSSPlugins
262 |
263 | Define additional PostCSS plugins in the format of an array.
264 |
265 | ### cssModulesExcludes
266 |
267 | The files in the specified project directory do not go css modules, the format is an array, and the items must be css or less files.
268 |
269 | ### copy
270 |
271 | Define a list of files that need to be copied simply. The format is an array. The format of the item refers to the configuration of [copy-webpack-plugin](https://github.com/webpack-contrib/copy-webpack-plugin).
272 |
273 | such as:
274 |
275 | ```markup
276 | "copy": [
277 | {
278 | "from": "",
279 | "to": ""
280 | }
281 | ]
282 | ```
283 |
284 | ### proxy
285 |
286 | Configure the [proxy](https://webpack.js.org/configuration/dev-server/#devserver-proxy) property of webpack-dev-server.
287 | If you want to proxy requests to other servers, you can do this:
288 |
289 | ```markup
290 | "proxy": {
291 | "/api": {
292 | "target": "http://jsonplaceholder.typicode.com/",
293 | "changeOrigin": true,
294 | "pathRewrite": { "^/api" : "" }
295 | }
296 | }
297 | ```
298 |
299 | Then visit `/api/users` to access the data of [http://jsonplaceholder.typicode.com/users](http://jsonplaceholder.typicode.com/users).
300 |
301 | ### sass
302 |
303 | Configure options for [node-sass](https://github.com/sass/node-sass#options). Note: The node-sass and sass-loader dependencies need to be installed in the project directory when using sass.
304 |
305 | ### manifest
306 |
307 | After configuration, manifest.json will be generated and the option will be passed to [https://www.npmjs.com/package/webpack-manifest-plugin](https://www.npmjs.com/package/webpack-manifest-plugin).
308 | such as:
309 |
310 | ```markup
311 | "manifest": {
312 | "basePath": "/app/"
313 | }
314 | ```
315 |
316 | ### ignoreMomentLocale
317 |
318 | Ignore the locale file for moment to reduce the size.
319 |
320 | ### lessLoaderOptions
321 |
322 | Additional configuration items for [less-loader](https://github.com/webpack-contrib/less-loader).
323 |
324 | ### cssLoaderOptions
325 |
326 | Additional configuration items for [css-loader](https://github.com/webpack-contrib/css-loader).Configure the [resolve.alias](https://webpack.js.org/configuration/resolve/#resolve-alias) property of webpack.
327 |
328 | ### browserslist
329 |
330 | Configure [browserslist](https://github.com/ai/browserslist) to work with babel-preset-env and autoprefixer.
331 | such as:
332 |
333 | ```js
334 | "browserslist": [
335 | "> 1%",
336 | "last 2 versions"
337 | ]
338 | ```
339 |
340 | ### devtool
341 |
342 | Configure the [devtool](https://webpack.js.org/configuration/devtool/) property of webpack.
343 |
344 | ### disableCSSModules
345 |
346 | Disable [CSS Modules](https://github.com/css-modules/css-modules).
347 |
348 | ### disableCSSSourceMap
349 |
350 | Disable SourceMap generation for CSS.
351 |
352 | ### extraBabelPresets
353 |
354 | Define an additional babel preset list in the form of an array.
355 |
356 | ### extraBabelPlugins
357 |
358 | Define an additional babel plugin list in the form of an array.
359 |
360 | ### extraBabelIncludes
361 |
362 | Define a list of additional files that need to be babel converted, in the form of an array, and the array item is [webpack#Condition](https://webpack.js.org/configuration/module/#condition).
363 |
364 | ### extraPostCSSPlugins
365 |
366 | Define additional PostCSS plugins in the format of an array.
367 |
368 | ### cssModulesExcludes
369 |
370 | The files in the specified project directory do not go css modules, the format is an array, and the items must be css or less files.
371 |
372 | ### copy
373 |
374 | Define a list of files that need to be copied simply. The format is an array. The format of the item refers to the configuration of [copy-webpack-plugin](https://github.com/webpack-contrib/copy-webpack-plugin).
375 |
376 | such as:
377 |
378 | ```markup
379 | "copy": [
380 | {
381 | "from": "",
382 | "to": ""
383 | }
384 | ]
385 | ```
386 |
387 | ### proxy
388 |
389 | Configure the [proxy](https://webpack.js.org/configuration/dev-server/#devserver-proxy) property of webpack-dev-server.
390 | If you want to proxy requests to other servers, you can do this:
391 |
392 | ```markup
393 | "proxy": {
394 | "/api": {
395 | "target": "http://jsonplaceholder.typicode.com/",
396 | "changeOrigin": true,
397 | "pathRewrite": { "^/api" : "" }
398 | }
399 | }
400 | ```
401 |
402 | Then visit `/api/users` to access the data of [http://jsonplaceholder.typicode.com/users](http://jsonplaceholder.typicode.com/users).
403 |
404 | ### sass
405 |
406 | Configure options for [node-sass](https://github.com/sass/node-sass#options). Note: The node-sass and sass-loader dependencies need to be installed in the project directory when using sass.
407 |
408 | ### manifest
409 |
410 | After configuration, manifest.json will be generated and the option will be passed to [https://www.npmjs.com/package/webpack-manifest-plugin](https://www.npmjs.com/package/webpack-manifest-plugin).
411 | such as:
412 |
413 | ```markup
414 | "manifest": {
415 | "basePath": "/app/"
416 | }
417 | ```
418 |
419 | ### ignoreMomentLocale
420 |
421 | Ignore the locale file for moment to reduce the size.
422 |
423 | ### lessLoaderOptions
424 |
425 | Additional configuration items for [less-loader](https://github.com/webpack-contrib/less-loader).
426 |
427 | ### cssLoaderOptions
428 |
429 | Additional configuration items for [css-loader](https://github.com/webpack-contrib/css-loader).
430 |
--------------------------------------------------------------------------------
/docs/zh/plugin/develop.md:
--------------------------------------------------------------------------------
1 | ---
2 | sidebarDepth: 2
3 | ---
4 |
5 | # 插件开发
6 |
7 | ## 初始化插件
8 |
9 | 在 umi 中,插件实际上就是一个 JS 模块,你需要定义一个插件的初始化方法并默认导出。如下示例:
10 |
11 | ```js
12 | export default (api, opts) => {
13 | // your plugin code here
14 | };
15 | ```
16 |
17 | 需要注意的是,如果你的插件需要发布为 npm 包,那么你需要发布之前做编译,确保发布的代码里面是 ES5 的代码。
18 |
19 | 该初始化方法会收到两个参数,第一个参数 `api`,umi 提供给插件的接口都是通过它暴露出来的。第二个参数 `opts` 是用户在初始化插件的时候填写的。
20 |
21 | ## 插件接口简介
22 |
23 | umi 的所有插件接口都是通过初始化插件时候的 api 来提供的。分为如下几类:
24 |
25 | - 环境变量,插件中可以使用的一些环境变量
26 | - 系统级变量,一些插件系统暴露出来的变量或者常量
27 | - 工具类 API,常用的一些工具类方法
28 | - 系统级 API,一些插件系统暴露的核心方法
29 | - 事件类 API,一些插件系统提供的关键的事件点
30 | - 应用类 API,用于实现插件功能需求的 API,有直接调用和函数回调两种方法
31 |
32 | **注:** 所有的 API 都是通过 `api.[theApiName]` 的方法使用的,内部的 API 会统一加上 `_` 的前缀。
33 |
34 | 下面是一个基本的使用示例:
35 |
36 | ```js
37 | export default (api, opts) => {
38 | api.onOptionChange(() => {
39 | api.rebuildTmpFiles();
40 | });
41 | }
42 | ```
43 |
44 | ## 插件示例
45 |
46 | 下面是参考 `umi-plugin-locale` 的需求添加的一个插件伪代码示例,完整的例子可以查看[源代码](https://github.com/umijs/umi/blob/master/packages/umi-plugin-locale/src/index.js)。
47 |
48 | ```js
49 | export default (api, opts = {}) => {
50 | const { paths } = api;
51 | // 监听插件配置变化
52 | api.onOptionChange((newOpts) => {
53 | opts = newOpts;
54 | api.rebuildTmpFiles();
55 | });
56 | // 添加 Provider 的包裹
57 | api.addRendererWrapperWithComponent(join(__dirname, './locale.js'));
58 | api.addRendererWrapperWithComponent(() => {
59 | if (opts.antd) {
60 | return join(__dirnae, './locale-antd.js');
61 | }
62 | });
63 | // 添加对 locale 文件的 watch
64 | api.addPageWatcher(
65 | join(paths.absSrcPath, config.singular ? 'locale' : 'locales'),
66 | );
67 | };
68 | ```
69 |
70 | ## 插件的顺序
71 |
72 | 插件的执行顺序依赖用户在配置文件 `.umirc.js` 或者 `config/config.js` 中配置的 `plugins` 配置项,有依赖的插件 umi 会通过插件的 `dependence` 配置检查插件的顺序做出警告,但是目前 umi 不会修改用户的顺序。
73 |
74 | 当插件调用 `api.applyPlugins` 触发插件的 hooks 时,hooks 的执行顺序对应 `plugins` 的顺序。至于 hooks 是否关心顺序由对应的 hooks 决定。
75 |
76 | ## 环境变量
77 |
78 | ### NODE_ENV
79 |
80 | `process.env.NODE_ENV`,区分 development 和 production
81 |
82 | ## 系统级变量
83 |
84 | ### config
85 |
86 | `.umirc.js` 或者 `config/config.js` 里面的配置。
87 |
88 | ### paths
89 |
90 | - outputPath: 构建产物的生成目录
91 | - absOutputPath: 构建产物的生成目录(绝对路径)
92 | - pagesPath: page(s) 路径
93 | - absPagesPath: page(s) 的绝对路径
94 | - tmpDirPath: .umi 临时目录的路径
95 | - absTmpDirPath: .umi 临时目录的路径(绝对路径)
96 | - absSrcPath: src 目录的路径(绝对路径),用户缺省 src 时则对应为项目根目录
97 | - cwd: 项目根目录
98 |
99 | ### routes
100 |
101 | umi 处理过后的路由信息。格式如下:
102 |
103 | ```js
104 | const routes = [{
105 | path: '/xxx/xxx',
106 | component: '',
107 | }];
108 | ```
109 |
110 | ## 系统级 API
111 |
112 | ### registerPlugin
113 |
114 | 加载插件,用于插件集等需要在一个插件中加载其它插件的场景。
115 |
116 | ```js
117 | const demoPlugin = require('./demoPlugin');
118 | api.registerPlugin({
119 | id: 'plugin-id',
120 | apply: demoPlugin,
121 | opts: {},
122 | });
123 | ```
124 |
125 | ### registerMethod
126 |
127 | 注册插件方法,用于给插件添加新的方法给其它插件使用。
128 |
129 | ```js
130 | // 类型通常和方法名对应 addXxx modifyXxx onXxx afterXxx beforeXxx
131 | api.registerMethod('addDvaRendererWrapperWithComponent', {
132 | type: api.API_TYPE.ADD
133 | type: api.API_TYPE.EVENT
134 | type: api.API_TYPE.MODIFY
135 | apply: () => {} // for custom type
136 | });
137 | ```
138 |
139 | 对于类型是 `api.API_TYPE.ADD` 的插件方法,你应该返回一项或者通过数组返回多项,也可以返回一个空数组,比如:
140 |
141 | ```js
142 | api.addHTMLMeta({ /* ... */ });
143 | api.addHTMLMeta([{ /* ... */ }, { /* ... */ }]);
144 | api.addHTMLMeta(() => {
145 | if (opt === 'h5') {
146 | return { /* ... */ };
147 | }
148 | return [];
149 | });
150 | ```
151 |
152 | 类型是 `api.API_TYPE.EVENT` 的插件方法,你应该传入一个 function 并且不需要返回任何内容。
153 |
154 | 类型是 `api.API_TYPE.MODIFY` 的插件方法,返回修改后的内容。
155 |
156 | 你也可以通过 `apply` 来自定义处理的函数,你注册的方法可能被多个插件使用,当你调用 `applyPlugins` 时在 umi 内部会通过 reduce 函数去处理这些插件的返回值。你定义的 `apply` 函数决定了 `applyPlugins` 是怎么处理多个插件的结果作为它的返回值的。通常情况下内置的三种类型就可以满足你的需求了。
157 |
158 | ### applyPlugins
159 |
160 | 在插件用应用通过 registerMethod 注册的某个方法。
161 |
162 | ```js
163 | // 如果 type 为 api.API_TYPE.ADD wrappers 为各个插件返回的值组成的数组
164 | // EVENT 则 wrappers 返回 undefined
165 | // MODIFY 则返回最后的修改值
166 | const wrappers = api.applyPlugins('wrapDvaRendererWithComponent');
167 | ```
168 |
169 | ### restart
170 |
171 | ```js
172 | api.restart('why');
173 | ```
174 |
175 | 重新执行 `umi dev`,比如在 bigfish 中修改了 appType,需要重新挂载插件的时候可以调用该方法。
176 |
177 | ### rebuildTmpFiles
178 |
179 | ```js
180 | api.rebuildTmpFiles('config dva changed');
181 | ```
182 |
183 | 重新生成 bootstrap file(entryFile)等临时文件,这个是最常用的方法,国际化,dva 等插件的配置变化都会用到。
184 |
185 | ### refreshBrowser
186 |
187 | 刷新浏览器。
188 |
189 | ### rebuildHTML
190 |
191 | 触发 HTML 重新构建。
192 |
193 | ### changePluginOption
194 |
195 | 设置插件的配置,比如在 react 插件集中中需要把插件集的 dva 配置传递给 dva 插件的时候用到。
196 |
197 | ```js
198 | api.changePluginOption('dva-plugin-id', {
199 | immer: true
200 | });
201 | ```
202 |
203 | ### registerCommand
204 |
205 | 注册 umi xxx 命令行,比如在 umi 内部 help 命令就是这么实现的。
206 |
207 | ```
208 | api.registerCommand('help', {
209 | hide: true
210 | }, args => {
211 | // more code...
212 | });
213 | ```
214 |
215 | ### \_registerConfig
216 |
217 | 注册一个配置项,系统方法,通常不要使用。
218 |
219 | ```js
220 | api._registerConfig(() => {
221 | return () => {
222 | return {
223 | name: 'dva',
224 | validate: validate,
225 | onChange(newConfig, oldConfig) {
226 | api.setPluginDefaultConfig('umi-plugin-dva', config);
227 | }
228 | };
229 | }
230 | });
231 | ```
232 |
233 | ## 工具类 API
234 |
235 | ### log
236 |
237 | ```js
238 | api.log.success('Done');
239 | api.log.error('Error');
240 | api.log.error(new Error('Error'));
241 | api.log.debug('Hello', 'from', 'L59');
242 | api.log.pending('Write release notes for %s', '1.2.0');
243 | api.log.watch('Recursively watching build directory...');
244 | ```
245 |
246 | 输出各类日志。
247 |
248 | ### winPath
249 |
250 | ```js
251 | api.winPath('/path/to.js');
252 | ```
253 |
254 | 将文件路径转换为兼容 window 的路径,用于在代码中添加 `require('/xxx/xxx.js')` 之类的代码。
255 |
256 | ### debug
257 |
258 | ```js
259 | api.debug('msg');
260 | ```
261 |
262 | ### findJS
263 |
264 | xxx -> xxx.js xxx.ts
265 |
266 | ### compatDirname
267 |
268 | 先找用户项目目录,再找插件依赖。
269 |
270 | ## 事件类 API
271 |
272 | 事件类 API 遵循以 onXxxXxx, beforeXxx, afterXxx 的命名规范,接收一个参数为回调函数。
273 |
274 | ### beforeDevServer
275 |
276 | dev server 启动之前。
277 |
278 | ### afterDevServer
279 |
280 | dev server 启动之后。
281 |
282 | ### onStart
283 |
284 | `umi dev` 或者 `umi build` 开始时触发。
285 |
286 | ### onDevCompileDone
287 |
288 | `umi dev` 编译完成后触发。
289 |
290 | ```js
291 | api.onDevCompileDone(({ isFirstCompile, stats }) => {
292 | });
293 | ```
294 |
295 | ### onOptionChange
296 |
297 | 插件的配置改变的时候触发。
298 |
299 | ```js
300 | export default (api, defaultOpts = { immer: false }) => {
301 | let opts = defaultOpts;
302 | api.onOptionChange((newOpts) => {
303 | opts = newOpts;
304 | api.rebuildFiles();
305 | });
306 | };
307 | ```
308 |
309 | ### onBuildSuccess
310 |
311 | 在 `umi build` 成功时候。主要做一些构建产物的处理。
312 |
313 | ```js
314 | api.onBuildSuccess({
315 | stats,
316 | } => {
317 | // handle with stats
318 | });
319 | ```
320 |
321 | ### onBuildFail
322 |
323 | 在 `umi build` 失败的时候。
324 |
325 | ### onHTMLRebuild
326 |
327 | 当 HTML 重新构建时被触发。
328 |
329 | ### onGenerateFiles
330 |
331 | 路由文件,入口文件生成时被触发。
332 |
333 | ### onPatchRoute
334 |
335 | 获取单个路由的配置时触发,可以在这里修改路由配置 `route`。比如可以向 `Routes` 中添加组件路径使得可以给路由添加一层封装。
336 |
337 | ```js
338 | api.onPatchRoute({ route } => {
339 | // route:
340 | // {
341 | // path: '/xxx',
342 | // Routes: []
343 | // }
344 | })
345 | ```
346 |
347 | ## 应用类 API
348 |
349 | 对于应用类 API,可以有直接调用和函数回调两种方式。
350 |
351 | 直接调用的示例如下:
352 |
353 | ```js
354 | api.addRendererWrapperWithComponent('/path/to/component.js');
355 | ```
356 |
357 | 函数回调的示例如下:
358 |
359 | ```js
360 | api.addRendererWrapperWithComponent(() => {
361 | if (opts.antd) {
362 | return '/path/to/component.js';
363 | }
364 | });
365 | ```
366 |
367 | 下面是具体的 API。
368 |
369 | ### modifyDefaultConfig
370 |
371 | 设置 umi 的默认配置。
372 |
373 | ```js
374 | api.modifyDefaultConfig(memo => {
375 | return {
376 | // 默认使用单数目录
377 | ...memo,
378 | singular: true,
379 | }
380 | });
381 | ```
382 |
383 | ### addPageWatcher
384 |
385 | 添加 watch 的文件。
386 |
387 | ```js
388 | api.addPageWatcher(['xxx.js', '*.mock.js']);
389 | ```
390 |
391 | ### addHTMLMeta
392 |
393 | 在 HTML 中添加 meta 标签。
394 |
395 | ### addHTMLLink
396 |
397 | 在 HTML 中添加 Link 标签。
398 |
399 | ### addHTMLStyle
400 |
401 | 在 HTML 中添加 Style 标签。
402 |
403 | ### addHTMLScript
404 |
405 | 在 HTML 尾部添加脚本。
406 |
407 | ```js
408 | api.addHTMLScript({
409 | content: '',
410 | src: '',
411 | // ...attrs
412 | });
413 | ```
414 |
415 | ### addHTMLHeadScript
416 |
417 | 在 HTML 头部添加脚本。
418 |
419 | ### modifyHTMLChunks
420 |
421 | 修改 chunks,默认值是 `['umi']`。
422 |
423 | ### modifyHTMLWithAST
424 |
425 | 修改 HTML,基于 cheerio 。
426 |
427 | 参数:
428 |
429 | * route,当前路由
430 | * getChunkPath ,获取 chunk 的完整路径,包含 publicPath 和 hash 信息
431 |
432 | 例子:
433 |
434 | ```js
435 | api.modifyHTMLWithAST(($, { route, getChunkPath }) => {
436 | $('head').append(``);
437 | });
438 | ```
439 |
440 | ### modifyHTMLContext
441 |
442 | 修改 html ejs 渲染时的环境参数。
443 |
444 | ```js
445 | api.modifyHTMLContext((memo, { route }) => {
446 | return {
447 | ...memo,
448 | title: route.title, // umi-plugin-react 的 title 插件包含了类似的逻辑
449 | };
450 | });
451 | ```
452 |
453 | ### modifyRoutes
454 |
455 | 修改路由配置。
456 |
457 | ```js
458 | api.modifyRoutes(({ memo, args}) => {
459 | return memo;
460 | })
461 | ```
462 |
463 | 路由配置的格式如下:
464 |
465 | ```js
466 | const route = {
467 | path: '/xxx',
468 | component: '/path/to/component',
469 | Routes: ['/permissionControl.js'],
470 | }
471 | ```
472 |
473 | ```js
474 | exports.routes = [{
475 | path: '/xxx',
476 | workspace: false,
477 | }];
478 | ```
479 |
480 | ```js
481 | //permissionControl.js
482 | export class Control extends Component (props) => {
483 | componentDidount() => {
484 | if(props.route.workspace === false) {
485 | window.AntdCloudNav.set()
486 | }
487 | }
488 | }
489 |
490 | ```
491 |
492 | ### addEntryImportAhead
493 |
494 | 在入口文件在最上面 import 模块。
495 |
496 | ```js
497 | api.addEntryImportAhead({
498 | source: '/path/to/module',
499 | specifier: 'name', // import 出来后的名称,可以缺省
500 | });
501 | ```
502 |
503 | ### addEntryPolyfillImports
504 |
505 | 同 addEntryImportAhead,但作为 polyfill,所以添加在最前面。
506 |
507 | ### addEntryImport
508 |
509 | 在入口文件中 import 模块。
510 |
511 | ```js
512 | api.addEntryImport({
513 | source: '/modulePath/xxx.js',
514 | specifier: 'moduleName',
515 | });
516 | ```
517 |
518 | ### addEntryCodeAhead
519 |
520 | 在 render 之前添加代码。
521 |
522 | ```js
523 | api.addEntryCodeAhead(`
524 | console.log('addEntryCodeAhead');
525 | `);
526 | ```
527 |
528 | ### addEntryCode
529 |
530 | 在 render 之后添加代码。
531 |
532 | ### addRouterImport
533 |
534 | 在路由文件中添加模块引入。
535 |
536 | ### addRouterImportAhead
537 |
538 | 在路由文件头部添加模块引入。
539 |
540 | ### addRendererWrapperWithComponent
541 |
542 | 在 外面包一层组件。
543 |
544 | ### addRendererWrapperWithModule
545 |
546 | 在挂载 前执行一个 Module,支持异步。
547 |
548 | ### modifyEntryRender
549 |
550 | modifyEntryRender
551 |
552 | ### modifyEntryHistory
553 |
554 | modifyEntryHistory
555 |
556 | ### modifyRouteComponent
557 |
558 | modifyRouteComponent
559 |
560 | ### modifyRouterRootComponent
561 |
562 | modifyRouterRootComponent
563 |
564 | ### modifyWebpackConfig
565 |
566 | 修改 webpack 配置。
567 |
568 | ```js
569 | // 示例
570 | api.chainWebpackConfig((memo) => {
571 | return memo;
572 | });
573 | ```
574 |
575 | ### modifyAFWebpackOpts
576 |
577 | 修改 af-webpack 配置。
578 |
579 | ```js
580 | // 示例
581 | api.modifyAFWebpackOpts((memo) => {
582 | return memo;
583 | });
584 | ```
585 |
586 | ### addMiddleware
587 |
588 | 往开发服务器后面添加中间件。
589 |
590 | ### addMiddlewareAhead
591 |
592 | 往开发服务器前面添加中间件。
593 |
594 | ### addMiddlewareBeforeMock
595 |
596 | 在 mock 前添加中间件。
597 |
598 | ### addMiddlewareAfterMock
599 |
600 | 在 mock 后添加中间件。
601 |
602 | ### addVersionInfo
603 |
604 | 添加版本信息,在 `umi -v` 或 `umi version` 时显示。
605 |
606 | ### addRuntimePlugin
607 |
608 | 添加运行时插件,参数为文件的绝对路径。
609 |
610 | ### addRuntimePluginKey
611 |
612 | 添加运行时可配置项。
613 |
--------------------------------------------------------------------------------
/docs/plugin/develop.md:
--------------------------------------------------------------------------------
1 | ---
2 | sidebarDepth: 2
3 | ---
4 |
5 | # Plugin develop
6 |
7 | ## initialize plugin
8 |
9 | In umi, the plugin is actually a JS module, you need to define a plugin initialization method and export by default. The following example:
10 |
11 | ```js
12 | export default (api, opts) => {
13 | // your plugin code here
14 | };
15 | ```
16 |
17 | It should be noted that if your plugin needs to be published as an npm package, then you need to compile before publishing, to ensure that the code in the release is ES5 code.
18 |
19 | The initialization method will receive two parameters, the first parameter `api`, the interface provided by the umi to the plugin is exposed through it. The second parameter, `opts`, is filled in by the user when initializing the plugin.
20 |
21 | ## Introduction to the plugin interface
22 |
23 | All of umi's plugin interfaces are provided through the api when the plugin is initialized. Divided into the following categories:
24 |
25 | - Environment variables, some environment variables that can be used in the plugin
26 | - System-level variables, variables or constants exposed by some plug-in systems
27 | - Tools API, some commonly used tool class methods
28 | - System level API, some core methods exposed by plugin systems
29 | - Event class API, key event points provided by some plugin systems
30 | - Application class API, API for implementing plugin function requirements, there are two methods of direct call and function callback
31 |
32 | **Note:** All APIs are used by the `api.[theApiName]` method, and the internal APIs are uniformly prefixed with `_`.
33 |
34 | Here's a basic usage example:
35 |
36 | ```js
37 | export default (api, opts) => {
38 | api.onOptionChange(() => {
39 | api.rebuildTmpFiles();
40 | });
41 | }
42 | ```
43 |
44 | ## Plugin demo
45 |
46 | The following is an example of plugin example code refer to `umi-plugin-locale` plugin code. For a complete example, see [source code](https://github.com/umijs/umi/blob/master/packages/umi- Plugin-locale/src/index.js).
47 |
48 | ```js
49 | export default (api, opts = {}) => {
50 | const { paths } = api;
51 | // Linstening plugin options changes
52 | api.onOptionChange((newOpts) => {
53 | opts = newOpts;
54 | api.rebuildTmpFiles();
55 | });
56 | // add Provider wrapper
57 | api.addRendererWrapperWithComponent(join(__dirname, './locale.js'));
58 | api.addRendererWrapperWithComponent(() => {
59 | if (opts.antd) {
60 | return join(__dirnae, './locale-antd.js'));
61 | }
62 | });
63 | // add watcher on locale files
64 | api.addPageWatcher(
65 | join(paths.absSrcPath, config.singular ? 'locale' : 'locales'),
66 | );
67 | };
68 | ```
69 |
70 | ## Plugins order
71 |
72 | The execution order of the plugins depends on the `plugins` configuration item configured by the user in the configuration file `.umirc.js` or `config config.js`. The dependent plugin umi will check the order of the plugins through the plugin's `dependence` configuration. A warning is issued, but currently umi does not modify the order of the users.
73 |
74 | When the plugin calls `api.applyPlugins` to trigger the hooks of the plugin, the execution order of the hooks corresponds to the order of `plugins`. The order in which hooks are concerned is determined by the corresponding hooks.
75 |
76 | ## Environmental variable
77 |
78 | ### NODE_ENV
79 |
80 | `process.env.NODE_ENV`, Distinguish between development and production
81 |
82 | ## System level variable
83 |
84 | ### config
85 |
86 | configuration in `.umirc.js` or `config/config.js`.
87 |
88 | ### paths
89 |
90 | - outputPath
91 | - absOutputPath
92 | - pagesPath
93 | - absPagesPath
94 | - tmpDirPath
95 | - absTmpDirPath
96 | - absSrcPath
97 | - cwd: project root
98 |
99 | ### routes
100 |
101 | umi processed routing information. The format is as follows:
102 |
103 | ```js
104 | const routes = [{
105 | path: '/xxx/xxx',
106 | component: '',
107 | }];
108 | ```
109 |
110 | ## System level API
111 |
112 | ### registerPlugin
113 |
114 | Register a plugin, usually used for plugin set.
115 |
116 | ```js
117 | const demoPlugin = require('./demoPlugin');
118 | api.registerPlugin({
119 | id: 'plugin-id',
120 | apply: demoPlugin,
121 | opts: {},
122 | });
123 | ```
124 |
125 | ### registerMethod
126 |
127 | Register a plugin method to add a new method to the plugin for use by other plugins.
128 |
129 | ```js
130 | // Type usually corresponds to the method name addXxx modifyXxx onXxx afterXxx beforeXxx
131 | api.registerMethod('addDvaRendererWrapperWithComponent', {
132 | type: api.API_TYPE.ADD
133 | type: api.API_TYPE.EVENT
134 | type: api.API_TYPE.MODIFY
135 | apply: () => {} // for custom type
136 | });
137 | ```
138 |
139 | For plugin methods of type `api.API_TYPE.ADD`, you should return an item or return a multiple of the array, or you can return an empty array, such as:
140 |
141 | ```js
142 | api.addHTMLMeta({ /* ... */ });
143 | api.addHTMLMeta([{ /* ... */ }, { /* ... */ }]);
144 | api.addHTMLMeta(() => {
145 | if (opt === 'h5') {
146 | return { /* ... */ };
147 | }
148 | return [];
149 | });
150 | ```
151 |
152 | The type is a plugin method of `api.API_TYPE.EVENT`, you should pass in a function and don't need to return anything.
153 |
154 | The plugin method of type `api.API_TYPE.MODIFY` returns the modified content.
155 |
156 | You can also use `apply` to customize the processing function. Your registered method may be used by multiple plugins. When you call `applyPlugins`, the return value of these plugins will be processed by the reduce function inside umi. The `apply` function you define determines how `applyPlugins` handles the result of multiple plugins as its return value. Usually three types of built-in can meet your needs.
157 |
158 | ### applyPlugins
159 |
160 | Trigger a method registered by the app via `registerMethod`.
161 |
162 | ```js
163 | // If the type is api.API_TYPE.ADD wrappers an array of values returned by each plugin
164 | // EVENT wrapper returns undefined
165 | // MODIFY returns the last modified value
166 | const wrappers = api.applyPlugins('wrapDvaRendererWithComponent');
167 | ```
168 |
169 | ### restart
170 |
171 | ```js
172 | api.restart('why');
173 | ```
174 |
175 | rerun `umi dev`.
176 |
177 | ### rebuildTmpFiles
178 |
179 | ```js
180 | api.rebuildTmpFiles('config dva changed');
181 | ```
182 |
183 | regenerate bootstrap file (entryFile), this is the most commonly used method, plugins such as dva and locale will be used.
184 |
185 | ### refreshBrowser
186 |
187 | refresh browser.
188 |
189 | ### rebuildHTML
190 |
191 | Trigger HTML rebuild.
192 |
193 | ### changePluginOption
194 |
195 | Set the options of the plugin, such as when you need to pass the dva configuration of the plugin set to the dva plugin in the umi-plugin-react.
196 |
197 | ```js
198 | api.changePluginOption('dva-plugin-id', {
199 | immer: true
200 | });
201 | ```
202 |
203 | ### registerCommand
204 |
205 | Register the umi xxx command line, as in the umi internal help command.
206 |
207 | ```js
208 | api.registerCommand('help', {
209 | hide: true
210 | }, args => {
211 | // more code...
212 | });
213 | ```
214 |
215 | ### \_registerConfig
216 |
217 | Register a configuration item, system method, usually do not use.
218 |
219 | ```js
220 | api._registerConfig(() => {
221 | return () => {
222 | return {
223 | name: 'dva',
224 | validate: validate,
225 | onChange(newConfig, oldConfig) {
226 | api.setPluginDefaultConfig('umi-plugin-dva', config);
227 | }
228 | };
229 | }
230 | });
231 | ```
232 |
233 | ## Tool class API
234 |
235 | ### log
236 |
237 | ```js
238 | api.log.success('Done');
239 | api.log.error('Error');
240 | api.log.error(new Error('Error'));
241 | api.log.debug('Hello', 'from', 'L59');
242 | api.log.pending('Write release notes for %s', '1.2.0');
243 | api.log.watch('Recursively watching build directory...');
244 | ```
245 |
246 | Output various types of logs.
247 |
248 | ### winPath
249 |
250 | ```js
251 | api.winPath('/path/to.js');
252 | ```
253 |
254 | Convert the file path to a path compatible with window to add code such as `require('/xxx/xxx.js')`.
255 |
256 | ### debug
257 |
258 | ```js
259 | api.debug('msg');
260 | ```
261 |
262 | ### findJS
263 |
264 | xxx -> xxx.js xxx.ts
265 |
266 | ### compatDirname
267 |
268 | Look for the user project directory first, then find the plugin dependencies.
269 |
270 | ## Event class API
271 |
272 | The event class API follows the naming convention of onXxxXxx, beforeXxx, afterXxx and receives a parameter as a callback function.
273 |
274 | ### beforeDevServer
275 |
276 | Before dev server start.
277 |
278 | ### afterDevServer
279 |
280 | After dev server start.
281 |
282 | ### onStart
283 |
284 | Triggered when `umi dev` or `umi build` start.
285 |
286 | ### onDevCompileDone
287 |
288 | Triggered after `umi dev` compilation is complete.
289 |
290 | ```js
291 | api.onDevCompileDone(({ isFirstCompile, stats }) => {
292 | });
293 | ```
294 |
295 | ### onOptionChange
296 |
297 | Triggered when the configuration of the plugin changes.
298 |
299 | ```js
300 | export default (api, defaultOpts = { immer: false }) => {
301 | let opts = defaultOpts;
302 | api.onOptionChange((newOpts) => {
303 | opts = newOpts;
304 | api.rebuildFiles();
305 | });
306 | };
307 | ```
308 |
309 | ### onBuildSuccess
310 |
311 | When the `umi build` was successful. Mainly do some processing of the construction products.
312 |
313 | ```js
314 | api.onBuildSuccess({
315 | stats,
316 | } => {
317 | // handle with stats
318 | });
319 | ```
320 |
321 | ### onBuildFail
322 |
323 | When the `umi build` failed.
324 |
325 | ### onHTMLRebuild
326 |
327 | Triggered when the HTML is rebuilt.
328 |
329 | ### onGenerateFiles
330 |
331 | The routing file is triggered when the entry file is generated.
332 |
333 | ### onPatchRoute
334 |
335 | Triggered when getting the configuration of a single route, you can modify the route configuration `route` here. For example, you can add a component path to `Routes` to add a layer of encapsulation to the route.
336 |
337 | ```js
338 | api.onPatchRoute({ route } => {
339 | // route:
340 | // {
341 | // path: '/xxx',
342 | // Routes: []
343 | // }
344 | })
345 | ```
346 |
347 | ## Application class API
348 |
349 | For the application class API, there are two ways to use: direct calling and function callback.
350 |
351 | direct calling:
352 |
353 | ```js
354 | api.addRendererWrapperWithComponent('/path/to/component.js');
355 | ```
356 |
357 | function callback:
358 |
359 | ```js
360 | api.addRendererWrapperWithComponent(() => {
361 | if (opts.antd) {
362 | return '/path/to/component.js';
363 | }
364 | });
365 | ```
366 |
367 | Below is the specific API.
368 |
369 | ### modifyDefaultConfig
370 |
371 | set umi default configuration.
372 |
373 | ```js
374 | api.modifyDefaultConfig(memo => {
375 | return {
376 | ...memo,
377 | singular: true,
378 | }
379 | });
380 | ```
381 |
382 | ### addPageWatcher
383 |
384 | add watching files.
385 |
386 | ```js
387 | api.addPageWatcher(['xxx.js', '*.mock.js']);
388 | ```
389 |
390 | ### addHTMLMeta
391 |
392 | add meta in HTML.
393 |
394 | ### addHTMLLink
395 |
396 | add link in HTML.
397 |
398 | ### addHTMLStyle
399 |
400 | add tyle in HTML.
401 |
402 | ### addHTMLScript
403 |
404 | Add a script at the bottom of the HTML.
405 |
406 | ```js
407 | api.addHTMLScript({
408 | content: '',
409 | src: '',
410 | // ...attrs
411 | });
412 | ```
413 |
414 | ### addHTMLHeadScript
415 |
416 | Add a script to the HTML head.
417 |
418 | ### modifyHTMLChunks
419 |
420 | Modify chunks in HTML, default `['umi']`.
421 |
422 | ### modifyHTMLWithAST
423 |
424 | Modify the HTML, based on cheerio.
425 |
426 | Options:
427 |
428 | * route, current route
429 | * getChunkPath , get the full path of chunk, including publicPath and hash
430 |
431 | e.g.
432 |
433 | ```js
434 | api.modifyHTMLWithAST(($, { route, getChunkPath }) => {
435 | $('head').append(``);
436 | });
437 | ```
438 |
439 | ### modifyHTMLContext
440 |
441 | Modify the environment parameters when html ejs is rendered.
442 |
443 | ```js
444 | api.modifyHTMLContext((memo, { route }) => {
445 | return {
446 | ...memo,
447 | title: route.title, // The title plugin for umi-plugin-react contains similar logic
448 | };
449 | });
450 | ```
451 |
452 | ### modifyRoutes
453 |
454 | Modify the routing configuration.
455 |
456 | ```js
457 | api.modifyRoutes(({ memo, args}) => {
458 | return memo;
459 | })
460 | ```
461 |
462 | The format of the route configuration is as follows:
463 |
464 | ```js
465 | const route = {
466 | path: '/xxx',
467 | component: '/path/to/component',
468 | Routes: ['/permissionControl.js'],
469 | }
470 | ```
471 |
472 | ```js
473 | exports.routes = [{
474 | path: '/xxx',
475 | workspace: false,
476 | }];
477 | ```
478 |
479 | ```js
480 | //permissionControl.js
481 | export class Control extends Component (props) => {
482 | componentDidount() => {
483 | if(props.route.workspace === false) {
484 | window.AntdCloudNav.set()
485 | }
486 | }
487 | }
488 |
489 | ```
490 |
491 | ### addEntryImportAhead
492 |
493 | add import at the top of the entry file.
494 |
495 | ```js
496 | api.addEntryImportAhead({
497 | source: '/path/to/module',
498 | specifier: 'name', // module name with import, can be ignored
499 | });
500 | ```
501 |
502 | ### addEntryPolyfillImports
503 |
504 | Same as `addEntryImportAhead`, but as a polyfill, so add it first.
505 |
506 | ### addEntryImport
507 |
508 | Import module in the entry file.
509 |
510 | ```js
511 | api.addEntryImport({
512 | source: '/modulePath/xxx.js',
513 | specifier: 'moduleName',
514 | });
515 | ```
516 |
517 | ### addEntryCodeAhead
518 |
519 | Add code before render.
520 |
521 | ```js
522 | api.addEntryCodeAhead(`
523 | console.log('addEntryCodeAhead');
524 | `);
525 | ```
526 |
527 | ### addEntryCode
528 |
529 | Add code after render.
530 |
531 | ### addRouterImport
532 |
533 | Add a module import to the routing file.
534 |
535 | ### addRouterImportAhead
536 |
537 | Add a module to the header of the routing file to introduce.
538 |
539 | ### addRendererWrapperWithComponent
540 |
541 | Wrapper a component outside the .
542 |
543 | ### addRendererWrapperWithModule
544 |
545 | Excute a module before mount .
546 |
547 | ### modifyEntryRender
548 |
549 | modifyEntryRender
550 |
551 | ### modifyEntryHistory
552 |
553 | modifyEntryHistory
554 |
555 | ### modifyRouteComponent
556 |
557 | modifyRouteComponent
558 |
559 | ### modifyRouterRootComponent
560 |
561 | modifyRouterRootComponent
562 |
563 | ### modifyWebpackConfig
564 |
565 | modify webpack Configuration.
566 |
567 | ```js
568 | // demo
569 | api.chainWebpackConfig((memo) => {
570 | return memo;
571 | });
572 | ```
573 |
574 | ### modifyAFWebpackOpts
575 |
576 | Modify the af-webpack configuration.
577 |
578 | ```js
579 | // demo
580 | api.modifyAFWebpackOpts((memo) => {
581 | return memo;
582 | });
583 | ```
584 |
585 | ### addMiddleware
586 |
587 | Append middleware to the dev server.
588 |
589 | ### addMiddlewareAhead
590 |
591 | Add middleware to the front of the development server.
592 |
593 | ### addMiddlewareBeforeMock
594 |
595 | Add middleware before the mock.
596 |
597 | ### addMiddlewareAfterMock
598 |
599 | Add middleware after the mock.
600 |
601 | ### addVersionInfo
602 |
603 | Added version information, displayed in `umi -v` or `umi version`.
604 |
605 | ### addRuntimePlugin
606 |
607 | Add a runtime plugin with parameters as the absolute path to the file.
608 |
609 | ### addRuntimePluginKey
610 |
611 | Add a runtime configurable item.
612 |
--------------------------------------------------------------------------------