Create vite理解Vite项目创建流程及代码实现

目录
  • 前言
    • monorepo
  • 主流程
    • 入口文件
    • 主要结构
    • 扩展插件
    • 模板配置
    • getProjectName
    • formatTargetDir
    • npm包名验证和转化
    • 取得模板目录
    • 得到npm包管理器相关信息
  • 文件操作相关的函数
    • write函数 写入文件
    • copy函数 复制文件
    • copyDir 复制目录
    • emptyDir 清空目录
    • isEmpty 判断目录为空
  • 核心代码
  • 总结

前言

继上次阅读create-vue后 ,本次接着来解析 create-vite, 得益于之前的阅读经验, 本篇笔记将会着重讲解代码执行流程以及函数的扩展

最新的 create-vite 已经升级为Ts编译了,为方便学习理解使用川哥提供的源码仓库

git clone github.com/lxchuan12/v…

monorepo

ViteVue都使用monorepo的形式管理代码,将原本多代码仓库变为单代码仓库,每一个包对应的就是一个项目,这些项目都具有相关性,但在逻辑上是独立的。

主流程

入口文件

vite2/packages/create-vite/index.js

主要结构

import fs from 'node:fs'
import path from 'node:path'
//...
 async function init() {
//...
  try {
    result = await prompts(
      [
       //省略若干选项代码
      ],
      {
        onCancel: () => {
          throw new Error(red('') + ' Operation cancelled')
        }
      }
    )
  } catch (cancelled) {
    console.log(cancelled.message)
    return
  }
      //若干处理代码
 }
 init().catch((e) => {
  console.error(e)
 })

index.js 核心就是执行 init这个异步函数, 通过选项式对话 取到配置变量后 执行操作

扩展插件

import minimist from 'minimist'
import prompts from 'prompts'
import {
  blue,
  cyan,
  green,
  lightRed,
  magenta,
  red,
  reset,
  yellow
} from 'kolorist'

minimist 用于获取命令行参数,用于跳过后续一些选项式对话

prompts 提供了选项式对话的 命令行工具

kolorist 用来在命令行输出不同颜色的字符

模板配置

const FRAMEWORKS = [
  {
    name: 'vanilla',
    color: yellow,
    variants: [
      {
        name: 'vanilla',
        display: 'JavaScript',
        color: yellow
      },
      {
        name: 'vanilla-ts',
        display: 'TypeScript',
        color: blue
      }
    ]
  },
  //若干代码
]
const TEMPLATES = FRAMEWORKS.map(
  (f) => (f.variants && f.variants.map((v) => v.name)) || [f.name]
).reduce((a, b) => a.concat(b), [])

TEMPLATES 主要用来根据定义好的配置对象 生成对应后续template用到的数组

getProjectName

const getProjectName = () =>
  //path.resolve() 默认返回当前目录
  //path.basename(path.resolve())  对应得到的就是 当前目录名
    targetDir === '.' ? path.basename(path.resolve()) : targetDir

用于获取项目名, 值得一提的是 path.resolve() 默认返回命令执行的目录,path.basename(path.resolve()) 就是获取当前目录名

formatTargetDir

function formatTargetDir(targetDir) {
  return targetDir?.trim().replace(/\/+$/g, '')
}

将文本去空,并将末尾的 /斜杠去掉

npm包名验证和转化

function toValidPackageName(projectName) {
  return projectName
    .trim()
    .toLowerCase()
    .replace(/\s+/g, '-')
    .replace(/^[._]/, '')
    .replace(/[^a-z0-9-~]+/g, '-')
}
function isValidPackageName(projectName) {
  return /^(?:@[a-z0-9-*~][a-z0-9-*._~]*\/)?[a-z0-9-~][a-z0-9-._~]*$/.test(
    projectName
  )
}

用于验证是否符合package.json name 的格式 以及转换函数

取得模板目录

 const templateDir = path.resolve(
    fileURLToPath(import.meta.url),
    '..',
    `template-${template}`
  )

通过resolve 拼接目录名,根据用户的选择会生成对应的 比如 template-vue-ts

得到npm包管理器相关信息

const pkgInfo = pkgFromUserAgent(process.env.npm_config_user_agent)
  const pkgManager = pkgInfo ? pkgInfo.name : 'npm'
  function pkgFromUserAgent(userAgent) {
  if (!userAgent) return undefined
  const pkgSpec = userAgent.split(' ')[0]
  const pkgSpecArr = pkgSpec.split('/')
  return {
    name: pkgSpecArr[0],
    version: pkgSpecArr[1]
  }
}

process.env.npm_config_user_agent 会返回类似这样的字符:

npm/6.7.5 xxxx/xxx xxx ,函数就是取出第一部分然后切割字符, 得到对应的 包管理器以及版本

文件操作相关的函数

write函数 写入文件

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)
  }
}

targetPath先匹配.gitignore,否则直接使用参数的file值。 然后根据是否传递了 content参数执行写入 和 复制 template目录下文件 两个操作

copy函数 复制文件

function copy(src, dest) {
  const stat = fs.statSync(src)
  if (stat.isDirectory()) {
    copyDir(src, dest)
  } else {
    fs.copyFileSync(src, dest)
  }
}

判断文件信息, 目录则执行 copyDir函数, 否则调用 fs 下 的 copyFileSync

copyDir 复制目录

function copyDir(srcDir, destDir) {
  fs.mkdirSync(destDir, { recursive: true })
  for (const file of fs.readdirSync(srcDir)) {
    const srcFile = path.resolve(srcDir, file)
    const destFile = path.resolve(destDir, file)
    copy(srcFile, destFile)
  }
}

创建目标文件夹,然后遍历源文件夹 依次将文件 copy过去

emptyDir 清空目录

function emptyDir(dir) {
  if (!fs.existsSync(dir)) {
    return
  }
  for (const file of fs.readdirSync(dir)) {
    fs.rmSync(path.resolve(dir, file), { recursive: true, force: true })
  }
}

将目录变为空目录。先判断目录是否存在, 再遍历执行删除操作

isEmpty 判断目录为空

function isEmpty(path) {
  const files = fs.readdirSync(path)
  return files.length === 0 || (files.length === 1 && files[0] === '.git')
}

通过fs.readdirSync 得到目录返回的数组长度 进行判断

核心代码

const { framework, overwrite, packageName, variant } = result
  const root = path.join(cwd, targetDir)
//检查是否可写入
  if (overwrite) {
    emptyDir(root)
  } else if (!fs.existsSync(root)) {
    fs.mkdirSync(root, { recursive: true })
  }
  // determine template
  template = variant || framework || template
  console.log(`\nScaffolding project in ${root}...`)
//得到模板目录
  const templateDir = path.resolve(
    fileURLToPath(import.meta.url),
    '..',
    `template-${template}`
  )
  const write = (file, content) => {
   //写文件函数
  }
  const files = fs.readdirSync(templateDir) //得到模板目录下文件信息
  //将默认目录中非package.json 的文件 复制到 templateDir中
  for (const file of files.filter((f) => f !== 'package.json')) {
    write(file) //不传 content 执行 copy操作
  }
//得到模板目录中的 package.json内容
  const pkg = JSON.parse(
    fs.readFileSync(path.join(templateDir, `package.json`), 'utf-8')
  )
  pkg.name = packageName || getProjectName()
// 修改name 后 写入 package.json 到 templateDir中中
  write('package.json', JSON.stringify(pkg, null, 2))
//得到对应包管理器的 信息 然后回显
  const pkgInfo = pkgFromUserAgent(process.env.npm_config_user_agent)
  const pkgManager = pkgInfo ? pkgInfo.name : 'npm'
  console.log(`\nDone. Now run:\n`)
  if (root !== cwd) {
    console.log(`  cd ${path.relative(cwd, root)}`)
  }
  switch (pkgManager) {
    case 'yarn':
      console.log('  yarn')
      console.log('  yarn dev')
      break
    default:
      console.log(`  ${pkgManager} install`)
      console.log(`  ${pkgManager} run dev`)
      break
  }
  console.log()

这一步总体流程如下:

  • 检查目录是否可写入
  • 得到对应的模板目录
  • 写入模板目录的文件到 用户的目录中
  • 取得包管理器信息 回返显示 提示信息

总结

path.resolve 是相对于当前工作目录 返回路径

path.join 是 根据path字符串片段拼接返回一个路径 需要注意区别

至此 代码和流程就分析完毕了,相对于create-vue, create-vite要简单一点点

对于不懂或者不了解的地方, 复现或者尝试重写进行举一反三 是加深 认知 和学习 更好的方式,光是看和阅读领悟还是不够的!

写了个练习用的小工具,可以用来快捷的生成Vue模板页面

create-harexs-tp

以上就是Create vite理解Vite项目创建流程及代码实现的详细内容,更多关于Create vite 项目创建流程的资料请关注我们其它相关文章!

(0)

相关推荐

  • Vite的createServer启动源码解析

    目录 启动Vite的createServer 通过vite3安装一个vue的工程 添加断点并开启调试 边调试边理解代码 启动Vite的createServer 为了能够了解vite里面运行了什么,通过执行单步调试能够更加直观的知道Vite具体内容.所以这次我们来试着启动Vite的createServer,并进行调试. 通过vite3安装一个vue的工程 进入工作目录,运行下面的代码,项目名称随意,语言用Vue. npm create vite 进入工程目录安装依赖 添加断点并开启调试 通过vsc

  • create vite 实例源码解析

    目录 代码结构 init() projectName:项目名称 overwrite:是否覆盖已存在的目录 overwriteChecker:检测覆盖的目录是否为空 framework:框架 variant:语言 获取用户输入 清空目录 生成项目 确定项目模板 确定包管理器 正式生成项目 创建package.json 完成 总结 代码结构 create-vite的源码很简单,只有一个文件,代码总行数400左右,但是实际需要阅读的代码大约只有200行左右,废话不多说,直接开始吧. create-vi

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

    目录 1.引言 2.走进“yarn create vite”的源码 2.1 Vite 创建项目的方式: 2.1.1 终端交互方式创建项目: 2.1.2 终端指定模版创建项目: 2.2 源码分析: 2.2.1 终端参数解析: 2.2.2 交互收集数据: 2.2.3 目录初始化: 2.2.4 拷贝模板文件夹: 2.2.5 重写 gitignore 名称: 2.2.6 重写 package 字段: 2.2.7 后续操作提示: 3. 总结 1.引言 我们在编程学习的过程中也会写一些项目的模板,这样的模板

  • Create vite理解Vite项目创建流程及代码实现

    目录 前言 monorepo 主流程 入口文件 主要结构 扩展插件 模板配置 getProjectName formatTargetDir npm包名验证和转化 取得模板目录 得到npm包管理器相关信息 文件操作相关的函数 write函数 写入文件 copy函数 复制文件 copyDir 复制目录 emptyDir 清空目录 isEmpty 判断目录为空 核心代码 总结 前言 继上次阅读create-vue后 ,本次接着来解析 create-vite, 得益于之前的阅读经验, 本篇笔记将会着重讲

  • 如何用Vite构建工具快速创建Vue项目

    目录 和Webpack相比,Vite具有以下特点 Vite构建Vue项目 构建过程可能会发生的一些问题 总结 和Webpack相比,Vite具有以下特点 1.快速的冷启动,不需要等待打包 2.即时的热模块更新,真正的按需编译,不用等待整个项目编译完成 Vite构建Vue项目 前提:安装Node.js和Vite 第一步通过npm创建Vite项目 npm init vite-app 项目名称 # 例如 npm init vite-app HelloVue 第二步当项目创建成功后,cd到项目目录 cd

  • Vite搭建React项目的方法步骤

    前言 日常放鸽,火钳刘明 这是一个基于 vite 搭建的 React 的项目,开发体验非常棒. 创建一个 Vite 项目 yarn create @vitejs/app 如上图,选择了 react-ts 预设模板,如果出现下图一样的工程 yarn // 安装依赖 yarn dev // 启动开发环境 打开浏览器输入http://localhost:3000/#/,如上图所示的话.那么恭喜你,你可以正常开发 React 项目了.完结撒花 如果不行的话,直接看 vite 官网,它比我写的详细 改造工

  • vite+vue3+element-plus项目搭建的方法步骤

    使用vite搭建vue3项目 通过在终端中运行以下命令,可以使用 Vite 快速构建 Vue 项目. $ npm init vite-app <project-name> $ cd <project-name> $ npm install $ npm run dev 引入Element Plus 安装Element Plus: npm install element-plus --save main.js中完整引入 Element Plus: import { createApp

  • Vue3+script setup+ts+Vite+Volar搭建项目

    目录 使用 Vite 创建 vue + ts 项目 Vue 3 的三种语法 Option API Composition API script setup(Composition API 的语法糖) 安装 Volar 结尾 好久没有写了,最近看到Vue3.2 发布了,害,又要开始卷了么. 其实我自己本身还没有使用过Vue3 做过实际的项目开发,然鹅又出新东西了--, 新时代农民工真的是左手工作,右手游戏,还要用jio去学习呢. 什么? 你说谈对象? xswl,我特么一个农民工也配谈对象? 不卷不

  • vite搭建vue2项目的实战过程

    目录 问题提出 搭建过程 1.初始化项目 1.1 创建项目 1.2 安装vite对vue2支持的插件 1.3 安装vue依赖 1.4 修改项目文件结构 1.5 运行一下项目 2.vue-router 2.1 安装 2.2 新建router目录 2.3 全局注册 3.vuex 3.1 安装 3.2 新建vuex目录 3.3 全局注册 4.组件库 4.1 安装 4.2 按需引入 4.3 在main.js全局注册 4.4 在页面中使用 5.axios 5.1 安装 5.2 封装axios 5.3 在页

  • vite构建vue3项目的全过程记录

    目录 环境准备 创建项目 启动 总结 环境准备 安装最新版本 @vuejs/app yarn global add @vue/cli # OR npm install -g @vue/cli 升级到最新版本 @vitejs/app yarn global upgrade @vue/cli # OR npm update -g @vue/cli 查看 vue 版本 vue -V 兼容性注意 Vite 需要 Node.js 版本 >= 12.0.0. 故切换 node 版本,可查看该文章:使用 nv

  • 尤雨溪开发vue dev server理解vite原理

    目录 1.引言 2. vue-dev-server 它的原理是什么 3. 准备工作 3.1 克隆项目 3.2 test 文件夹 3.3 vue-dev-server.js 3.4 用 VSCode 调试项目 4. vueMiddleware 源码 4.1 有无 vueMiddleware 中间件对比 4.2 vueMiddleware 中间件概览 4.3 对 .vue 结尾的文件进行处理 4.3.1 bundleSFC 编译单文件组件 4.3.2 readSource 读取文件资源 4.4 对

  • 如何使用vite搭建vue3项目详解

    目录 一:npm构建 二:更改http://localhost:3000/到8080与Network路由访问 三:配置vite别名(npm install @types/node --save-dev) 四 :路由(npm install vue-router@4) 五:vuex(npm install vuex@next --save) 六:Eslint(可选)(npm install --save-dev eslint eslint-plugin-vue) 七:less/sass(可选)(n

  • IntelliJ IDEA2019实现Web项目创建示例

    一.创建web项目 1.打开idea软件,点击界面上的Create New Project 2.进入如下界面.选中 java Enterprise,配置jdk,tomcat,勾选Web Application案例,注意勾选生成web.xml文件 3.指定项目的名称及项目文件的保存地址 4.创建成功 5.创建class文件和lib文件夹   点击项目的WEF-INF文件夹 ,右键,New → Directory 创建两个文件夹,classes(用来存放编译后输出的class文件) 和 lib(用于

随机推荐