前言
伴随着前端技术日新月异的发展,前端开发中前后端分离,工程化,自动化等现代化的开发模式越来普及,前端项目也引入了编译,构建,单元测试等现代软件工程化的标准环节。这样大提高了前端的开发效率和业务交付能力。
Yeoman构建脚手架源码
Lerna 和 Jsdoc 包管理脚手架:https://github.com/ge-tbms/generator-lerna-jsdoc-packages
TS SDK以及配合Jest测试脚手架:https://github.com/ge-tbms/generator-typescript-jest-sdk
React+SCSS+Mobx 开发环境脚手架: https://github.com/ge-tbms/generator-react-mobx-scss
Rax 组件构建脚手架(实现页面和组件分别生成):https://github.com/ge-tbms/generator-rax-component
开箱即用的源码
源码地址:https://github.com/dkypooh/front-end-develop-demo/tree/master/senior/workflow
NPM Script搭建开发工作流
npm 允许在 package.json
里面,使用 scripts
字段定义脚本命令
{
"scripts": {
"start": "node start.js"
}
}
脚本语法
npm run-script <command> [--silent] [-- <args>...]
命令行下需要使用 npm run <comand>
方式执行脚本
$ npm run start
## 等同于
$ node start.js
执行原理
配置参数
npm scripts
参数传递的命令行分割符是 '--'
, 即可将后续参数添加到 process.env.argv
数组中。例如:
$ npm run build -- --name hello
npm scripts 组合命令
npm脚本需要执行多个任务,首先需要明确它们的执行顺序,然后把他们组合起来。 如果是并行执行(即同时的平行执行),可以使用 &
符号。
$ npm run build-js & npm run build-css
如果是串行执行(即只有前一个任务成功,才执行下一个任务),可以使用 &&
符号。
$ npm run eslint && npm run build && npm run publish
从代码检查,到代码构建,最后到发布。
默认命令
默认命令可以省略掉 run
npm start 是 npm run start
npm stop 是 npm run stop的简写
npm test 是 npm run test的简写
npm restart 是 npm run stop && npm run restart && npm run start的简写
npm钩子
npm提供了两种钩子,pre和post,分别代表操作前和操作后
{
"scripts": {
"prebuild": "echo 1",
"build": "echo 2",
"postbuild": "echo 3"
}
}
用户执行 npm run build
的时候,会自动按照下面的顺序执行。
$ npm run prebuild && npm run build && npm run postbuild
## 最终输出
$ 123
默认钩子
- prepublish,postpublish
- preinstall,postinstall
- preuninstall,postuninstall
- preversion,postversion
- pretest,posttest
- prestop,poststop
- prestart,poststart
- prerestart,postrestart
Yeoman Generator搭建开发工作流
Yeoman,它不只是一个工具,而是一个工作流。它其实包括了三个部分yo、grunt、bower,分别用于项目的启动、文件操作、包管理。
打造一个自己的集成工具流
安装及步骤
可以同时安装 Yeoman(yo
) 和 Generator(generator-generator
)构建器脚本
$ npm i -g yo generator-generator
生成文件目录
$ yo generator
标准Generator目录
templates
是模板目录,例如 React
工程脚手架, index.js
入口文件,维护 Yoeman
各个生命周期。
├── LICENSE
├── README.md
├── __tests__
│ └── app.js
├── generators
│ └── app
│ └── templates // 模板目录
│ ├── index.js // 入口文件
└── package.json
生命周期回调
- initializing - Your initialization methods (checking current project state, getting configs, etc)
- 初始化方法(检验当前项目状态、获取configs、等)
- prompting - Where you prompt users for options (where you’d call this.prompt())
- 人机交互,获取用户选项
- configuring - Saving configurations and configure the project (creating .editorconfig files and other metadata files)
- 保存配置(创建 .editorconfig 文件)
- default - If the method name doesn’t match a priority, it will be pushed to this group.
- 如果函数名称如生命周期钩子不一样,则会被放进这个组
- writing - Where you write the generator specific files (routes, controllers, etc)
- 写generator特殊的文件(路由、控制器、等)
- conflicts - Where conflicts are handled (used internally)
- 冲突后处理办法
- install - Where installations are run (npm, bower)
- 选择安装依赖(npm、bower)
- end - Called last, cleanup, say good bye, etc
- 安装结束、清除文件、设置good bye文案、等
构建React开发脚手架
我们以 Mobx状态管理 这章我们一起搭建React + Mobx + SCSS
工程环境为脚手架模板(app/templates)。通过 yeoman
集成成通用脚手架工具。视频案例:
生成器安装
$ npm i -g generator-react-mobx-scss
入口文件初始化
Generator
的 index.js
文件,需要集成 yeoman-generator
基类
var Generator = require('yeoman-generator');
module.exports = class extends Generator {};
生命周期节点实现
Initializing
初始化获取用户名信息
// 初始化获取用户名信息
initializing() {
try {
this.username = process.env.USER || process.env.USERPROFILE.split(require('path').sep)[2]
} catch (e) {
this.username = ''
}
}
Prompting
获取基本配置信息
// 获取基本配置信息
return this.prompt([
// 项目名称
{
type: 'input',
name: 'name',
message: 'Your project name',
// 项目描述
{
type: 'input',
name: 'description',
message: 'Your project description',
default: ''
},
// 用户名(默认系统)
{
type: 'input',
name: 'username',
message: 'Your name',
default: this.username
},
// 邮箱信息
{
type: 'input',
name: 'email',
message: 'Your email',
default: ''
},
// npm 镜像选择
{
type: 'list',
name: 'registry',
message: 'Which registry would you use?',
choices: [
'https://registry.npm.taobao.org',
'https://registry.npmjs.org'
]
}
]).then(answers => {
this.answers = answers
this.obj = {answers: this.answers}
})
Writing
模板文件复制到项目目录,同时动态插入配置信息
const _ = require('lodash')
this.fs.copy(this.templatePath('static', '*'), this.destinationPath('static'))
this.fs.copyTpl(this.templatePath('src'), this.destinationPath('src'), this.obj, {
interpolate: /<%=([\s\S]+?)%>/g
});
this.fs.copy(this.templatePath('index.js'), this.destinationPath('index.js'))
this.fs.copy(this.templatePath('babelrc'), this.destinationPath('.babelrc'))
this.fs.copy(this.templatePath('gitignore'), this.destinationPath('.gitignore'))
this.fs.copy(this.templatePath('eslintrc'), this.destinationPath('.eslintrc'))
this.fs.copy(this.templatePath('editorconfig'), this.destinationPath('.editorconfig'))
this.fs.copyTpl(this.templatePath('webpack.config.js'), this.destinationPath('webpack.config.js'))
// 动态插入配置信息, 生成Package.json文件
this.fs.copyTpl(this.templatePath('package.json_vm'), this.destinationPath('package.json'), this.obj)
// 动态插入配置信息, 生成模板ReadME.md
this.fs.copyTpl(this.templatePath('readme.md'), this.templatePath('readme.md'), this.obj)
Install
可以选择 npm
或者 yarn
安装依赖。
// 语法结构:npmInstall(pkgs?: string|string[], options?: object, spawnOptions?: object): void;
// undefined为全部安装
install() {
this.npmInstall(undefined, {
registry: this.answers.registry
})
}
End
end() {
this.log.ok('Project ' + this.answers.name + ' generated!!!')
this.spawnCommand('npm', ['start'])
}
结语
在 React组件
章节学习中,大家也接触到了 npm scripts
的使用,本章节系统化的带大家一起学习 npm
脚本以及 npm hooks
来管理项目周期。同时带大家一起学习了 Yeoman
基本原理和生命周期。最后以 react-mobx-scss
项目为模板,一起开发了 generator-react-mobx-scss
脚手架生成器,读者可以在自己平时的项目中使用此脚手架生成器。