前端进阶能力 - 构建开发工作流 - 图1

前言

伴随着前端技术日新月异的发展,前端开发中前后端分离,工程化,自动化等现代化的开发模式越来普及,前端项目也引入了编译,构建,单元测试等现代软件工程化的标准环节。这样大提高了前端的开发效率和业务交付能力。

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 字段定义脚本命令

  1. {
  2. "scripts": {
  3. "start": "node start.js"
  4. }
  5. }

脚本语法

  1. npm run-script <command> [--silent] [-- <args>...]

命令行下需要使用 npm run <comand> 方式执行脚本

  1. $ npm run start
  2. ## 等同于
  3. $ node start.js

执行原理

配置参数

npm scripts 参数传递的命令行分割符是 '--', 即可将后续参数添加到 process.env.argv 数组中。例如:

  1. $ npm run build -- --name hello

npm scripts 组合命令

npm脚本需要执行多个任务,首先需要明确它们的执行顺序,然后把他们组合起来。 如果是并行执行(即同时的平行执行),可以使用 & 符号。

  1. $ npm run build-js & npm run build-css

如果是串行执行(即只有前一个任务成功,才执行下一个任务),可以使用 && 符号。

  1. $ npm run eslint && npm run build && npm run publish

从代码检查,到代码构建,最后到发布。

默认命令

默认命令可以省略掉 run

  1. npm start 是 npm run start
  2. npm stop 是 npm run stop的简写
  3. npm test 是 npm run test的简写
  4. npm restart 是 npm run stop && npm run restart && npm run start的简写

npm钩子

npm提供了两种钩子,pre和post,分别代表操作前和操作后

  1. {
  2. "scripts": {
  3. "prebuild": "echo 1",
  4. "build": "echo 2",
  5. "postbuild": "echo 3"
  6. }
  7. }

用户执行 npm run build 的时候,会自动按照下面的顺序执行。

  1. $ npm run prebuild && npm run build && npm run postbuild
  2. ## 最终输出
  3. $ 123

默认钩子

  • prepublish,postpublish
  • preinstall,postinstall
  • preuninstall,postuninstall
  • preversion,postversion
  • pretest,posttest
  • prestop,poststop
  • prestart,poststart
  • prerestart,postrestart

Yeoman Generator搭建开发工作流

Yeoman,它不只是一个工具,而是一个工作流。它其实包括了三个部分yo、grunt、bower,分别用于项目的启动、文件操作、包管理。

打造一个自己的集成工具流

源码地址:https://github.com/dkypooh/front-end-develop-demo/tree/master/senior/workflow/generator-react-mobx-scss

安装及步骤

可以同时安装 Yeoman(yo) 和 Generator(generator-generator)构建器脚本

  1. $ npm i -g yo generator-generator

生成文件目录

  1. $ yo generator

标准Generator目录

templates 是模板目录,例如 React 工程脚手架, index.js 入口文件,维护 Yoeman 各个生命周期。

  1. ├── LICENSE
  2. ├── README.md
  3. ├── __tests__
  4. │ └── app.js
  5. ├── generators
  6. │ └── app
  7. │ └── templates // 模板目录
  8. │ ├── index.js // 入口文件
  9. └── package.json

生命周期回调

前端进阶能力 - 构建开发工作流 - 图2

  1. initializing - Your initialization methods (checking current project state, getting configs, etc)
    • 初始化方法(检验当前项目状态、获取configs、等)
  2. prompting - Where you prompt users for options (where you’d call this.prompt())
    • 人机交互,获取用户选项
  3. configuring - Saving configurations and configure the project (creating .editorconfig files and other metadata files)
    • 保存配置(创建 .editorconfig 文件)
  4. default - If the method name doesn’t match a priority, it will be pushed to this group.
    • 如果函数名称如生命周期钩子不一样,则会被放进这个组
  5. writing - Where you write the generator specific files (routes, controllers, etc)
    • 写generator特殊的文件(路由、控制器、等)
  6. conflicts - Where conflicts are handled (used internally)
    • 冲突后处理办法
  7. install - Where installations are run (npm, bower)
    • 选择安装依赖(npm、bower)
  8. end - Called last, cleanup, say good bye, etc
    • 安装结束、清除文件、设置good bye文案、等

构建React开发脚手架

我们以 Mobx状态管理 这章我们一起搭建React + Mobx + SCSS工程环境为脚手架模板(app/templates)。通过 yeoman 集成成通用脚手架工具。视频案例:

生成器安装

  1. $ npm i -g generator-react-mobx-scss

入口文件初始化

Generator 的 index.js 文件,需要集成 yeoman-generator 基类

  1. var Generator = require('yeoman-generator');
  2. module.exports = class extends Generator {};

生命周期节点实现

Initializing

初始化获取用户名信息

  1. // 初始化获取用户名信息
  2. initializing() {
  3. try {
  4. this.username = process.env.USER || process.env.USERPROFILE.split(require('path').sep)[2]
  5. } catch (e) {
  6. this.username = ''
  7. }
  8. }

Prompting

获取基本配置信息

  1. // 获取基本配置信息
  2. return this.prompt([
  3. // 项目名称
  4. {
  5. type: 'input',
  6. name: 'name',
  7. message: 'Your project name',
  8. // 项目描述
  9. {
  10. type: 'input',
  11. name: 'description',
  12. message: 'Your project description',
  13. default: ''
  14. },
  15. // 用户名(默认系统)
  16. {
  17. type: 'input',
  18. name: 'username',
  19. message: 'Your name',
  20. default: this.username
  21. },
  22. // 邮箱信息
  23. {
  24. type: 'input',
  25. name: 'email',
  26. message: 'Your email',
  27. default: ''
  28. },
  29. // npm 镜像选择
  30. {
  31. type: 'list',
  32. name: 'registry',
  33. message: 'Which registry would you use?',
  34. choices: [
  35. 'https://registry.npm.taobao.org',
  36. 'https://registry.npmjs.org'
  37. ]
  38. }
  39. ]).then(answers => {
  40. this.answers = answers
  41. this.obj = {answers: this.answers}
  42. })

Writing

模板文件复制到项目目录,同时动态插入配置信息

  1. const _ = require('lodash')
  2. this.fs.copy(this.templatePath('static', '*'), this.destinationPath('static'))
  3. this.fs.copyTpl(this.templatePath('src'), this.destinationPath('src'), this.obj, {
  4. interpolate: /<%=([\s\S]+?)%>/g
  5. });
  6. this.fs.copy(this.templatePath('index.js'), this.destinationPath('index.js'))
  7. this.fs.copy(this.templatePath('babelrc'), this.destinationPath('.babelrc'))
  8. this.fs.copy(this.templatePath('gitignore'), this.destinationPath('.gitignore'))
  9. this.fs.copy(this.templatePath('eslintrc'), this.destinationPath('.eslintrc'))
  10. this.fs.copy(this.templatePath('editorconfig'), this.destinationPath('.editorconfig'))
  11. this.fs.copyTpl(this.templatePath('webpack.config.js'), this.destinationPath('webpack.config.js'))
  12. // 动态插入配置信息, 生成Package.json文件
  13. this.fs.copyTpl(this.templatePath('package.json_vm'), this.destinationPath('package.json'), this.obj)
  14. // 动态插入配置信息, 生成模板ReadME.md
  15. this.fs.copyTpl(this.templatePath('readme.md'), this.templatePath('readme.md'), this.obj)

Install

可以选择 npm 或者 yarn 安装依赖。

  1. // 语法结构:npmInstall(pkgs?: string|string[], options?: object, spawnOptions?: object): void;
  2. // undefined为全部安装
  3. install() {
  4. this.npmInstall(undefined, {
  5. registry: this.answers.registry
  6. })
  7. }

End

  1. end() {
  2. this.log.ok('Project ' + this.answers.name + ' generated!!!')
  3. this.spawnCommand('npm', ['start'])
  4. }

结语

在 React组件 章节学习中,大家也接触到了 npm scripts 的使用,本章节系统化的带大家一起学习 npm 脚本以及 npm hooks 来管理项目周期。同时带大家一起学习了 Yeoman 基本原理和生命周期。最后以 react-mobx-scss 项目为模板,一起开发了 generator-react-mobx-scss 脚手架生成器,读者可以在自己平时的项目中使用此脚手架生成器。

参考文献