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的资料请关注Devmax其它相关文章!

创建项目及包管理yarn create vite源码学习的更多相关文章

  1. 使用Vite+Vue3+Vant全家桶快速构建项目步骤详解

    这篇文章主要为大家介绍了使用Vite+Vue3+Vant全家桶快速构建项目步骤详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

  2. 使用PHP反射机制来构造"CREATE TABLE"的sql语句

    今天小编就为大家分享一篇关于使用PHP反射机制来构造"CREATE TABLE"的sql语句,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧

  3. yarn的安装及使用详解

    Yarn 就是一个类似于 npm 的包管理工具,它是由 facebook 推出并开源,与 npm 相比,yarn 有着众多的优势,主要的优势在于:速度快、离线模式、版本控制,这篇文章主要介绍了yarn的安装及使用教程,需要的朋友可以参考下

  4. Vite创建Vue3项目及Vue3使用jsx详解

    vite是新一代的前端构建工具,下面这篇文章主要给大家介绍了关于Vite创建Vue3项目以及Vue3使用jsx的相关资料,文中通过实例代码介绍的非常详细,需要的朋友可以参考下

  5. vite插件打包更顺畅使用技巧示例

    这篇文章主要为大家介绍了vite插件打包更顺畅的使用技巧示例,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

  6. 一步步带你用vite简单搭建ts+vue3全家桶

    Vue3与TS的联合是大趋势,下面这篇文章主要给大家介绍了关于用vite简单搭建ts+vue3全家桶的相关资料,文中通过实例代码介绍的非常详细,需要的朋友可以参考下

  7. vite创建一个标准vue3+ts+pinia项目

    本文主要介绍了vite创建一个标准vue3+ts+pinia项目,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

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

    这篇文章主要为大家介绍了创建项目及包管理yarn create vite源码学习分析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

  9. 如何使用Vue3+Vite+TS快速搭建一套实用的脚手架

    Vite是一个面向现代浏览器的一个更轻、更快的 Web 应用开发工具,下面这篇文章主要给大家介绍了关于如何使用Vue3+Vite+TS快速搭建一套实用脚手架的相关资料,文中通过示例代码介绍的非常详细,需要的朋友可以参考下

  10. vite的搭建与使用的详细步骤

    本文主要介绍了vite的搭建与使用,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

随机推荐

  1. js中‘!.’是什么意思

  2. Vue如何指定不编译的文件夹和favicon.ico

    这篇文章主要介绍了Vue如何指定不编译的文件夹和favicon.ico,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教

  3. 基于JavaScript编写一个图片转PDF转换器

    本文为大家介绍了一个简单的 JavaScript 项目,可以将图片转换为 PDF 文件。你可以从本地选择任何一张图片,只需点击一下即可将其转换为 PDF 文件,感兴趣的可以动手尝试一下

  4. jquery点赞功能实现代码 点个赞吧!

    点赞功能很多地方都会出现,如何实现爱心点赞功能,这篇文章主要为大家详细介绍了jquery点赞功能实现代码,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  5. AngularJs上传前预览图片的实例代码

    使用AngularJs进行开发,在项目中,经常会遇到上传图片后,需在一旁预览图片内容,怎么实现这样的功能呢?今天小编给大家分享AugularJs上传前预览图片的实现代码,需要的朋友参考下吧

  6. JavaScript面向对象编程入门教程

    这篇文章主要介绍了JavaScript面向对象编程的相关概念,例如类、对象、属性、方法等面向对象的术语,并以实例讲解各种术语的使用,非常好的一篇面向对象入门教程,其它语言也可以参考哦

  7. jQuery中的通配符选择器使用总结

    通配符在控制input标签时相当好用,这里简单进行了jQuery中的通配符选择器使用总结,需要的朋友可以参考下

  8. javascript 动态调整图片尺寸实现代码

    在自己的网站上更新文章时一个比较常见的问题是:文章插图太宽,使整个网页都变形了。如果对每个插图都先进行缩放再插入的话,太麻烦了。

  9. jquery ajaxfileupload异步上传插件

    这篇文章主要为大家详细介绍了jquery ajaxfileupload异步上传插件,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  10. React学习之受控组件与数据共享实例分析

    这篇文章主要介绍了React学习之受控组件与数据共享,结合实例形式分析了React受控组件与组件间数据共享相关原理与使用技巧,需要的朋友可以参考下

返回
顶部