1. 腳手架介紹
1. 腳手架的本質(zhì)作用
創(chuàng)建項目基礎(chǔ)結(jié)構(gòu)、提供項目規(guī)范和約定
約定:
- 相同的組織結(jié)構(gòu)
- 相同的開發(fā)范式
- 相同的模塊依賴
- 相同的工具配置
- 相同的基礎(chǔ)代碼
eg: 舉個例子
IDE 創(chuàng)建項目的過程就是一個腳手架的工作流程
例如iOS項目在使用XCode的新建項目時而线,選擇好選項點擊創(chuàng)建流昏,最后生成的項目文件及目錄就是一個腳手架的執(zhí)行結(jié)果
前端腳手架
- 腳手架的作用
- 常用的腳手架工具
- 通用腳手架工具剖析
- 開發(fā)一款腳手架
常用的腳手架工具
- React項目 -> create-reace-app
- Vue項目 -> vue-cli
- Angular項目 -> angular-cli
都是根據(jù)信息創(chuàng)建對應(yīng)的項目基礎(chǔ)結(jié)構(gòu)
還有通用型
- Yeoman 根據(jù)一套模板生成一個對應(yīng)的項目結(jié)構(gòu)
- Plop 項目開發(fā)過程中用于生成特定類型的文件
- 例如創(chuàng)建一個組件 / 模塊所需要的文件
2. 腳手架的工作原理
2. Yeoman、Generator
Yeoman
The web's scaffolding tool for modern webapps
1. Yeoman的基本使用
- 在全局范圍安裝yo
npm install yo --global
# 或者
yarn global add yo
- 安裝對應(yīng)的generator
github.com/yeoman/generator-node
npm install generator-node --global
# 或者
yarn global add generator-node
- 通過
yo
運行generator
cd path/to/project-dir
mkdir my-module
yo node
2. Yeoman (Sub Generator)
子集生成器
yo node:cli
# 為了執(zhí)行該模塊命令可以如下操作
npm link
[module_name] --help # 查看一下
3. 常規(guī)使用步驟
- 明確你的需求;
- 找到合適的
Generator
; - 全局范圍安裝找到的
Generator
; - 通過
Yo
運行對應(yīng)的Generator
; - 通過命令行交互填寫選項;
- 生成你所需要的項目結(jié)構(gòu);
4. 自定義 Generator
基于Yeoman搭建自己的腳手架
4.1 創(chuàng)建Generator模塊
Generator 本質(zhì)上就是一個NPM模塊
- Generator 基本結(jié)構(gòu)
模塊名稱必須是 generator-<name>
# 1. 創(chuàng)建
mkdir generator-sample
# 2. 進入
cd generator-sample
# 3. 創(chuàng)建身份證
npm init
# 4. 安裝 yeoman-generator (生成器的基類)
npm i yeoman-generator
// 目錄結(jié)構(gòu)
// generators/app/index.js
// 在index.js當(dāng)中
module.exports = class extends Generator {
writing() {
// Yeoman 自動在生成文件階段調(diào)用此方法
// 我們這里嘗試往項目目錄中寫入文件
this.fs.write(
this.destinationPath('temp.txt'),
Math.random().toString()
)
}
}
- 將該模塊link到全局
npm link
- 進入到新目錄(腳手架創(chuàng)建的新項目) 執(zhí)行
yo sample
4.2 根據(jù)模板創(chuàng)建文件
模板文件夾 templates
// 創(chuàng)建模板文件夾 templates
writing() {
// Yeoman 自動在生成文件階段調(diào)用此方法
// 通過模板方式寫入文件到目標目錄
// 1. 模板文件路徑
const tmpl = this.templatePath('foo.txt')
// 2. 輸出目標路徑
const output = this.destinationPath('foo.txt')
// 3. 模板數(shù)據(jù)上下文
const context = { title: 'Hello zce~', success: false }
this.fs.copyTpl(tmpl, output, context)
}
- 相對于手動創(chuàng)建每一個文件吞获,模板的方式大大提高了效率
4.3 接收用戶輸入
prompting() {
// Yeoman 在詢問用戶環(huán)節(jié)會自動調(diào)用此方法
// 在此方法中可以調(diào)用父類的 prompt() 方法發(fā)出對用戶的命令詢問
return this.prompt([
{
type: 'input', // 用戶輸入的方式
name: 'name', // 得到結(jié)果的鍵
message: 'Your project name', // 給用戶的提示
default: this.appname // appname 為項目生成目錄的文件夾的名稱
}
]).then(answers => {
// answers = { name: 'user input value' }
this.answers = answers
})
}
4.4 Vue Generator案例
- 示例代碼
prompting() {
return this.prompt([
{
type: 'input',
name: 'projectName',
message: 'Your project name',
default: this.appname
}
]).then(answers => {
this.answers = answers
})
}
writing() {
const templates = [
'.browserslistrc',
'.editorconfig',
'.eslintrc.js',
'.gitignore',
'babel.config.js',
'package.json',
'README.md',
'tsconfig.json',
'public/favicon.ico',
'public/index.html',
'src/assets/logo.png',
'src/components/HelloWorld.vue',
'src/store/index.ts',
'src/App.vue',
'src/main.ts',
'src/shims-tsx.d.ts',
'src/shims-vue.d.ts',
'tests/unit/example.spec.ts'
]
templates.forEach(item => {
this.fs.copyTpl(
this.templatePath(item),
this.destinationPath(item),
this.answers
)
})
}
4.5 發(fā)布 Generator
3. Plop
Plop
一個小而美的腳手架工具况凉;
創(chuàng)建項目中特定類型文件的小工具;
類似于Yeoman的Sub Generator
- 舉例:比如說react項目中 每次創(chuàng)建一個頁面時需要有3個文件
- Header.css
- Header.js
- Header.test.js
- 可以將這個封裝成一個模板
1. Plop 的具體使用
- 在根目錄下創(chuàng)建 plopfile.js 文件各拷,需要導(dǎo)出一個函數(shù)刁绒,接收一個 plop 對象
- 創(chuàng)建模板文件夾
plop-templates/xxxxx.hbs
```javascript
// 模板文件舉例
import React from 'react'
export default () => {
<div className="{{name}}">
<h1>{{name}}</h1>
</div>
}
module.exports = plop => {
// arg1 生成器的名稱
// arg2 配置選項
plop.setGenerator('component', {
description: 'create a compoent', // 描述
// 命令交互
prompts: [
{
type: 'input',
name: 'name', // 鍵
message: 'component name', // 問題描述
default: 'MyComponent', // 默認值
}
],
actions: [
{
type: 'add', // 代表添加文件
path: 'src/components/{{name}}/{{name}}.js',
templateFile: 'plop-templates/components.hbs'
}
]
})
}
- 執(zhí)行
yarn plop component # (component是生成器的名稱)
總結(jié):
使用plop的步驟
- 將
plop
模塊作為項目開發(fā)依賴安裝 - 在項目根目錄下創(chuàng)建一個
plopfile.js
文件 - 在
plopfile.js
文件中定義腳手架任務(wù) - 編寫用于生成特定類型文件的模板
- 通過
Plop
提供的CLI
運行腳手架任務(wù)
4. 腳手架的工作原理
使用nodejs創(chuàng)建一個腳手架
npm init
在
pagkage.json
中添加一個"bin": "cli.js"
在
cli.js
內(nèi)
#!/usr/bin/env node
// Node CLI 應(yīng)用入口文件必須 要有這樣的文件頭
// 如果是 Linux 或者 macOS 系統(tǒng)下還需要修改此文件的讀寫權(quán)限為 755
console.log('cli working!')
// scaffolding-cli
// 腳手架的工作過程:
// 1. 通過命令行交互詢問用戶問題
// 2. 根據(jù)用戶回答的結(jié)果生成文件
// 使用 inquirer
const fs = require('fs')
const path = require('path')
const inquirer = require('inquirer')
const ejs = require('ejs')
inquirer.prompt([
{
type: 'input',
name: 'projectName',
message: 'Project name',
default: 'scaffolding-cli'
}
]).then(answers => {
console.log(answers)
// 模板目錄
const tempDir = path.join(__dirname, 'templates')
// 目標目錄
const destDir = process.cwd()
// 將模板下的文件全部輸出到目標目錄
fs.readdir(tempDir, (err, files) => {
if (err) throw err;
files.forEach(file => {
// console.log(file)
// 通過模板引擎渲染文件
ejs.renderFile(
path.join(tempDir, file),
answers,
(err, result) => {
if (err) throw err;
// 將結(jié)果寫入目標目錄
fs.writeFileSync(path.join(destDir, file), result)
}
)
})
})
})