尤雨溪同款脚手架写法,你确定不进来学习下?(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...

相关推荐
学不会•1 小时前
css数据不固定情况下,循环加不同背景颜色
前端·javascript·html
EasyNTS2 小时前
H.264/H.265播放器EasyPlayer.js视频流媒体播放器关于websocket1006的异常断连
javascript·h.265·h.264
活宝小娜3 小时前
vue不刷新浏览器更新页面的方法
前端·javascript·vue.js
程序视点3 小时前
【Vue3新工具】Pinia.js:提升开发效率,更轻量、更高效的状态管理方案!
前端·javascript·vue.js·typescript·vue·ecmascript
coldriversnow4 小时前
在Vue中,vue document.onkeydown 无效
前端·javascript·vue.js
我开心就好o4 小时前
uniapp点左上角返回键, 重复来回跳转的问题 解决方案
前端·javascript·uni-app
开心工作室_kaic4 小时前
ssm161基于web的资源共享平台的共享与开发+jsp(论文+源码)_kaic
java·开发语言·前端
刚刚好ā4 小时前
js作用域超全介绍--全局作用域、局部作用、块级作用域
前端·javascript·vue.js·vue
沉默璇年6 小时前
react中useMemo的使用场景
前端·react.js·前端框架
yqcoder6 小时前
reactflow 中 useNodesState 模块作用
开发语言·前端·javascript