npm init @vitejs/app 到底干了什么

背景

最近在闲暇时间学习尤大大的新框架 ViteJs 的时候发现,创建一个新的基于 Vite 的项目时,使用的命令方式是:

npm init @vitejs/app
复制代码

这跟我们熟悉的 CLI 创建 Vue 项目的命令完全不一样:

vue create project-name
复制代码

「在不安装脚手架工具的情况下,还能直接使用 npm 创建项目?」带着好奇心小小的探究了一下。

首先我们要知道这个命令 npm init @vitejs/app 是要做什么?

一番谷歌 + 官网文档,实际上这个命令就是要创建一个新的 Vite 项目,且基于某个模版,这个模版可以是 Vue / React 或其它。那么它到底是如何创建的?带着这个问题我们先来重温下 npm init

复习 npm init

npm init 对于我们来说应该非常熟悉了,通常我们使用 npm init 初始化一个 package.json 文件来起手一个项目。大多数小伙伴只用到这,但是这个命令后面是可以携带参数的?这个参数能干什么呢?对于我这见惯大场面的 cv 程序员来说,翻手就是一个谷歌。谷歌大佬告诉我们 npm-init

npm init <initializer> 通常被用于创建一个新的或者已经存在的 npm 包。

initializer 在这里是一个名为 create-<initializer> 的 npm 软件包,该软件包将由 npx 来安装,然后执行其 package.json 中 bin 属性对应的脚本,会创建或更新 package.json 并运行一些与初始化相关的操作。

官方说明也给出了命令相对应的一些示例:

命令等同
npm init foonpx create-foo
npm init @usr/foonpx @usr/create-foo
npm init @usrnpx @usr/create

文章开头的命令 npm init @vitejs/app 正好匹配到了第二条示例,对应起来应该是这样:

npm init @vitejs/app -> npx @vitejs/create-app
复制代码

从上面的解释可以看出,在命令行中运行 npm init @vitejs/app,实际上是通过了 npx 运行了名为 @vitejs/create-app 这个包,那么我们就去 Vite 官方仓库找一找有没有叫 create-app 的文件?

查看 ViteJs 源码发现 packages 文件夹中确实存在一个 create-app 目录,那我们就再深入的看看这个目录里面有什么?

create-app

@vitejs/create-app 项目做了什么?

在 create-app 文件夹下的 package.json 中发现 bin 入口:

{
  "name": "@vitejs/create-app",
  // ...没错了,就是这
  "bin": {
    "create-app": "index.js",
    "cva": "index.js"
  },
}
复制代码

bin 属性配置了 create-app 的执行入口文件 index.js ,那我们就去看看 index.js 中做了什么操作,源码过长,部分精简以便享用,感兴趣的小伙伴可深挖:

// https://github.com/vitejs/vite/blob/main/packages/create-app/index.js

// 省略非关键代码
const TEMPLATES = [
  yellow('vanilla'),
  green('vue'),
  green('vue-ts'),
  //...
]

async function init() {
  let targetDir = argv._[0]
  if (!targetDir) {
    // 第一步:确定用户录入的 Project name
    const { name } = await prompt({
      type: 'input',
      name: 'name',
      message: `Project name:`,
      initial: 'vite-project'
    })
    targetDir = name
  }

  const root = path.join(cwd, targetDir)
  console.log(`\nScaffolding project in ${root}...`)
  
  // 第二步:检查是否存在同名目录且是否为空目录
  if (!fs.existsSync(root)) {
    fs.mkdirSync(root, { recursive: true })
  } else {
    const existing = fs.readdirSync(root)
    if (existing.length) {
        //...
    }
  }

  // 第三步 校验并选择模版
  let template = argv.t || argv.template
  let message = 'Select a template:'
  if (!template || !isValidTemplate) {
    const { t } = await prompt({
      type: 'select',
      name: 't',
      message,
      choices: TEMPLATES
    })
    template = stripColors(t)
  }

  const templateDir = path.join(__dirname, `template-${template}`)

  const write = (file, content) => {
    const targetPath = renameFiles[file]
      ? path.join(root, renameFiles[file])
      : path.join(root, file)
    if (content) {
      fs.writeFileSync(targetPath, content)
    } else {
      copy(path.join(templateDir, file), targetPath)
    }
  }
  // 第四步:拷贝并写入文件
  const files = fs.readdirSync(templateDir)
  for (const file of files.filter((f) => f !== 'package.json')) {
    write(file)
  }

  const pkg = require(path.join(templateDir, `package.json`))

  // 第五步:拷贝 package.json 提示安装运行
  write('package.json', JSON.stringify(pkg, null, 2))
  // ...提示 `npm install / npm run dev`
}

// 省略功能函数...
init().catch((e) => {
  console.error(e)
})
复制代码

上面的代码主要逻辑如下:

  • 第一步:确定 Project name ,用户输入或默认;
  • 第二步:检查本地是否存在同名目录,并判断是否为空目录;
  • 第三步:选择要创建的模板,vue、vue-ts、react 等;
  • 第四部(核心):根据选择的模板匹配到项目下以 template- 开头的目录,将目录中的所有文件拷贝到本地项目目录中;
  • 第五步:拷贝修改完 name 的新 package.json 到新项目中,并提示安装依赖和运行;

到此我们已经搞清楚 npm init @vitejs/app 背后是通过执行 create-app 中 bin 所指定的脚本文件。而这个脚本文件(这里是 index.js)所做的工作,就是根据一些配置和模版项目,利用 node 将所有模版文件拷贝到本地项目目录中,从而完成了一个根据模板创建项目的系列操作。

创建项目可用 CLI 脚手架,为何要如此大费周章呢?莫急且看。

npm init VS vue create

我们使用 vue create 来创建项目时,背后是 Vue-CLI 给予我们的能力。所以我们得首先安装 Vue-Cli,然后才可以使用它来创建项目。而 npm init 则跳过了 CLI 这部分,它基于指定脚本来实现,所以与 vue create 对比,它的优点:

  • 项目即工具,更加简单直接;
  • 不用安装额外的 CLI 工具,多一个工具就多一个使用成本;
  • 更新方便,无需同时维护模板和 CLI 工具;

所以,总的来说使用 npm init 创建项目更加简单和纯粹。

加深 package.json 认识

不难发现,create-app 入口文件关键是 package.json 文件的 bin 属性,那么 bin 和 main 有什么区别呢?

mainbin
属性是一个 module ID,是程序的主要的入口点,当然如果不设置,默认值就是 index.js如果此 npm 包带有 bin 属性,那么此 npm 包的可执行文件就会被链接到当前项目的 ./node_modules/.bin 中,此后在命令行中就很方便的执行这个包,比如:node node_modules/.bin/myapp,更加详细的解释可参照 package.json bin

不得不说,package.json 中每个属性都有它的用处,只有仔细的阅读和分析其的含义和用法,才会有创造轮子的那点灵光啊!

学完能做什么?

公司新的项目层出不穷,目前项目还在做微前端的重构,微前端中的各个子模块都需要使用一个模板 Ctrl + C / Ctrl + V 来创建,虽然对于我们 cv 程序员来说是小 case,但是如果我们有了自己的 create-app,我们翻手一个 npm init @company/app,岂不更美哉?

不单如此,我们还可以建立公司内部或对外的模板库项目,将所有常用的模板项目维护到一个项目中,统一维护管理,岂不快哉?(坑已挖好,活已安排,下次一定)...

以上便是本次分享的全部内容,希望对你有所帮助 ^_^


作者:VANTOP前端团队
链接:https://juejin.cn/post/6948202986573135908
来源:掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

  • 4
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值