
前言
伴随着前端技术日新月异的发展,前端开发中前后端分离,工程化,自动化等现代化的开发模式越来普及,前端项目也引入了编译,构建,单元测试等现代软件工程化的标准环节。这样大提高了前端的开发效率和业务交付能力。
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 startnpm 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 = answersthis.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.mdthis.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 脚手架生成器,读者可以在自己平时的项目中使用此脚手架生成器。
