工程化概述

所有以提高效率、降低成本、质量保证为目标的伎俩都属于工程化
  • 创立我的项目

    • 通过脚手架工具创立我的项目构造
  • 编码

    • 格式化代码
    • 编译、构建、打包
  • 预览/测试

    • Web Server/Mock
    • HMR
    • Source Map
  • 提交

    • Git Hooks
    • 继续集成
  • 部署

    • CI/CD
    • 主动公布

脚手架工具

实质:创立我的项目根底构造、提供我的项目标准和约定

Yeoman(通用型脚手架工具)

根本应用

装置 yeoman

npm install -g yo

而后装置所需的 generatorGenerators 是名为 generator-XYZnpm 包。这里装置 node generator

npm install -g generator-node

执行脚手架搭建新我的项目

yo node

Sub Generator

须要依据对应的 Generator 文档判断是否存在 Sub Generator

装置对应 sub Generator

yo node:cli

链接以后模块到全局

npm link

执行查看后果

my-module --help// 输入  testing  Usage    $ my-module [input]  Options    --foo  Lorem ipsum. [Default: false]  Examples    $ my-module    unicorns    $ my-module rainbows    unicorns & rainbows

应用步骤总结

  • 明确需要,找到适合的 Generator
  • 全局范畴装置找到的 Generator
  • 通过 yo 运行对应的 Generator
  • 通过命令行交互填写选项
  • 生成所须要的我的项目构造

自定义 Generator

装置 generator 基类

yarn add yeoman-generator

创立 generators/app/index.js 为 Generator 的外围入口

// 此文件作为 Generator 的外围入口// 须要导出一个继承自 Yeoman Generator 的类型// Yeoman Generator 在工作时会主动调用咱们在此类型中定义的一些生命周期办法// 咱们在这些办法中能够通过调用父类提供的一些工具办法实现一些性能,例如文件写入const Generator = require("yeoman-generator");module.exports = class extends Generator {  writing() {    // Yeoman 主动在生成文件阶段调用此办法    this.fs.write(this.destinationPath("temp.txt"), Math.random().toString());  }};

执行 npm link后,创立新模块并执行

yo sample

依据模板创立文件

// 模板module.exports = class extends Generator {  writing() {    // 模板文件门路    const tmpl = this.templatePath("foo.txt");    // 输入文件门路    const output = this.destinationPath("foo.txt");    // 模板数据上下文    const context = { title: "hello", success: true };    this.fs.copyTpl(tmpl, output, context);  }};

接管用户输出

module.exports = class extends Generator {  prompting() {    // Yeoman 在询问用户环节会主动调用此办法    // 在此办法中能够调用父类的 prompt() 办法收回对用户的命令行询问    return this.prompt([      {        type: "input", // 用户输出类        name: "title", // 接管参数的键        message: "message title", // 提醒        default: "hello", // 默认值      },      {        type: "input", // 用户输出类        name: "success", // 接管参数的键        message: "message status", // 提醒        default: false, // 默认值      },    ]).then((answer) => {      this.answer = answer;    });  }  writing() {    // 模板文件门路    const tmpl = this.templatePath("foo.txt");    // 输入文件门路    const output = this.destinationPath("input.txt");    // // 模板数据上下文    // const context = { title: "hello", success: true };    this.fs.copyTpl(tmpl, output, this.answer);  }};

Plop(创立特定类型文件)

根本应用

  • 将 plop 模块作为我的项目开发依赖装置
  • 在我的项目根目录下创立一个 plopfile.js 文件
  • 在 plopfile.js 文件中定义脚手架工作
  • 编写用于生成特定类型文件的模板
  • 通过 plop 提供的 cli 运行脚手架工作

装置 plop 扩大模块

yarn add plop --dev

在我的项目根目录下创立 plopfile.js 入口文件

// plop 入口文件,须要导出一个函数// 此函数接管一个 plop 对象,用户创立生成器工作module.exports = (plop) => {  plop.setGenerator("component", {    description: "create component",    prompts: [      {        type: "input",        name: "name",        message: "component name",        default: "myComponent",      },    ],    actions: [      {        type: "add",        path: "src/components/{{name}}/index.js",        templateFile: "templates/component.js.hbs",      },      {        type: "add",        path: "src/components/{{name}}/index.css",        templateFile: "templates/component.css.hbs",      },      {        type: "add",        path: "src/components/{{name}}/index.html",        templateFile: "templates/component.html.hbs",      },    ],  });};

编写用于生成特定类型文件的模板 component.html.hbs

console.log("{{name}}")

运行

yarn plop component

脚手架工具原理

  • 通过命令行交互询问用户问题
  • 依据用户答复的后果生成文件

Node CLI 的入口配置是 package.json 文件中的 bin,利用入口文件必须要有这样的文件头。如果是 Linux 或者 macOS 零碎下还须要批改此文件的读写权限为 755

#!/usr/bin/env node

文件配置

#!/usr/bin/env nodeconsole.log("start......");const inquirer = require("inquirer");const fs = require("fs");const path = require("path");const ejs = require("ejs");inquirer  .prompt([    {      type: "input",      name: "name",      message: "project name",    },  ])  .then((answer) => {    console.log(answer);    // 模板目录    const tmplDir = path.join(__dirname, "templates");    // 目标目录    const destDir = process.cwd();    // 将模板下的文件全副转换到目标目录    fs.readdir(tmplDir, (err, files) => {      if (err) throw err;      files.forEach((file) => {        // 通过模板引擎渲染文件        ejs.renderFile(path.join(tmplDir, file), answer, (err, result) => {          if (err) throw err;          // 将后果写入指标文件门路          fs.writeFileSync(path.join(destDir, file), result);        });      });    });  });