什么是脚手架?
一般每个公司或者团队的前端项目,都会有固定的项目结构,打包配置方案,代码风格规范等。但是不同项目,项目名称,配置等又有所不同。
脚手架就是可以帮助我们生成特定的项目结构,打包配置方案,代码风格规范的新项目模板,同时又可以个性化配置一些选项。
脚手架的工作过程
1. 通过命令行交互询问用户问题
2. 根据用户回答的结果生成文件
为什么要自己写?
现在的确有很多主流的脚手架比如vue-cli、create-react-app等,还有专注开发脚手架yeoman等,主要是因为这些不符合公司项目结构,还有就是这个是公司内部的项目模,不能开源。
开发脚手架
项目模板
因为考虑到项目模板会更新,所以模板作为一个单独项目维护,托管在gitlab的仓库中,模板就是模板引擎。
基本流程如下:
- 将项目模板clone到当前运行目录的templates目录下
- 判断是否已经存在templates,如果存在需要删除在重新clone
- templates不存在,直接clone
-
使用inquirer进行控制台交互,获取用户自定义信息
-
递归遍历模板
- 如果是目录,创建目录
- 如果是文件,使用ejs包去替换模板引擎中用户自定义的信息,然后将处理后的结果文件写到目标目录下
使用到的工具如下
- git项目克隆工具:download-git-repo
- 删除文件工具包: rimraf
- 控制台交互工具:inquirer
- 控制台输出字符串的样式:chalk
- js模板引擎: ejs
工具代码
- package.json中指定npm包命令的入口文件
{
"name": "test-template",
"version": "1.0.1",
"description": "脚手架",
"main": "index.js",
"bin": "cli.js", // 指定npm包命令的入口文件
"keywords": ["npm","node"],
"author": "jill",
"license": "ISC",
"dependencies": {
"chalk": "^4.1.0",
"download-git-repo": "^3.0.2",
"ejs": "^3.1.6",
"inquirer": "^7.3.3",
"rimraf": "^3.0.2"
}
}
- 用户交互配置文件config/index.js
module.exports = [
{ // 初始化项目名称
type: 'input',
name: 'name',
message: `what's this project name?`,
// default: '11',
validate: function (input) {
// Declare function as asynchronous, and save the done callback
let done = this.async();
const reg = new RegExp('[\\\\/:*?\"<>|@]')
if (reg.test(input)) {
done('You cannot enter special characters');
return;
}
// Pass the return value in the done callback
done(null, true);
}
},
{ // 初始化项目的版本号
type: 'input',
name: 'version',
message: `what's this project version?`,
default: '1.0.0',
validate: function (input) {
// Declare function as asynchronous, and save the done callback
let done = this.async();
const reg = new RegExp('^[1-9]\d?(\.(0|[1-9]\d?)){2}$')
if (!reg.test(input)) {
done('Please enter the correct version number');
return;
}
// Pass the return value in the done callback
done(null, true);
}
},
// 根据实际情况,自定义配置
......
]
- 主文件cli.js:
#!/usr/bin/env node
// Node CLI 应用入口文件必须要有这样的文件头
const path = require('path')
const fs = require('fs')
const inquirer = require('inquirer')
const download = require('download-git-repo')
const chalk = require('chalk');
const ejs = require('ejs')
const rimraf = require('rimraf');
const inquirerConfig = require('./config')
const log = console.log;
const project = {
repository: 'xxxx/test-template.git',
branch: 'develop'
}
const templateDir = path.join(__dirname, 'templates')
if (fs.existsSync(templateDir)) {
// templates已经存在要删除重新下载
rimraf(templateDir, function (err) {
if (err) throw err;
downloadTemplate()
});
} else {
downloadTemplate()
}
function downloadTemplate () {
log(chalk.green.bold('loading...'));
download(`direct:${project.repository}#${project.branch}`, templateDir, { clone: true }, function (err) {
if (err) {
throw err
}
// 下载成功, 用户交互:获取用户自定义信息
inquirer.prompt(inquirerConfig).then(answers => {
const templateDir = path.join(__dirname, 'templates')
let targetDir = process.cwd()
targetDir = path.join(targetDir, answers.name)
// 创建项目目录
fs.mkdirSync(targetDir)
readTemplate(templateDir, targetDir, answers)
})
})
}
// 深度遍历读取文件内容,进行模板替换
function readTemplate (templateDir, destDir, answers) {
fs.readdir(templateDir, (err, files) => {
if (err) throw err
files.forEach(file => {
const crrentTemplate = path.join(templateDir, file)
let state = fs.lstatSync(crrentTemplate);
if (state.isDirectory()) {
/***
* 是文件夹
* 在目标目录下创建文件夹
* 递归遍历子文件
* ***/
const targetPath = path.join(destDir, file)
fs.mkdirSync(targetPath)
readTemplate(crrentTemplate, targetPath, answers)
} else {
/***
* 是文件
* 读取文件,通过模板引擎渲染文件
* 将渲染结果写入目标文件
* **/
const targetPath = path.join(destDir, file)
ejs.renderFile(crrentTemplate, answers, (err, result) => {
if (err) throw err
fs.writeFileSync(targetPath, result)
})
}
})
})
}
最后,把项目pushlish到公司npm镜像即可
如何使用
### hc-template
前端项目脚手架工具
#### 如何安装
npm install -g test-template
#### 初始化命令
hc-template
注意点
在开发过程中可以通过添加软链对项目进行调试
在工具项目目录下运行命令:
npm link / yarn link // 添加
npm unlink / yarn unlink // 移除
即可在全局范围内使用 test-template命令,对项目进行调试
如果运行命令报错,可能是权限问题:
-
如果是 Linux 或者 macOS 系统下还需要修改此文件的读写权限为 755
-
具体就是通过 chmod 755 cli.js 实现修改