尤雨溪同款脚手架写法,你确定不进来学习下?(4)

前言:听说不会做脚手架的前端不是好前端,本系列带你从0到1创建一个属于个人的脚手架,适合快速创建模板项目

最终完成效果可以点击查看 npm 包:create-tpl

这一章节主要针对上一篇文章的问题,本期将一一进行解决,这里采用的思路跟尤大大写的 create-vite 思路基本一致。

1、如何修改 package.json 中的 name 属性?

这一块的思路其实很简单,实现方式就在于 package.jsonjson 格式中,咱们只需要使用方法将 json 读取为一个 js 对象,再将 name 赋值,再重新写入即可

这里回顾下复制文件流程:

  1. 读取路径对应的文件
  2. 将文件写入到生成路径的文件中

这里我们将新增后续步骤:

  1. 将生成好的 package.json 重新进行 json 读取
  2. 将 name 赋值为项目名
  3. 重新写入到生成好的 ackage.json 中

接下来开始我们的实现

  1. 创建对应函数,并获取生成好的文件路径

    ts 复制代码
    export 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");
    }
  2. 将文件读取成 json 格式,我们需要使用到一个库 fs-extra,里面扩展了很多关于 fs 操作文件的方法

    bash 复制代码
    npm i fs-extra
    npm i @types/fs-extra
    ts 复制代码
    // 引入, 将 node:fs 模块 替换掉,fs-extra 是完美兼容原方法的
    import fs from "fs-extra" 
    ts 复制代码
    function 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))
    }
  3. 测试效果,可以看到已经完美实现了 package.json 的 name 属性变更

    bash 复制代码
    test aa-web

2、.gitignore 有没有更巧妙地方式去 copy?

为什么不推荐直接用 .gitignore 原文件呢,因为在咱们项目中是存在 git 的,会自动读取这个文件在文件夹中去应用,在某些情况下可能导致文件或者文件夹不会上传,因此最好是不直接使用这个命名。

在尤大大的 create-vite 中,实现方法如下:

  1. .gitignore 的��件改名为 _gitignore,这样就完美规避了 git 检测的问题
  2. 在写入该文件时,将 _ 更改为 . 去命名文件

实现方式如下:

  1. util 文件中抽象一个 Obj 类型,代表对象类型,避免重复定义

    ts 复制代码
    export type Obj<T = any> = Record<string, T>
  2. 定义两个相关过滤函数:

    • filterItem:过滤掉在 filterArr 中存在的项
    • filterRename:传入一段字符串,判断在 filter 过滤数组中是否存在,存在则转化掉所有在 rules 上对应的键值
    ts 复制代码
    export const filterItem = (arr: any[], filterArr: any[]) => arr.filter(v => (!filterArr.includes(v)))
    ts 复制代码
    export 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
    }
  3. 修改 util 文件中的 copyDir 函数,添加一个新的参数 renameRule

    ts 复制代码
    export 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)
      }
    }
  4. 切换到创建函数,往 copyDir 中添加对应的规则对象

    ts 复制代码
    import 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("================================== 模板生成成功 ==================================");
    }
  5. 测试效果,将 common 文件夹中的通用文件的 . 改成 _,再进行生成测试

3、结尾的完成提示是否可以更好看点?

大家如果使用过 create-vite 都知道完成的提示是比较精美使用的,这里用我已经完成的脚手架类似的输出:

我们只需要下载一个通用的工具库 chalk,就可以实现文字的变色,大家有兴趣同样可以了解下原生写法,不是很难的。

接下来开始我们的实现:

  1. 安装对应依赖

    bash 复制代码
    npm i chalk
  2. 引入使用,并替换掉原来比较丑的提示:

    ts 复制代码
    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)
      // 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`);
    }
  3. 测试使用,完美输出

4、总结

本篇文章主要讲解上一大篇遗留下来的几个问题,并且模仿的是比较优秀的 create-vite 写法,相信大家跟着实操完后,可以做出自己熟悉的脚手架。

最后,再留一个问题:如何不生成文件夹,把模板直接生成到本地

bash 复制代码
test .

这个就留给大家思考解决啦!

源代码放这里啦,有需要自取:gitee.com/ma_zipeng/c...

相关推荐
狗头大军之江苏分军4 分钟前
iPhone 17 vs iPhone 17 Pro:到底差在哪?买前别被忽悠了
前端
小林coding4 分钟前
再也不怕面试了!程序员 AI 面试练习神器终于上线了
前端·后端·面试
文心快码BaiduComate16 分钟前
WAVE SUMMIT深度学习开发者大会2025举行 文心大模型X1.1发布
前端·后端·程序员
babytiger17 分钟前
python 通过selenium调用chrome浏览器
前端·chrome
passer98123 分钟前
基于webpack的场景解决
前端·webpack
华科云商xiao徐30 分钟前
Java并发编程常见“坑”与填坑指南
javascript·数据库·爬虫
奶昔不会射手36 分钟前
css3之grid布局
前端·css·css3
举个栗子dhy40 分钟前
解决在父元素上同时使用 onMouseEnter和 onMouseLeave时导致下拉菜单无法正常展开或者提前收起问题
前端·javascript·react.js