npm发布一个插件(个人笔记)

第一步:创建插件项目结构

首先创建项目目录并初始化:

mkdir vue-toast-notification
cd vue-toast-notification
npm init -y
npm install vue@3
npm install -D vite @vitejs/plugin-vue

第二步:编写插件代码

创建 src/index.js 文件:

import { createVNode, render } from 'vue';
import ToastComponent from './Toast.vue';

// 创建一个容器元素
const container = document.createElement('div');
document.body.appendChild(container);

// 存储当前显示的 toast 实例
let currentToast = null;

// Toast 函数,用于显示提示
function showToast(options = {}) {
  // 如果已有 toast 显示,则先移除
  if (currentToast) {
    render(null, container);
  }

  // 默认配置
  const defaults = {
    message: '',
    type: 'info', // info, success, error, warning
    duration: 3000,
    position: 'top-center' 
  };

  // 合并配置
  const props = { ...defaults, ...options };

  // 创建虚拟节点
  const vnode = createVNode(ToastComponent, props);
  
  // 渲染组件
  render(vnode, container);
  currentToast = vnode;

  // 设置自动关闭
  if (props.duration > 0) {
    setTimeout(() => {
      closeToast();
    }, props.duration);
  }

  return {
    close: closeToast
  };
}

// 关闭 toast
function closeToast() {
  if (currentToast) {
    render(null, container);
    currentToast = null;
  }
}

// 插件安装函数
const ToastPlugin = {
  install(app) {
    // 全局注册
    app.config.globalProperties.$toast = showToast;
    
    // 提供组合式 API
    app.provide('toast', showToast);
  }
};

// 导出插件和工具函数
export default ToastPlugin;
export const toast = showToast;

创建 src/Toast.vue 组件文件:

<template>
  <div 
    class="vue-toast"
    :class="[typeClass, positionClass]"
    :style="{ opacity: visible ? 1 : 0, transform: visible ? 'translateY(0)' : transformValue }"
  >
    <div class="toast-content">
      <slot>{{ message }}</slot>
    </div>
  </div>
</template>

<script setup>
import { ref, onMounted } from 'vue';

const props = defineProps({
  message: {
    type: String,
    default: ''
  },
  type: {
    type: String,
    default: 'info',
    validator: (value) => {
      return ['info', 'success', 'error', 'warning'].includes(value);
    }
  },
  position: {
    type: String,
    default: 'top-center',
    validator: (value) => {
      return [
      'top-left', 'top-center', 'top-right', 'bottom-left', 'bottom-center', 
      'bottom-right'].includes(value);
    }
  }
});

const visible = ref(false);

// 计算样式类
const typeClass = `toast-${props.type}`;
const positionClass = `toast-${props.position}`;

// 计算初始位移
const transformValue = ref('translateY(-20px)');

onMounted(() => {
  // 触发过渡动画
  setTimeout(() => {
    visible.value = true;
  }, 10);
});
</script>

<style scoped>
.vue-toast {
  position: fixed;
  padding: 12px 20px;
  border-radius: 4px;
  color: #fff;
  font-size: 14px;
  transition: all 0.3s ease;
  z-index: 9999;
  max-width: 300px;
  word-break: break-word;
}

/* 位置样式 */
.toast-top-left {
  top: 20px;
  left: 20px;
}

.toast-top-center {
  top: 20px;
  left: 50%;
  transform: translateX(-50%);
}

.toast-top-right {
  top: 20px;
  right: 20px;
}

.toast-bottom-left {
  bottom: 20px;
  left: 20px;
}

.toast-bottom-center {
  bottom: 20px;
  left: 50%;
  transform: translateX(-50%);
}

.toast-bottom-right {
  bottom: 20px;
  right: 20px;
}

/* 类型样式 */
.toast-info {
  background-color: #4285f4;
}

.toast-success {
  background-color: #0f9d58;
}

.toast-error {
  background-color: #d93025;
}

.toast-warning {
  background-color: #f4b400;
}
</style>

第三步:配置打包文件

创建 vite.config.js 配置文件:

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

export default defineConfig({
  plugins: [vue()],
  build: {
    lib: {
      entry: path.resolve(__dirname, 'src/index.js'),
      name: 'VueToastNotification',
      // format 参数:由 Vite/Rollup 自动传递,根据你配置的打包格式变化,常见值包括:
      // es:ES 模块格式(对应 module 字段)
      // umd:通用模块定义格式(对应 main 字段)
      // 这种命名方式让使用者和工具链能清晰识别不同模块格式的文件,
      // 确保在各种环境下都能正确引入你的 Vue 插件。
      fileName: (format) => `vue-toast-notification.${format}.js`
    },
    rollupOptions: {
      // 确保外部化处理那些你不想打包进库的依赖
      external: ['vue'],
      output: {
        // 在 UMD 构建模式下为这些外部化的依赖提供一个全局变量
        globals: {
          vue: 'Vue'
        }
      }
    }
  }
});

修改 package.json 文件,添加必要的字段:

{
  "name": "vue-toast-notification",
  "version": "1.0.0",
  "description": "A simple toast notification plugin for Vue 3",
  "main": "dist/vue-toast-notification.umd.js",
  "module": "dist/vue-toast-notification.es.js",
  "exports": {
    ".": {
      "import": "./dist/vue-toast-notification.es.js",
      "require": "./dist/vue-toast-notification.umd.js"
    }
  },
  "files": [
    "dist"
  ],
  "scripts": {
    "build": "vite build"
  },
  "keywords": [
    "vue",
    "vue3",
    "toast",
    "notification",
    "plugin"
  ],
  "author": "",
  "license": "MIT",
  "dependencies": {
    "vue": "^3.3.4"
  },
  "devDependencies": {
    "@vitejs/plugin-vue": "^4.2.3",
    "vite": "^4.4.5"
  }
}
  • main定义包的默认入口文件,主要供使用 CommonJS 模块系统的环境(如 Node.js 或使用 require() 导入的工具)使用。这里指向 UMD 格式的文件(umd.js),因为 UMD 格式兼容 CommonJS 和 AMD 规范。
  • module定义 ES 模块入口文件,供支持 ES 模块的工具(如 Webpack、Rollup、Vite 等)使用。工具会优先读取 module 字段,加载 ES 模块格式的文件(es.js),有利于 Tree-shaking 优化(删除未使用的代码)。
  • exports这是 ES 模块规范中更现代的导出定义方式,比 main 和 module 更灵活,可根据导入方式(import 或 require)自动匹配对应的文件:
    当使用 import 导入时,使用 ES 模块格式(es.js)
    当使用 require 导入时,使用 UMD 格式(umd.js)
    这种配置能更精确地控制不同模块系统的加载行为,是对 main 和 module 的补充和增强。
  • files字段用于指定 当包发布到 npm 时,需要包含哪些文件或目录,它是控制 npm 包体积和内容的重要配置。

第四步:打包并发布到 npm

  1. 首先打包插件:
npm run build
  1. 登录 npm(如果还没有账号,先在 npm 官网注册):
npm login
  1. 发布插件:
npm publish
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容