/ 前端
分类:前端来源:站内 最近更新:2020-09-23 17:28:56浏览:836留言: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
下一篇:前端高级进阶知识