使用monorepo發佈vue3組件庫

安裝pnpm

npm install pnpm -g

初始化package.json

pnpm init

新建配置文件 .npmrc

  • 在根目錄下新建.npmrc文件,並寫入如下內容
shamefully-hoist = true

::: tip 注意
如果某些工具僅在根目錄的node_modules時纔有效,可以將其設置爲true來提升那些不在根目錄的node_modules,就是將你安裝的依賴包的依賴包的依賴包的...都放到同一級別(扁平化)。說白了就是不設置爲true有些包就有可能會出問題。
:::

安裝依賴包:vue@next、typescript、sass

pnpm i vue@next typescript sass -D -w

::: tip 注意
我們開發環境中的依賴一般全部安裝在整個項目根目錄下,方便下面我們每個包都可以引用,所以在安裝的時候需要加個 -w ,-w 代表工作區(workspace)
:::

初始化tsconfig.json

  • 初始化
npx tsc --init
  • 配置tsconfig.json
//tsconfig.json
{
  "compilerOptions": {
    "baseUrl": ".",
    "jsx": "preserve",
    "strict": true,
    "target": "ES2015",
    "module": "ESNext",
    "skipLibCheck": true,
    "esModuleInterop": true,
    "moduleResolution": "Node",
    "lib": ["esnext", "dom"]
  }
}

monorepo實現

介紹

一個倉庫多個項目

新建pnpm-workspace.yaml

  • 根目錄下新建pnpm-workspace.yaml

  • 配置yaml

# pnpm-workspace.yaml
packages:
    - 'packages/**'
    - 'examples'

::: tip 注意
爲了我們各個項目之間能夠互相引用我們要新建一個pnpm-workspace.yaml文件將我們的包關聯起來
:::

搭建utils包

介紹

utils是公共庫包

創建utils目錄

  • 手動創建utils目錄

進入utils文件夾

cd utils

初始化package.json

pnpm init
  • 配置package.json
{
  "name": "@quick-vue3-ui/utils",//utils修改爲@quick-vue3-ui/utils
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC"
}

待完善

搭建components庫包

介紹

components是組件包

創建packages目錄

  • 手動創建packages目錄

創建components包

  • 手動在packages目錄下創建components文件夾

進入components文件夾

cd components

初始化package.json

pnpm init
  • 配置package.json
{
  "name": "@quick-vue3-ui/components",//components修改爲@quick-vue3-ui/components
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC"
}

開發一個button組件 (正式進入核心區)

  • 在components目錄下新建src目錄

  • 在src目錄下新建button目錄

  • button目錄下新建button.vue文件

<!-- button/button.vue 此處使用的是vue3.0方式,爲了是增加組件名稱方便。3.2需要特殊處理纔可以增加組件名稱 -->
<script lang="ts">
import { defineComponent } from 'vue'
export default defineComponent({
name:'QuickButton'
})
</script>
<template>
<button>我是按鈕</button>
</template>
  • button目錄下新建index.ts文件,(局部導出)
// button/index.ts
import Button from './button.vue'

export default Button

導出所有組件,供局部導入使用(局部導出)

// components/src/index.ts
import Button from "./button";

export { Button as QuickButton };

導出增加版本及相關信息(全局導出)

  • components目錄下新建index.ts
// components/index.ts
import pack from '../../package.json'
import * as components from './src/index'
export * from './src/index'

const install =(app: any) => {
    for (const comkey in components) {
        app.component((components as any)[comkey].name, (components as any)[comkey])
    }
}
export default {
    name: pack.name,
    version: pack.version,
    install,
  }
暫時告一段落,如下測試
----------------------------------------
## 搭建examples包

### 介紹

examples基於vite+vue3,目的用於調試組件

### 創建examples包

- 手動創建examples文件夾

### 進入examples文件夾

```sh
cd examples

初始化package.json

pnpm init

安裝vite、@vitejs/plugin-vue

pnpm install vite @vitejs/plugin-vue -D -w

配置vite.config.ts

//vite.config.ts
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'

export default defineConfig({
    plugins:[vue()]
})

創建入口html文件

  • 手動創建index.html
<!-- index.html -->
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>examples</title>
</head>
<body>
    <div id="app"></div>
    <script src="src/main.ts" type="module"></script>
</body>
</html>

創建src目錄

創建根組件

  • 手動創建app.vue文件

  • 配置app.vue

<!-- src/app.vue -->
<template>
    <div>
        測試
    </div>
</template>

創建入口ts

  • 手動創建main.ts文件

  • 配置main.ts

//src/main.ts
import {createApp} from 'vue'
import App from './app.vue'

const app = createApp(App)

app.mount('#app')

配置啓動命令

// package.json
...
"scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
     "dev": "vite"//新增
  },
  ...

運行

pnpm run dev

::: tip 注意
如上沒有問題才能按照下面的進行
包之間本地調試(全局安裝)由於組件庫是基於ts的,所以需要安裝esno來執行ts文件便於測試包之間的引入情況

npm i esno -g
# 哪裏用就切換到那個包下執行,例如:examples要用那麼就 cd examples 然後執行安裝依賴命令即可
pnpm install @quick-vue3-ui/utils 
pnpm install @quick-vue3-ui/components 

:::

安裝組件庫的依賴

pnpm i @quick-vue3-ui/components

全局導入

  • main.ts中導入
//examples/src/main.ts
import {createApp} from 'vue'
import quickVue3UI from '@quick-vue3-ui/components' //++
import App from './app.vue'

const app = createApp(App)
app.use(quickVue3UI) //++
app.mount('#app')

局部導入

  • app.vue中導入
//examples/src/app.vue
<script lang="ts" setup>
import {QuickButton} from '@quick-vue3-ui/components'
</script>
<template>
    <div>
        <quick-button></quick-button>
    </div>
</template>

發佈到npm

打包組件庫

::: tip 注意
vite提供了庫模式,下面我們來配置。
:::

打包配置

::: tip 注意
這裏我們選擇打包cjs(CommonJS)和esm(ESModule)兩種形式,cjs模式主要用於服務端引用(ssr),而esm就是我們現在經常使用的方式,它本身自帶treeShaking而不需要額外配置按需引入(前提是你將模塊分別導出)。
:::

  • 在components包下新建vite.config.ts文件

  • 配置vite.config.ts

//components/vite.config.ts
import { defineConfig } from "vite";
import vue from "@vitejs/plugin-vue"
export default defineConfig(
    {
        build: {
            target: 'modules',
            //打包文件目錄
            outDir: "es",
            //壓縮
            minify: false,
            //css分離
            //cssCodeSplit: true,
            rollupOptions: {
                //忽略打包vue文件
                external: ['vue'],
                input: ['src/index.ts'],
                output: [
                    {
                        format: 'es',
                        //不用打包成.es.js,這裏我們想把它打包成.js
                        entryFileNames: '[name].js',
                        //讓打包目錄和我們目錄對應
                        preserveModules: true,
                        //配置打包根目錄
                        dir: 'es',
                        preserveModulesRoot: 'src'
                    },
                    {
                        format: 'cjs',
                        entryFileNames: '[name].js',
                        //讓打包目錄和我們目錄對應
                        preserveModules: true,
                        //配置打包根目錄
                        dir: 'lib',
                        preserveModulesRoot: 'src'
                    }
                ]
            },
            lib: {
                entry: './index.ts',
                formats: ['es', 'cjs']
            }
        },
        plugins: [
            vue()
        ]
    }
)

打包

  • 配置package.json
 ...
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "build":"vite build"//++
  },
 ...
  • 打包命令
pnpm run build
  • 打包後

::: tip 注意
其實到這裏就已經可以直接打包了;components下執行: pnpm run build你就會發現打包了es和lib兩個目錄。
到這裏其實打包的組件庫只能給js項目使用,在ts項目下運行會出現一些錯誤,而且使用的時候還會失去代碼提示功能,這樣的話我們就失去了用ts開發組件庫的意義了。所以我們需要在打包的庫里加入聲明文件(.d.ts)。
:::

  • 配置d.ts

那麼如何向打包後的庫里加入聲明文件呢? 其實很簡單,只需要引入vite-plugin-dts

pnpm i vite-plugin-dts -D -w
  • 再次配置vite.config.ts
//components/vite.cofig.ts

import { defineConfig } from "vite";
import vue from "@vitejs/plugin-vue"
import dts from 'vite-plugin-dts'

export default defineConfig(
    {
        build: {...},
        plugins: [
            vue(),
            dts({
                //指定使用的tsconfig.json爲我們整個項目根目錄下掉,如果不配置,你也可以在components下新建tsconfig.json
                tsConfigFilePath: '../../tsconfig.json'
            }),
            //因爲這個插件默認打包到es下,我們想讓lib目錄下也生成聲明文件需要再配置一個
            dts({
                outputDir:'lib',
                tsConfigFilePath: '../../tsconfig.json'
            })

        ]
    }
)

::: tip 注意
因爲這個插件默認打包到es下,我們想讓lib目錄下也生成聲明文件需要再配置一個dts插件,暫時沒有想到其它更好的處理方法.
然後執行打包命令你就會發現你的es和lib下就有了聲明文件
:::

發佈組件庫

::: tip 注意
其實後面就可以進行發佈了,發佈之前更改一下我們components下的package.json如下:
:::

{
  "name": "quick-vue3-ui",
  "version": "1.0.1",
  "private": false,//這個很關鍵,如果爲true,不能發佈
  "description": "quick-vue3--ui組件庫",
  "main": "lib/index.js",
  "module":"es/index.js",
  "typings": "lib/index.d.ts",
  "files": [
    "es",
    "lib"
  ],
  "scripts": {
    "build":"vite build"
  },
  "keywords": [
    "quick-vue3-ui",
    "quick-vue3--ui組件庫"
  ],
  "author": "zhanglp",
  "license": "MIT"
}
  • 如果是第一次

::: tip 注意

  1. 去npm官網註冊、登錄及相關信息修改

  2. 使用pnpm登錄、發佈

  3. 發佈使用鏡像必須是npm(如果是淘寶鏡像恢復回npm)

  4. 發佈前修改package.json版本並執行build命令。
    :::

  5. 註冊

https://www.npmjs.com/

  1. 登錄
pnpm login 

Username: 迷的賬號
Password:  你的密碼
Email: (this IS public) 你的郵箱   

Enter one-time password: 郵箱驗證碼
  1. 發佈
  • 非第一次
pnpm publish 即可

常見錯誤

  • 錯誤:
    ::: tip 注意
     ERROR  --workspace-root may only be used inside a workspace
    :::

  • 解決方案:

比如:去掉 後面的 -w
pnpm i vue@next typescript sass -D -w

暫時忽略,找解決方案中。。。

  • 錯誤

::: tip 注意
找不到模塊“./app.vue”或其相應的類型聲明。ts
:::

  • 解決方案:
//src/env.d.ts
declare module '*.vue' {
    import type { DefineComponent } from 'vue'
    const component: DefineComponent<{}, {}, any>
    export default component
  }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章