Vue3中使用pnpm搭建monorepo开发环境_第1页
Vue3中使用pnpm搭建monorepo开发环境_第2页
Vue3中使用pnpm搭建monorepo开发环境_第3页
Vue3中使用pnpm搭建monorepo开发环境_第4页
Vue3中使用pnpm搭建monorepo开发环境_第5页
已阅读5页,还剩7页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

第Vue3中使用pnpm搭建monorepo开发环境目录前言Pnpm和Monorepo搭建开发环境创建项目配置monorepo安装依赖初始化Typescript准备两个模块sharedreactivity编写构建脚本完成第一次调试小结

前言

Vue3源码阅读系列,计划从环境搭建开始,将Vue3的响应式模块,运行时模块和编译器模块,以及状态库Pinia、路由库Vue-Router的核心原理做一个梳理。这大概是一个漫长的过程。祝自己不要烂尾,祝大家有所收获。

Pnpm和Monorepo

Pnpm是新一代的nodejs包管理工具。第一个P意为Performance,代表着更佳的性能。

它的主要优点有两个,一是采用了hard-link机制,避免了包的重复安装,节省了空间,同时能提高项目依赖的安装速度。二是对monorepo的支持非常友好,只需要一条配置就能实现。

Monorepo是一种新的仓库管理方式。过去的项目,大多采用一个仓库维护一个项目的方案。对于一个庞大复杂的项目,哪怕只进行一处小小的修改,影响的也是整体。而采用monorepo的形式,我们可以在一个仓库中管理多个包。每个包都可以单独发布和使用,就好像是一个仓库中又有若干个小仓库。

Vue3源码采用monorepo方式进行管理,将众多模块拆分到packages目录中。

这带来的最直观的好处,就是方便管理和维护。而且,它不像Vue2那样将源码整体打包对外暴露。Vue3的这种组织形式,方便的实现了Tree-shaking,需要哪个功能就引入对应的模块,能大大减少打包后项目的体积。

搭建开发环境

创建项目

首先全局安装pnpm:

npminstall-gpnpm

新建一个目录并进行初始化:

mkdirvue3-learn

cdvue3-learn

pnpminit

mkdirpackages

配置monorepo

在项目根目录下新建pnpm-workspace.yaml文件:

packages:

-'packages/*'

意思是,将packages目录下所有的目录都作为单独的包进行管理。

通过这样一个简单的配置,Monorepo开发环境搭建好了。

如果大家之前接触过lerna+yarnworkspace的方案,就会深有体会,使用pnpm的确方便。Vue3,ElementPlus以前采用的方案就是前者,现在都已经改用后者了。

安装依赖

如果你使用过Vite,就一定体验过它的快。因为Vite内置了esbuild作为开发阶段的构建工具。esbuild的特点就是快。

Vue3采用了和vite一致的选择,开发阶段使用esbuild作为构建工具,在生产阶段采用rollup进行打包。

我们先安装一些依赖:

#源码采用typescript编写

pnpmadd-D-wtypescript

#构建工具,命令行参数解析工具

pnpmadd-D-wesbuildrolluprollup-plugin-typescript2@rollup/plugin-json@rollup/plugin-node-resolve@rollup/plugin-commonjsminimistexeca

说明:

-D:作为开发依赖安装

-w:monorepo环境默认会认为应该将依赖安装到具体的package中。使用-w参数,告诉pnpm将依赖安装到workspace-root,也就是项目的根目录。

依赖说明:

依赖描述typescript项目使用typescript进行开发esbuild开发阶段的构建工具rollup生产阶段的构建工具rollup-plugin-typescript2rollup编译ts的插件@rollup/plugin-jsonrollup默认采用esm方式解析模块,该插件将json解析为esm供rollup处理@rollup/plugin-node-resolverollup默认采用esm方式解析模块,该插件可以解析安装在node_modules下的第三方模块@rollup/plugin-commonjs将commonjs模块转化为esm模块minimist解析命令行参数execa生产阶段开启子进程

初始化Typescript

pnpmtsc--init

pnpm的使用基本和npm一致。这里的用法就相当于npm中的npx:

npxtsc--init

意思是,去node_modules下的.bin目录中找到tsc命令,并执行它。

执行完该命令,会在项目根目录生成一个tsconfig.json文件,进行一些配置:

{

"compilerOptions":{

"outDir":"dist",//输出的目录

"sourceMap":true,//开启sourcemap

"target":"es2016",//转译的目标语法

"module":"esnext",//模块格式

"moduleResolution":"node",//模块解析方式

"strict":false,//关闭严格模式,就能使用any了

"resolveJsonModule":true,//解析json模块

"esModuleInterop":true,//允许通过es6语法引入commonjs模块

"jsx":"preserve",//jsx不转义

"lib":["esnext","dom"],//支持的类库esnext及dom

"baseUrl":".",//当前目录,即项目根目录作为基础目录

"paths":{//路径别名配置

"@my-vue/*":["packages/*/src"]//当引入@my-vue/时,去packages/*/src中找

准备两个模块

我们先在packages目录下新建两个模块,分别是reactivity响应式模块和shared工具库模块。然后编写构建脚本进行第一次的开发调试。

shared

在packages下新建shared目录,并初始化:

pnpminit

然后修改package.json:

{

"name":"@my-vue/shared",

"version":"1.0.0",

"description":"@my-vue/shared",

"main":"dist/shared.cjs.js",

"module":"dist/shared.esm-bundler.js"

注意name字段的值,我们使用了一个@scope作用域,它相当于npm包的命名空间,可以使项目结构更加清晰,也能减少包的重名。

编写该模块的入口文件:

//src/index.ts

*判断对象

exportconstisObject=(value)={

returntypeofvalue==='object'value!==null

*判断函数

exportconstisFunction=(value)={

returntypeofvalue==='function'

*判断字符串

exportconstisString=(value)={

returntypeofvalue==='string'

*判断数字

exportconstisNumber=(value)={

returntypeofvalue==='number'

*判断数组

exportconstisArray=Array.isArray

reactivity

在packages下新建reactivity目录,并初始化:

pnpminit

然后修改package.json:

{

"name":"@my-vue/reactivity",

"version":"1.0.0",

"description":"@my-vue/reactivity",

"main":"dist/reactivity.cjs.js",

"module":"dist/reactivity.esm-bundler.js",

"buildOptions":{

"name":"VueReactivity"

在浏览器中以IIFE格式使用响应式模块时,需要给模块指定一个全局变量名字,通过buildO进行指定,将来打包时会作为配置使用。

main指定的文件支持commonjs规范进行导入,也就是说在nodejs环境中,通过require方法导入该模块时,会导入main指定的文件。

同理,module指定的是使用ESModule规范导入模块时的入口文件。

编写该模块的入口文件:

//src/index.ts

import{isObject}from'@my-vue/shared'

constobj={name:'Vue3'}

console.log(isObject(obj))

在reactivity包中用到了另一个包shared,需要安装才能使用:

pnpmadd@my-vue/shared@workspace--filter@my-vue/reactivity

意思是,将本地workspace内的@my-vue/shared包,安装到@my-vue/reactivity包中去。

此时,查看reactivity包的依赖信息:

"dependencies":{

"@my-vue/shared":"workspace:^1.0.0"

编写构建脚本

在根目录下新建scripts目录,存放项目构建的脚本。

新建dev.js,作为开发阶段的构建脚本。

//scripts/dev.js

//使用minimist解析命令行参数

constargs=require('minimist')(process.argv.slice(2))

constpath=require('path')

//使用esbuild作为构建工具

const{build}=require('esbuild')

//需要打包的模块。默认打包reactivity模块

consttarget=args._[0]||'reactivity'

//打包的格式。默认为global,即打包成IIFE格式,在浏览器中使用

constformat=args.f||'global'

//打包的入口文件。每个模块的src/index.ts作为该模块的入口文件

constentry=path.resolve(__dirname,`../packages/${target}/src/index.ts`)

//打包文件的输出格式

constoutputFormat=format.startsWith('global')'iife':format==='cjs''cjs':'esm'

//文件输出路径。输出到模块目录下的dist目录下,并以各自的模块规范为后缀名作为区分

constoutfile=path.resolve(__dirname,`../packages/${target}/dist/${target}.${format}.js`)

//读取模块的package.json,它包含了一些打包时需要用到的配置信息

constpkg=require(path.resolve(__dirname,`../packages/${target}/package.json`))

//buildO是模块打包为IIFE格式时的全局变量名字

constpgkGlobalName=pkg.buildO

console.log('模块信息:\n',entry,'\n',format,'\n',outputFormat,'\n',outfile)

//使用esbuild打包

build({

//打包入口文件,是一个数组或者对象

entryPoints:[entry],

//输入文件路径

outfile,

//将依赖的文件递归的打包到一个文件中,默认不会进行打包

bundle:true,

//开启sourceMap

sourcemap:true,

//打包文件的输出格式,值有三种:iife、cjs和esm

format:outputFormat,

//如果输出格式为IIFE,需要为其指定一个全局变量名字

globalName:pgkGlobalName,

//默认情况下,esbuild构建会生成用于浏览器的代码。如果打包的文件是在node环境运行,需要将平台设置为node

platform:format==='cjs''node':'browser',

//监听文件变化,进行重新构建

watch:{

onRebuild(error,result){

if(error){

console.error('build失败:',error)

}else{

console.log('build成功:',result)

}).then(()={

console.log('watching...')

使用该脚本,会使用esbuild对packages下的包进行构建,打包的结果放到各个包的dist目录下。

在开发阶段,我们默认打包成IIFE格式,方便在浏览器中使用html文件进行测试。在生产阶段,会分别打包成CommonJS,ESModule和IIFE的格式。

完成第一次调试

给项目增加一条scripts命令:

//package.json

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论