【学习笔记】Vue3源码解析:第一部分-实现vue3环境搭建

news2024/9/24 7:25:58

课程地址:【已完结】全网最详细Vue3源码解析!(一行行带你手写Vue3源码)

第一部分:实现vue3环境搭建(对应课程的第1-3节)

VUE2与VUE3的对比:

也即vue2的痛点:

  1. 对TypeScript支持不友好,所有属性都放在this对象上,难以推导数据类型
  2. 大量API挂载在vue对象原型上,难以实现TreeShaking
  3. 架构层面对跨平台DOM渲染开发支持不友好(这一点我不太理解)
  4. 推出CompositionAPI(受reactHook启发)
  5. 对虚拟DOM进行了重写,对模板的编译进行了优化

Monorepo介绍

Monorepo 是一种项目代码管理方式,指单个仓库中管理多个项目,是一种将多个peckage放在一个repo中的代码管理模式。其有助于简化代码共享、版本控制、构建和部署等方面的复杂性,并提供更好的可重用性和协作性。更多可参阅:带你了解更全面的 Monorepo - 优劣、踩坑、选型
vue3中使用 yarn workspace+lerna 来管理项目。

Monorepo环境搭建

1、项目初始化:由于Monorepo是不支持npm的,所以使用yarn来初始化一个项目:

yarn init -y

2、 Monorope分包:打开项目根目录中的package.json文件,在其中加入如下配置:private与workspaces

//package.json
{
  "private": true,
  "workspaces": [
    "packages/*"
  ],
  "name": "vue3",
  "version": "1.0.0",
  "main": "index.js",
  "license": "MIT",
  "dependencies": {
    "typescript": "^5.3.3"
  },
  "devDependencies": {
    "@rollup/plugin-json": "^6.1.0",
    "@rollup/plugin-node-resolve": "^15.2.3",
    "execa": "^8.0.1",
    "rollup": "^4.9.6",
    "rollup-plugin-typescript2": "^0.36.0"
  },
  "type":"module"
}
  • private:表示私有
  • workspaces:表示分包,所有的包都会放在packages目录下

3、新建两个包文件夹
根目录下新建packages文件夹,在packages目录下新建reactivity与shared文件夹,并分别进入reactivity与shared文件夹中,分别执行 yarn init -y 生成各自的package.json文件,并在这两个文件夹下各自创建src文件,在src中创建入口文件index.ts;
在两个index.ts文件中随意编写一点不同的代码(如不写代码,稍后打包时会报错),如:

let a = 1
export {
  a
}

在这里插入图片描述
4、安装ts:注意:如果是所有包都要用的,比如ts,那就安装在最外层的package.json中,即项目根目录中的package.json中:

yarn add typescript -D -W

-D表示开发环境;由于进行了分包,所以在根目录中安装需要加上 -W 配置项
在这里插入图片描述
5、通过ts的tsc命令自动生成配置项tsconfig.json:

npx tsc --init

在这里插入图片描述
6、安装rollup打包的相关依赖,在命令行中执行如下命令:

yarn add rollup rollup-plugin-typescript2 @rollup/plugin-node-resolve @rollup/plugin-json execa -D -W

7、创建一个脚本执行命令scripts,在根目录中的package.json中:
在这里插入图片描述
8、配置打包选项,分别在reactivity和shared文件夹下的package.json文件中配置各个包对应的打包配置:
在这里插入图片描述
将name分别修改为"@vue/reactivity" 与 “@vue/shared”;
reactivity文件夹下的package.json增加如下配置:
shared文件夹下的package.json增加的配置中去掉global:

"buildOptions":{
    "name":"VueReactivity",    // shared文件夹下为"VueShared"
    "formats":[
      "esm-bundler",
      "cjs",
      "global"     // shared文件夹下的package.json增的配置中去掉此行
    ]
  }

9、编写打包配置文件build.js:
在这里插入图片描述

// build.js
/ 1、获取打包目录
// const fs = require("fs")
// const execa = require("execa")

import fs from "fs"
import {execa} from "execa"

// 读取packages下所有文件名字,并过滤掉非文件夹,只保留packages下的文件夹
const dirs = fs.readdirSync("packages").filter(p=>{
  if(!fs.statSync(`packages/${p}`).isDirectory()){
    return false
  }
  return true
})

console.log('888888',dirs)    //[ 'reactivity', 'shared' ]

// 2、进行打包 并行打包
async function build(target){
  console.log(target,666)
  // await execa('rollup',['-c --bundleConfigAsCjs',"--environment",`TARGET:${target}`],{stdio:'inherit'})
  await execa('rollup',['-c',"--environment",`TARGET:${target}`],{stdio:'inherit'})
}

function runParaller(dirs,itemfn){
  let result = []
  for(let item of dirs){
    result.push(itemfn(item))
  }
  return Promise.all(result)
}

runParaller(dirs,build).then(()=>{
  console.log("成功")
})

10、根目录下新建rollup配置文件,rollup.config.js,在其中编写配置代码:

// 编写打包配置
// import ts from 'rollup-plugin-typescript2'   //解析ts
// import json from '@rollup/plugin-json'
// import resolvePlugin from '@rollup/plugin-node-resolve'  // 解析第三方插件
// import path from 'path'  // 处理路径

const ts = require('rollup-plugin-typescript2')   //解析ts
const json = require('@rollup/plugin-json')
const resolvePlugin = require('@rollup/plugin-node-resolve')  // 解析第三方插件
const path = require('path')  // 处理路径

// (2)获取文件路径
let packagesDir = path.resolve(__dirname,'packages')
// console.log(packagesDir, 888)    // D:\suyou\study\vue3-source-code\vue3\packages

// 2.1  获取需要打包的包
let packageDir = path.resolve(packagesDir, process.env.TARGET)
// console.log(packageDir, 888)   // D:\suyou\study\vue3-source-code\vue3\packages\reactivity

// 2.1  获取到每个包的项目配置
const resolve = p => path.resolve(packageDir, p)
const pkg = require(resolve('package.json'))    // 获取json
const packageOptions = pkg.buildOptions || {}
const name = path.basename(packageDir)
console.log(packageOptions, 888)   //{ name: 'VueReactivity', formats: [ 'esm-bundler', 'cjs', 'global' ] }
console.log(name, 888)   // reactivity

// 3  创建一个表
const outputOptions = {
  "esm-bundler":{
    file: resolve(`dist/${name}.esm-bundler.js`),
    format:'es'
  },
  "cjs": {
    file: resolve(`dist/${name}.cjs.js`),
    format: 'cjs'
  },
  "global": {
    file: resolve(`dist/${name}.global.js`),
    format: 'iife'
  },
}

const options = pkg.buildOptions

function createConfig(format,output){
  // 进行打包
  output.name = options.name
  output.sourcemap = true
  // 生成rollup配置
  return {
    input:resolve('src/index.ts'),
    output,
    plugins:[
      json(),
      ts({  //解析ts
        tsconfig:path.resolve(__dirname,'tsconfig.json')
      }),
      resolvePlugin()  //解析第三方插件
    ]
  }
}

// export default options.formats.map(format => createConfig(format, outputOptions[format]))

module.exports = options.formats.map(format => createConfig(format, outputOptions[format]))

11、将 tsconfig.json中的 target 和module 字段都改为 ESNext
在这里插入图片描述
12、运行打包:npm run build,成功:
此时会发现reactivity文件夹和shared文件夹下会出现打包生成的dist文件夹:
在这里插入图片描述
13、根目录下package.json文件中新增 dev 运行脚本命令:
在这里插入图片描述
14、scripts目录下新建dev.js并在其中编写:
'-c’处增加w,表示实时监控文件更新并自动编译

// dev.js
import {execa} from "execa"

// 进行打包
async function build(target){
  // console.log(target,666)   // reactivity  
  // {stdio:'inherit'} 配置项表示在子进程中输出内容可以在主包中输出
  await execa('rollup',['-cw','--environment',`TARGET:${target}`],{stdio:'inherit'})
}

build('reactivity')

运行npm run dev,此时可以修改代码后实时打包:
在这里插入图片描述
15、解决包之间的引入问题:
在reactivity的入口文件中引入shared:

import {b} from '@vue/shared'

在这里插入图片描述
此时 @vue/shared 处会出现波浪线,提示找不到这个模块。这时就需要到tsconfig.json中增加如下配置:
在这里插入图片描述

// 解决引入的问题 ts
    "moduleResolution": "node",  //node
    "baseUrl": ".",  // 根路径
    "paths":{
      "@vue/*":["packages/*/src"]
    } 

总结

1、yarn init -y初始工程
2、package.json文件中,增加:
“private”:“true”;
“workspaces”:[“packages/*”]
3、项目目录下新建文件夹packages,在其中新建两个文件夹reactivity、shared,分别进入这两个文件夹,执行yarn init -y,生成各自的package.json,分别在其package.json文件中增加配置:
修改name:“@vue/reactivity” name:“@vue/shared”
增加buildOptions:{
“name”:“VueReactivity” “name”:“VueShared”
format:[
“esm-bundler”,
“cjs”,
“global”
]
}
4、分别在文件夹reactivity、shared中新建src文件夹,并在其中新建index.ts入口文件
5、使用ts就要安装ts,因为ts是全局使用的,所以需要安装在根目录下,即在根目录下执行 yarn add typescript -D -W (-D表示开发环境,由于进行了分包,所以在根目录中安装需要加上 -W 配置项)
6、ts安装完成后,node_modules目录下会新增typescript-bin-tsc,此时使用tsc生成ts配置文件:执行:npx tsc --init,自动生成 tsconfig.json 文件
7、安装rollup打包的相关依赖:
yarn add rollup rollup-plugin-typescript2 @rollup/plugin-node-resolve @rollup/plugin-json execa -D -W
8、配置脚本执行命令:根目录 package.json 文件中,新增:
“scripts”:{
“build”:“node scripts/build.js”
}
9、根目录下新建scripts目录,并在其中创建build.js文件,在其中编写打包逻辑代码(详见代码)
10、根目录下新建rollup配置文件,rollup.config.js,在其中编写配置代码(详见代码)
11、将 tsconfig.json中的 target 和 module 字段都改为 ESNext(不然运行打包会报错)
12、配置开发环境打包:根目录package.json中添加dev运行命令,并在scripts目录下新建对应的dev.js文件,在其中编写打包逻辑代码(详见代码)
13、解决包之间引入问题,在tsconfig.json中增加相应配置(详见代码)
14、运行打包 npm run build 或 npm run dev,实现都可以成功打包

实践问题

编写build.js这一步跟着课程里的代码自己实践中,我遇到了问题,记录如下:

在这里插入图片描述

猜测报错信息大致是说execa不支持用require方式引入,改成import试试吧,又出现如下报错:

在这里插入图片描述

按照提示在package.json中增加"type": “module”,还是报错:

在这里插入图片描述

报错信息说execa没提供default暴露的接口,那就用 import {} 方式试试:

在这里插入图片描述

这是注意报错,不是execa引入有问题了,而是fs有问题了,因为我们配置了"type": “module”,所以把fs引入方式也改成import方式:

在这里插入图片描述

此时的报错信息为找不到rollup配置文件了。
在rollup.config.js配置文件中编写如下代码运行后报错如下:

在这里插入图片描述

按照错误提示把rollup.config.js文件后缀分别改为.cjs和.mjs,以及在execa()执行配置项中增加–bundleConfigAsCjs ,都无效;

在这里插入图片描述

在execa()执行配置项中增加–bundleConfigAsCjs 时报这个错:

在这里插入图片描述

最终解决方案如下:将依赖的引入方式都改为require形式,同时将配置文件后缀改为.cjs:

在这里插入图片描述

解决思路来源于rollup官网中的一句话。看来还是要多看官方文档。

在这里插入图片描述

rollup.config.js文件中的配置编写完成后,运行报错如下:

在这里插入图片描述

将export default 方式改为 module.exports 方式后此报错解决,出现如下报错:

在这里插入图片描述

参考 第11 步解决:

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1420815.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

vue3前端开发框架的安全特性,非常适合现在的市场需求

vue3前端开发框架的安全特性,非常适合现在的市场需求!现在几乎所有的前端开发,都是使用的vue3做了开发。下面给大家展示一下。为什么说vue3框架自带安全特性呢。 如图,这个是我们在浏览器内看见的,渲染后的数据页面信息。很齐全。…

超越人类上限的策划:百度输入法在候选词区域植入广告

一位 V2EX 用户最新发帖称,百度输入法的最新版本中引入了一个新功能,将广告直接植入到候选词区域。 具体表现为,当用户输入某些关键词时,候选词区域会显示与输入内容相关的广告链接。例如,用户输入“招商”时&#xf…

【C++】类与对象(二)特殊成员函数

前言 类与对象(二) 文章目录 一、特殊成员函数二、构造函数三、析构函数四、拷贝构造函数五、拷贝赋值运算符 一、特殊成员函数 如果在类的声明中未显式提供某个成员函数的定义,编译器会自动生成一个默认实现。 这包括默认构造函数、默认析构…

Flutter 开发3:创建第一个Flutter应用

Step 1: 安装Flutter 1.1 下载Flutter SDK 首先,你需要访问Flutter官方网站下载最新的Flutter SDK。选择适合你操作系统的安装包。 $ cd ~/development $ unzip ~/Downloads/flutter_macos_2.2.3-stable.zip1.2 更新环境变量 接下来,你需要将Flutter…

笔记本电脑系统Win10重装教程

当前很多用户都会使用笔记本电脑办公,如果笔记本电脑携带的操作系统不好用,就会影响到用户的办公效率,这时候可以给笔记本电脑重新安装一款好用的系统。以下小编带来笔记本电脑系统Win10重装教程,让用户们轻松给笔记本电脑重新安装…

张维迎《博弈与社会》纳什均衡与囚徒困境博弈(2)囚徒困境博弈

囚徒困境大家应该都比较熟悉了,我觉得这篇的意义大概在与,经济学术语的运用? 囚徒困境:个人理性与集体理性的矛盾 假定有两个犯罪嫌疑人共同作案。警察抓住他们以后,分开拘押,并告诉他们:可以选…

GWIT 和GWFI

关于燃烧的历史: -UL request needle flame (open fire) test to rate flammability per UL-94 Vxx UL 要求针焰(明火)试验以评定UL-94的易燃性。 - industry recognized that glowing wires ( caused by electrical overload) may put …

《幻兽帕鲁》游戏公司如何打造全球爆款 《幻兽帕鲁Palworld》怎么在Mac上玩?

玩法融合之外,《幻兽帕鲁》设计的成功和难点其实是把大部分系统及玩法结合得更紧密,做到多个系统之间互相强化。 “下班,该当帕鲁训练家了。”近日,记者从多个游戏群中看到,《幻兽帕鲁》正在取代其他游戏,成…

蓝桥杯-常用STL(一)

常用STL 🎈1.动态数组🎈2.vector的基础使用🔭2.1引入库🔭2.2构造一个动态数组🔭2.3插入元素🔭2.4获取长度并且访问元素🔭2.5修改元素🔭2.6删除元素🔭2.7清空 &#x1f38…

抽象类(Java)、模板方法设计模式

一、概念 在Java中有abstract关键字,就是抽象的意思,可用来修饰类和成员方法。 用abstract来修饰类,那这个类就是抽象类;修饰方法,那这个方法就是抽象方法。 修饰符 abstract class 类名{修饰符 abstract 返回值类型…

知识库是什么 产品经理必须知道的行业知识

现如今,我们生活在一个知识爆炸的时代。对于产品经理来说,信息不再是稀缺资源,如何高效地管理和利用这些信息,是他们面临的重要问题。这时,知识库便悄然成为产品经理必备的工具。所以,什么是知识库呢&#…

Python网络拓扑库之mininet使用详解

概要 网络工程师、研究人员和开发人员需要进行各种网络实验和测试,以评估网络应用和协议的性能,以及解决网络问题。Python Mininet是一个功能强大的工具,它允许用户创建、配置和仿真复杂的网络拓扑,以满足各种实际应用场景。本文…

2024美赛备战--六大题型常用模型简要分析

美国大学生数学建模竞赛(MCM)是全球知名的数学建模比赛之一,每年都吸引了来自世界各地的学生参加。在这场充满挑战的竞赛中,参赛者将面对多种题目,需要利用他们的数学建模技能来解决实际问题。下面,建模忠哥…

深入了解Yum:Linux系统的软件包管理利器

目录 软件包 软件包的来源 关于yum yum是什么 yum的相关操作 介绍rzsz rz(从Windows本地传到Linux服务器) sz(从Linux服务器传到Windows本地) 注意事项 查看软件包 安装软件 卸载软件 yum的本地配置 为什么要进行配置…

Redis学习——高级篇④

Redis学习——高级篇④ Redis7高级之Redis与Mysql数据双写一致性工程案例(四) 4.1 MySQL主从复制原理4.2 canal 工作原理4.3 mySQL->canal->redis 双写一致性1.环境2.配置Mysql3.配置canal4. Canal客户端(Java编写&#xff0…

03:华为云管理|云主机管理|云项目实战

华为云管理|云主机管理|云项目实战 安全组配置部署跳板机配置yum源,安装软件包优化系统服务安装配置ansible管理主机 模版镜像配置配置yum源,安装软件包优化系统 网站云平台部署实战华为云的负载均衡 安全组配置 设置安全组 云…

Whatsapp 相关(七) -网络请求

本篇主要用来完善上篇文章 frida 监测网络请求的. whatsapp相关(五)- frida监测网络请求 1: 脚本 本次的脚本与上次的区别是,之前只能输出请求的地址,本次优化后,可输出请求参数,结果等. 代码如下: Java.perform(function () {var HttpURLConnection Java.use(java.net.H…

PyTorch][chapter 12][李宏毅深度学习][Semi-supervised Linear Methods-1]

这里面介绍半监督学习里面一些常用的方案: K-means ,HAC, PCA 等 目录: K-means HAC PCA 一 K-means 【预置条件】 N 个样本分成k 个 簇 step1: 初始化簇中心点 (随机从X中抽取k个样本点作为) Repeat: For all in X: 根据其到 &…

MP4格式视频怎么提取gif?一招教你在线做

MP4是一种常见的数字多媒体容器格式,它是一种使用最广泛的视频文件格式之一。MP4文件可以包含音频、视频和字幕等多种媒体数据,并且可以通过各种播放器和设备进行播放和共享。它是一种压缩格式,可以在保持相对较小文件大小的同时提供较高的视…

数学建模学习笔记||灰色关联分析

灰色系统 信息绝对透明的是白色系统,信息绝对秘密的是黑色系统,灰色系统介于两者之间 关联分析 即系统的分析因素 包含多种因素的系统中,哪些因素是主要的,哪些因素是次要的,哪些因素影响大,哪些因素影响小…