简易前端脚手架的搭建
脚手架流程图 :
脚手架技术实现文档:
一、初期准备工作:
1.1.新建项目并初始化 npm init
1.2.安装依赖:
- commander:添加命令、完善命令处理逻辑
- inquirer:交互式获取用户指令
- chalk:添加颜色样式,代码不再单调
- fs-extra:覆盖旧有文件夹
- download-git-repo:下载gitlab/github代码
- glob:操作目录
- ora:下载进度条
1.3.挂载命令(本地调试使用): npm link ,卸载则是npm unlink
二、主要的实现代码:
## 项目结构
|- bin 执行入口目录
|- enter.js 入口文件,初始化相关指令对应逻辑
|- lib 交互式命令对应执行目录
|- create.js 模板创建文件,命令的详细执行逻辑
|- download.js 下载文件配置
|- inquirerChoise.js 百望云、运营侧的特有可配置信息
|- maually.js 手动配置实现函数
|-presetsCommon 公共预置信息
|-api 公共接口请求
|-components 公共组件
|-utils 字典相关维护
|-uiComponets 公共ui组件
|-presetsCloud 百望云预置信息
|-api 特有接口请求
|-components 特有组件
|-utils 特有字典相关维护
|-uiComponets 特有ui组件
|-store vuex仓库
|-presetsZeus 运营后台预置信息
2.1.bin文件夹下的入口文件enter.js
顶部代码 #! /usr/bin/env node,作用:定位命令执行的目录
2.2.create.js创建具体的创建交互效果
2.3 对于store入口文件,使用动态引入模块的方式一一自动添加,重新导出各个模块的导出内容,此处可开启命名空间,支持按模块引用对应方法。
2.4 对于ui组件的入口文件,亦使用动态引入的方式进行添加,重新导出各个模块的导出内容
2.5.手动配置的实现过程:
- 提出公共部分至工具包的presets文件夹;
- 创建一个全局变量的文件获取交互窗口中用户选择的内容;
1.使用path的join获取待写入的文件地址
2.使用fs的readFileSync方法读取文件的内容
3.将内容转换为数组,将数组中的元素转为key-value的键值对对象
4.遍历此对象,与用户选择内容进行比对,设置其变量值
5.将修改后的内容重新写入此文件更新内容
3.根据不同的变量使用不同的配置函数,注入至模板内;
let {
Introduce_Components_Needed: icd,
Introduce_Autoplugins: ia,
Introduce_Leftmenu: il,
Introduce_MultiTabbed: im,
Introduce_Dictionary: id,
Scss_Variable: sv,
Introduce_OrgTree: io,
Iframe_Listen_Methods: ilm,
SearchAndTable: sat,
Global_Introduce_Components: gic,
Header_Components: hc
} = envVariables
if (icd === 'true') {
// 按需引入bw-design组件
addComponents(targetDir)
}
if (ia === 'true') {
// 引入autoplugins
addAutoplugins(targetDir)
}
4.部分预设注入逻辑
// 复制文件--可覆盖
function copyFiles (sourceFile, targetFile) {
fs.copyFile(sourceFile, targetFile, (err) => {
if (err) {
console.error(`复制文件 ${sourceFile} 到文件 ${targetFile} 失败`, err)
}
})
}
// 复制文件夹
function copyFloders (source, target) {
// 如果目标文件夹不存在,则创建
if (!fs.existsSync(target)) {
fs.mkdirSync(target, { recursive: true })
}
const files = fs.readdirSync(source)
files.forEach((file) => {
const currentS = path.join(source, file)
const currentT = path.join(target, file)
if (fs.statSync(currentS).isDirectory()) {
copyFloders(currentS, currentT)
} else {
copyFiles(currentS, currentT)
}
})
}
// 左菜单
function addLeftmenu (targetDir) {
const sPth = path.join(__dirname, '../presetsCloud/components/LeftMenu')
const tPath = path.join(targetDir, 'src/components/LeftMenu')
copyFloders(sPth, tPath)
const sPth1 = path.join(__dirname, '../presetsCloud/components/LeftMenuContent.vue')
const tPath1 = path.join(targetDir, 'src/pages/Content.vue')
copyFiles(sPth1, tPath1)
}
// 添加前端预置字典 --字典涉及接口
function addDictionary (targetDir, type) {
// 创建api文件夹--注入index
const apiDir = path.join(targetDir, 'src/api')
if (!fs.existsSync(apiDir)) {
fs.mkdirSync(apiDir)
}
const targetFile = path.join(targetDir, 'src/api/index.js')
copyFiles(reqInitPath, targetFile)
// 创建methods文件夹---注入方法
const methodsDir = path.join(targetDir, 'src/api/methods')
if (!fs.existsSync(methodsDir)) {
fs.mkdirSync(methodsDir)
}
if (type === '2') {
// api请求方法
const sPath = path.join(__dirname, '../presetsCloud/api/methods/_dict.js')
const tPath = path.join(targetDir, 'src/api/methods/sysDict.js')
copyFiles(sPath, tPath)
// 配置转换文件
const sPath1 = path.join(__dirname, '../presetsCommon/utils/_dictTrans.js')
const tPath1 = path.join(targetDir, 'src/utils/dictTrans.js')
copyFiles(sPath1, tPath1)
// 存入vuex
const stroreDir = path.join(targetDir, 'src/store')
const stroreDir1 = path.join(targetDir, 'src/store/modules')
if (!fs.existsSync(stroreDir)) {
fs.mkdirSync(stroreDir)
}
if (!fs.existsSync(stroreDir1)) {
fs.mkdirSync(stroreDir1)
}
const sPath2 = path.join(__dirname, '../presetsCloud/store/index.js')
const tPath2 = path.join(targetDir, 'src/store/index.js')
copyFiles(sPath2, tPath2)
const sPath3 = path.join(
__dirname,
'../presetsCloud/store/modules/_dict.js'
)
const tPath3 = path.join(targetDir, 'src/store/modules/_dict.js')
copyFiles(sPath3, tPath3)
} else if (type === '3') {
const sPath = path.join(__dirname, '../presetsZeus/api/methods/_dict.js')
const tPath = path.join(targetDir, 'src/api/methods/sysDict.js')
copyFiles(sPath, tPath)
// 配置转换文件
const sPath1 = path.join(__dirname, '../presetsCommon/utils/_dictTrans.js')
const tPath1 = path.join(targetDir, 'src/utils/dictTrans.js')
copyFiles(sPath1, tPath1)
}
}
5.返回最终模板文件夹。
spinner.succeed()
resolve(target)
6.下载download.js
direct方式:输入完整的gitlab/github的url(浏览器的url)+分支名
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 【自荐】一款简洁、开源的在线白板工具 Drawnix