Skip to content

组件库打包

注意

  • 全量打包

  • 按需打包

全量打包

  • 新建 根目录/command/build.js

  • 新建 根目录/packages/ 打包入口文件夹

复制结构

  • (1) 把 components 下面的所有文件复制到 packages 下面

  • (2) 把写组件用到的都放到 packages 下面

复制 interfaces,hooks,utils,stores 等等文件夹到 packages 下面

  • 架构
bash
├── command
   ├── build.js
├── src
├── packages
      ├── stores
      ├── utils
      ├── interfaces
      ├── hooks
      ├── index.ts
      ├── chooseArea
      ├── lib (引入的第三方库)
    └── xxx.json
      ├── src (源码)
   ├── index.vue
      ├── index.ts
      ├── chooseIcon
      ├── lib (引入的第三方库)
    └── xxx.json
      ├── src (源码)
   ├── index.vue
      ├── index.ts
  • 修改 packages 文件夹下面的引入路径(重点)

都换成引入 packages 目录下面的

创建打包文件

  • src/command/build.js
js
import { createRequire } from "module";
import { fileURLToPath } from "node:url";
// 使用require
const require = createRequire(import.meta.url);

const path = require("path");
// 使用文件路径
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);

const { defineConfig, build } = require("vite");
const vue = require("@vitejs/plugin-vue");
// const vueJsx = require('@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()],
});
// rollup 配置
const rollupOptions = {
  // vue 全家桶不需要打包
  external: ["vue", "vue-router", "pinia"],
  output: {
    globals: {
      vue: "Vue",
      vueRouter: "VueRouter",
      pinia: "Pinia",
    },
  },
};
// 全量打包配置
const buildAll = async () => {
  await build({
    ...baseConfig,
    build: {
      rollupOptions,
      lib: {
        entry: path.resolve(entryDir, "index.ts"),
        name: "YJ-elementplus-components",
        fileName: "YJ-elementplus-components",
        formats: ["es", "umd"],
      },
      outDir,
    },
  });
};

// 打包成库
const buildLib = async () => {
  await buildAll();
};

buildLib();

配置 vue 模块

新建 packages/vue.d.ts

  • packages/vue.d.ts
ts
/// <reference types="vite/client" />

declare module "*.vue" {
  import { DefineComponent } from "vue";
  // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/ban-types
  const component: DefineComponent<{}, {}, any>;
  export default component;
}

配置打包命令

  • 使用的时候直接执行 npm run lib 即可
js
  "scripts": {
    "dev": "vite",
    "build": "run-p type-check \"build-only {@}\" --",
    "preview": "vite preview",
    "build-only": "vite build",
    "type-check": "vue-tsc --build",
    "build:components":"node ./command/build.js",
    "lib":"npm run build:components"
  },

测试的时候直接引入

  • main.js 中 引入
bash
import YJUI from '../lib/YJ-elementplus-components.js'
import '../lib/YJ-elementplus-components.css'

单独打包组件

前面的步骤和全量一样

安装一个输出库

js
npm i fs-extra -D

修改 command/build.js

js
import { createRequire } from "module";
import { fileURLToPath } from "node:url";
// 使用require
const require = createRequire(import.meta.url);

const path = require("path");
// 使用文件路径
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);

const { defineConfig, build } = require("vite");
const vue = require("@vitejs/plugin-vue");
// const vueJsx = require('@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()],
});

/* 单独打包 要引入的 */

const fsExtra = require("fs-extra");

const fs = require("fs");

// rollup 配置
const rollupOptions = {
  // vue 全家桶不需要打包
  external: ["vue", "vue-router", "pinia"],
  output: {
    globals: {
      vue: "Vue",
      vueRouter: "VueRouter",
      pinia: "Pinia",
    },
  },
};
// 全量打包配置
const buildAll = async () => {
  await build({
    ...baseConfig,
    build: {
      rollupOptions,
      lib: {
        entry: path.resolve(entryDir, "index.ts"),
        name: "YJ-elementplus-components",
        fileName: "YJ-elementplus-components",
        formats: ["es", "umd"],
      },
      outDir,
    },
  });
};

// 单组件打包
// name 就是最终的组件名称
const buildSingle = async (name) => {
  await build({
    ...baseConfig,
    build: {
      rollupOptions,
      lib: {
        entry: path.resolve(entryDir, name),
        name: "index",
        fileName: "index",
        formats: ["es", "umd"],
      },
      outDir: path.resolve(outDir, name),
    },
  });
};

// 每个组件生成package.json
const createPackageJson = async (name) => {
  const fileStr = `
    {
      "name": "${name}",
      "main": "index.umd.js",
      "module": "index.es.js",
      "style":"styles.css"
    }
    `;
  // 如果有css就是
  /*
     const fileStr = `
    {
      "name": "${name}",
      "main": "index.umd.js",
      "module": "index.es.js",
      "style":"styles.css"
    }
    `
    */

  // 输出
  fsExtra.outputFile(
    path.resolve(outDir, `${name}/package.json`),
    fileStr,
    "utf-8"
  );
};
// 打包成库
const buildLib = async () => {
  await buildAll();

  // 获取到组件名称组成的数组

  const components = fs.readdirSync(entryDir).filter((name) => {
    // 判断是否是组件
    const componentsDir = path.resolve(entryDir, name);
    // 判断是否是一个目录
    const isDir = fs.lstatSync(componentsDir).isDirectory();
    // 是一个目录 并且包含index.ts
    return isDir && fs.readdirSync(componentsDir).includes("index.ts");
  });

  // 循环构建

  for (const name of components) {
    // 单独打包
    await buildSingle(name);
    // 生成package.json
    await createPackageJson(name);
  }
};

buildLib();

修改 package.json

js

  "scripts": {
    "dev": "vite",
    "build": "run-p type-check \"build-only {@}\" --",
    "preview": "vite preview",
    "build-only": "vite build",
    "type-check": "vue-tsc --build",
    "build:components": "node ./command/build.js",
    "lib": "npm run build:components"
  },

使用

  • 如果是 TS 项目在根目录下env.d.ts 里面写
ts
declare module "*.vue";
declare module "*.js";
  • main.ts
ts
// 单独引入组件

import "../lib/chooseIcon/index.css";
import chooseIcon from "../lib/chooseIcon/index.js";

// 单独引入地区

import chooseArea from "../lib/chooseArea/index.js";

app.use(chooseIcon);
app.use(chooseArea);