Vue3+element-plus+vite 组件的二次封装– 新建npm打包项目,生成二次封装npm组件库,本地测试

  • Post author:
  • Post category:vue

Vue 笔记

本人是一个web前端开发工程师,主要是vue框架,整理了一些Vue常用的技术,一方面是分享,一方面是做总结,今后也会一直更新,有好建议的同学欢迎评论区分享 ;-)

Vue专栏:点击此处
Vue组件库专栏:点击此处
Vue2 vs Vue3 专栏:点击此处
Typescript专栏:点击此处

在这里插入图片描述


组件库开发流程

Vue组件库专栏会按顺序执行一下流程,不断完善组件库开发流程

  1. Vue3+element-plus+vite 组件的二次封装,封装了头部的搜索条件栏,tabel栏,分页栏,form表单,都设置成了通过json可配置项,方便复用;
  2. 封装好了就开始打包,并且进行本地测试;
  3. 组件库发布到npm;
  4. 添加vitest单元测试框架;
  5. 添加vuepress文档。


前言

封装好的组件,只能在当前项目里面复用,如果其他项目也有类似的需求,除了可以copy外,还有发布到npm库中。

npm包的样式文件也需要在pakeage.json中显式导出,不会有会报错!!!

[plugin:vite:import-analysis] Missing "./dist/style.css" export in "penk-ui" package
You can also disable this overlay by setting server.hmr.overlay to false in vite.config.js.
在这里插入图片描述


1. 新建vue工程

1.1 初始化vue项目

npm init vue@latest

初始化目录结构如下:

在这里插入图片描述

1.2 引入element-plus组件库

是基于element-plus的二次封装,不需要的可以不添加
官网:此处

npm install element-plus --save

1.3 引入less

npm i less less-loader -D

或许有其他的库我忘记加了...自行判断...


2. 修改目录结构

因为是为了创建组件库,因为打包的组件库是没有html的。

2.1 原目录结构

  • 组件库是没有html,所以移除了App.vue 以及 main.ts
  • 删除原来的demo组件
    在这里插入图片描述

2.2 新目录结构

  • dist:存放打包好的组件库的文件夹;
  • src/client:用于测试组件的文件目录;
  • src/component: 是用来存放封装好的组件的;
  • index.html:这是用来npm run dev,由于组件库没有html,这边就用client 来当测试demo,所以需要修改里面的配置;
  • vite.config.ts:主要配置build 的打包参数;
  • src/index.ts:用于配置打包内容;
  • package.json 修改配置,使其指向生成的库文件;以及基础的配置信息,方便上传到npm 中。

在这里插入图片描述

2.3 测试组件 PenkButton.vue

这边弄2个按钮,一个是原生的,一个是引用elementPlus的按钮
按钮组件如下:

<!--
 * @Author: Penk
 * @LastEditors: Penk
 * @LastEditTime: 2022-12-14 11:00:10
 * @FilePath: \penk-ui\src\components\PenkButton.vue
 * @email: 492934056@qq.com
-->
<template>
  <button @click="clickBtn">test</button>
  <el-button>test2</el-button>
</template>

<script setup lang="ts">
function clickBtn() {
  console.log("clickBtn...");
}
</script>
<script lang="ts">
export default {
  name: "PenkButton",
};
</script>

<style lang="less" scoped></style>


3. 修改源文件

目录结构发生了变化,所以一些配置也要发生改变

3.1 vite.config.ts

官网的库模式就是生成组件库:此处

如果没有配置该文件,默认是从根目录的index.html 文件开始,下方文件只修改了build ,没有修改dev!!!

  • dev 模式下,是从index.html 开始
  • build 模式下,是从下方的配置, src/index.ts 开始
import { fileURLToPath, URL } from "node:url";
import { resolve } from "path";

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

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [vue()],
  resolve: {
    alias: {
      "@": fileURLToPath(new URL("./src", import.meta.url)),
    },
  },
  build: {
    // 到处文件目录,penk-ui 用于存放package.json,避免被覆盖
    // 这里不设置也是默认dist
    outDir:"dist",
    // 兼容
    target: "es2015",
    lib: {
      // Could also be a dictionary or array of multiple entry points
      entry: resolve(__dirname, "src/index.ts"),
      name: "PenkUi",
      // the proper extensions will be added
      // 如果不用format文件后缀可能会乱
      fileName: (format) => `penk-ui.${format}.js`,
    },
    rollupOptions: {
      // 确保外部化处理那些你不想打包进库的依赖
      external: ["vue", "element-plus"],
      output: {
        // 在 UMD 构建模式下为这些外部化的依赖提供一个全局变量
        globals: {
          vue: "Vue",
          "element-plus": "ElementPlus",
        },
      },
    },
  },
});

3.2 index.html

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <link rel="icon" href="/favicon.ico">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Vite App</title>
  </head>
  <body>
    <div id="app"></div>
    <!-- 主要是运行npm run dev的时候会触发该文件 -->
    <!-- 现在跑到src/client 中了 -->
    <script type="module" src="/src/client/main.ts"></script>
  </body>
</html>

3.3 src/client/main.ts

只引入一个按钮,测试即可。

import { createApp } from "vue";
import ElementPlus from "element-plus";
import "element-plus/dist/index.css";
import App from "./App.vue";

const app = createApp(App);

app.use(ElementPlus);
app.mount("#app");


3.4 src/client/App.vue

只引入一个按钮,测试即可。

<script setup lang="ts">
import PenkButton from "@/components/PenkButton.vue";
</script>

<template>
  <PenkButton></PenkButton>
</template>

<style scoped></style>

至此,npm run dev 就可以打开网站了,效果如下:
在这里插入图片描述


3.5 src/index.ts

用于打包组件库

/*
 * @Author: Penk
 * @LastEditors: Penk
 * @LastEditTime: 2022-12-14 11:38:24
 * @FilePath: \penk-ui\src\index.ts
 * @email: 492934056@qq.com
 */

// 引入封装好的组件
import PenkButton from "./components/PenkButton.vue";

let arr = [PenkButton]; // 如果有多个其它组件,都可以写到这个数组里

// 批量组件注册
const install = function (Vue: any) {
  arr.forEach((com) => {
    Vue.component(com.name, com);
  });
};

export default install; // 这个方法使用的时候可以被use调用


4. 编译生成组件库

npm run build

运行打包命令,生成如下文件
在这里插入图片描述


5. 配置package.json

官网:此处

  • files:可选的files字段是一个文件模式数组,它描述了包作为依赖项安装时要包含的条目。
  • main:主字段是一个模块ID,它是程序的主要入口点。也就是说,如果你的包被命名为foo,用户安装了它,然后确实需要(“foo”),那么你的主模块的exports对象将被返回。如果main未设置,则默认为包根文件夹中的index.js。
  • exports:导出的文件,这里要注意样式文件的导出
{
  "name": "penk-ui",
  "version": "1.0.1",
  "description": "对elementPlus进行二次封装的组件库",
  "files": [
    "dist",
    "dist/**"
  ],
  "keywords": [],
  "author": "penk",
  "email": "492934056@qq.com",
  "license": "ISC",
  "scripts": {
    "dev": "vite",
    "build": "run-p type-check build-only",
    "preview": "vite preview",
    "build-only": "vite build",
    "type-check": "vue-tsc --noEmit"
  },
  "dependencies": {
    "element-plus": "^2.2.26",
    "vue": "^3.2.45"
  },
  "devDependencies": {
    "@types/node": "^18.11.12",
    "@vitejs/plugin-vue": "^4.0.0",
    "@vue/tsconfig": "^0.1.3",
    "less": "^4.1.3",
    "less-loader": "^11.1.0",
    "npm-run-all": "^4.1.5",
    "typescript": "~4.7.4",
    "vite": "^4.0.0",
    "vue-tsc": "^1.0.12"
  },
  "main": "./dist/penk-ui.umd.js",
  "module": "./dist/penk-ui.es.js",
  "exports": {
    ".": {
      "import": "./dist/penk-ui.es.js",
      "require": "./dist/penk-ui.umd.js"
    },
    "./dist/style.css": "./dist/style.css"
  }
}


6. 本地测试

6.1 新建一个vue项目

npm init vue@latest
cd xxx
npm i

6.2 安装本地库文件

npm install F:\SOFTWARE_PROJECT\penk-ui
npm run dev

6.3 修改App.vue

<script setup>
</script>

<template>
  <PenkButton></PenkButton>
</template>

<style scoped>
</style>

6.4 查看效果

在这里插入图片描述


版权声明:本文为cs492934056原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。