VUE3+TS+VITE实现npm组件发布

454 阅读2分钟

一,组件发布

1,项目目录结构

image.png

2,代码

(1)package.json

{
  "name": "tl-app",
  "private": false,
  "version": "0.1.3",
  "type": "module",
  "files": [
    "lib"
  ], // 发布的文件清单
  "module": "./lib/tl-app.js",
  "main": "./lib/tl-app.umd.cjs",
  "exports": {
    ".": {
      "import": "./lib/tl-app.js",
      "require": "./lib/tl-app.umd.cjs"
    }
  },
  "scripts": {
    "dev": "vite",
    "build": "vite build",
    "preview": "vite preview",
    "build:components": "node --trace-warnings ./command/build.js",
    "lib": "npm run build:components",
    "test": "jest"
  },
  "peerDependencies": {
    "vue": ">=3.0.0"
  },
  "devDependencies": {
    "@babel/core": "^7.20.5",
    "@babel/preset-env": "^7.20.2",
    "@babel/preset-typescript": "^7.18.6",
    "@types/jest": "^29.2.4",
    "@vitejs/plugin-vue": "^3.0.0",
    "@vitejs/plugin-vue-jsx": "^2.0.0",
    "@vue/test-utils": "^2.0.0-rc.18",
    "babel-jest": "^26.6.3",
    "jest": "^26.6.3",
    "sass": "^1.56.2",
    "ts-jest": "^26.5.6",
    "vite": "^3.0.0",
    "vue": "^3.2.37",
    "vue-jest": "^5.0.0-alpha.10",
    "async-validator": "^4.2.5",
    "mitt": "^3.0.0"
  }
}

(2)vite.config.js

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

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [vue()]
})

(3).npmignore

# 忽略目录
.idea
.vscode
build/
docs/
examples/
src/
packages/
public/
node_modules/
typings/
test/
command/
 
# 忽略指定文件
.babel.config.js
tsconfig.json
tslint.json
vue.config.js
.gitignore
.browserslistrc
*.map
jest.config.js

(4)command/build.js

/**
 * 实现组件全局(全量)打包
 * @description 因为通过 node 打包,所以采用 CommonJS 规范,也就是 require
 */
 
 import { createRequire } from 'module';
 import path from "path"
  
 const requireds = createRequire(import.meta.url);
 const __dirname = path.resolve();
  
 // vite 打包需要的配置
 const { defineConfig, build } = requireds('vite');
  
 // vite 插件
 const vue = requireds('@vitejs/plugin-vue');
 const vueJsx = requireds('@vitejs/plugin-vue-jsx');
  
 // 添加打包入口文件夹 packages(需要手动创建)
 const entryDir = path.resolve(__dirname, 'packages');
 // 添加出口文件夹 lib(不需要手动创建,会自动生成)
 const outDir = path.resolve(__dirname, 'lib');
  
 // vite 配置
 const baseConfig = defineConfig({
   configFile: false,
   publicDir: false,
   plugins: [vue(), vueJsx()]
 });
  
 // rollup 配置(vite 基于 rollup 打包)
 const rollupOptions = {
   // 这两个库不需要打包
   external: ['vue', 'vue-router'],
   output: {
     globals: {
       vue: 'Vue'
     }
   }
 };
  
 /**
  * 全量打包构建的方法
  */
 const buildAll = async () => {
   await build({
     ...baseConfig,
     build: {
       rollupOptions,
       lib: {
         // 入口
         entry: path.resolve(entryDir, 'index.ts'),
         // 组件库名字
         name: 'tl-app',
         fileName: 'tl-app',
         // 输出格式
         formats: ['es', 'umd']
       },
       outDir
     }
   })
 };
  
 /**
  * 打包成库
  */
 const buildLib = async () => {
   await buildAll();
 };
  
 buildLib();

(5)packages/index.ts

import { App } from 'vue'
import TlButton from './button/index.ts' 
 
const install = (app:App) => {  // 进行注册
  app.use(TlButton)
}
 
const LUI = {
  install
}
 
export {  // 按需导出
  TlButton
}
 
export default LUI // 默认全部导出

(6)packages/button/index.ts

//index.ts
 
import { App } from 'vue'
 
import TlButton from './index.vue'
 
TlButton.install = (app:App) => {
  app.component(TlButton.name, TlButton)
}
 
export default TlButton

(7)packages/button/index.vue

<template>
  <button class="tl-button" :class="[size ? `tl-button--${size}` : '']">
    <slot />
  </button>
</template>
<script lang="ts">
export default {
  name: "TlButton", // 注册的时候会用到
};
</script>
<script setup lang="ts">
import { computed, withDefaults } from "vue";
interface Props {
  size?: "" | "small" | "medium" | "large";
}
const props = withDefaults(defineProps<Props>(), {
  size: "",
});
</script>   
<style lang="scss" scoped>
@import '../styles/mixin.scss';
.tl-button--small {
  width: 50px;
  height: 20px;
}
.tl-button--medium {
  width: 80px;
  height: 40px;
}
.tl-button--large {
  width: 100px;
  height: 50px;
}
</style>

3,组件打包、发布

执行以下指令

  组件打包:npm run lib
  npm登录(初次上传才需要):npm login -registry=https://registry.npmjs.org/
  组件发布:npm publish

注:这个操作需要npm帐号,在官网上直接申请即可

二,组件使用

1,组件下载

npm install tl-app

2,组件引入(main.js)

import { createApp } from 'vue'
import App from './App.vue'
import LUI from 'tl-app';
createApp(App).use(LUI).mount('#app')

3,组件使用(App.vue)

<script setup>
</script>

<template>
  <tl-button>测试</tl-button>
</template>

<style>
#app {
  font-family: Avenir, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
</style>

注:该组件只能供vue3+vite项目引入使用

源码地址: