打包 Vue3 Component Package

tags: Vue Vite
category: Front-End
description: 打包 Vue3 Component Package
created_at: 2023/02/05 22:00:00

cover image


前言的題外話

好久沒寫文章,前陣子吃壞肚子+確診,現在整體比較好了(但還是常常好累)。但一個寒假也就要過了QQ


前言

在寫前端常常有些元件是在各個系統都用的到的 Component,又或者是某些子功能不想重複做又找不到現成的套件直接用,如果從自己舊的 code 貼過去又感覺很蠢(?),所以就想說包成套件了。


預備知識(寫完之後發現好像沒有也沒差)

  • 寫過 Vue3 (廢話)
  • 用過 Vite

本次目標

  • 簡單寫一個 Component
  • Local 測試
  • 發布到 NPM 上,載回 Local 做測試

至於是什麼 Component 呢? 既然是範例當然是萬年 Counter


建立 Vue3 專案

$ npm init vue@latest

之後切進你的專案後用你熟悉的套件管理器去安裝套件。

※提示: 這邊就卡住的話可以參考 Vue3系列文章


整理專案目錄

先留下 App.vue 然後把內容換成

<script setup></script>

<template>Hello World</template>

然後 assets 當中的 CSS 也可以先刪掉,免得後面礙事

※提醒: 如果你是把 assets 整個資料夾刪掉,要記得調整 main.js 的內容

import { createApp } from "vue";
import App from "./App.vue";

// import "./assets/main.css"; <-- 刪掉這行

createApp(App).mount("#app");

之後跑起測試伺服器看看有沒有問題,沒問題應該會看到畫面上有個 Hello World


開始寫 Counter

建立檔案: ./src/components/TheCounter.vue

<script setup></script>

<template>TheCounter</template>

養成好習慣,先在 App.vue 使用他,看看正不正常

<script setup>
import TheCounter from "./components/TheCounter.vue";
</script>

<template>
  <h1>App</h1>
  <TheCounter />
</template>

沒問題的話就可以開始完成 Counter 的功能了。


簡單的需求

  • 一個按鈕,點下去會+1

就這麼單純,畢竟主要練習的不是這個。

<script setup>
import { ref } from "vue";

const count = ref(0);

const increment = () => {
  count.value++;
};
</script>
<template>
  <button @click="increment">Count is {{ count }}.</button>
</template>

<style scoped>
button {
  background-color: #eee;
  font-size: 2rem;
  padding: 1rem;
  border: 1px solid #ccc;
  border-radius: 0.5rem;
  cursor: pointer;
}
</style>

打包

再來進入打包的環節,可以根據 Vite官方文件

修改 vite.config.js

import { fileURLToPath, URL } from "node:url";

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

import { resolve } from "path";

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [vue()],
  resolve: {
    alias: {
      "@": fileURLToPath(new URL("./src", import.meta.url)),
    },
  },
  build: {
    lib: {
      entry: resolve(__dirname, "src/index.js"),
      name: "SimpleCounter",
      fileName: "simple-counter",
    },
    rollupOptions: {
      external: ["vue"],
      output: {
        globals: {
          vue: "Vue",
        },
      },
    },
  },
});

如果在開專案的時候有裝 ESLint,顯示 resolve 有問題的話,可以修改 .eslintrc.cjs

/* eslint-env node */
require("@rushstack/eslint-patch/modern-module-resolution");

module.exports = {
  root: true,
  // 加入 env 設定
  env: {
    node: true,
  },
  extends: [
    "plugin:vue/vue3-essential",
    "eslint:recommended",
    "@vue/eslint-config-prettier",
  ],
  parserOptions: {
    ecmaVersion: "latest",
  },
};

再來要建立上面 build.lib.entry 寫到的檔案,這是未來套件的進入點,所以建立 src/index.js,把你要 export 的東西寫進去。

import TheCounter from "./components/TheCounter.vue";

export default TheCounter;

再來就可以跑 Build 的指令了,可以用你熟悉的工具去執行,以 npm 來說是

$ npm run build

跑完之後會看到多了一個 dist 資料夾,這個就是之後要發佈到 NPM 上面的東西。

在發布之前要先設定 package.json


設定 Package.json

把官方建議的設定貼進來改一下

{
  "name": "vue3-simple-counter",
  "type": "module",
  "files": ["dist"],
  "main": "./dist/simple-counter.umd.js",
  "module": "./dist/simple-counter.mjs",
  "exports": {
    ".": {
      "import": "./dist/simple-counter.mjs",
      "require": "./dist/simple-counter.umd.js"
    },
    "./style.css": {
      "import": "./dist/style.css",
      "require": "./dist/style.css"
    }
  },
  "version": "0.0.0",
  // ...
}

Local 測試

Local 測試,可以在套件的專案下

$ npm link

然後為了要在 Local 測試,可以再開一個新的 Vue 專案。

建立好且裝好相依套件後,可以在 link 使用我們剛剛做的套件

$ npm link <name>

以剛剛的範例的話就是下

$ npm link vue3-simple-counter

這樣你會發現 node_modules 下有一個捷徑,他連到 vue3-simple-counter 這個專案,而你就可以在 Vue 專案中 import 來測試可不可用。

App.vue

<script setup>
import TheCounter from "vue3-simple-counter";
import "vue3-simple-counter/style.css";
</script>

<template>
  <TheCounter />
</template>

理論上可以正常執行,然後畫面上就有剛剛製作的那個 TheCounter


處理 CSS

剛才 Build 出來的結果包含了 style.css ,這樣使用還需要多 import,有點麻煩,想說把他整併到 js 當中,有個工具可以幫忙達成。

vite-plugin-css-injected-by-js

安裝

$ npm i vite-plugin-css-injected-by-js -D

修改 vite.config.js

import cssInjectedByJsPlugin from "vite-plugin-css-injected-by-js";

// ...

export default defineConfig({
  plugins: [vue(), cssInjectedByJsPlugin()],
  //   ...
});

重新 Build

$ npm run build

之後你會看到 dist 當中少了 style.css,他被搬到了 javascript 當中。

再來修改 package.json,因為他不再需要 style.css 這個進入點。

{
  // ...
  "exports": {
    ".": {
      "import": "./dist/simple-counter.js",
      "require": "./dist/simple-counter.umd.cjs"
    }
  },
  //   ...
}

再來可以回到 Vue 專案中測試,把 css 的引入拿掉,應該可以正常運作,就完成了。


總結

這一篇主要是紀錄如何包裝 Vue3Component ,這樣未來就可以更輕鬆的重複使用自己曾寫過的工具,不過使用 JavaScript 在開發套件上還是有些缺點,下一篇會紀錄如何發布 TypeScript 的版本,且再加入 TailwindCSS




最後更新時間: 2023年02月05日.