创建项目及包管理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实现会议室拖拽布局排座功能

    vue实现会议室拖拽布局排座功能

    vue-draggable-resizable-gorkys是一更强大的拖拽组件,可以随意拖拽,有点坐标,会议室拖拽布局排座是vue-draggable结合vue-draggable-resizable-gorkys进行开发的,本文重点给大家介绍vue实现会议室拖拽布局排座,感兴趣的朋友一起看看吧
    2023-11-11
  • 解决vue动态为数据添加新属性遇到的问题

    解决vue动态为数据添加新属性遇到的问题

    今天小编就为大家分享一篇解决vue动态为数据添加新属性遇到的问题,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2018-09-09
  • vue如何解决数据加载时,插值表达式闪烁问题

    vue如何解决数据加载时,插值表达式闪烁问题

    这篇文章主要介绍了vue如何解决数据加载时,插值表达式闪烁问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-01-01
  • vue引入jquery时报错 $ is not defined的问题及解决

    vue引入jquery时报错 $ is not defined的问题及解决

    这篇文章主要介绍了vue引入jquery时报错 $ is not defined的问题及解决,具有很好的参考价值,希望对大家有所帮助。
    2022-09-09
  • Vite热更新失效的问题解决

    Vite热更新失效的问题解决

    本文主要介绍了Vite热更新失效的问题解决,原因是文件夹和文件名大小写不一致,下面就来解决一下次问题,感兴趣的可以了解一下
    2024-08-08
  • Vue实现百度下拉提示搜索功能

    Vue实现百度下拉提示搜索功能

    这篇文章主要为大家详细介绍了Vue实现百度下拉提示搜索功能,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-06-06
  • Vue实现随机验证码功能

    Vue实现随机验证码功能

    这篇文章主要为大家详细介绍了Vue实现随机验证码功能,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2020-12-12
  • Vue3通过ref操作Dom元素及hooks的使用方法

    Vue3通过ref操作Dom元素及hooks的使用方法

    这篇文章主要介绍了Vue3通过ref操作Dom元素及hooks的使用方法,需要的朋友可以参考下
    2023-01-01
  • 前端设置cookie之vue-cookies使用及说明

    前端设置cookie之vue-cookies使用及说明

    这篇文章主要介绍了前端设置cookie之vue-cookies使用及说明,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-05-05
  • Vue组件懒加载的操作代码

    Vue组件懒加载的操作代码

    在本文中,我们学习了如何使用 Intersection Observer API 和 defineAsyncComponent 函数在 Vue 组件可见时对其进行懒加载,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友一起看看吧
    2023-09-09

最新评论