前言:听说不会做脚手架的前端不是好前端,本系列带你从0到1创建一个属于个人的脚手架,适合快速创建模板项目
最终完成效果可以点击查看 npm 包:create-tpl
这一章节主要针对上一篇文章的问题,本期将一一进行解决,这里采用的思路跟尤大大写的 create-vite 思路基本一致。
1、如何修改 package.json 中的 name 属性?
这一块的思路其实很简单,实现方式就在于 package.json
的 json 格式中,咱们只需要使用方法将 json 读取为一个 js 对象,再将 name 赋值,再重新写入即可。
这里回顾下复制文件流程:
- 读取路径对应的文件
- 将文件写入到生成路径的文件中
这里我们将新增后续步骤:
- 将生成好的 package.json 重新进行 json 读取
- 将 name 赋值为项目名
- 重新写入到生成好的 ackage.json 中
接下来开始我们的实现:
-
创建对应函数,并获取生成好的文件路径
tsexport function createProject(answer: Choosed) { // ... // 3 修改 package.json 的 name changePackageName(destPath, projectName) console.log("================================== 模板生成成功 =================================="); } function changePackageName(destPath: string, projectName: string) { const packageDestPath = path.join(destPath, "package.json"); }
-
将文件读取成 json 格式,我们需要使用到一个库
fs-extra
,里面扩展了很多关于 fs 操作文件的方法bashnpm i fs-extra npm i @types/fs-extra
ts// 引入, 将 node:fs 模块 替换掉,fs-extra 是完美兼容原方法的 import fs from "fs-extra"
tsfunction changePackageName(destPath: string, projectName: string) { // 1 获取 package.json const packageDestPath = path.join(destPath, "package.json"); const data = fs.readJSONSync(packageDestPath) // 2 修改名 data.name = projectName // 3 重新写入 fs.writeFileSync(packageDestPath, JSON.stringify(data, null, 2)) }
-
测试效果,可以看到已经完美实现了 package.json 的 name 属性变更
bashtest aa-web
2、.gitignore
有没有更巧妙地方式去 copy?
为什么不推荐直接用 .gitignore
原文件呢,因为在咱们项目中是存在 git 的,会自动读取这个文件在文件夹中去应用,在某些情况下可能导致文件或者文件夹不会上传,因此最好是不直接使用这个命名。
在尤大大的 create-vite
中,实现方法如下:
- 将
.gitignore
的��件改名为_gitignore
,这样就完美规避了 git 检测的问题 - 在写入该文件时,将
_
更改为.
去命名文件
实现方式如下:
-
在
util
文件中抽象一个 Obj 类型,代表对象类型,避免重复定义tsexport type Obj<T = any> = Record<string, T>
-
定义两个相关过滤函数:
- filterItem:过滤掉在 filterArr 中存在的项
- filterRename:传入一段字符串,判断在 filter 过滤数组中是否存在,存在则转化掉所有在 rules 上对应的键值
tsexport const filterItem = (arr: any[], filterArr: any[]) => arr.filter(v => (!filterArr.includes(v)))
tsexport const filterRename = (str: string, filter: string[], rules: Obj<string>) => { if (filter.includes(str)) Object.keys(rules).forEach(key => str = str.replace(key, rules[key])) return str }
-
修改
util
文件中的copyDir
函数,添加一个新的参数renameRule
tsexport const copyDir = (srcDir: string, destDir: string, renameRule: [string[], Obj<string>] = [[], {}], exclude?: string[]) => { // 1 创建目录 fs.mkdirSync(destDir, { recursive: true }) // 2 循环复制 const dirs = fs.readdirSync(srcDir) const FileArr = filterItem(dirs, [".git"]) // 3 循环目录 for (let fileName of FileArr) { if (exclude?.includes(fileName)) continue; const destFileName = filterRename(fileName, ...renameRule) const srcFile = resolve(srcDir, fileName) const destFile = resolve(destDir, destFileName) copyFile(srcFile, destFile) } }
-
切换到创建函数,往 copyDir 中添加对应的规则对象
tsimport type { Obj } from "./util.js" export function createProject(answer: Choosed) { // 1 获取相关路径 const { projectName, variant } = answer const srcPath = getPathFromRoot(`template/${variant}`) const commonPath = getPathFromRoot(`template/common`) const destPath = getPathFromExecRoot(projectName); // 2 复制文件夹 const renameRule: [string[], Obj<string>] = [["_gitignore", "_editorconfig"], { '_': '.' }] copyDir(commonPath, destPath, renameRule) copyDir(srcPath, destPath, renameRule) // 3 修改 package.json 的 name changePackageName(destPath, projectName) console.log("================================== 模板生成成功 =================================="); }
-
测试效果,将 common 文件夹中的通用文件的
.
改成_
,再进行生成测试
3、结尾的完成提示是否可以更好看点?
大家如果使用过 create-vite
都知道完成的提示是比较精美使用的,这里用我已经完成的脚手架类似的输出:
我们只需要下载一个通用的工具库 chalk
,就可以实现文字的变色,大家有兴趣同样可以了解下原生写法,不是很难的。
接下来开始我们的实现:
-
安装对应依赖
bashnpm i chalk
-
引入使用,并替换掉原来比较丑的提示:
tsexport function createProject(answer: Choosed) { // 1 获取相关路径 const { projectName, variant } = answer const srcPath = getPathFromRoot(`template/${variant}`) const commonPath = getPathFromRoot(`template/common`) const destPath = getPathFromExecRoot(projectName); // 2 复制文件夹 const renameRule: [string[], Obj<string>] = [["_gitignore", "_editorconfig"], { '_': '.' }] copyDir(commonPath, destPath, renameRule) copyDir(srcPath, destPath, renameRule) // 3 修改 package.json 的 name changePackageName(destPath, projectName) // 4 输出完成信息 console.log(chalk.blue(`Scaffolding project in ${destPath}...\n`)); console.log(chalk.red("Done.") + ` Now run:\n`); console.log(`${[".", "./"].includes(projectName) ? "" : ` cd ${projectName}\n`} npm install npm run dev\n`); }
-
测试使用,完美输出
4、总结
本篇文章主要讲解上一大篇遗留下来的几个问题,并且模仿的是比较优秀的 create-vite
写法,相信大家跟着实操完后,可以做出自己熟悉的脚手架。
最后,再留一个问题:如何不生成文件夹,把模板直接生成到本地
bash
test .
这个就留给大家思考解决啦!
源代码放这里啦,有需要自取:gitee.com/ma_zipeng/c...