使用 Umi 的微生成器快速助力业务交付
在项目中的最好的提效方案就是复用,比如将常用模块封装,给到其他页面复用,就是我们经常提到的组件(复制使用的情况)。将项目中的方案进行封装,给到不同的项目中使用,就是我们说到的脚手架。而这些好的组件或者脚手架,要快速的被其他人员使用,就要用到生成器。简单的理解就是使用脚本帮你复制了一份,像很多项目中经常会执行的新建项目就是生成器的一种能力体现。
npx create-xxx appName
Umi 中将生成器的目标定的更加细化,不是提供一整个脚手架,而是提供脚手架中的某一个方案,所以取名微生成器,其实灵感来源是 modern.js 的微生成器。
Umi 的微生成器有统一的命令入口调用:
umi generate (alias: umi g) [type]
内置微生成器列表
页面生成器
比如快速生成一个初始的简单页面,可以使用一下方法方式。
交互式输入页面名称和文件生成方式:
$ umi g page
? What is the name of page? › mypage
? How dou you want page files to be created? › - Use arrow-keys. Return to submit.
❯ mypage/index.{tsx,less}mypage.{tsx,less}
或者直接指明页面名称直接生成:
$ umi g page foo
Write: src/pages/foo.tsx
Write: src/pages/foo.less
如果你的项目风格是使用目录方式,比如基于 Umi 构建的前端框架 alita 中,就只有目录下的 index 文件才会被识别成路由,所以就可以采用以目录方式生成页面,目录下为页面的组件和样式文件:
$ umi g page bar --dir
Write: src/pages/bar/index.less
Write: src/pages/bar/index.tsx
批量生成多个页面:
$ umi g pagepage1page2 a/nested/page3
info- @local
Write: src/pages/page1.tsx
Write: src/pages/page1.less
Write: src/pages/page2.tsx
Write: src/pages/page2.less
Write: src/pages/a/nested/page3.tsx
Write: src/pages/a/nested/page3.less
剩余内置微生成器清单
后续我们会在介绍每一个能力的时候,使用到对应的微生成器。
组件生成器
在 src/components/
目录下生成项目需要的组件。和页面生成器一样,组件生成器也有多种生成方式。
交互式生成:
$ umi g component
info- @local
✔ Please input you component Name … foo
Write: src/components/Foo/index.ts
Write: src/components/Foo/Foo.tsx
直接生成:
$ umi g component bar
info- @local
Write: src/components/Bar/index.ts
Write: src/components/Bar/Bar.tsx
嵌套生成:
$ umi g component group/subgroup/baz
info- @local
Write: src/components/group/subgroup/Baz/index.ts
Write: src/components/group/subgroup/Baz/Baz.tsx
批量生成:
$ umi g component apple banana orange
info- @local
Write: src/components/Apple/index.ts
Write: src/components/Apple/Apple.tsx
Write: src/components/Banana/index.ts
Write: src/components/Banana/Banana.tsx
Write: src/components/Orange/index.ts
Write: src/components/Orange/Orange.tsx
RouteAPI 生成器
生成 routeAPI 功能的模板文件。
交互式生成:
$umi g api
info- @local
✔ please input your api name: … starwar/people
Write: api/starwar/people.ts
直接生成:
$ umi g api films
info- @local
Write: api/films.ts
嵌套生成器:
$ umi g api planets/[id]
info- @local
Write: api/planets/[id].ts
批量生成:
$ umi g api spaceships vehicles species
info- @local
Write: api/spaceships.ts
Write: api/vehicles.ts
Write: api/species.ts
Mock 生成器
生成 Mock 功能的模板文件,mock 的具体实现参考文档。
交互式生成:
$ umi g mock
info- @local
✔ please input your mock file name … auth
Write: mock/auth.ts
直接生成:
$ umi g mock acl
info- @local
Write: mock/acl.ts
嵌套生成:
$ umi g mock users/profile
info- @local
Write: mock/users/profile.ts
Prettier 配置生成器
为项目生成 prettier 配置,命令执行后,umi
会生成推荐的 prettier 配置和安装相应的依赖。
$ umi g prettier
info- @local
info- Write package.json
info- Write .prettierrc
info- Write .prettierignore
Jest 配置生成器
为项目生成 jest 配置,命令执行后,umi
会生成 Jest 配置和安装相应的依赖。根据需要选择是否要使用 @testing-library/react 做 UI 测试。
$ umi g jest
info- @local
✔ Will you use @testing-library/react for UI testing?! … yes
info- Write package.json
info- Write jest.config.ts
Tailwind CSS 配置生成器
为项目开启 Tailwind CSS 配置,命令执行后,umi
会生成 Tailwind CSS 和安装相应的的依赖。
$ umi g tailwindcss
info- @local
info- Write package.json
set config:tailwindcss on /Users/umi/playground/.umirc.ts
set config:plugins on /Users/umi/playground/.umirc.ts
info- Update .umirc.ts
info- Write tailwind.config.js
info- Write tailwind.css
DvaJS 配置生成器
为项目开启 Dva 配置,命令执行后,umi
会生成 Dva
$ umi g dva
info- @local
set config:dva on /Users/umi/umi-playground/.umirc.ts
set config:plugins on /Users/umi/umi-playground/.umirc.ts
info- Update config file
info- Write example model
自定义微生成器
当然官方提供的基本的微生成器,肯定无法满足我们特定的项目需求,我们可以通过简单的调用和约定来自定义微生成器。 比如官方提供的 g page
只生成了简单的页面。
import React from 'react';
import styles from './abc.less';
export default function Page() {return (<div><h1 className={styles.title}>Page abc</h1></div>);
}
而我们的项目中需要的初始化页面内容可能会更加复杂,要带有请求等页面模版:
import React from 'react';
import type { FC } from 'react';
import { useRequest } from 'umi';
import { query } from './service';
import styles from './index.less';
interface HomePageProps {}
const HomePage: FC<HomePageProps> = () => {const { data } = useRequest(query);return <div className={styles.center}>Hello {data?.text}</div>;
};
export default HomePage;
以上模版中提到的能力和内容会在后续的文章中体现,这里仅仅作为一个展示
要自定义微生成器,只需要调用 generateFile
指定模版存放的路径,指定需要替换的模版中的变量,既可。
generateFile({path: join(__dirname, '../../../templates/generate/page'),target: join(api.paths.absPagesPath, name),data: {color: randomColor(),name: lodash.upperFirst(name),},
});
generateFile
的目的是让开发人员在编写微生成器的时候,将精力更加聚焦于目标文件生成时的模版维护工作中。 不许花费而外的心力,去学习微生成器的功能开发。
比如我们生成上面的页面,用到的模版如下:
import React from 'react';
import type { FC } from 'react';
import { useRequest } from 'alita';
import { query } from './service';
import styles from './index.less';
interface {{{ name }}}PageProps {}
const {{{ name }}}Page: FC<{{{ name }}}PageProps> = () => {const { data } = useRequest(query);return <div className={styles.center}>Hello {data?.text}</div>;
};
export default {{{ name }}}Page;
在为用户提供微生成器时,有一些数据需要用户提供给我们,会有一些交互式的问答功能需要实现,在微生成器中,我们只需要关注问题本身。
Umi 中提供了两种问答的手段,(底层是同一套方案)第一种就是在插件中使用的,配合上面提到的 generateFile
使用
import { prompts } from '@umijs/utils';
if (!name) {const response = await prompts({type: 'text',name: 'name',message: 'What is the name of page?',});name = response.name;
}
使用 Umi 的基础微生成器工具
第二种方式就是可以脱离 Umi 的声明周期使用的,是一个基础的生成模块,你可以将它用在任意的项目中,比如我们实现一个脚手架的生成器。
const appPrompts = [{name: 'name',type: 'text',message: `What's the app name?`,default: name,},{name: 'author',type: 'text',message: `What's your name?`,},
];
const generator = new BaseGenerator({path: join(__dirname, '..', 'templates', args.plugin ? 'plugin' : 'app'),target: name ? join(cwd, name) : cwd,data:{version: require('../package').version,npmClient,registry,},questions: appPrompts,
});
await generator.run();
我们的关注点就只在模版文件(templates
)和问题(questions
)这两点上,如果模版有修改或者问题有变更,我们也只需修改这两个地方,不用耗费大量的心力去处理当前复制和写入的是文件还是文件夹,目标文件夹是否为空等文件写入边界问题。
以上提供的只是基本的模块使用方式,后续的课程中我们会展示以上代码的完整场景和实现。
(cwd, name) : cwd,data:{version: require('../package').version,npmClient,registry,},questions: appPrompts,
});
await generator.run();
我们的关注点就只在模版文件(templates
)和问题(questions
)这两点上,如果模版有修改或者问题有变更,我们也只需修改这两个地方,不用耗费大量的心力去处理当前复制和写入的是文件还是文件夹,目标文件夹是否为空等文件写入边界问题。
以上提供的只是基本的模块使用方式,后续的课程中我们会展示以上代码的完整场景和实现。
感谢阅读,今天教程仓库中没写一行代码,就不放源码归档链接了。今天更多的是微生成器的介绍,实际应用场景涉及整个最佳实践方案,我们会在后续的文章中一一体现。
最后
为大家准备了一个前端资料包。包含54本,2.57G的前端相关电子书,《前端面试宝典(附答案和解析)》,难点、重点知识视频教程(全套)。
有需要的小伙伴,可以点击下方卡片领取,无偿分享