我正在参加会员专属活动-源码共读第一期,点击参加

前言

上篇文章剖析了 vue-create 的原理,这篇将参阅 vue-create 构建自己的脚手架。

痛点

日常开发中敞开新项意图办法:复制粘贴,这种办法的缺陷:

  • 重复性劳动,繁琐且浪费时间
  • 简单忽略项目中的装备设置
  • copy过来的模板会存有重复代码

How

假如咱们自己开发一套脚手架,自己定制自己的模板,复制粘贴的人工流程就会转换为cli的自动化流程, 还能够经过保护不同的模板以适应不同业务需求。

首要为了达成以下意图:

  • 快速建立新的项目
  • 协助团队成员遵循共同的开发流程

脚手架将具备的功用:

  • 交互式指令
  • 模板选择
  • 注入封装好的 request 模块
  • 注入登录页面

规划脚手架架构

项目结构

参阅 vue-create 的项目,运用 pnpm 进行项目管理。运用 pnpm-workspace 建立 monorepo 环境。

新建项目并初始化:

pnpm init

装备文件

创立 .npmrc 文件并输入以下内容:

.npmrc 文件是 npm 包管理东西的装备文件,用来存储 npm 的装备信息。

hoist-pattern[]=*eslint*
hoist-pattern[]=*babel*
hoist-pattern[]=@emotion/*
hoist-pattern[]=postcss
hoist-pattern[]=pug
hoist-pattern[]=source-map-support
hoist-pattern[]=ts-node
strict-peer-dependencies=false
auto-install-peers=false

各项装备的意义:

  • hoist-pattern 表明将依靠包中满意某些条件的模块打包到一个文件中
  • strict-peer-dependencies 表明假如一个包被装置到项目中,它的同级依靠包也有必要被装置。
  • auto-install-peers 表明当装置某个包时,自动装置该包的同级依靠包。

装备 monorepo

pnpm-workspace.yaml 文件中能够存储多个作业空间的装备信息,而且能够设置不同作业空间之间的依靠关系。

根目录下新建一个 pnpm-workspace.yaml 文件,并输入如下内容:

packages:
    - 'packages/**'

根目录创立 packages 文件夹,这是子项意图存在目录。

装备 eslint

pnpm add
    eslint 
    eslint-define-config 
    eslint-plugin-import 
    eslint-plugin-node 
    eslint-plugin-regexp 
    --save-dev -w 

-w 表明在根目录装置

装备 prettier

pnpm add prettier --save-dev -w 

装备 typescript

pnpm add typescript --save-dev -w 

在 create-niu 文件夹创立 tsconfig.json 文件,并输入:

{
  "include": ["src", "__tests__"],
  "compilerOptions": {
    "outDir": "dist",
    "target": "ES2020",
    "module": "ES2020",
    "moduleResolution": "Node",
    "strict": true,
    "declaration": false,
    "sourceMap": true,
    "noUnusedLocals": true,
    "esModuleInterop": true
  }
}

编写脚手架脚本

创立进口文件

在create-niu 目录下 新建文件 index.js

#!/usr/bin/env node
console.log('hello niu')

#!/usr/bin/env node指定当时脚本的解释器为node

指定可履行脚本的方位

在 package.json 中增加下面代码:

{
  "bin": {
    "create-niu": "index.js",
    "cnu": "index.js"
  },
}

"bin" 字段用来指定包中可履行文件的路径, 也就是说当咱们的包上线后,履行指令 npm create niu,就会开始履行这个index文件。

验证一下

在在终端进入到create-niu目录下,履行:

npm link

然后在终端中履行:

create-niu
// or
cnu

不出意外的话能够看到控制台输出的信息了

打包构建

脚本运用TS编写,那么就需求构建东西将TS代码转换成JS。

东西:

  • rollup 打包构建东西。
  • unbuild 是一致的JavaScript构建东西。

在项目根目录装置依靠:

pnpm add unbuild rollup --save-dev -w

进入到create-niu 文件夹下,创立build.config.ts,并输入以下装备:

import { defineBuildConfig } from 'unbuild'
export default defineBuildConfig({
  entries: ['src/index'],
  clean: true,
  rollup: {
    inlineDependencies: true,
    esbuild: {
      minify: true
    }
  },
  alias: {
    // we can always use non-transpiled code since we support 14.18.0+
    prompts: 'prompts/lib/index.js'
  }
})

在 package.json 参加脚本:

  "scripts": {
    "dev": "unbuild --stub",
    "build": "unbuild",
    "prepublishOnly": "npm run build"
  },

新建src目录,并增加 index.ts 文件,上述构建装备文件中指定的进口在此, entries: ['src/index']:

履行pnpm run dev 查看 dist 文件夹下已构建好的文件。

将create-niu 目录下的index.js修正为:

#!/usr/bin/env node
import './dist/index.mjs'

此后在 src/index.ts 编写脚手架脚本

解析指令行参数

在指令行环境中,用户能够经过输入指令来履行程序。指令的格式一般是:<command> [options] [arguments],其间,指令表明要履行的操作,选项(options)用于指定指令的行为或许装备信息,参数(arguments)表明指令要操作的数据。

例如,grep -i "hello" file.txt 是一个常见的指令,其间,grep 是指令,-i 是选项,表明忽略大小写,”hello” 是参数,表明要查找的字符串,file.txt 是参数,表明要查找的文件。

怎么解析

解析指令行参数的进程:

  • 程序从用户输入中读取指令行参数
  • 剖析它们的内容
  • 获取指令、选项和参数的值

command:

  • create-niu
  • cnu 别号

[options]:

  • -v 显现版本号
  • -h 显现协助信息
  • –template 履行模板

[arguments]:

  • projectName 项目名
  • framework 结构
  • language variety 言语变体

代码完结

装置 minimist, minimist 是一个常用的 Node.js 库,用于解析指令行参数。

pnpm -F create-niu  add minimist

-F create-niu 是指在create-niu包中装置依靠

在ts中增加如下代码:

import minimist from 'minimist'
const argv = minimist<{
  t?: string
  template?: string
}>(process.argv.slice(2), { string: ['_'] })
console.log('hello niu', argv)

在测验包中履行,结果如图:

源码共读 - 构建脚手架(2K字长文)

询问用户信息

prompts 供给了一个简单易用的指令行提示库,能够让你快速构建交互式的指令行应用。

装置

pnpm -F create-niu  add prompts --save-dev
pnpm add @types/prompts --save-dev -w 

修正index.ts:

  try {
    result = await prompts([
      {
        type: argTargetDir ? null : 'text',
        name: 'projectName',
        message: 'Project name:',
        initial: defaultTargetDir,
        onState: (state) => {
          targetDir = formatTargetDir(state.value) || defaultTargetDir
        }
      }
    ])
  } catch (cancelled: any) {
    console.log(cancelled.message)
    return
  }
  const { projectName } = result
  console.log(projectName)

npm link 后能够在控制台看到你输入项目名称了

写入模板

运用 fs.copyFileSync 同步地将一个文件复制到另一个文件或目录。fs.copyFileSyncNode.js 中的一个文件系统办法它会读取源文件的内容,并将其写入方针文件,完结复制操作。

与 create-niu 目录下创立模板文件夹 template-demo ,如图:

源码共读 - 构建脚手架(2K字长文)

修正脚本,复制模板的流程大致如下:

  1. 设置模板寄存路径
  2. 便利模板文件夹中文件
  3. 复制目录
  4. 复制文件
  5. 递归3,4过程,完结文件复制作业

复制进程中需求特别处理 package.json 文件,因为要往里边写入包名。

源码共读 - 构建脚手架(2K字长文)

美化交互信息

完结必要的作业之后发现交互信息不是很好看,能够给交互式提示信息增加各式色彩。

pnpm -F create-niu add kolorist --save-dev

修正脚本:

import {
  blue,
  cyan,
  green,
  lightGreen,
  lightRed,
  magenta,
  red,
  reset,
  yellow
} from 'kolorist'
{
    type: 'select', //模板选择
    name: 'template',
    message: reset('select a framework'),
    choices: [
      { title: blue('project1'), value: 1 },
      { title: cyan('project2'), value: 2 }
    ]
}

作用

源码共读 - 构建脚手架(2K字长文)

发布脚手架

假如脚手架功用正常,能够将其发布到 npm 库房中,以便其他人运用。能够运行如下指令来发布脚手架:

npm publish

为了方便管理,这里运用上期学习的 release-it 进行项意图发布。

初始化:

npm init release-it

增加装备文件后履行:

npm run release

发布后,其他人就能够经过 npm 指令来装置和运用您的脚手架了.

@codeniu/create-niu

源码共读 - 构建脚手架(2K字长文)

总结

这篇文章描绘了重零建立一个脚手架项意图全进程,包括怎么运用pnpm workspace 管理 monorepo 项目,脚本的编写,npm 包的发布。