在前端快速发展的今天,如果不能时刻保持学习就会很快被淘汰。分享一下前端工程化中有关于脚手架的相关知识,文章有点长,希望对大家有所帮助。每天进步一点点。
1、脚手架是前端工程化的发起者,它可以自动创建项目基础解构,提供项目规范和约定
2、脚手架工具的工作原理其实很简单,在启动脚手架之后,它会自动的询问一些预设的问题,然后将你回答的问题结合模板文件生成项目的结构
3、在搭建新项目的时候,项目中会有一些相同的组织结构,相同的开发范式,相同的模块依赖,相同的工具配置,相同的基础代码。使用脚手架工具可以快速搭建一个特定的项目骨架,把这些大量的重复的机械性的复杂的工作自动完成,后期基于这个骨架进行开发。
4、例如,IDE创建项目的过程就是一个脚手架的工作流程
脚手架的实现方式:根据开发者提供的信息自动创建对应的项目基础结构、文件,以及一些特定的配置
React 项目:create-react-app
Vue.js 项目:vue-cli
Angular 项目:angular-cli
Yeoman、Plop
可以说是最老牌,最强大,最通用的一款工具,它有很多值得我们借鉴和学习的地方。Yeoman搭配Generator可以创建任何类型的项目,所以我们可以通过创建自己的Generator来定制我们自己的前端脚手架
<1> 步骤概述:
a、明确你的需求
b、找到合适的Generator
c、全局范围安装找到的Generator
d、通过 yo 运行对应的Generator
e、通过命令行交互填写选项
f、生成你所需要的项目结构
<2> 具体步骤:【以 generator-node 为例】
a、确保node环境已安装
b、全局安装Yeoman npm -g i yo
c、搭配特定Generator搭建项目,全局安装 npm i -g generator-node
d、定位到项目根目录,运行 yo node
搭建项目 ,如果提示没有安装generator-node,可以再安装一下,npm i generator-node
e、根据提示输入 模块名,描述,项目地址,作者姓名,邮箱,主页,关键词(多个关键词用英文逗号隔开),是否发送代码覆盖率到平台(与后续持续集成和代码质量保证有关,可先选择No),支持 node 的版本(不输入默认全部版本),github用户名,license选择 (MIT 相对宽松的软件授权条款)
f、输入完毕后会自动在当前目录下生成一些基础文件,并自动运行 npm i
安装相应的依赖。
g、这样我们就得到了一些基础的项目结构和项目代码
了解了yeoman的使用,我们就可以基于 Yeoman 自定义 Generator 来搭建我们自己的脚手架。接下来我们使用大白话描述,快速上手实现一个我们自己的脚手架工具。
① cmd 进入终端,创建文件夹 mkdir generator-self;
② cd generator-self 进入文件夹,npm init -y 初始化 packjson.json 文件;
③ npm i yeoman-generator 安装 yeoman-generator;
④ 根据约定创建文件: generators/app/index.js , 并在编辑器中打开index.js
mkdir generators -> cd generators -> mkdir app ->echo test>app/index.js
index.js文件内容:
// index.js 是 Generator 的核心入口文件
// 在这里需要导出一个继承自 Yeoman Generator 的类型
// Yeoman Generator 在工作时会自动调用我们在此类型中定义的一些生命周期方法
// 我们在这些方法中可以通过调用父类提供的一些工具方法实现一些功能,例如写入文件
const Generator = require('yeoman-generator')
module.exports = class extends Generator {
writing() {
// Yeoman 自动在生成文件阶段调用此方法
// 我们这里尝试往项目目录中写入文件
this.fs.write( // 接收两个参数,第一个是绝对路径,第二个是写入的内容
this.destinationPath('self1.txt'),
'好好学习,天天长胖!'
)
}
}
⑤ cd… 回到 generator-self 文件夹下,运行 yarn link 将自己写的generator link到全局
⑥ 在桌面新建文件夹 my-product,在终端中切换到 my-product 文件夹下,运行 yo self,my-product文件夹中就多出一个self1.txt文本文件,内容为 好好学习,天天长胖!【若出现版本报错,可指定版本:npm i yeoman-generator**@4.0.1**】
a. 与入口文件 index.js 同级,创建 templates 文件夹(作为模板目录),并在该文件下创建 self2.txt
self2.txt文件内容:
对 templates 模板的一些说明:
将我们要生成的文件都放入templates 目录,作为模板
模板中遵循 EJS 模板引擎的模板语法,例如可以通过
<%= title %>
动态输出数据
其他的 EJS 语法也同样支持
b. 在我们的 index.js 中,我们就可以通过模板方式写入文件到目标目录
index.js 中的内容:
const Generator = require('yeoman-generator')
module.exports = class extends Generator {
writing() {
// 使用模板的方式,接收3个参数,
// 模板文件路径 输出目标路径 模板数据上下文
// 模板文件路径
const tmpl = this.templatePath('self2.txt')
// 输出目标路径
const output = this.destinationPath('self2.txt')
// 模板数据上下文
const context = { title: 'hello generator-self'}
this.fs.copyTpl(tmpl, output, context)
}
}
c. 运行 yo self,在 self2.txt 中的文件内容如下:
对template模板的一些说明:
将我们要生成的文件都放入template目录,作为模板
模板中遵循 EJS 模板引擎的模板语法,例如可以通过
hello generator-self
动态输出数据
其他的 EJS 语法也同样支持
相对于手动创建每一个文件,模板的方式大大提高了效率。特别是在文件特别多,特别复杂的情况。
a. 对于模板中的动态数据,例如项目的标题,项目的描述等等,这样的数据一般通过用户的输入来得到。可以通过 Generator 中的 prompting 方法来实现。
index.js 中的内容:
const Generator = require('yeoman-generator')
module.exports = class extends Generator {
prompting() {
// Yeoman 在询问用户环节会自动调用此方法
// 在此方法中可以调用父类的 prompt() 方法发出对用户的命令行询问
return this.prompt([ // 数组中的每一个对象是一个问题
{
type: 'input',
name: 'name',
message: 'Your project name',
default: this.appname // 用户项目生成目录的文件夹名字
},
{
type: 'input',
name: 'description',
message: 'Your project description',
default: '好好学习,天天长胖!'
}
])
.then(answers => {
this.answers = answers
})
}
writing() {
// 模板文件路径
const tmpl = this.templatePath('self.html')
// 输出目标路径
const output = this.destinationPath('self.html')
// 模板数据上下文
const context = this.answers
this.fs.copyTpl(tmpl, output, context)
}
}
b. 在templates文件夹下创建 self.html ,内容:
<%= name %>
<%= name %>
<%= description %>
c. 运行 yo self,在 self.html 中的项目名字和描述为用户自己输入的
脚手架工具其实就是node-cli的应用,创建脚手架工具就是创建一个node-cli应用。
1、创建项目文件夹,作为项目根目录【gongye-test】
2、进入项目根目录,npm init -y 初始化项目
3、打开 package.json 文件,增加"bin": "cli.js"
, 作为应用入口文件
4、与 package.json 同级创建 cli.js 文件,而且应用入口文件必须要有文件头 #!/usr/bin/env node
5、与 package.json 同级创建 templates 文件夹,文件夹下添加脚手架在工作时需要生成文件的模板文件【 index.html 和 index.css】
6、使用 npm link 将当前 gongye-test link 到全局
7、在桌面创建 demo 文件夹,终端进入到文件夹下,运行 gongye-test,自动生成文件
核心代码如下:
// package.json:
{
"name": "gongye-test",
"version": "1.0.0",
"description": "",
"main": "index.js",
"bin": "cli.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"ejs": "^3.1.6",
"inquirer": "^8.0.0"
}
}
// 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')
// 需要下载 inquirer 模块
const inquirer = require('inquirer')
// 需要下载 ejs 模块
const ejs = require('ejs')
inquirer.prompt([
{
type: 'input',
name: 'name',
message: 'Product name?'
}
])
.then(anwsers => { // 根据用户的回答结果生成文件
// 模板目录
const tmpDir = path.join(__dirname, 'templates')
// 目标目录
const destDir = process.cwd()
// 将模板下的文件全部转换到目标目录
// 使用 fs.readdir 方法读取模板文件夹下的所有文件
fs.readdir(tmpDir, (err, files) => {
if (err) throw err
files.forEach(file => {
// 通过模板引擎渲染文件
// renderFile 方法
// 参数1:文件的绝对路径;
// 参数2:模板引擎工作时的上下文;
// 参数3:回调函数,渲染成功之后执行
ejs.renderFile(path.join(tmpDir, file), anwsers, (err, result) => {
if (err) throw err
// fs.writeFileSync 接收两个参数,写入目录,写入内容
fs.writeFileSync(path.join(destDir, file), result)
})
})
})
})
// index.html:
<%= name %>
<%= name %>
// index.css:
body {
margin: 0;
background: #f0f0f0;
}
主要用于在项目使用中,创建特定类型文件的小工具,类似于 Yeoman 中的 sub-generator 。不过,它一般不会独立去使用,我们会把 Plop 集成到项目当中,用来自动化的去创建同类型的项目文件
在项目开发中,我们可能经常重复去创建相同类型的文件,甚至文件中的基础代码也是相同的,整个过程非常繁琐。
使用Plop就相对简单很多。我们在命令行中去运行Plop,命令行会根据之前Plop中的配置,去询问我们一些信息,然后根据我们输入的信息自动的去创建对应的文件。这样就确保了我们每次创建的文件都是统一的,而且整个过程自动完成,大大提高了我们去创建新的文件的效率。
a. 首先在项目中安装Plop模块 npm i plop --dev
b. 在项目的根目录下创建 plopfile.js 文件,作为 Plop 工作的入口文件
// Plop 入口文件,需要导出一个函数
// 此函数接收一个 plop 对象,用于创建生成器任务
module.exports = plop => {
plop.setGenerator('component', {
description: 'create a component',
prompts: [
{
type: 'input',
name: 'name',
message: 'component name',
default: 'MyComponent',
}
],
actions: [
{
type: 'add', // 添加文件
path: 'src/components/{{name}}/{{name}}.js',
templateFile: 'plop-templates/component.js.hbs'
},
{
type: 'add', // 添加文件
path: 'src/components/{{name}}/{{name}}.css',
templateFile: 'plop-templates/component.css.hbs'
},
{
type: 'add', // 添加文件
path: 'src/components/{{name}}/{{name}}.html',
templateFile: 'plop-templates/component.html.hbs'
}
]
})
}
c. 在项目的根目录下创建 plop-templates 文件夹作为模板文件目录,以及在文件夹下新建 component.html.hbs 文件,component.css.hbs 文件,以及 component.js.hbs 文件等
// component.html.hbs 文件中:
html
// component.css.hbs 文件中:
css
// component.js.hbs 文件中:
js
d. 运行 plop 创建文件 yarn plop component
将plop模块作为项目开发依赖安装
在项目根目录下创建一个 plopfile.js 文件
在plopfile.js 文件中定义脚手架任务
编写用于生成特定类型文件的模板
通过Plop 提供的CLI运行脚手架任务