相同的组织结构 相同的开发模式 相同的模块依赖 相同的工具配置 相同的基础代码
应用于现代化脚手架工具 主要与generator联合使用 可以创建module等
在Yeoman官网中查找
全局范围安装找到的 Generator通过yarn进行全局安装
yarn global add generator-name 通过 Yo 运行对应的 Generator使用 yo 命令运行,并自动安装对应的依赖
yo generatorName下载过程缓慢,可以对进行镜像配置
通过命令行交互填写选项生成你所需要的项目结构创建Generator就是创建一个 NPM 模块
generator-<generatorName>
generator-simple |----generators |----|----app |----|----|----index.js package.json
其中index.js文件为作为Generator的核心入口需要导出一个继承自 Yeoman Generator 的类型Yeoman Generator 在工作时会自动调用我们在此类型中定义的一些生命周期方法我们在这些方法中可以通过调用父类提供的一些工具方法实现一些功能,例如文件写入 (index.js) const Generator = require('yeoman-generator') module.exports = class extends Generator { writing () { // Yeoman 自动在生成文件阶段调用此方法 // 我们这里尝试往项目目录中写入文件 this.fs.write( this.destinationPath('temp.txt'), Math.random().toString() ) } } 使用 yarn link,将该 generator包 链接到全局 yarn link 在另一个项目中,使用generator包,会根据在index.js中的代码,生成对应的内容 cd my-proj yo simple(my-proj/temp.txt)
generator-simple |----generators |----|----app |----|----|----templates |----|----|----|----foo.txt |----|----|----index.js package.json (foo.txt)
有了模板文件,我们在生成文件时,就不需要借助于 fs.write() 方法写入了
需要通过模板方式写入文件到目标目录copyTpl,将我们的模板文件自动映射到生成的文件上 (index.js)
在另一个项目里,使用generator,得到的便是相应的模板文件内容 (my-proj/foo.txt)
generator-my-vue |----generators |----|----app |----|----|----templates |----|----|----|----。。。 |----|----|----index.js package.json
编写入口文件 app/index.js const Generator = require('yeoman-generator') module.exports = class extends Generator { prompting() { return this.prompt([ { type: 'input', name: 'name', message: 'Your project name', default: this.appname } ]) .then(answers => { this.answers = answers }) } writing() { // 把每一个文件都通过模板转换到目标路径 // 将app/templates 目录下的文件,将其相对路径用数组写出来 const templates = [ '...', '...', ... ] // 遍历 templates 下的文件路径,并通过模板文件生成对应的目标文件 templates.forEach( item => { // item => 每个文件的相对路径 const tmpl = this.templatePath(item) const output = this.destinationPath(item) const context = this.answers // 传入模板引擎 this.fs.copyTpl(tmpl, output, context) }) } } 在终端,将该generator模块生成全局模块 yarn link创建项目中,特定类型文件的小工具 如下,若项目中,需要创建很多下面这种结构的目录,且内部的文件的结构也大致一样
我们可以使用plop命令,自动创建类似的目录和文件
(plopfile.js)
// Plop 入口文件,需要导出一个函数 // 此函数接受一个 plop 对象,用于创建生成器任务 module.exports = plop = { plop.setGenerator('mycomponent', { // 生成器 名称 description : 'create a component', // 生成器 描述 prompts : [ // 生成器 输入设置(问题设置) { type : 'input', name : 'myname', message : 'MyComponent' }, ], // 指明 命令行交互过后,需要执行的动作 actions : [ { type : 'add', // 添加一个全新的文件 path : 'src/components/{{myname}}/{{myname}}.js', // 创建的路径,{{name}}指交互中的name取值 templateFile : 'plop-templates/component.hbs', // 指定 模板文件是什么 } ] }) }(component.hbs)
import React from 'react' export default () => ( <div className="{{name}}"> <h1>{{name}} Component</h1> </div> )项目目录结构
指定项目的入口文件,以及所需的包 (package.json)
{ "name": "sample-scaffolding", "version": "0.1.0", "main": "index.js", "author": "zce <w@zce.me> (https://zce.me)", "license": "MIT", "bin": "cli.js", "dependencies": { "ejs": "^2.6.2", "inquirer": "^7.0.0" } } 写模板文件 (templates/index.html) <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title><%= name %></title> </head> <body> </body> </html>(templates/style.css)
body { margin: 0; background-color: #f8f9fb; } 写脚手架入口文件 (cli.js) #!/usr/bin/env node // Node CLI 应用入口文件必须要有这样的文件头 // 如果是 Linux 或者 macOS 系统下还需要修改此文件的读写权限为 755 // 具体就是通过 chmod 755 cli.js 实现修改 // 脚手架的工作过程: // 1. 通过命令行交互询问用户问题 // 2. 根据用户回答的结果生成文件 const fs = require('fs') const path = require('path') const inquirer = require('inquirer') const ejs = require('ejs') inquirer.prompt([ { type: 'input', name: 'name', message: 'Project name?' } ]) .then(anwsers => { // console.log(anwsers) // 根据用户回答的结果生成文件 // 模板目录 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), anwsers, (err, result) => { if (err) throw err // 将结果写入目标文件路径 fs.writeFileSync(path.join(destDir, file), result) }) }) }) })