创建项目及包管理yarn create vite源码学习

 更新时间:2022年09月27日 08:59:12   作者:小鑫同学  
这篇文章主要为大家介绍了创建项目及包管理yarn create vite源码学习分析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

1.引言

我们在编程学习的过程中也会写一些项目的模板,这样的模板在后期其实并没有进行很好的管理,以至于下次再来回顾或使用的时候还需要从“零”开始,在使用过 Vite 来创建项目后顺便拿看了一下仓库中create-vite包中的源码,得到了很好的启发~

2.走进“yarn create vite”的源码

2.1 Vite 创建项目的方式:

  • 终端交互方式创建项目;
  • 终端指定模版创建项目;

2.1.1 终端交互方式创建项目:

相比于以往的 CLI 工具提供的创建项目都需要优先手动安装 CLI 工具后再执行对应的创建命令,另一种就是 Vite 目前采用的直接通过包管理器内置命令使用统一的规范来实现项目的快速创建;

如果你使用 YARN:

# yarn
yarn create vite

接下来就可以按终端提示进行项目名称的录入和项目模板的选择了~

2.1.2 终端指定模版创建项目:

如果我们很明确内置的模板选项的话我们可以在终端执行时同时录入项目名称和模板名称更快速的创建项目;

# yarn
yarn create vite my-vue-app --template vue

备注:使用“.”来在当前目录创建项目;

2.2 源码分析:

  • 终端参数解析;
  • 交互收集数据;
  • 目录初始化;
  • 拷贝模板文件夹;
  • 重写 gitignore 名称;
  • 重写 package 字段;
  • 后续操作提示;

2.2.1 终端参数解析:

通过 minimist 模块将终端参数解析为对象形式:

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

通过读取对象属性来得到 argTargetDir 和 argTemplate 两个参数:

const argTargetDir = formatTargetDir(argv._[0])
const argTemplate = argv.template || argv.t

2.2.2 交互收集数据:

通过交互收集的数据包括:projectName、overwrite、packageName、framework、variant:

projectName:默认值是 defaultTargetDir ,对应的值是vite-project,当通过终端解析到 argTargetDir 后将跳过此步骤;

{
  type: argTargetDir ? null : 'text',
  name: 'projectName',
  message: reset('Project name:'),
  initial: defaultTargetDir,
  onState: (state) => {
    targetDir = formatTargetDir(state.value) || defaultTargetDir
  }
}

overwrite:在确认好 targetDir 参数后,我们要看 targetDir 对应的文件夹是否存在或是文件夹中是否有文件,要提示用户是否需要情况或终端操作;

{
  type: () =>
    !fs.existsSync(targetDir) || isEmpty(targetDir) ? null : 'confirm',
  name: 'overwrite',
  message: () =>
    (targetDir === '.'
      ? 'Current directory'
      : `Target directory "${targetDir}"`) +
    ` is not empty. Remove existing files and continue?`
},
{
  type: (_, { overwrite }: { overwrite?: boolean }) => {
    if (overwrite === false) {
      throw new Error(red('✖') + ' Operation cancelled')
    }
    return null
  },
  name: 'overwriteChecker'
}

packageName:packageName 的值通过 路径targetDir 来确定,在终端交互收集数据的时候需要对值做格式的校验来确定合法性;

// 确定项目名称
const getProjectName = () =>
    targetDir === '.' ? path.basename(path.resolve()) : targetDir
// 校验项目名称合法性
{
  type: () => (isValidPackageName(getProjectName()) ? null : 'text'),
  name: 'packageName',
  message: reset('Package name:'),
  initial: () => toValidPackageName(getProjectName()),
  validate: (dir) =>
    isValidPackageName(dir) || 'Invalid package.json name'
}

framework:如果终端已获取到 argTemplate 参数,且已内置该模板将跳过这步,否则将进行预置模板配置的解析并选择;

{
  type:
    argTemplate && TEMPLATES.includes(argTemplate) ? null : 'select',
  name: 'framework',
  message:
    typeof argTemplate === 'string' && !TEMPLATES.includes(argTemplate)
      ? reset(
          `"${argTemplate}" isn't a valid template. Please choose from below: `
        )
      : reset('Select a framework:'),
  initial: 0,
  choices: FRAMEWORKS.map((framework) => {
    const frameworkColor = framework.color
    return {
      title: frameworkColor(framework.display || framework.name),
      value: framework
    }
  })
}

variant:通过上一步得到的 framework 参数将确定这个步的配置,因为同样的 framework 看一配置多种 variant ;

{
  type: (framework: Framework) =>
    framework && framework.variants ? 'select' : null,
  name: 'variant',
  message: reset('Select a variant:'),
  choices: (framework: Framework) =>
    framework.variants.map((variant) => {
      const variantColor = variant.color
      return {
        title: variantColor(variant.display || variant.name),
        value: variant.name
      }
    })
}

2.2.3 目录初始化:

目录如果不存在的话我们需要创建对应的目录,因为在前期收集参数可能是个目录,这儿创建的时候需要递归创建,但是当目录存在且有内容的时候我们就需要清空掉里面的文件了,但是在清空的时候我们要考虑当时目录可能已经被版本管理过了,所以需要对.git目录过滤掉,这样才更完整;

const root = path.join(cwd, targetDir)
if (overwrite) {
  emptyDir(root)
} else if (!fs.existsSync(root)) {
  fs.mkdirSync(root, { recursive: true })
}

2.2.4 拷贝模板文件夹:

模板拷贝的时候需要过滤掉package.json,我们会在后面单独进行处理;

const files = fs.readdirSync(templateDir)
for (const file of files.filter((f) => f !== 'package.json')) {
  write(file)
}

2.2.5 重写 gitignore 名称:

在上一步的模板文件夹拷贝的时候已经用到了这个函数,我们这里关系第二行中的关键对象 renameFiles ,实际上就是要将 _gitignore 重命名为 .gitignore ,因为在模板中直接使用 .gitignore 可能就导致关节的文件被丢失掉了;

const write = (file: string, content?: string) => {
  const targetPath = path.join(root, renameFiles[file] ?? file)
  if (content) {
    fs.writeFileSync(targetPath, content)
  } else {
    copy(path.join(templateDir, file), targetPath)
  }
}

2.2.6 重写 package 字段:

最后来输出 package.json ,需要改变里面的内容,尤其是重要的项目名称,命名规范也是为了符合 package 中 name 的规则;

const pkg = JSON.parse(
  fs.readFileSync(path.join(templateDir, `package.json`), 'utf-8')
)
pkg.name = packageName || getProjectName()
write('package.json', JSON.stringify(pkg, null, 2))

2.2.7 后续操作提示:

在模板拷贝完毕后项目的创建阶段也就结束了,接着就是判断在终端执行的包管理器来提示用户下一步的操作了~

const pkgInfo = pkgFromUserAgent(process.env.npm_config_user_agent)
const pkgManager = pkgInfo ? pkgInfo.name : 'npm'
switch (pkgManager) {
  case 'yarn':
    console.log('  yarn')
    console.log('  yarn dev')
    break
  default:
    console.log(`  ${pkgManager} install`)
    console.log(`  ${pkgManager} run dev`)
    break
}

3. 总结

在源码中还支持了第三方模板通过自定义命令来创建项目,关键词可以搜索 customCommand ,整体源码是很简单的,你准备好为自己创建一套模板管理工具了吗~

以上就是创建项目及包管理yarn create vite源码学习的详细内容,更多关于创建项目包管理yarn create vit的资料请关注脚本之家其它相关文章!

相关文章

  • vue+elementUI如何实现顶部路由标签跳转

    vue+elementUI如何实现顶部路由标签跳转

    这篇文章主要介绍了vue+elementUI如何实现顶部路由标签跳转问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-03-03
  • vue中图片加载不出来的问题及解决

    vue中图片加载不出来的问题及解决

    这篇文章主要介绍了vue中图片加载不出来的问题及解决,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-03-03
  • VUE如何利用vue-print-nb实现打印功能详解

    VUE如何利用vue-print-nb实现打印功能详解

    这篇文章主要给大家介绍了关于VUE如何利用vue-print-nb实现打印功能的相关资料,文中还给大家介绍了vue-print-nb使用中的常见问题,如空白页,需要的朋友可以参考下
    2022-04-04
  • vue 项目地址去掉 #的方法

    vue 项目地址去掉 #的方法

    vue 项目往往会搭配 vue-router 官方路由管理器,它和 vue.js 的核心深度集成,让构建单页面应用变得易如反掌。这篇文章主要介绍了vue 项目地址去掉 #的方法,需要的朋友可以参考下
    2018-10-10
  • 解决父子组件通信的三种Vue插槽

    解决父子组件通信的三种Vue插槽

    这篇文章主要为大家介绍了Vue插槽解决父子组件通信,具有一定的参考价值,感兴趣的小伙伴们可以参考一下,希望能够给你带来帮助
    2021-11-11
  • Vue实现Dialog封装

    Vue实现Dialog封装

    在写业务的时候很常见的一个场景就是需要在不同的页面调用同一个表单,常用的交互就是把表单以弹窗的形式展示,本文主要介绍了Vue实现Dialog封装,感兴趣的可以了解一下
    2021-07-07
  • Vue通过Blob对象实现导出Excel功能示例代码

    Vue通过Blob对象实现导出Excel功能示例代码

    这篇文章主要介绍了Vue通过Blob对象实现导出Excel功能,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-07-07
  • 详解vue项目中使用vuedraggable

    详解vue项目中使用vuedraggable

    这篇文章主要介绍了vue项目中使用vuedraggable,本文给大家介绍了错误问题分析及解决方法,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2022-05-05
  • vue.js系列中的vue-fontawesome使用

    vue.js系列中的vue-fontawesome使用

    这篇文章主要介绍了vue.js系列中的vue-fontawesome使用,需要的朋友可以参考下
    2018-02-02
  • vue组件讲解(is属性的用法)模板标签替换操作

    vue组件讲解(is属性的用法)模板标签替换操作

    这篇文章主要介绍了vue组件讲解(is属性的用法)模板标签替换操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-09-09

最新评论