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, "../src");
// 出口文件夹,打包到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"],
  output: {
    globals: {
      vue: "Vue",
    },
  },
};
// 全量打包配置
const buildAll = async () => {
  await build({
    ...baseConfig,
    build: {
      rollupOptions,
      lib: {
        entry: path.resolve(entryDir, "index.ts"),
        name: "index",
        fileName: "index",
        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 createJson = async (name) => {
  if (name) {
    const fileStr = `
    {
      "name": "yj-components-test4-${name}",
      "main": "index.umd.js",
      "module": "index.mjs",
      "style":"styles.css"
    }
    `;
    // 输出
    fsExtra.outputFile(
      path.resolve(outDir, `${name}/package.json`),
      fileStr,
      "utf-8",
    );
  } else {
    const fileStr = `
    {
    "name":"yj-components-test4",
    "version":"1.0.1",
    "main":"index.umd.js",
    "module":"index.mjs",
    "types":"index.d.ts",
    "author":{
      "name":"yj"
    },
    "keywords":[
      "element-plus",
      "ts",
      "封装组件",
      "二次封装",
      "element-plus二次封装",
      "yj"
    ]
    }
    `;
    // 输出
    fsExtra.outputFile(
      path.resolve(outDir, `./package.json`),
      fileStr,
      "utf-8",
    );
  }
};

// 生成index.d.ts 文件

const createDTS = async (name) => {
  const fileStr = `
  import { App } from 'vue'
    declare const _default: {
      install(app: App): void
  }
  export default _default
    `;
  // 输出
  if (name) {
    fsExtra.outputFile(
      path.resolve(outDir, `${name}/index.d.ts`),
      fileStr,
      "utf-8",
    );
  } else {
    fsExtra.outputFile(path.resolve(outDir, `./index.d.ts`), fileStr, "utf-8");
  }
};
// 打包成库
const buildLib = async () => {
  await buildAll();
  await createJson();
  await createDTS();
  // 获取到组件名称组成的数组
  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 createJson(name);
    // 生成index.d.ts
    await createDTS(name);
  }
};

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/index.js'
import '../lib/index.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, "../src");
// 出口文件夹,打包到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"],
  output: {
    globals: {
      vue: "Vue",
    },
  },
};
// 全量打包配置
const buildAll = async () => {
  await build({
    ...baseConfig,
    build: {
      rollupOptions,
      lib: {
        entry: path.resolve(entryDir, "index.ts"),
        name: "index",
        fileName: "index",
        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 createJson = async (name) => {
  if (name) {
    const fileStr = `
    {
      "name": "yj-components-test4-${name}",
      "main": "index.umd.js",
      "module": "index.mjs",
      "style":"styles.css"
    }
    `;
    // 输出
    fsExtra.outputFile(
      path.resolve(outDir, `${name}/package.json`),
      fileStr,
      "utf-8",
    );
  } else {
    const fileStr = `
    {
    "name":"yj-components-test4",
    "version":"1.0.1",
    "main":"index.umd.js",
    "module":"index.mjs",
    "types":"index.d.ts",
    "author":{
      "name":"yj"
    },
    "keywords":[
      "element-plus",
      "ts",
      "封装组件",
      "二次封装",
      "element-plus二次封装",
      "yj"
    ]
    }
    `;
    // 输出
    fsExtra.outputFile(
      path.resolve(outDir, `./package.json`),
      fileStr,
      "utf-8",
    );
  }
};

// 生成index.d.ts 文件

const createDTS = async (name) => {
  const fileStr = `
  import { App } from 'vue'
    declare const _default: {
      install(app: App): void
  }
  export default _default
    `;
  // 输出
  if (name) {
    fsExtra.outputFile(
      path.resolve(outDir, `${name}/index.d.ts`),
      fileStr,
      "utf-8",
    );
  } else {
    fsExtra.outputFile(path.resolve(outDir, `./index.d.ts`), fileStr, "utf-8");
  }
};
// 打包成库
const buildLib = async () => {
  await buildAll();
  await createJson();
  await createDTS();
  // 获取到组件名称组成的数组
  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 createJson(name);
    // 生成index.d.ts
    await createDTS(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);