Monorepo项目管理,vue3+ts+antd+pinia后台管理模板搭建记录(三)

266 阅读3分钟

写在开头

之前的链接

Monorepo项目管理,vue3+ts+antd+pinia后台管理模板搭建记录(一)

Monorepo项目管理,vue3+ts+antd+pinia后台管理模板搭建记录(二)

包含内容

  1. ts方法类库打包
  2. vue3+ts组件库,按需加载打包。均使用rollup,因为不涉及到一些静态资源
  3. vue3中svg封装

正文

ts方法类库打包

当前项目文件结构如下

── packages
 ├── components
 ├── utils
 ├── project1
 └── project2

components为组件库,utils为方法库。

所需依赖

npm i rollup-plugin-typescript2 rollup rollup-plugin-commonjs rollup-plugin-eslint rollup-plugin-node-resolve @typescript-eslint/parser -D

方法库只有ts文件,所以只需要rollup基础依赖和ts依赖,还有eslint校验依赖

tsconfig.js

{
  "compilerOptions": {
    "baseUrl": ".",
    "outDir": "./lib", // 输出目录
    "sourceMap": false, // 是否生成sourceMap
    "target": "esnext", // 编译目标
    "module": "esnext", // 模块类型
    "moduleResolution": "node",
    "allowJs": false, // 是否编辑js文件
    "strict": true, // 严格模式
    "noUnusedLocals": true, // 未使用变量报错
    "experimentalDecorators": true, // 启动装饰器
    "resolveJsonModule": true, // 加载json
    "esModuleInterop": true,
    "removeComments": false, // 删除注释
    "declaration": true, // 生成定义文件
    "declarationMap": false, // 生成定义sourceMap
    "lib": [
      "esnext",
      "dom",
      "ES2015.promise",
      "ES2015"
    ], // 导入库类型定义
    "types": [
      "node"
    ] // 导入指定类型包
  },
  "include": [
    "src/*" // 导入目录
  ]
}

打包时,rollup-plugin-typescript2插件感觉有点微妙,能用但说不上来,没仔细研究,有些配置好像没有效果。

rollup.config.js

import path from 'path'
import resolve from 'rollup-plugin-node-resolve' // 依赖引用插件
import commonjs from 'rollup-plugin-commonjs' // commonjs模块转换插件
import { eslint } from 'rollup-plugin-eslint' // eslint插件
import ts from 'rollup-plugin-typescript2'
const getPath = _path => path.resolve(__dirname, _path)
import packageJSON from './package.json'

const extensions = [
  '.js',
  '.ts',
  '.tsx'
]

// ts
const tsPlugin = ts({
  tsconfig: getPath('./tsconfig.json'), // 导入本地ts配置
  extensions
})

// eslint
const esPlugin = eslint({
  throwOnError: true,
  include: ['src/**/*.ts'],
  exclude: ['node_modules/**', 'lib/**']
})

// 基础配置
const commonConf = {
  input: getPath('./src/index.ts'),
  plugins: [
    resolve(extensions),
    commonjs(),
    esPlugin,
    tsPlugin,
  ]
}
// 需要导出的模块类型
const outputMap = [
  {
    file: packageJSON.main,
    format: 'es',
  }
]

const buildConf = options => Object.assign({}, commonConf, options)

export default outputMap.map(output => buildConf({ output: { name: packageJSON.name, ...output } }))

直接引入了package.json里的一些参数,直接导出在dist文件夹下,声明文件也在同级目录。

组件库打包

组件库实现vue3+ts的按需引入

所需依赖

npm i rollup-plugin-esbuild rollup-plugin-css-only rollup-plugin-vue rollup-plugin-scss rollup-plugin-commonjs rollup-plugin-eslint rollup-plugin-node-resolve @rollup/plugin-typescript -D

这边用的ts插件是@rollup/plugin-typescript,因为rpt2在打包vue的时候一直找不到声明文件或者找不到对应module,看了issue问题还是open状态。就直接换了@rollup/plugin-typescript解决问题。

tsconfig.js

{
  "compilerOptions": {
    "baseUrl": ".",
    "outDir": "./", // 输出目录
    "sourceMap": false, // 是否生成sourceMap
    "target": "esnext", // 编译目标
    "module": "esnext", // 模块类型
    "moduleResolution": "node",
    "allowJs": false, // 是否编辑js文件
    "strict": true, // 严格模式
    "noUnusedLocals": true, // 未使用变量报错
    "experimentalDecorators": true, // 启动装饰器
    "resolveJsonModule": true, // 加载json
    "esModuleInterop": true,
    "removeComments": false, // 删除注释
    "declaration": true, // 生成定义文件
    "declarationMap": false, // 生成定义sourceMap
    "declarationDir": "./",
    "lib": [
      "esnext",
      "dom",
      "ES2015.promise",
      "ES2015"
    ], // 导入库类型定义
    "types": [
      "node"
    ] // 导入指定类型包
  },
  "include": [
    "vue.d.ts",
    "src/*" // 导入目录
  ],
  "exclude": ["node_modules", "es", "lib"]
}

这里include下多加了一个vue.d.ts,这个文件下内容如下。就是声明文件,不然打包时候会报没有module之类的错

/* eslint-disable */
declare module '*.vue' {
  import type { DefineComponent } from 'vue'
  const component: DefineComponent<{}, {}, any>
  export default component
}

以及@rollup/plugin-typescript中引入的tsconfig.js在打包时候是起作用的,注意outDir和declarationDir两个输出目录的值。

rollup.config.js

import path from 'path';
import fs from 'fs';
import esbuild from 'rollup-plugin-esbuild';
import css from 'rollup-plugin-css-only';
import vue from 'rollup-plugin-vue';
import scss from 'rollup-plugin-scss';
import commonjs from 'rollup-plugin-commonjs';
import { eslint } from 'rollup-plugin-eslint' // eslint插件
import resolve from 'rollup-plugin-node-resolve' // 依赖引用插件
import typescript from '@rollup/plugin-typescript';
const NOT_COMPS = ['index.ts', 'vue.d.ts'];

let comps = fs.readdirSync('./src');
comps = comps.filter(v => !NOT_COMPS.includes(v));

const inputComps = comps.map(fileName => ({
  input: `src/${fileName}/index.ts`,
  dir: fileName + '/'
}));

const defaultComps = [{ input: 'src/index.ts', dir: '' }];

const inputs = defaultComps.concat(inputComps);

const getPath = _path => path.resolve(__dirname, _path)

const extensions = [
  '.js',
  '.ts',
  '.tsx',
  '.vue'
]

// ts
const tsPlugin = dir =>typescript({
  tsconfig: getPath('./tsconfig.json'), // 导入本地ts配置
  declaration: dir === ''
})


// eslint
const esPlugin = eslint({
  throwOnError: true,
  include: ['src/**/*.ts'],
  exclude: ['node_modules/**', 'lib/**', 'es/**']
})

// rollup config
export default inputs.map(item => ({
  input: getPath(item.input),
  output: [
    {
      name: item.name,
      file: `es/${item.dir}index.js`,
      format: 'esm'
    },
    {
      name: item.name,
      file: `lib/${item.dir}index.js`,
      format: 'cjs',
      exports: 'named'
    }
  ],
  plugins: [
    scss(),
    css(),
    vue({
      target: 'browser',
      css: false
    }),
    commonjs(extensions),
    esbuild(),
    resolve(extensions),
    esPlugin,
    tsPlugin(item.dir),
  ],
  external: ['vue']
}));

在导入tsconfig的时候多做了一个declaration的判断,配置是按照按需引入做的,所以会对index.ts和每个文件夹都做一次打包,而声明文件只需要在index.ts打包的时候打包就可以了。

不然会导致打包后的结果里存在如下目录

── lib
 ├── SvgIcon
 │     ├── SvgIcon
 │     │    └── index.d.ts
 │     ├── index.d.ts
 │     └── index.ts
 ├── index.d.ts
 └── index.ts

但实际只需要

── lib
 ├── SvgIcon
 │     ├── index.d.ts
 │     └── index.ts
 ├── index.d.ts
 └── index.ts

svg封装

封装在了组件库了,使用了vite-plugin-svg-icons插件

vite.config.ts 配置

import { createSvgIconsPlugin } from 'vite-plugin-svg-icons'

...
  plugins: [
    ...
    createSvgIconsPlugin({
      iconDirs: [resolve(process.cwd(), 'src/assets/svg')],
      symbolId: 'icon-[dir]-[name]',
      customDomId: '__svg__icons__dom__',
    }),
  ],

SvgIcon.vue

<template>
  <svg
    :height="height"
    :width="width"
    aria-hidden="true"
  >
    <use
      :href="symbolId"
      :fill="color"
      :height="height"
      :width="width"
    />
  </svg>
</template>

<script setup name="SvgIcon" lang="ts">
  import { computed } from 'vue'
  interface Props {
    prefix?: string,
    name: string,
    color?: string,
    height?: string,
    width?: string
  }
  const props = withDefaults(defineProps<Props>(), {prefix: 'icon', color: '#ffffff', height: '16px', width: '16px'})
  const symbolId = computed(() => `#${props.prefix}-${props.name}`)
</script>

项目中使用

需要先安装项目之间的依赖,

pnpm add @test/components -r -F @test/two
<svg-icon
    height="20px"
    width="20px"
    name="usercenter"
    color="#333"
/>
<script setup lang="ts">
import { SvgIcon } from '@test/components'
</script>

结束

  1. gitee store-build分支,保存文章结束时代码状态。
  2. 基础内容基本搭建好了,组件库,工具库都有。