發布一個 npm 組件
一直希望能做公有組件並考慮上傳 npm ,
想了一個一直想做而且頗鬧的題目來實作😂
上傳圖片後可以轉化成文字顯示畫上 Canvas。
設立目標
想實作的方式,列下幾種必須達到的 Goal
- 必須透過 Vue3 Typescript 實作
- 必需使用自動化流程版號
- package.json 的各項值設定
- 簡單好玩的程式實作
遇到挑戰
實際上實作時卻發現...
Typescript 環境設定
- 起初不熟悉 Typescript 各種 .json 的後綴檔案代表的意義,熟悉了一陣子,後來才理解 tsconfig.app.json 「app」 為代表管理的環境,app 為應用、node 為後端建構等等。並統一在 tsconfig.json 中參考,以便 Ts 編譯器可以知道使用的環境。
tsconfig.json
{
"references": [
{
"path": "./tsconfig.app.json" // [!code focus] 應用程式的 TypeScript 配置
},
{
"path": "./tsconfig.node.json" // Node.js 環境的 TypeScript 配置
},
{
"path": "./tsconfig.config.json" // 特定配置的 TypeScript 配置
}
],
"compilerOptions": {
"allowSyntheticDefaultImports": true, // 允許合成默認導入
"baseUrl": "./", // 基本路徑設置
"declaration": true, // 生成宣告文件
"declarationDir": "./dist/types", // 宣告文件的輸出目錄
"esModuleInterop": true, // 允許 ES 模組互操作性
"experimentalDecorators": true, // 啟用實驗性的裝飾器功能
"importHelpers": true, // 引入幫助函數
"isolatedModules": true, // 每個文件作為一個單獨的模組處理
"jsx": "preserve", // 保留 JSX 語法
"lib": ["esnext", "dom", "dom.iterable", "scripthost"], // 使用的 TypeScript 標準庫
"module": "esnext", // 模組格式
"target": "esnext", // 編譯目標
"moduleResolution": "node", // 模組解析策略
"noUnusedLocals": true, // 不允許未使用的本地變量
"noUnusedParameters": true, // 不允許未使用的參數
"outDir": "dist", // 輸出目錄
"paths": {
"@/*": ["src/*"] // 路徑別名設置
},
"resolveJsonModule": true, // 允許導入 JSON 模組
"sourceMap": true, // 生成 source map
"strict": true, // 啟用所有嚴格的類型檢查選項
"types": ["node", "vue"], // 包含的類型定義
"useDefineForClassFields": true // 使用 `define` 關鍵字定義類字段
},
"exclude": [
"node_modules", // 排除 node_modules 目錄
"dist" // 排除 dist 目錄
]
}
tsconfig.app.json
{
"compilerOptions": {
"composite": true,
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
"target": "esnext",
"useDefineForClassFields": true,
"module": "esnext",
"lib": ["ES2020", "DOM", "DOM.Iterable"],
"skipLibCheck": true,
/* Bundler mode */
"moduleResolution": "bundler",
"allowImportingTsExtensions": true,
"resolveJsonModule": true,
"isolatedModules": true,
"moduleDetection": "force",
"noEmit": true,
"jsx": "preserve",
/* Linting */
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noFallthroughCasesInSwitch": true
},
"include": ["src/**/*", "src/**/*.vue"]
}
tsconfig.node.json
{
"compilerOptions": {
"composite": true,
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
"skipLibCheck": true,
"moduleResolution": "bundler",
"allowSyntheticDefaultImports": true,
"strict": true,
"noEmit": true,
"module": "esnext",
"types": ["node"]
},
"include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"]
}
有些雷真的是踩過才知道😭
bundler 的設定及輸出
本來以為打包只需要設定好輸出就好了吧,照著網路上的教學及文件,應該能簡單的上線😊,結果自己還是太年輕了。 要設定 package.json vite.config,有一個很重要的提醒
INFO
"author": "一定要是本人且正確", <== publish 快一小時懷疑人生的時候,發現改這個就過了👼
package.json
{
// 以上略
"main": "dist/canvas-image.umd.js", // 主入口文件,使用 UMD 格式
"module": "dist/canvas-image.es.js", // ES 模塊格式的入口文件
"exports": { // 當用不同引入方式時文件的指向,做了這個之後才真的知道 npm 真的幫忙做了很多
".": {
"import": "./dist/canvas-image.es.js", // 當使用 import 時的入口文件
"require": "./dist/canvas-image.umd.js", // 當使用 require 時的入口文件
"types": "./dist/types/index.d.ts" // 型別定義文件
},
"./dist/style.css": "./dist/style.css" // 對應 CSS 文件的路徑
},
"types": "./vue3-canvas-image.d.ts" // 預設型別定義文件的入口
}
vite.config.ts
export default defineConfig({
plugins: [
vue(), // Vue 插件,用於處理 Vue 文件
dts({
clearPureImport: true, // 清除純導入
}),
],
resolve: {
alias: {
"@/": new URL("./src/", import.meta.url).pathname, // 設置路徑別名,指向 src 目錄
},
},
build: {
cssCodeSplit: true, // 啟用 CSS 代碼分割
sourcemap: true, // 生成 source map 文件
emptyOutDir: true, // 構建時清空輸出目錄
target: "esnext", // 目標環境設置為 ESNext
outDir: "./dist", // 輸出目錄
lib: {
// 入口文件,可以是多個入口點的字典或數組
entry: resolve(dirname(fileURLToPath(import.meta.url)), "src/index.ts"),
name: "canvas-image", // 庫的全局名稱
// 生成的文件名,根據格式附加相應的擴展名
fileName: (fileName) => `${"canvas-image"}.${fileName}.js`,
},
rollupOptions: {
// 確保將不應該打包進庫的依賴設置為外部化
external: ["vue"],
output: {
// 為外部化的依賴提供全局變量,在 UMD 構建中使用
globals: {
vue: "Vue",
},
},
},
},
});
npm 上版失敗
這真的是這次實作最痛最哭的部分,因為網路上的資源都寫 npm publish 就好,但實際是若啟用 auth 認證,就必須實作 git action 的 secrets token,然後要複製 .npmrc 指向路徑,並且要把 org 設置好,不然就會上板上到歪頭。
release 版號問題
release 自動化也是,我猜考了 vue/core 的上版流程,使用 .husky pre-commit pre-push 作用如名,在 commit push 之前先去做我寫好的指令。
- pre-commit 檢查 commit 是否有按照規則
- pre-push 執行 auto update release version
github actions yml 的撰寫
因為之前就有在寫類似的 pipeline 倒是簡單的參考一下別下的 CI/CD,
學習結論
實際走過一次流程後發現,做自己的第三方插件好像也沒那麼難,而且看到下載量真的有點嚇到的感覺,想說只是跑個流程的專案居然有 500 下載量,但星星倒是沒人按哈哈哈哈哈, 之後會真的想想實際的需求後再繼續我的插件之旅~寫個後端相關的好像也可以👍