前端进阶能力 - 构建开发工作流 - 图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

入口文件初始化

Generatorindex.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 脚手架生成器,读者可以在自己平时的项目中使用此脚手架生成器。

参考文献