ui 分包打包上架
ui分包
目录
bash
├── packages
│ ├── ui
│ │ ├── public
│ │ ├── packages(最后把要打包的文件都放到这里面)
│ │ ├── command
│ │ ├── lib (打包后生成的)
│ │ ├── vite.config.ts
│ │ ├── package.json
│ │ ├── packages
│ │ │ ├── chooseButton
│ │ │ ├── hooks
│ │ │ ├── utils
│ │ │ ├── index.ts
│ │ │ ├── vue.d.ts
│ │ ├── src
│ │ │ ├── assets
│ │ │ ├── hooks
│ │ │ ├── utils
│ │ │ ├── styles
│ │ │ ├── router
│ │ │ ├── App.vue
│ │ │ ├── mian.ts
│ │ │ ├── components
│ │ │ │ ├── chooseButton
│ │ │ │ │ ├── lib(外部依赖)
│ │ │ │ │ ├── index.ts
│ │ │ │ │ ├── src
│ │ │ │ │ │ ├── index.vue
│ │ │ │ ├── index.ts第一步
安装vue
- cd 到packages/ui目录下
bash
npm create vite@latest安装elementuiplus
- 执行命令
npm
pnpm add element-plus -S- main.ts
ts
import { createApp } from "vue";
import "./style.css";
import App from "./App.vue";
import ElementPlus from "element-plus";
import "element-plus/dist/index.css";
const app = createApp(App);
app.use(ElementPlus);
app.mount("#app");创建command文件夹
- build.js 里面的yjtestone换成你自己的
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"],
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": "yjtestone-${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":"yjtestone",
"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();tsconfig.src.json
- 全局搜索
tsconfig.src.json里面增加include 对应的路径
json
// tsconfig.src.json
{
// 继承基础配置
"extends": "./tsconfig.base.json",
"compilerOptions": {
"composite": true,
// 组件库依赖浏览器的 DOM API
"lib": ["ESNext", "DOM", "DOM.Iterable"],
"types": ["node"]
},
"include": [
"typings/env.d.ts",
"packages/**/src",
"packages/ui/packages/hooks/**/*.ts",
"packages/ui/**/*.ts",
"src/**/*.ts"
],
"exclude": ["**/*.config.*"]
}修改package.json
json
{
"name": "ui",
"private": true,
"version": "0.0.0",
"type": "module",
"scripts": {
"dev": "vite",
"build:components": "node ./command/build.js",
"build": "npm run build:components",
"preview": "vite preview"
},
"dependencies": {
"element-plus": "^2.13.2",
"vue": "^3.5.24"
},
"devDependencies": {
"@types/node": "^24.10.1",
"@vitejs/plugin-vue": "^6.0.1",
"@vue/tsconfig": "^0.8.1",
"sass": "^1.97.3",
"typescript": "~5.9.3",
"vite": "^7.2.4",
"vue-tsc": "^3.1.4"
}
}第二步
创建组件
- 新建 src/components/index.ts
ts
import { type App } from "vue";
import YJButton from "./chooseButton";
const components = [YJButton];
export default {
install(app: App) {
components.map((item) => {
app.use(item);
});
},
};- 新建 src/components/chooseButton/index.ts
ts
import { type App } from "vue";
import YJButton from "./src/index.vue";
// 让这个组件可以通过use的形式使用
export default {
install(app: App) {
app.component("YJButton", YJButton);
},
};- 新建 src/components/chooseButton/src/index.vue
vue
<template>
<div>
<el-button type="success" @click="handleClick">{{ name }}</el-button>
</div>
</template>
<script setup lang="ts">
import { useButton } from "../../../hooks/chooseButton/useButton";
const { handleClick, name } = useButton();
</script>
<style scoped></style>- 新建hooks/chooseButton/useButton.ts
ts
import { ref, onMounted } from "vue";
export const useButton = () => {
// 名字
const name = ref("点击我");
// 点击事件
const handleClick = () => {
window.alert("弹出层");
};
onMounted(() => {
console.log("Button里面的onMounted");
});
return {
name,
handleClick,
};
};安装路由
- 安装路由
bash
npm install vue-router@next- 新建 router/router.ts
ts
// 写一个vue-router 入口文件
import { createRouter, createWebHistory } from "vue-router";
import ChooseButtonPage from "../pages/chooseButton/index.vue";
//
const routes = [
{
path: "/chooseButton",
name: "home",
component: ChooseButtonPage,
meta: { title: "按钮" }, // 可以在 meta 中存放自定义信息,如页面标题
},
];
// 创建 router 实例
const router = createRouter({
history: createWebHistory(import.meta.env.BASE_URL), // 使用 HTML5 模式
routes,
});
// 全局前置守卫
router.beforeEach((to, from, next) => {
// 设置页面标题
document.title = `${to.meta.title || "默认标题"} - 我的网站`;
// 这里可以添加登录验证逻辑
// const isAuthenticated = checkAuth()
// if (to.name !== 'Login' && !isAuthenticated) next({ name: 'Login' })
// else next()
next();
});
// 全局后置钩子
router.afterEach(() => {
// 完成导航后的逻辑,例如页面滚动到顶部
window.scrollTo(0, 0);
});
export default router;新建pages/chooseButton/index.vue
vue
<template>
<div>
<YJButton></YJButton>
</div>
</template>
<script setup lang="ts"></script>引用
- main.ts
ts
import { createApp } from "vue";
import App from "./App.vue";
import router from "./router/router";
import ComponentsAll from "./components";
const app = createApp(App);
app.use(router);
app.use(ComponentsAll);
app.mount("#app");App.vue
vue
<template>
<div>
<router-view></router-view>
</div>
</template>新建src/utils/tools.ts
ts
// 写一个生成年月日的函数 不足双位 前面补0 就是测试打包
export const formatDate = (date: Date) => {
const year = date.getFullYear();
const month = date.getMonth() + 1;
const day = date.getDate();
return `${year}-${month < 10 ? `0${month}` : month}-${day < 10 ? `0${day}` : day}`;
};搬家
把components下面的所有文件复制一份搬到ui/packages下面
把 hooks 下面的的所有文件复制一份搬到ui/packages/hooks下面
把 utils 下面的的所有文件复制一份搬到ui/packages/utils下面
把 styles 下面的的所有文件复制一份搬到ui/packages/styles下面
ui/packages/vue.d.ts
ts
/// <reference types="vite/client" />
declare module "*.vue" {
import { DefineComponent } from "vue";
const component: DefineComponent<{}, {}, any>;
export default component;
}第三步 打包
- 根目录 执行
bash
npm run build发布
打包成功后这个时候在ui下面会多了一个文件夹叫做lib
cd 到packages/ui
执行命令
bash
npm publish ./lib本地使用
本地安装
- apps/web下面安装vue,element-plus 等等
安装包
bash
npm install 文件路径到你的那个lib文件夹 例如 (D:\Code\MyCode\testelement1\packages\ui\lib)使用
- main.ts
ts
import { createApp } from "vue";
import "./style.css";
import App from "./App.vue";
import ElementPlus from "element-plus";
import "element-plus/dist/index.css";
// yjtestone 换成你那个包的名字
import CustomComponents from "yjtestone/index.js";
const app = createApp(App);
app.use(ElementPlus);
app.use(CustomComponents);
app.mount("#app");- 组件目录使用
vue
<template>
<div>
<YJButton></YJButton>
</div>
</template>
<script setup lang="ts"></script>