发布自己的第一个npm包

369 阅读3分钟

该示例采用vite+vue3+ts手把手教你发布自己的第一个npm包,快点学习起来吧!

一、新建项目

  • 使用npm
    npm create vite@latest

  • 使用yarn
    yarn create vite

  • 使用pnpm
    pnpm create vite

    注意:框架选择vue,语言选择typescript

二、改造目录

  1. 在根目录下创建packages目录,用来存放组件
  2. 将src目录改为examples用作示例
  3. 将index.html文件的src从“/src/main.ts”改为“/examples/main.ts”

三、组件开发

  1. 在packages目录下开发我们的组件
  2. packeges目录下存放每个组件单独的开发目录以及一个index.ts用于整合所有的组件对外导出
  3. 每个组件又包括src目录和index.ts文件,src目录下我们把index.vue当作组件的入口文件
  4. 我们以el-button为例,目录图大致如下

image.png

  1. 编写el-button/src/index.vue,组件的入口文件
<template>   
    <button class="el-Button">按钮</button> 
</template> 
<script lang="ts" setup> 
// el-button/src/index.vue
</script> 
<style  scoped> 
.el-Button {     
    background-color: #1188ff;     
    color: white;     
    border: none;     
    padding: 6px 12px;   
} 
</style>
  1. 编写el-button/index.ts,用来实现组件的导出
import elButton from "./src/index.vue"; 

// 一定要先给name赋值,这样后面的局部install和全局install方法才能读到同一个name
elButton.name = "el-button";

// 为组件添加 install 方法,用于按需引入
// 如果想通过CDN方式引入,需要编写install函数
elButton.install = function (Vue: any) {
  // 注册组件
  Vue.component("el-button", elButton);
};
export default elButton;

  1. 编写 packages/index.ts 文件,实现组件的全局注册
import elButton from "./el-button/index";
// 以数组的结构保存组件,便于遍历
const components = [elButton];
// 用于按需导入
export { elButton };
// 定义 install 方法
const install = function (Vue: any) {
  if ((install as any).installed) return;
  (install as any).installed = true; // 遍历并注册全局组件
  components.map((component) => {
    Vue.component(component.name, component);
  });
};
if (typeof window !== "undefined" && window.Vue) {
  install(window.Vue);
}
export default {
  // 导出的对象必须具备一个 install 方法
  install,
};

这一步会因为ts检验报错:

image.png

我们只需要在根目录中建立一个ts声明文件即可。

//env.d.ts
declare module "*.vue" {
  import { DefineComponent } from "vue";
  const component: DefineComponent<{}, {}, any>;
  export default component;
}
declare interface Window {
  Vue: any;
}

然后在tsconfig.json中修改include

 - "include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"],
 + "include": ["packages/**/*.ts", "packages/**/*.d.ts", "packages/**/*.tsx", "packages/**/*.vue", "./*.d.ts"],

四、本地测试

<script setup lang="ts">
// examples/App.vue
import elButton from "../packages/el-button/index";
</script>
<template>
  <elButton />
</template>
<style scoped></style>

五、编写package.json文件

  1. 需要填写的字段有
  • name:包名,唯一
  • version:版本号
  • files:配置需要发布的文件
  • main:入口文件
  • module:模块入口
  1. 示例
{
 "name": "npm-test",
 "private": false,
 "version": "0.0.1",
 "type": "module",
 "main": "dist/npm-test.umd.js",
 "module": "dist/npm-test.es.js",
 "files": [
  "dist/*",
  "env.d.ts"
 ],
 "scripts": {
  "dev": "vite",
  "build": "vue-tsc && vite build",
  "preview": "vite preview"
 },
 "dependencies": {
  "path": "^0.12.7",
  "vue": "^3.2.47"
 },
 "devDependencies": {
  "@types/node": "^20.2.5",
  "@vitejs/plugin-vue": "^4.1.0",
  "@vitejs/plugin-vue-jsx": "^3.0.2",
  "sass": "^1.62.1",
  "typescript": "^5.0.2",
  "vite": "^4.3.9",
  "vue-tsc": "^1.4.2"
 }
}

六、vite打包配置

// vite.config.ts
import { defineConfig } from "vite";
import vue from "@vitejs/plugin-vue";
import vueJsx from "@vitejs/plugin-vue-jsx";
import path from "path";
const resolve = (dir) => path.join(__dirname, dir);
// https://vitejs.dev/config/
export default defineConfig({
  plugins: [vue(), vueJsx({})],
  resolve: {
    alias: {
      "@": resolve("examples"),
      packages: resolve("packages"),
    },
  },
  build: {
    rollupOptions: {
      // 请确保外部化那些你的库中不需要的依赖
      external: ["vue"],
      output: {
        // 在 UMD 构建模式下为这些外部化的依赖提供一个全局变量
        globals: {
          vue: "Vue",
        },
      },
    },
    lib: {
      entry: "packages/index.ts",
      name: "npm-test",
      fileName: (format) => `npm-test.${format}.js`,
    },
  },
});

七、打包

执行yarn build,会生成dist文件夹

image.png

八、本地模拟

  • 直接引入
  1. 在examples/main.ts中引入style.css文件
    import { createApp } from 'vue'
    import './style.css'
    import App from './App.vue'
    import '../dist/style.css'
    createApp(App).mount('#app')
  1. 在examples/App.vue中引入组件
<template>
  <elButton />
</template>
<script setup lang="ts">
import { elButton } from "../dist/npm-test.js";
</script>
<style scoped>
</style>
  • 全局引入
  1. 在examples/main.ts中使用use全局注册组件
import { createApp } from 'vue'
import './style.css'
import App from './App.vue'
import '../dist/style.css'
import elButton from "../dist/npm-test.es.js";
const app = createApp(App);
app.use(elButton)
app.mount('#app');
  1. 直接在examples/App.vue中使用
<template>
  <elButton />
</template>
<script setup lang="ts">
</script>
<style scoped>
</style>

九、发布

  1. npm config get registry 查看是否是官方源 registry.npmjs.org, 不是的话通过npm config set registry registry.npmjs.org 切换
  2. npm login 输入账号密码登陆
  3. npm publish

至此,我们的第一个npm包就发布成功了,快去登陆npm官网查看自己的包吧!