保姆级发布自己的组件到npm

506 阅读4分钟

前言

从创建项目开始,由 0 到 1编写一个 ui 组件并且发布到 npm 上。本组件库可以在 npm 中搜索 vue-zeey-ui 搜索到,完整代码可前往我的 GitHub 仓库:zeey-ui 查看。

使用方法:

  1. 安装组件:npm install vue-zeey-ui.
  2. 引入组件:import { ZButton } from 'vue-zeey-ui'.
  3. 使用组件:<ZButton>按钮</ZButton>.
  4. 如果样式没有生效,需要在 main.ts 中引入 vue-zeey-ui/css 文件。

1. 创建一个 Vue3 项目

pnpm create vite

image.png

2. 创建一个 Vue 组件

首先,我们在 src 中新建一个 packages 文件夹,该文件夹用于存放我们自己封装的组件,我这里封装了一个 Button,该文件的目录结构如下:

image.png

其中 button.vue 的部分代码(完整代码可前往我的 GitHub 仓库:zeey-ui 查看):

<template>
  <div class="z-button-container">
    <div class="wave" :class="type" v-if="showWave"></div>
    <button class="z-button" type="button" @click="createWave" :class="type">
      <slot>button</slot>
    </button>
  </div>
</template>

向外导出 button:

// index.ts
import type { App } from 'vue'
import ZButton from "./Button.vue"

// 使用install方法,在app.use挂载
ZButton.install = (app: App) => {
    app.component(ZButton.__name as string, ZButton) //注册组件
}

export default ZButton

3. 编写入口文件 index.ts

向外导出我们封装的组件

//index.ts
import type { App } from 'vue';
import ZButton from './Button/index';

// 组件列表
const components = [ZButton];

export { ZButton };

export default {
  // 定义 install 方法
  install(app: App) {
    components.forEach((component) =>
      app.component(component.__name as string, component),
    );
  },
};

4. 编写 vite 配置文件

通过 lib 配置项指定了库的入口文件、名称和文件名。

使用 terser 作为代码压缩工具,并配置了 terserOptions 来移除 console 和 debugger 语句,以及删除注释。。

import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import path from 'path'

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [vue()],
  base:'/',
  build:{
    lib:{
      entry: path.resolve(__dirname, './src/packages/index.ts'), //指定组件编译入口文件
      name: 'vueZeeyUI',
      fileName: 'vue-zeey-ui'
    },//库编译模式配置
    rollupOptions: {
      external: ['vue', 'swiper', '@vuepic/vue-datepicker', 'qrcode'],
      output: {
        // format: 'es', // 默认es,可选 'amd' 'cjs' 'es' 'iife' 'umd' 'system'
        exports: 'named',
        globals: { //在UMD构建模式下为这些外部化的依赖提供一个全局变量
          vue:'Vue',
          // 'vue-router': 'VueRouter', // 引入vue-router全局变量,否则router.push将无法使用
          swiper: 'Swiper',
          '@vuepic/vue-datepicker': 'VueDatePicker',
          qrcode: 'qrcode'
        }
      }
    },
     /** 设置为 false 可以禁用最小化混淆,或是用来指定使用哪种混淆器。
        默认为 Esbuild,它比 terser 快 20-40 倍,压缩率只差 1%-2%。
        注意,在 lib 模式下使用 'es' 时,build.minify 选项不会缩减空格,因为会移除掉 pure 标注,导致破坏 tree-shaking。
        当设置为 'terser' 时必须先安装 Terser。(yarn add terser -D)
    */
    minify: 'terser', // Vite 2.6.x 以上需要配置 minify: "terser", terserOptions 才能生效
    terserOptions: { // 在打包代码时移除 console、debugger 和 注释
      compress: {
        /* (default: false) -- Pass true to discard calls to console.* functions.
          If you wish to drop a specific function call such as console.info and/or
          retain side effects from function arguments after dropping the function
          call then use pure_funcs instead
        */
        drop_console: true, // 生产环境时移除console
        drop_debugger: true
      },
      format: {
        comments: false // 删除注释comments
      }
    }
  }
})


5. 编写 package.json 文件

各部分释义:

"type": 指定模块类型。

"module" 表示使用 ES 模块。

"license": 项目的许可证类型。

"files": 指定发布到 npm 时包含的文件或目录。

"main": 指定包的入口文件,适用于 CommonJS。

"module": 指定包的入口文件,适用于 ES 模块。

"exports": 定义包的导出路径,支持不同的模块格式。

{
  "name": "vue-zeey-ui",
  "private": false,
  "version": "0.2.2",
  "author": "Zeey",
  "description": "组件发布npm练习",
  "type": "module",
  "license": "MIT",
  "files": [
    "dist"
  ],
  "main": "./dist/vue-zeey-ui.umd.cjs",
  "module": "./dist/vue-zeey-ui.js",
  "exports": {
    "./dist/style.css": "./dist/style.css",
    "./css": "./dist/style.css",
    ".": {
      "import": "./dist/vue-zeey-ui.js",
      "require": "./dist/vue-zeey-ui.umd.cjs"
    }
  },
  "scripts": {
    "start": "vite",
    "dev": "vite",
    "build": "vue-tsc -b && vite build",
    "preview": "vite preview"
  },
  "dependencies": {
    "dayjs": "^1.11.9",
    "lodash-es": "^4.17.21",
    "vue": "^3.5.12"
  },
  "devDependencies": {
    "@types/node": "^22.8.5",
    "@vitejs/plugin-vue": "^5.1.4",
    "@vitejs/plugin-vue-jsx": "^4.0.1",
    "@vueuse/core": "^11.2.0",
    "@vueuse/nuxt": "^11.2.0",
    "sass": "^1.64.1",
    "terser": "^5.36.0",
    "typescript": "~5.6.2",
    "vite": "^5.4.10",
    "vue-tsc": "^2.1.8"
  }
}

6. 本地测试

在这里我们使用软链来进行测试,查看 npm-link 的更多信息

使用 npm link创建一个全局软链接,接着在其他项目中使用npm link vue-zeey-ui进行使用。需要注意的是vue-zeey-ui对应的是 package.json 中的 name

在当前项目的根目录下执行:

npm link    

在其他项目中执行:

npm link vue-zeey-ui

然后在 main.ts 中引入 css

import { createApp } from 'vue'
import './style.css'
import App from './App.vue'
import 'vue-zeey-ui/css'

createApp(App).mount('#app')

最后在 vue 文件中使用:

<script setup lang="ts">
import { ZButton } from 'vue-zeey-ui';
</script>

<template>
  <div class="button-container">
    <strong>Zeey-UI 按钮组件预览:</strong>
    <ZButton>Default</ZButton>
    <ZButton type="primary">Primary</ZButton>
    <ZButton type="tertiary">Tertiary</ZButton>
    <ZButton type="info">Info</ZButton>
    <ZButton type="success">Success</ZButton>
    <ZButton type="warning">Warning</ZButton>
    <ZButton type="error">Error</ZButton>
  </div>
</template>

运行结果:

image.png

7. 打包

命令:pnpm bulid

如果执行 pnpm build 报错,请先执行 yarn add terser -D 安装 Terser。

打包完成后将在根目录下生成dist目录:

image.png

8. 发布

首先登录 npm 官网:npm login.

然后发布组件:npm publish.

注意:在每次发布之前需要先切换版本号:npm version x.x.x.

9. 更多

完整代码可前往我的 GitHub 仓库查看。