414 lines
11 KiB
Markdown
414 lines
11 KiB
Markdown
# 一、依赖管理
|
||
  本项目会传递安装的依赖有:
|
||
|
||
| 包名称 | 版本 | 含义和用途说明 |
|
||
|-------|------|---------------|
|
||
| `@fortawesome/fontawesome-free` | ^6.7.2 | FontAwesome 图标库的免费版本 |
|
||
| `@popperjs/core` | ^2.11.8 | 工具提示和弹出框定位引擎 |
|
||
| `axios` | ^1.4.0 | 基于 Promise 的 HTTP 客户端 |
|
||
| `compressorjs` | ^1.2.1 | 纯 JavaScript 图片压缩库 |
|
||
| `crypto-js` | ^4.2.0 | JavaScript 加密算法库 |
|
||
| `dayjs` | ^1.11.13 | 轻量级的日期处理库 |
|
||
| `echarts` | ^5.5.1 | 百度开源的数据可视化图表库 |
|
||
| `element-plus` | ^2.6.0 | 基于 Vue 3 的桌面端 UI 组件库 |
|
||
| `js-cookie` | ^3.0.5 | JavaScript Cookie 操作库 |
|
||
| `lunar-calendar` | ^0.1.4 | 农历日历转换库 |
|
||
| `lunar-javascript` | ^1.6.13 | 农历日期处理的 JavaScript 库 |
|
||
| `path-browserify` | ^1.0.1 | Node.js path 模块的浏览器版本兼容实现 |
|
||
| `qs` | ^6.13.0 | URL 查询字符串解析和序列化库 |
|
||
| `v-calendar` | ^3.1.2 | Vue.js 的日历和日期选择器组件 |
|
||
|
||
::: tip
|
||
如果使用pnpm安装,会传递peerDependencies部分。
|
||
:::
|
||
|
||
::: warning
|
||
建议将Vite、Typescript、@types等构建工具依赖放在devDependencies中。
|
||
:::
|
||
|
||
# 二、vite.config.ts配置
|
||
## 2.1 生成Typescript类型文件
|
||
  安装vite-plugin-dts插件
|
||
|
||
```cmd
|
||
pnpm add vite-plugin-dts -D
|
||
```
|
||
|
||
```typescript
|
||
import dts from 'vite-plugin-dts'
|
||
|
||
// 打包输出文件夹
|
||
const outDirPath = 'dist'
|
||
// 需要打包的类型文件
|
||
const TARGET_TYPE_FOLDERS = ['src/components', 'src/utils', 'src/types', 'src/vue3-common.ts']
|
||
|
||
export default defineConfig({
|
||
plugins: [
|
||
// 生成类型文件
|
||
dts({
|
||
// 需要处理的文件
|
||
include: TARGET_TYPE_FOLDERS,
|
||
// 使用特定的 tsconfig 配置
|
||
tsconfigPath: path.resolve(__dirname, 'tsconfig.app.json'),
|
||
// 类型文件输出目录
|
||
outDir: path.resolve(__dirname, outDirPath)
|
||
})
|
||
],
|
||
})
|
||
```
|
||
|
||
  打包后会在dist目录生成.d.ts文件,提供完整的Typescript类型支持。
|
||
|
||
## 2.2 build打包配置
|
||
```typescript
|
||
import { defineConfig } from 'vite'
|
||
import vue from '@vitejs/plugin-vue'
|
||
import dts from 'vite-plugin-dts'
|
||
import path from 'path'
|
||
import fs from 'fs'
|
||
import { ICommonObj } from './src/types'
|
||
|
||
// 打包输出文件夹
|
||
const outDirPath = 'dist'
|
||
// 需要单个打包的文件夹(组件和工具类)
|
||
const TARGET_LIB_FOLDERS = ['src/components', 'src/utils']
|
||
// 需要排除的第三方依赖
|
||
const EXTERNAL = ['vue', 'element-plus', 'echarts', 'axios', 'moment', 'crypto-js', 'spark-md5', 'path-browserify']
|
||
|
||
/**
|
||
* 递归读取文件夹下的所有文件
|
||
* @param folderPath 文件夹
|
||
*/
|
||
const getFilesFromFolder = (folderPath: string) => {
|
||
const files: string[] = []
|
||
|
||
// 读取文件夹中的内容
|
||
fs.readdirSync(folderPath).forEach((item: string) => {
|
||
const fullPath = path.join(folderPath, item)
|
||
// 读取文件状态 如果是文件夹,递归读取
|
||
if (fs.statSync(fullPath).isDirectory()) {
|
||
files.push(...getFilesFromFolder(fullPath))
|
||
} else {
|
||
// 否则添加至文件列表
|
||
files.push(fullPath)
|
||
}
|
||
})
|
||
|
||
return files
|
||
}
|
||
|
||
// 动态生成入口文件
|
||
const inputEntries = TARGET_LIB_FOLDERS.reduce((entries: ICommonObj, folder) => {
|
||
// 获取文件夹内的所有文件
|
||
const files = getFilesFromFolder(path.resolve(__dirname, folder))
|
||
|
||
files.forEach((filePath) => {
|
||
// 判断文件是否是 .vue 或 .ts 文件
|
||
if (filePath.endsWith('.vue') || filePath.endsWith('.ts')) {
|
||
// 获取相对路径并保持目录结构
|
||
const relativePath = path.relative('src', filePath)
|
||
const entryName = path.join('lib', relativePath.replace(/\.(vue|ts)$/, ''))
|
||
|
||
entries[entryName] = filePath // 为每个文件创建一个入口
|
||
}
|
||
})
|
||
|
||
return entries
|
||
}, {})
|
||
|
||
// https://vitejs.dev/config/
|
||
export default defineConfig({
|
||
build: {
|
||
// lib文件配置
|
||
lib: {
|
||
// 入口文件
|
||
entry: path.resolve(__dirname, 'src/vue3-common.ts'),
|
||
formats: ['es'],
|
||
name: 'vue3-common',
|
||
// 文件名
|
||
fileName: (format) => `vue3-common.${format}.js`
|
||
},
|
||
// 输出文件路径
|
||
outDir: outDirPath,
|
||
// 是否将css文件分割
|
||
cssCodeSplit: true,
|
||
// Rollup打包配置
|
||
rollupOptions: {
|
||
// 需要排除的依赖 通常为第三方库
|
||
external: EXTERNAL,
|
||
// 输入配置
|
||
input: {
|
||
// 入口文件
|
||
'vue3-common': path.resolve(__dirname, 'src/vue3-common.ts'),
|
||
// 其余需要单独打包的文件
|
||
...inputEntries
|
||
},
|
||
// 输出配置
|
||
output: {
|
||
dir: path.resolve(__dirname, outDirPath),
|
||
// 入口文件
|
||
entryFileNames: '[name].js',
|
||
// chunk文件
|
||
chunkFileNames: 'lib/[name].js',
|
||
// 资源文件
|
||
assetFileNames: 'styles/[name].[ext]'
|
||
}
|
||
},
|
||
// 是否压缩代码
|
||
minify: false
|
||
}
|
||
})
|
||
|
||
```
|
||
|
||
  打包后会在dist目录生成源码文件。
|
||
|
||
# 三、package.json配置
|
||
## 3.1 导出路径
|
||
```json
|
||
{
|
||
"exports": {
|
||
".": {
|
||
"import": "./dist/vue3-common.js",
|
||
"require": "./dist/vue3-common.js",
|
||
"types": "./dist/vue3-common.d.ts"
|
||
},
|
||
"./components/SvgIcon.vue": {
|
||
"import": "./dist/lib/components/SvgIcon.js",
|
||
"types": "./dist/components/SvgIcon.vue.d.ts"
|
||
},
|
||
"./styles/SvgIcon.css": "./dist/styles/SvgIcon.css",
|
||
"./components/LoginForm.vue": {
|
||
"import": "./dist/lib/components/LoginForm.js",
|
||
"types": "./dist/components/LoginForm.vue.d.ts"
|
||
},
|
||
"./styles/LoginForm.css": "./dist/styles/LoginForm.css",
|
||
"./components/MenuItem.vue": {
|
||
"import": "./dist/lib/components/MenuItem.js",
|
||
"types": "./dist/components/MenuItem.vue.d.ts"
|
||
},
|
||
"./components/MenuList.vue": {
|
||
"import": "./dist/lib/components/MenuList.js",
|
||
"types": "./dist/components/MenuList.vue.d.ts"
|
||
},
|
||
"./components/Hamburger.vue": {
|
||
"import": "./dist/lib/components/Hamburger.js",
|
||
"types": "./dist/components/Hamburger.vue.d.ts"
|
||
},
|
||
"./styles/Hamburger.css": "./dist/styles/Hamburger.css",
|
||
"./components/MultiInput.vue": {
|
||
"import": "./dist/lib/components/MultiInput.js",
|
||
"types": "./dist/components/MultiInput.vue.d.ts"
|
||
},
|
||
"./styles/MultiInput.css": "./dist/styles/MultiInput.css",
|
||
"./types": {
|
||
"types": "./dist/types/index.d.ts"
|
||
},
|
||
"./utils/axiosUtil": {
|
||
"import": "./dist/lib/utils/axiosUtil.js",
|
||
"types": "./dist/types/utils/axiosUtil.d.ts"
|
||
},
|
||
"./utils/cryptoUtil": {
|
||
"import": "./dist/lib/utils/cryptoUtil.js",
|
||
"types": "./dist/types/utils/cryptoUtil.d.ts"
|
||
},
|
||
"./utils/dataUtil": {
|
||
"import": "./dist/lib/utils/dataUtil.js",
|
||
"types": "./dist/types/utils/dataUtil.d.ts"
|
||
},
|
||
}
|
||
}
|
||
```
|
||
|
||
  在项目中引入common包后,通过配置tsconfig.json即可实现按需引入功能`import { fun1 } from 'vue3-common/utils/index'`。
|
||
```json
|
||
{
|
||
"compilerOptions": {
|
||
"baseUrl": ".",
|
||
"paths": {
|
||
"vue3-common/*": ["node_modules/vue3-common/dist/*"]
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
# 四、发布框架
|
||
1. 发布到本地
|
||
执行`npm pack`命令,会在项目文件夹下生成`.tgz`文件,其他项目通过文件路径形式引入:
|
||
```json
|
||
"vue3-common": "file:../vue3-common/vue3-common-1.0.0.tgz"
|
||
```
|
||
|
||
2. 发布到git
|
||
将dist文件夹发布到git仓库,其他项目通过git形式引入:
|
||
```json
|
||
"vue3-common": "git+https://gitee.com/Cxx0822/vue3-common#master"
|
||
```
|
||
|
||
# 五、组件使用说明
|
||
## 5.1 菜单组件
|
||
1. 安装Vue Router
|
||
```cmd
|
||
pnpm install vue-router
|
||
```
|
||
|
||
2. 在src/views文件夹中新建vue文件,例如:
|
||
```cmd
|
||
views
|
||
viewA
|
||
index.vue
|
||
viewB
|
||
index.vue
|
||
```
|
||
|
||
3. 在src/views文件夹下新建meta.ts配置文件
|
||
```typescript
|
||
import type { IRouteMetaConfig } from 'vue3-common/types'
|
||
|
||
export const metaList: IRouteMetaConfig = {
|
||
'/viewA': {
|
||
title: 'viewA',
|
||
icon: 'viewA',
|
||
order: 1,
|
||
redirect: '/viewA/index'
|
||
},
|
||
'/viewA/index': {
|
||
title: 'viewA-Index',
|
||
icon: ''
|
||
},
|
||
'/viewB': {
|
||
title: 'viewB',
|
||
icon: 'viewB',
|
||
order: 2,
|
||
redirect: '/viewB/index'
|
||
},
|
||
'/viewB/index': {
|
||
title: 'viewB-index',
|
||
icon: ''
|
||
}
|
||
}
|
||
```
|
||
|
||
  order对应的显示顺序关系,icon对应的为src/icons/svg中的svg图标文件(参考下文图标组件)。
|
||
|
||
4. 在src目录新建router文件夹,新建menu.ts文件
|
||
```typescript
|
||
import { getRoutersByModules, sortRoutesByOrder } from 'vue3-common/utils/routerUtil'
|
||
import Layout from '@/layout/index.vue'
|
||
import { metaList } from '@/views/meta'
|
||
|
||
const modules = {
|
||
...import.meta.glob('@/views/viewA/**/*.vue'),
|
||
...import.meta.glob('@/views/viewB/**/*.vue'),
|
||
}
|
||
|
||
const menuRoutes = getRoutersByModules(modules, Layout, metaList)
|
||
|
||
export default sortRoutesByOrder(menuRoutes)
|
||
```
|
||
|
||
  导入刚才的views文件夹并生成路由菜单。
|
||
|
||
5. 如果还有其他的常量路由,可以在src/router中新建constant.ts文件:
|
||
```typescript
|
||
import type { RouteRecordRaw } from 'vue-router'
|
||
|
||
const constantRoutes: RouteRecordRaw[] = [
|
||
{
|
||
path: '/',
|
||
redirect: '/login'
|
||
},
|
||
// 主页
|
||
{
|
||
path: '/login',
|
||
component: () => import('@/views/login/index.vue'),
|
||
meta: { hidden: true }
|
||
}
|
||
]
|
||
|
||
export default constantRoutes
|
||
```
|
||
|
||
  该部分即Vue Router中的路由定义。
|
||
|
||
6. 在src/router中新建index.ts:
|
||
```typescript
|
||
import { createRouter, createWebHashHistory } from 'vue-router'
|
||
import type { RouteRecordRaw } from 'vue-router'
|
||
|
||
import { setupRouteGuard } from 'vue3-common/utils/permissionUtil'
|
||
|
||
// 使用 import.meta.glob 自动导入所有 src/router 目录下的 .ts 文件
|
||
const routeModules = import.meta.glob('./*.ts', { eager: true })
|
||
|
||
// 将所有模块的默认导出(即路由配置)合并成一个路由数组
|
||
const routes: RouteRecordRaw[] = Object.values(routeModules)
|
||
.map((module: any) => module.default) // 获取每个模块的默认导出
|
||
.flat() // 扁平化数组,确保所有路由项都在一个数组中
|
||
|
||
const router = createRouter({
|
||
history: createWebHashHistory(),
|
||
scrollBehavior: () => ({ top: 0 }),
|
||
routes
|
||
})
|
||
|
||
// 设置路由守卫
|
||
setupRouteGuard(router)
|
||
|
||
export default router
|
||
```
|
||
|
||
  遍历src/router文件夹下所有的路由文件,并添加路由守卫。
|
||
|
||
7. 在main.ts中配置路由:
|
||
```ts
|
||
// 引入路由
|
||
import router from './router'
|
||
|
||
// 创建Vue3实例
|
||
const app = createApp(App)
|
||
|
||
// 使用路由
|
||
app.use(router)
|
||
```
|
||
|
||
## 5.2 图标组件
|
||
1. 安装vite-plugin-svg-icons依赖
|
||
```cmd
|
||
pnpm install vite-plugin-svg-icons -D
|
||
```
|
||
|
||
2. 配置vite.config.ts
|
||
```typescript
|
||
import { createSvgIconsPlugin } from 'vite-plugin-svg-icons'
|
||
|
||
export default defineConfig({
|
||
plugins: [
|
||
vue(),
|
||
createSvgIconsPlugin({
|
||
// 指定 SVG图标 保存的文件夹路径
|
||
iconDirs: [path.resolve(process.cwd(), 'src/icons/svg')],
|
||
// 指定 使用svg图标的格式
|
||
symbolId: 'icon-[dir]-[name]'
|
||
})
|
||
],
|
||
})
|
||
```
|
||
|
||
3. 在main.ts中注册
|
||
```typescript
|
||
// 注册svg-icon
|
||
import 'virtual:svg-icons-register'
|
||
```
|
||
|
||
4. 在src/icons/svg目录中添加svg图标
|
||
5. 在组件中使用
|
||
```vue
|
||
<template>
|
||
<svg-icon name="user"/>
|
||
</template>
|
||
|
||
<script setup>
|
||
import { SvgIcon } from 'vue3-common'
|
||
</script>
|
||
``` |