欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Vue3中使用pnpm搭建monorepo開發(fā)環(huán)境

 更新時(shí)間:2022年11月07日 14:57:13   作者:昆吾kw  
這篇文章主要為大家介紹了Vue3中使用pnpm搭建monorepo開發(fā)環(huán)境示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪

前言

Vue3 源碼閱讀系列,計(jì)劃從環(huán)境搭建開始,將 Vue3 的響應(yīng)式模塊,運(yùn)行時(shí)模塊和編譯器模塊,以及狀態(tài)庫 Pinia、路由庫 Vue-Router的核心原理做一個(gè)梳理。這大概是一個(gè)漫長的過程。祝自己不要爛尾,祝大家有所收獲。

Pnpm 和 Monorepo

Pnpm 是新一代的 nodejs 包管理工具。第一個(gè) “P”意為 Performance,代表著更佳的性能。

它的主要優(yōu)點(diǎn)有兩個(gè),一是采用了 hard-link 機(jī)制,避免了包的重復(fù)安裝,節(jié)省了空間,同時(shí)能提高項(xiàng)目依賴的安裝速度。二是對monorepo 的支持非常友好,只需要一條配置就能實(shí)現(xiàn)。

Monorepo 是一種新的倉庫管理方式。過去的項(xiàng)目,大多采用一個(gè)倉庫維護(hù)一個(gè)項(xiàng)目的方案。對于一個(gè)龐大復(fù)雜的項(xiàng)目,哪怕只進(jìn)行一處小小的修改,影響的也是整體。而采用 monorepo 的形式,我們可以在一個(gè)倉庫中管理多個(gè)包。每個(gè)包都可以單獨(dú)發(fā)布和使用,就好像是一個(gè)倉庫中又有若干個(gè)小倉庫。

Vue3 源碼采用 monorepo 方式進(jìn)行管理,將眾多模塊拆分到 packages 目錄中。

這帶來的最直觀的好處,就是方便管理和維護(hù)。而且,它不像 Vue2 那樣將源碼整體打包對外暴露。Vue3的這種組織形式,方便的實(shí)現(xiàn)了 Tree-shaking,需要哪個(gè)功能就引入對應(yīng)的模塊,能大大減少打包后項(xiàng)目的體積。

搭建開發(fā)環(huán)境

創(chuàng)建項(xiàng)目

首先全局安裝 pnpm

npm install -g pnpm

新建一個(gè)目錄并進(jìn)行初始化:

mkdir vue3-learn
cd vue3-learn
pnpm init
mkdir packages

配置 monorepo

在項(xiàng)目根目錄下新建 pnpm-workspace.yaml 文件:

packages:
  - 'packages/*'

意思是,將 packages 目錄下所有的目錄都作為單獨(dú)的包進(jìn)行管理。

通過這樣一個(gè)簡單的配置,Monorepo 開發(fā)環(huán)境搭建好了。

如果大家之前接觸過 lerna + yarn workspace的方案,就會深有體會,使用 pnpm 的確方便。Vue3,Element Plus以前采用的方案就是前者,現(xiàn)在都已經(jīng)改用后者了。

安裝依賴

如果你使用過 Vite,就一定體驗(yàn)過它的快。因?yàn)?Vite 內(nèi)置了 esbuild 作為開發(fā)階段的構(gòu)建工具。esbuild 的特點(diǎn)就是快。

Vue3 采用了和 vite 一致的選擇,開發(fā)階段使用 esbuild 作為構(gòu)建工具,在生產(chǎn)階段采用 rollup 進(jìn)行打包。

我們先安裝一些依賴:

# 源碼采用 typescript 編寫
pnpm add  -D -w typescript
# 構(gòu)建工具,命令行參數(shù)解析工具
pnpm add -D -w esbuild rollup rollup-plugin-typescript2 @rollup/plugin-json @rollup/plugin-node-resolve @rollup/plugin-commonjs minimist execa 

說明:

-D:作為開發(fā)依賴安裝

-wmonorepo 環(huán)境默認(rèn)會認(rèn)為應(yīng)該將依賴安裝到具體的 package中。使用 -w 參數(shù),告訴 pnpm 將依賴安裝到 workspace-root,也就是項(xiàng)目的根目錄。

依賴說明:

依賴描述
typescript項(xiàng)目使用 typescript 進(jìn)行開發(fā)
esbuild開發(fā)階段的構(gòu)建工具
rollup生產(chǎn)階段的構(gòu)建工具
rollup-plugin-typescript2rollup 編譯 ts 的插件
@rollup/plugin-jsonrollup 默認(rèn)采用 esm 方式解析模塊,該插件將 json 解析為 esm 供 rollup 處理
@rollup/plugin-node-resolverollup 默認(rèn)采用 esm 方式解析模塊,該插件可以解析安裝在 node_modules 下的第三方模塊
@rollup/plugin-commonjs將 commonjs 模塊 轉(zhuǎn)化為 esm 模塊
minimist解析命令行參數(shù)
execa生產(chǎn)階段開啟子進(jìn)程

初始化Typescript

pnpm tsc --init

pnpm 的使用基本和 npm 一致。這里的用法就相當(dāng)于 npm 中的 npx

npx tsc --init

意思是,去 node_modules 下的 .bin 目錄中找到tsc 命令,并執(zhí)行它。

執(zhí)行完該命令,會在項(xiàng)目根目錄生成一個(gè) tsconfig.json 文件,進(jìn)行一些配置:

{
  "compilerOptions": {
    "outDir": "dist", // 輸出的目錄
    "sourceMap": true, // 開啟 sourcemap
    "target": "es2016", // 轉(zhuǎn)譯的目標(biāo)語法
    "module": "esnext", // 模塊格式
    "moduleResolution": "node", // 模塊解析方式
    "strict": false, // 關(guān)閉嚴(yán)格模式,就能使用 any 了
    "resolveJsonModule": true, // 解析 json 模塊
    "esModuleInterop": true, // 允許通過 es6 語法引入 commonjs 模塊
    "jsx": "preserve", // jsx 不轉(zhuǎn)義
    "lib": ["esnext", "dom"], // 支持的類庫 esnext及dom
    "baseUrl": ".",  // 當(dāng)前目錄,即項(xiàng)目根目錄作為基礎(chǔ)目錄
    "paths": { // 路徑別名配置
      "@my-vue/*": ["packages/*/src"]  // 當(dāng)引入 @my-vue/時(shí),去 packages/*/src中找
    },
  }
}

準(zhǔn)備兩個(gè)模塊

我們先在 packages 目錄下新建兩個(gè)模塊,分別是 reactivity 響應(yīng)式模塊 和 shared 工具庫模塊。然后編寫構(gòu)建腳本進(jìn)行第一次的開發(fā)調(diào)試。

shared

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

pnpm init

然后修改 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 字段的值,我們使用了一個(gè) @scope 作用域,它相當(dāng)于 npm 包的命名空間,可以使項(xiàng)目結(jié)構(gòu)更加清晰,也能減少包的重名。

編寫該模塊的入口文件:

// src/index.ts
/**
 * 判斷對象
 */
export const isObject = (value) =>{
    return typeof value === 'object' && value !== null
}
/**
 * 判斷函數(shù)
 */
export const isFunction= (value) =>{
    return typeof value === 'function'
}
/**
 * 判斷字符串
 */
export const isString = (value) => {
    return typeof value === 'string'
}
/**
 * 判斷數(shù)字
 */
export const isNumber =(value)=>{
    return typeof value === 'number'
}
/**
 * 判斷數(shù)組
 */
export const isArray = Array.isArray

reactivity

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

pnpm init

然后修改 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 格式使用響應(yīng)式模塊時(shí),需要給模塊指定一個(gè)全局變量名字,通過 buildOptions.name 進(jìn)行指定,將來打包時(shí)會作為配置使用。

main 指定的文件支持 commonjs 規(guī)范進(jìn)行導(dǎo)入,也就是說在nodejs 環(huán)境中,通過 require 方法導(dǎo)入該模塊時(shí),會導(dǎo)入 main 指定的文件。

同理,module 指定的是使用 ES Module 規(guī)范導(dǎo)入模塊時(shí)的入口文件。

編寫該模塊的入口文件:

// src/index.ts
import { isObject } from '@my-vue/shared'
const obj = {name: 'Vue3'}
console.log(isObject(obj))

reactivity 包中用到了另一個(gè)包 shared ,需要安裝才能使用:

pnpm add @my-vue/shared@workspace --filter @my-vue/reactivity

意思是,將本地 workspace 內(nèi)的 @my-vue/shared 包,安裝到 @my-vue/reactivity包中去。

此時(shí),查看 reactivity 包的依賴信息:

"dependencies": {
   "@my-vue/shared": "workspace:^1.0.0"
}

編寫構(gòu)建腳本

在根目錄下新建 scripts 目錄,存放項(xiàng)目構(gòu)建的腳本。

新建 dev.js,作為開發(fā)階段的構(gòu)建腳本。

// scripts/dev.js
// 使用 minimist 解析命令行參數(shù)
const args = require('minimist')(process.argv.slice(2))
const path = require('path')
// 使用 esbuild 作為構(gòu)建工具
const { build } = require('esbuild')
// 需要打包的模塊。默認(rèn)打包 reactivity 模塊
const target = args._[0] || 'reactivity'
// 打包的格式。默認(rèn)為 global,即打包成 IIFE 格式,在瀏覽器中使用
const format = args.f || 'global'
// 打包的入口文件。每個(gè)模塊的 src/index.ts 作為該模塊的入口文件
const entry = path.resolve(__dirname, `../packages/${target}/src/index.ts`)
// 打包文件的輸出格式
const outputFormat = format.startsWith('global') ? 'iife' : format === 'cjs' ? 'cjs' : 'esm'
// 文件輸出路徑。輸出到模塊目錄下的 dist 目錄下,并以各自的模塊規(guī)范為后綴名作為區(qū)分
const outfile = path.resolve(__dirname, `../packages/${target}/dist/${target}.${format}.js`)
// 讀取模塊的 package.json,它包含了一些打包時(shí)需要用到的配置信息
const pkg = require(path.resolve(__dirname, `../packages/${target}/package.json`))
// buildOptions.name 是模塊打包為 IIFE 格式時(shí)的全局變量名字
const pgkGlobalName = pkg?.buildOptions?.name
console.log('模塊信息:\n', entry, '\n', format, '\n', outputFormat, '\n', outfile)
// 使用 esbuild 打包
build({
  // 打包入口文件,是一個(gè)數(shù)組或者對象
  entryPoints: [entry], 
  // 輸入文件路徑
  outfile, 
  // 將依賴的文件遞歸的打包到一個(gè)文件中,默認(rèn)不會進(jìn)行打包
  bundle: true, 
  // 開啟 sourceMap
  sourcemap: true,
  // 打包文件的輸出格式,值有三種:iife、cjs 和 esm
  format: outputFormat, 
  // 如果輸出格式為 IIFE,需要為其指定一個(gè)全局變量名字
  globalName: pgkGlobalName, 
  // 默認(rèn)情況下,esbuild 構(gòu)建會生成用于瀏覽器的代碼。如果打包的文件是在 node 環(huán)境運(yùn)行,需要將平臺設(shè)置為node
  platform: format === 'cjs' ? 'node' : 'browser',
  // 監(jiān)聽文件變化,進(jìn)行重新構(gòu)建
  watch: {
   onRebuild (error, result) {
       if (error) {
           console.error('build 失?。?, error)
       } else {
           console.log('build 成功:', result) 
       }
    }
  }
}).then(() => {
  console.log('watching ...')
})

使用該腳本,會使用 esbuildpackages 下的包進(jìn)行構(gòu)建,打包的結(jié)果放到各個(gè)包的 dist 目錄下。

在開發(fā)階段,我們默認(rèn)打包成 IIFE 格式,方便在瀏覽器中使用 html 文件進(jìn)行測試。在生產(chǎn)階段,會分別打包成 CommonJS,ES ModuleIIFE 的格式。

完成第一次調(diào)試

給項(xiàng)目增加一條 scripts 命令:

// package.json
"scripts": {
    "dev": "node scripts/dev.js reactivity -f global"
}

意思是,以 IIFE 的格式,打包 reactivity 模塊,打包后的文件可以運(yùn)行在瀏覽器中。

在終端中執(zhí)行:

pnpm dev

輸出:

PS D:\vue3-learn> pnpm dev
> vue3-learn@1.0.0 dev D:\vue3-learn
> node scripts/dev.js reactivity -f global
模塊信息:
 D:\vue3-learn\packages\reactivity\src\index.ts
 global
 iife
 D:\demo3\vue3-learn\packages\reactivity\dist\reactivity.global.js
watching ...

編寫一個(gè) html 文件進(jìn)行測試:

// packages/reactivity/test/index.html
<body>
    <div id="app"></div>
    <script src="../dist/reactivity.global.js"></script>
</body>

打開瀏覽器控制臺:

小結(jié)

到此,一個(gè)基本的 monorepo 開發(fā)環(huán)境就搭建完畢了。

代碼已上傳至 Github ,點(diǎn)擊訪問

更多關(guān)于Vue3 pnpm搭建monorepo的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • vue項(xiàng)目中如何使用video.js實(shí)現(xiàn)視頻播放與視頻進(jìn)度條打點(diǎn)

    vue項(xiàng)目中如何使用video.js實(shí)現(xiàn)視頻播放與視頻進(jìn)度條打點(diǎn)

    這篇文章主要給大家介紹了關(guān)于vue項(xiàng)目中如何使用video.js實(shí)現(xiàn)視頻播放與視頻進(jìn)度條打點(diǎn)的相關(guān)資料,video.js是一款基于HTML5的網(wǎng)絡(luò)視頻播放器,文中通過代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2023-12-12
  • Vuepress 搭建帶評論功能的靜態(tài)博客的實(shí)現(xiàn)

    Vuepress 搭建帶評論功能的靜態(tài)博客的實(shí)現(xiàn)

    這篇文章主要介紹了Vuepress 搭建帶評論功能的靜態(tài)博客的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-02-02
  • Vue 創(chuàng)建組件的兩種方法小結(jié)(必看)

    Vue 創(chuàng)建組件的兩種方法小結(jié)(必看)

    Vue 創(chuàng)建組件的方法有哪些呢?下面小編就為大家分享一篇Vue 創(chuàng)建組件的兩種方法小結(jié),具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2018-02-02
  • vue頁面加載時(shí)的進(jìn)度條功能(實(shí)例代碼)

    vue頁面加載時(shí)的進(jìn)度條功能(實(shí)例代碼)

    這篇文章主要介紹了vue頁面加載時(shí)的進(jìn)度條功能,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-01-01
  • requirejs + vue 項(xiàng)目搭建詳解

    requirejs + vue 項(xiàng)目搭建詳解

    這篇文章主要介紹了requirejs + vue 項(xiàng)目搭建詳解,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-06-06
  • vue中對token有效期的深入理解

    vue中對token有效期的深入理解

    本文主要介紹了vue中對token有效期的深入理解,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-07-07
  • element的el-upload組件上傳文件跨域問題的幾種解決

    element的el-upload組件上傳文件跨域問題的幾種解決

    跨域問題網(wǎng)上搜索很多,感覺情況都不一樣,本文主要介紹了element的el-upload組件上傳文件跨域問題的幾種解決,具有一定的參考價(jià)值,感興趣的可以了解一下
    2024-03-03
  • vuecli3打包后出現(xiàn)跨域問題,前端配置攔截器無效的解決

    vuecli3打包后出現(xiàn)跨域問題,前端配置攔截器無效的解決

    這篇文章主要介紹了vuecli3打包后出現(xiàn)跨域問題,前端配置攔截器無效的解決,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-06-06
  • vue3 emit is not a function問題及解決

    vue3 emit is not a function問題及解決

    這篇文章主要介紹了vue3 emit is not a function問題及解決方案,具有很好的參考價(jià)值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-09-09
  • Vue中Vue.extend()的使用及解析

    Vue中Vue.extend()的使用及解析

    這篇文章主要介紹了Vue中Vue.extend()的使用及解析,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-10-10

最新評論