脚手架的本质作用

创建项目基础结构、提供项目规范和约定

  • 相同的组织结构
  • 相同的开发范式
  • 相同的模块依赖
  • 相同的工具配置
  • 相同的基础代码

内容概要:

  • 脚手架的作用
  • 常用的脚手架工具
  • 通用脚手架工具剖析
  • 开发一款脚手架

常见的脚手架工具

  • React → create-react-app
  • Vue.js项目 → vue-cli
  • Angular项目→ angular-cli

根据信息创建对应的项目基础结构

Yeoman:通用型脚手架工具

Plop:用于项目开发过程当中创建特定类型的文件
例如创建一个组件/模块所需要的文件

Yeoman

The web’s scaffolding tool for modern webapps
不同于vue-cli工具Yeoman更像是一个脚手架运行平台,我们可以通过Yeoman搭配不同的generator去创建任何类型的项目,也就是说我们可以通过创建自己的generator去定制属于我们自己的前端脚手架。

Yeoman基础使用

  • 在全局范围安装yo

    1. $ npm install yo --global
  • 安装对应的generator

    1. $ npm install generator-node --global
  • 通过yo运行generator

    1. $ cd path/to/project-dir
    2. $ mkdir my-module
    3. $ yo node

Sub Generator

  1. yo node:cli
  2. yarn link
  3. yarn
  4. my-module --help

Yeoman使用步骤总结

  1. 明确你的需求
  2. 找到合适的Generator
  3. 全局范围安装找到的Generator
  4. 通过Yo运行对应的Generator
  5. 通过命令行交互填写选项
  6. 生成你所需要的项目结构

自定义Generator

基于Yeoman搭建自己的脚手架

创建Generator模块

Generator本质上就是一个NPM模块
image.png

Plop的基本使用

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

脚手架工具的工作原理

启动脚手架工具过后,会自动的去询问预设的问题,根据回答的结果结合模板文件生成对应的项目结构
脚手架实际上就是一个cli应用

  1. // 首先通过命令行mkdir创建一个项目目录
  2. $ mkdir sample-scaffolding
  3. // 进入创建的目录
  4. $ cd sample-scaffolding\
  5. // 初始化package.json
  6. $ yarn init
  7. // 使用vscode打开项目目录
  8. code .

在package.json当中添加bin字段,用于指定cli的入口文件

  1. {
  2. "name": "sample-scaffolding",
  3. "version": "0.1.0",
  4. "main": "index.js",
  5. "bin": "cli.js",
  6. "author": "zce <w@zce.me> (https://zce.me)",
  7. "license": "MIT",
  8. "dependencies": {
  9. "ejs": "^2.6.2",
  10. "inquirer": "^7.0.0"
  11. }
  12. }

接下来再创建指定的入口文件

  1. #!/usr/bin/env node
  2. // Node CLI 应用入口文件必须要有这样的文件头
  3. // 如果是 Linux 或者 macOS 系统下还需要修改此文件的读写权限为 755
  4. // 具体就是通过 chmod 755 cli.js 实现修改
  5. // 脚手架的工作过程:
  6. // 1. 通过命令行交互询问用户问题
  7. // 2. 根据用户回答的结果生成文件
  8. const fs = require('fs')
  9. const path = require('path')
  10. const inquirer = require('inquirer')
  11. // 载入询问模块
  12. const ejs = require('ejs')
  13. // 发起命令行的询问,接受的是数组参数,数组当中每一个成员就是我们发起的命令行问题
  14. // 通过type指定输入方式,name指定问题返回值的键,message指定屏幕上给用户的提示
  15. inquirer.prompt([
  16. {
  17. type: 'input',
  18. name: 'name',
  19. message: 'Project name?'
  20. }
  21. ])
  22. .then(anwsers => {
  23. // 在then中可以接收到用户的答案
  24. // console.log(anwsers)
  25. // 根据用户回答的结果生成文件,即动态的生成项目文件,生成项目文件一般根据模板去生成文件
  26. // 明确模板目录和目标目录
  27. // 模板目录
  28. const tmplDir = path.join(__dirname, 'templates')
  29. // 目标目录
  30. const destDir = process.cwd()
  31. // 将模板下的文件全部转换到目标目录
  32. fs.readdir(tmplDir, (err, files) => {
  33. if (err) throw err
  34. files.forEach(file => {
  35. // 通过模板引擎渲染文件
  36. ejs.renderFile(path.join(tmplDir, file), anwsers, (err, result) => {
  37. if (err) throw err
  38. // 将结果写入目标文件路径
  39. fs.writeFileSync(path.join(destDir, file), result)
  40. })
  41. })
  42. })
  43. })
  1. // index.html
  2. <!DOCTYPE html>
  3. <html lang="en">
  4. <head>
  5. <meta charset="UTF-8">
  6. <meta name="viewport" content="width=device-width, initial-scale=1.0">
  7. <meta http-equiv="X-UA-Compatible" content="ie=edge">
  8. <title><%= name %></title>
  9. </head>
  10. <body>
  11. </body>
  12. </html>
  1. // style.css
  2. body {
  3. margin: 0;
  4. background-color: #f8f9fb;
  5. }

接着进入终端

  1. // 将模块link到全局
  2. $ yarn link
  3. // 通过这个命令,对应的模块就会运行
  4. $ sample-scaffolding
  5. // 安装inquirer模块对用户发起询问
  6. $ yarn add inquirer