《前端那些事》从0到1开发简单脚手架
❞
❝ 上一篇树酱讲《前端工程化那些事》,聊到脚手架,不过时间比较仓促,导致内容较少,而在我实践开发中,随着新项目愈来愈多,脚手架工具就起到提高效能的作用,借此机会跟小伙伴们分享下我是如何从0到1开发一个简单脚手架 ❞
1.什么是脚手架
❝ 脚手架用于快速生成新项目的目录模板,并集成一系列体系化工具的安装,能够提升前端开发人员的效率,减少copy操作 ❞
目前比较主流的脚手架:
- Vue脚手架:Vue-cli
- React脚手架:create-react-app
- Yeoman
2.我期望的脚手架
❝ 而我所期望的脚手架是怎么样的呢? ❞
当我要开启一个新项目的开发,可以快速生成新项目的目录模板,而这个目录结构是每个项目统一个模版规范(目录规范),同时也设定了通用的配置包括如下
- 通用的Webpack配置(vue cli 3x 以上是vue.config.js)
- 统一的Eslint 校验规则:如Airbnb、eslint-plugin-vue等(eslintConfig)
- 统一的单元测试框架配置:单元测试覆盖率、测试的目录等
- 统一的Dockerfile和jenkinsfile (用来打包成镜像和部署流水线定义)
- 统一babel的配置(.babelrc或babel.config.js)
- 统一的常量配置(缓存字段等等)
- 不同环境的配置文件(development、test、production)
❝ 没有脚手架,我只能通过copy拷贝代码来完成,这样繁琐又机械化的操作浪费大量时间,而且还可能在拷贝过程中,因为某个细节出错,导致项目出错,排查问题又耗时。或许你可能会想,我们不是可以用vue或者react官方的脚手架来生成模版吗?是,但是这种方式创建的模版不一定符合你内部结构化标准 ❞
为了解决上述问题,脚手架就起到一个至关重要的角色,我们可以通过脚手架来约束好规范,统一的配置,来打通新项目的开发工具链,一方面提升开发效率,一方面则提高项目对接可维护性及新员工熟悉项目简易性。
3.开发脚手架
3.1 如何开发
❝ 如果是要开发一个高度可定制化的脚手架,需要考虑的因素很多,因为某种限制,选择了一种简易的方式来实现内部的脚手架工具,远离就是通过准备两个模版,一个是pc端的,另一个是mobile端的模版,然后用git管理起来,我需要如下工具: ❞
- 可用于控制台选择的工具:inquirer
- 可处理控制台命令的工具:commander
- 可改变输出log颜色的工具:chalk
- 可执行shell命令的工具: child_process
入口文件 index.js
#!/usr/bin/env node
const fs = require('fs');
const path = require('path');
const chalk = require('chalk');
const commander = require('commander');
const inquirer = require('inquirer');
const checkDire = require('./utils/checkDire.js');
const { exec } = require('child_process');
const { version } = require('../package.json');
const { promptTypeList } = require('./config');
//version 版本号
commander.version(version, '-v, --version')
.command('init ')
.alias("i")
.description("输入项目名称,初始化项目模版")
.action(async (projectName,cmd) => {
await checkDire(path.join(process.cwd(),projectName),projectName); // 检测创建项目文件夹是否存在
inquirer.prompt(promptTypeList).then(result => {
const {url, gitName, val} = result.type;
console.log("您选择的模版类型信息如下:" + val);
console.log('项目初始化拷贝获取中...');
if(!url){
console.log(chalk.red(`${val} 该类型暂不支持...`));
process.exit(1);
}
exec('git clone ' + url, function (error, stdout, stderr) {
if (error !== null) {
console.log(chalk.red(
`clone fail,${error}`
));
return;
}
fs.rename(gitName, projectName, (err)=>{
if (err) {
exec('rm -rf '+gitName, function (err, out) {});
console.log(chalk.red(`The ${projectName} project template already exist`));
} else {
console.log(chalk.green(`The ${projectName} project template successfully create(项目模版创建成功)`));
}
});
});
})
});
commander.parse(process.argv);
复制代码
这里定义的是npm包命令bin的入口文件
需要注意在文件前面定义#!/usr/bin/env node
❝ #!/usr/bin/env node设置后,可以让系统动态的去查找node,已解决不同机器不同用户设置不一致问题 ❞
检测目录是否存在
// utils/checkDire.js
const fs = require('fs');
const chalk = require('chalk');
const path = require('path');
module.exports = function (dir,name) {
let isExists = fs.existsSync(dir);
if (isExists) {
console.log(chalk.red(
`The ${name} project already exists in directory. Please try to use another projectName`
));
process.exit(1);
}
复制代码
配置文件
// config/index.js
配置文件
/*
@dest: 使用配置文件
@Author: tree
*/
module.exports = {
promptTypeList:[{
type: 'list',
message: '请选择拉取的模版类型:',
name: 'type',
choices: [{
name: 'mobile',
value: {
url: '',
gitName: 'vue-web-template',
val:'移动端模版'
}
},{
name: 'pc',
value: {
url: 'https://github.com/littleTreeme/vue-web-template.git',
gitName: 'vue-web-template',
val:'PC端模版'
}
}]
}],
};
复制代码
❝ 源码链接:github.com/littleTreem… 如果你觉得实用请给个
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- Java HelloWorld 學習
- Bytecodes.java
- GenerateOopMap.java
- CellTypeState.java
- 终于开始了,微软的野心将通过全场景开发平台.NET 5体现得淋漓尽致!
- 微信小程序开发实战(27):录音
- 微信小程序开发实战(28):播放、暂停、停止声音
- 微信小程序开发实战(29):控制背景音乐
- 面试:如何从 100 亿 URL 中找出相同的 URL?
- Spring Boot+Gradle+ MyBatisPlus3.x搭建企业级的后台分离框架
- 不要再对类别变量进行独热编码了
- 面试Java基础问题汇总
- K8s集群上使用Helm部署2.4.6版本Rancher集群
- 一个工作三年的同事,居然还搞不清深拷贝、浅拷贝...
- 太有意思了,教你实现实现王者荣耀团战!