/ 前端
分类:前端来源:站内 最近更新:2020-09-23 17:28:56浏览:1041留言:0
现在前端开发越来越把重心放到业务层上,有效的缩短了研发周期,找个开箱即用的脚手架模板项目,直接开搞。比如vue-cli,creat-react-app,umi等等。如果我们自己想要搭建一个自己的脚手架,该如何做。
首先得分析一下脚手架做了什么?脚手架主要有两个部分组成,初始化命令模块和模板项目。以vue-cli为例,脚手架包含了询问的能力,比如目录的名称,项目的描述,是否需要css预处理器,路由组件,单元测试模块等等。其次,脚手架还包含了复制下载模板项目的能力,大部分的脚手架都会把模板放到github上或者脚手架自己的目录结构里,不要以为一个空白的目录里多出的文件是写进去的,没那么复杂,大部分都是先搭建一个独立的项目作为之后复制的模板。脚手架只是替换模板里的变量,然后复制模板到项目的路径里。最后,有的脚手架还带了git初始化和安装依赖的能力。
所以,脚手架一般的步骤可分为:询问==》下载模板==》复制并写入模板==》git初始化和安装依赖。
安装脚手架的能力,我们先安装以下几个重要的依赖
commander //完整的node.js命令行解决方案,帮您通过shell里打命令的,
inquirer //node.js交互式命令行,处理一些询问的功能
download-git-repo //负责从git下载仓库到本地文件夹
mem-fs-editor //负责编辑模板里变量
其实把这几个主要的依赖包API文档看下来,就基本知道我们改如何下手单间初始化工具了。
除了上述主要依赖包,还有其他辅助依赖
const chalk = require('chalk'); // 带颜色的命令提示
const ora = require('ora'); // 提供交互spinner,就像VUE-ClI中的各种小图标├── bin //脚手架启动目录, | ├── index //入口的启动文件,和package.json总的main值对应 ├── src | ├── project.js //脚手架构造函数 | └── utils.js //辅助类工具 └── package.json
#! /usr/bin/env node
const program = require('commander');
const fse = require('fs-extra');
const inquirer = require('inquirer');
const Project = require('../src/project');
const {getPackageVersion} = require('../src/utils');
const creactProject = (projectName) => {
const project = new Project({projectName});
project.create();
};
function setProjectName(msg) {
let prompts = [];
prompts.push({
type: 'input',
name: 'projectName',
message: msg,
validate(value) {
if (!value) {
return '项目名不能为空';
}
if (fse.existsSync(value)) {
return '当前目录已存在同名项目,请更换项目名';
}
return true;
}
});
inquirer.prompt(prompts).then(answer => {
creactProject(answer.projectName);
});
}
program
.version(getPackageVersion(), '-v, --version', '当前版本')
.command('init [dirname]')
.description('创建新引用')
.action(dirname => {
if (dirname && fse.existsSync(dirname)) {
setProjectName('当前目录已存在同名项目,请更换项目名')
} else if (dirname) {
creactProject(dirname);
} else {
let prompts = [
{
type: 'confirm',
name: 'empty',
message: '确定在当前目录下建立项目吗?',
default: false
}
];
inquirer.prompt(prompts).then(answer => {
if (answer.empty) {//如果是当前目录
creactProject(dirname);
} else {
setProjectName('请输入目录名称')
}
});
}
});
program.parse(process.argv);/* 项目初始化 */
/* ================================================== */
project.prototype.create = function () {
let __this = this;
let questions = [
{
type: 'input',
name: 'appName',
message: "您的项目名称是什么?",
validate: function (value) {
let pass = value.match(/^[a-zA-Z_\-]+$/);
if (pass) {
return true;
}
return '项目名称最好是英文,下划线或者-';
},
default: 'App'
},
//…………
];
inquirer.prompt(questions).then(answers => {
__this.options = Object.assign(__this.options, answers);
__this.generate();
});
};/* 渲染项目 */
/* ================================================== */
project.prototype.generate = function () {
const __this = this;
const projectPath = path.join(process.cwd(), this.options.projectName);//新项目绝对路径
const downloadPath = path.join(projectPath, '__download__');//模板copy临时目录
const downloadSpinner = ora('正在下载模板,请稍等...');
downloadSpinner.start();
/*开始下载模板*/
const gitRepositories = 'direct:https://xxxx.git';//模板项目仓库地址
download(gitRepositories, downloadPath, {clone: true}, (err) => {
if (err) {
downloadSpinner.color = 'red';
downloadSpinner.fail(err.message);
return;
}
downloadSpinner.color = 'green';
downloadSpinner.succeed('下载模板成功');
const filesSpinner = ora('开始创建项目文件,请稍等...');
const copyFiles = getDirFileName(downloadPath);
const injectFiles = ['package.json', 'app.config.js'];
/* 复制文件 */
copyFiles.forEach((file) => {
fse.copySync(path.join(downloadPath, file), path.join(projectPath, file));
});
/* 写入变量 */
injectFiles.forEach((file) => {
this.memFsEditor.copyTpl(path.join(downloadPath, file), path.join(this.options.projectName, file), {
appName: __this.options.appName,
description: __this.options.description
});
});
/* 变量写入完成后 */
this.memFsEditor.commit(() => {
fse.remove(downloadPath);//移除临时文件
process.chdir(projectPath);//cd 到项目文件夹目录
downloadSpinner.color = 'green';
downloadSpinner.succeed('项目创建完成');
//…………
});
})
};如packjson
{
"name": "<%= appName %>",
"version": "1.0.0",
"description": "<%= description %>",
"main": "index.js",
"scripts": {
"lint": "eslint --quiet --no-inline-config src/",
},编辑好自己的脚手架之后就可以发布到npm上,供大家使用了。
npm publish
查看完整的脚手架代码,可以查看创蓝脚手架:https://github.com/chanlan253/cl253-cli
下一篇:前端高级进阶知识