工程化:依托模板搭建企业级脚手架(cli)
source link: https://lianpf.github.io/posts/%E5%BC%80%E5%8F%91%E6%97%A5%E8%AE%B0/25.%E6%90%AD%E5%BB%BA%E4%BC%81%E4%B8%9A%E7%BA%A7%E8%84%9A%E6%89%8B%E6%9E%B6/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
本篇是前端工程化之依托模板搭建企业级脚手架(cli)。通过脚手架,我们可以快速初始化一个项目,无需自己从零开始一步步…
1.为什么
通过脚手架,我们可以快速初始化一个项目,无需自己从零开始一步步配置,有效提升开发体验。
当然,社区已经贡献了vue-cli
、create-react-app
、react-native-cli
等非常优秀的脚手架,
但是,这些脚手架未必完全符合我们的实际应用,特别是作为企业通用脚手架而言,所以我们需要定制自己的脚手架,来提升开发效率。
2.脚手架的作用
- 减少重复性工作:不需要复制其他项目再删除无关代码,或者从零创建一个项目和文件。
- 多套模板:可以根据交互动态生成项目结构和配置文件。
- 协作:多人协作更为方便,不需要把文件传来传去。
本项目完整代码地址,在文章末尾。
二、提供的功能
明确脚手架(@lianpf/create-app-cli
)需要提供的功能:
ca init <template-name> <project-name>
根据远程模板,初始化一个项目(远程模板可配置)ca config set <template-name> <repository>
设置模板信息(暂未实现)ca config get templates
查看模板配置信息ca cfg get templates
同上ca -v
查看当前版本号ca -h
帮助
如果有其他需求,可根据需求,自行拓展commander
三、配置搭建cli
1.依赖的第三方库
@babel/cli
、@babel/core
和@babel/preset-env
: 语法转换commander
: 命令行工具download-git-repo
: 用来下载远程模板- ini: 配置项格式转换
- 『暂时没用』一般用于物理机本地配置项
inquirer
: 交互式命令行工具ora
: 显示node
命令环境loading
动画chalk
: 修改控制台输出内容样式log-symbols
: 显示出√
或×
等的图标ascii-table
: 以表格形式展示数据,比如:模板列表
关于以上第三方
package
的介绍,可直接npm.org
上查看相应的说明
2.搭建cli
2.1 初始化项目
创建一个空项目(
create-app-cli
)
create-app-cli $ npm init // 项目初始化
create-app-cli $ npm install @babel/cli @babel/core @babel/preset-env chalk commander download-git-repo ini inquirer log-symbols ora -D
.
├── bin
│ └── www // 可执行文件
├── lib
├── ... // 生成文件
├── src
│ ├── config.js // 管理 @lianpf/create-app-cli 配置文件
│ ├── index.js // 主流程入口文件
│ ├── init.js // init command
│ ├── main.js // 入口文件
│ └── utils
│ ├── constants.js // 定义常量
│ ├── download.js // 模板远程仓库下载
│ └── rc.js // 配置文件
├── templates.json // 模板配置文件
├── .babelrc // babel配置文件
├── package.json
└── README.md
babel
配置:开发使用了ES6语法,使用 babel 进行转义
.bablerc
{
"presets": [
[
"@babel/preset-env",
{
"targets": {
"node": "current"
}
},
"@babel/preset-react" // react 语法
]
],
"plugins": [
"transform-class-properties",
"transform-decorators",
"transform-react-constant-elements",
"transform-react-inline-elements"
]
}
2.2 @lianpf/create-app-cli
开发环境搭建
2.2.1 脚手架开发:启动命令配置
node.js
内置了对命令行操作的支持,package.json
中的bin
字段可以定义命令名和关联的执行文件。在package.json
中添加 bin
字段
package.json
{
"name": "@lianpf/create-app-cli",
"version": "0.2.1",
"description": "A cli to help create a project",
"main": "index.js",
"bin": {
"ca": "./bin/www"
},
"scripts": {
"compile": "babel src -d lib",
"watch": "npm run compile -- --watch"
}
}
www 文件
行首加入一行#!/usr/bin/env node
指定当前脚本由node.js
进行解析
#! /usr/bin/env node
require('../lib/main.js');
2.2.2 脚手架测试:链接到全局环境
开发过程中为了方便调试,在当前的create-app-cli
目录下执行 npm link
,将ca
命令链接到全局环境
2.2.3 脚手架开发:启动项目
create-app-cli $ npm run watch
2.3 @lianpf/create-app-cli
命令行处理
利用commander
来处理命令行
/create-app-cli/src/main.js
import program from 'commander';
import { VERSION, make_success, make_fail } from './utils/constants';
import apply from './index';
/**
* ca commands
* - config
* - init
* - v
* - h
*/
let actionMap = {
// init 命令配置
init: {
...
},
// config 命令配置
config: {
...
}
}
// 遍历预设命令,进行处理配置
Object.keys(actionMap).forEach((action) => {
program.command(action)
.description(actionMap[action].description)
.alias(actionMap[action].alias)
.action(() => {
switch (action) {
case 'config':
apply(action, ...process.argv.slice(3));
break;
case 'init':
apply(action, ...process.argv.slice(3));
break;
default:
break;
}
});
});
function help() {
// -h 参数是,遍历列出所有命令
...
}
program.usage('<command> [options]');
program.on('-h', help);
program.on('--help', help);
program.version(VERSION, '-v, --version').parse(process.argv);
// ca 不带参数时
if (!process.argv.slice(2).length) {
program.outputHelp(make_success);
}
2.4 @lianpf/create-app-cli
下载模板
download-git-repo
支持从Github、Gitlab
下载远程仓库到本地
/create-app-cli/src/util/download.js
import downloadGit from 'download-git-repo';
import { templateConfig, hasTemplate } from './constants';
export const downloadLocal = async (templateName, projectName) => {
const _hasTemplate = hasTemplate(templateName)
let api = ''
// 判断是否存在模板
if (_hasTemplate) {
// 获取 模板下载地址
api = `${templateConfig[templateName].type}:${templateConfig[templateName].user}/${templateConfig[templateName].repository}#${templateConfig[templateName].branch}`;
}
return new Promise((resolve, reject) => {
// projectName 为下载到的本地目录
downloadGit(api, projectName, { clone: true }, (err) => {
if (err) {
reject(err);
} else {
resolve();
}
});
});
}
constants.js
获取template
配置
/create-app-cli/src/util/constants.js
...
import templates from '../../templates.json'
...
// template config
export const templateConfig = templates
// 判断是否存在当前模板
export const hasTemplate = (templateName) => {
return Object.keys(templateConfig).indexOf(templateName) > -1
}
...
静态template
配置
/create-app-cli/template.json
{
"react-template": {
"type": "https://github.com",
"user": "xxx",
"repository": "xxx",
"branch": "master",
"templateName": "react-template",
"keyWords": "react、webpack"
},
...
}
注意,这里没有实现
ca config set <template-name> <repository>
设置模板命令,且企业级脚手架对应模板相对固定,故我们将模板预先内置到template.json
文件中
2.5 @lianpf/create-app-cli
交互式命令和美化
2.5.1 命令行交互
用户执行init
命令后,向用户提出问题,接收用户的输入并作出相应的处理。命令行交互利用inquirer
实现:
/create-app-cli/src/init.js
inquirer.prompt([
{
name: 'description',
message: 'Please enter the project description: '
},
{
name: 'author',
message: 'Please enter the author name: '
}
]).then((answer) => {
//...
});
类似于:
npm init
命令执行后,项目初始化,会问询你作者、版本信息、描述等添加到package.json
配置文件的交互操作。
2.5.2 视觉美化
在上一步,用户输入后,开始下载模板,此时使用ora
提示用户正在下载模板,以及下载结束后给出相应提示。
/create-app-cli/src/init.js
...
import ora from 'ora';
...
let loading = ora('downloading template ...');
loading.start();
//download
loading.succeed(); //或 loading.fail();
2.6 @lianpf/create-app-cli
获取模板配置
config配置
支持使用其它仓库作为模板。这样使用者可以自由选择下载目标
/create-app-cli/src/config.js
import { get } from './utils/rc';
import { make_success, make_fail, make_warn } from './utils/constants';
let config = async (action, key) => {
switch (action) {
case 'get':
if (key) {
let result = await get(key);
if (result.code === 0) {
console.log(make_success(result.message));
} else {
console.log(make_fail(result.message));
}
} else {
console.log(make_warn('Command does not exist!'));
}
break;
// set 模板命令暂未实现,需通过 template.json 配置
// case 'set':
// set(key, value);
// break;
// case 'remove':
// remove(key);
// break;
default:
console.log(make_warn('Command does not exist!'));
break;
}
}
module.exports = config;
rc.js
负责对本地物理机『模板配置文件』的增删改查,这里改造为对脚手架模板配置文件template.json
的查询
/create-app-cli/src/util/rc.js
import { configCommand, make_success, make_warn, templateConfig } from './constants';
import AsciiTable from 'ascii-table'
// constants 配置文件
export const get = async (key) => {
...
if (opts.indexOf(key) !== -1) {
switch (key) {
case 'templates':
// code、message、data处理
...
break;
default:
...
break;
}
}
...
console.log(make_success(templateTable.toString()))
return {
code,
data: {},
message
};
}
四、发布cli
npm publish
脚手架发布。- 其它用户可通过
npm install @lianpf/create-app-cli -g
全局安装,即可使用ca
命令。
谢谢各位花费宝贵的时间阅读本文,以下是源码仓库地址,如果本文给了您一点帮助或者是启发,请动动小手点进Github仓库,不要吝啬你的Star,您的肯定是我前进的最大动力
最后, 希望大家早日实现:成为前端高手的伟大梦想!
欢迎交流~
本文版权归原作者曜灵所有!未经允许,严禁转载!对非法转载者, 原作者保留采用法律手段追究的权利!
若需转载,请联系微信公众号:连先生有猫病,可获取作者联系方式!
Recommend
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK