组件库环境搭建及封装组件

250 阅读3分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第1天,点击查看活动详情

在完成了一个项目,去做另一个项目时,会用到重复的组件,我们可以去打开上一个工程,把组件代码拷过来,再重新调整数据,这样会很麻烦,随着项目的越来越多,也不好定位哪个项目中使用了可复用的组件,所以业务组件库就发挥了它的优势,直接安装好后,按需引入,不用再手搬代码。本篇文章会讲述如何从0-1搭建自己的组件库。

技术栈:

  • Vue3
  • TypeScript
  • pnpm

1 环境准备

在cmd终端安装pnpm

npm install pnpm -g

创建工程目录:vue3-components。

用vscode打开工程目录,在vscode终端执行:

pnpm init

根目录新建.npmrc文件,写入下面的语句,作用是与项目不直接相关的不会安装在node modules下:

shamefully-hoist = true

在根目录安装依赖:

pnpm install vue@next typescript -D

配置tsconfig.json:

{
  "compilerOptions": {
    "module": "esnext",
    "declaration": false,
    "noImplicitAny": false,
    "removeComments":true,
    "esModuleInterop": true,
    "moduleResolution": "node",
    "jsx": "preserve",
    "noLib": false,
    "target": "es2018",
    "sourceMap": true,
    "lib": ["esnext", "DOM"],
    "allowSyntheticDefaultImports": true,
    "experimentalDecorators": true,
    "forceConsistentCasingInFileNames": true,
    "resolveJsonModule": true,
    "strict": true,
    "skipLibCheck": true,
  },
  "exclude": [
    "node_modules",
    "dist/**",
    "**/__tests__",
  ]
}

根目录新建pnpm-workspace.yaml文件,写入:

packages:
  - "packages/**" # 存放编写的组件
  - play # 使用组件的地方

2 项目创建

在根目录新建paly目录,进入play,执行:pnpm init, 修改package.json文件配置:

{
  "name": "@vue3-components/play",
  "private": true,
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "liuhp",
  "license": "ISC"
}

在play目录下安装依赖:

pnpm install vite @vitejs/plugin-vue -D

在play目录下新建vite.config.ts, 写入:

import { defineConfig } from "vite"
import vue from "@vitejs/plugin-vue"

export default defineConfig({
  plugins: [vue()],
})

新建index.html,写入:

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>

<body>
  <div id="app"></div>
  <script src="/main.ts" type="module"></script>
</body>
</html>

新建app.vue, 写入:

<template>
  <div>测试</div>
</template>

新建main.js, 写入:

import { createApp } from "vue"
import App from "./app.vue"

const app = createApp(App)
app.mount("#app")

main.ts此时会提示:

image.png

所以我们在vue3-components根目录下新建typings文件夹,在typings下新建vue-shim.d.ts文件,写入:

declare module "*.vue" {
  import type { DefineComponent } from "vue"
  const component: DefineComponent<{}, {}, any>
  export default component
}

此时,main.ts就不会报错了。 修改package.json里script的命令:

"scripts": {
    "dev": "vite"
  },

然后就可以在play目录下运行npm run dev, 为了能够在vue3-components根目录下直接运行play项目,需要修改vue3-components根目录下的package.json里script的命令:

"scripts": {
   "dev": "pnpm -C play dev"
 },

就可以在vue3-components根目录下直接运行npm run dev了。

3 封装组件

3.1创建三个文件夹

packages下建立3个文件夹:

  • components:存放封装的组件;
  • utils: 存放公共方法;
  • theme-chalk: 存放公共样式;

这三个文件夹下都要执行pnpm init,为package.json中的name起好名字(后面安装需要用这个名字),都是独立包,可以独立发布。

然后在vue3-components根目录下安装这三个包,例如:pnpm install @vue3-components/components -w -w是安装在根目录下,安装好后根目录下的package.json如下:

image.png

3.2封装组件:

在packages\components\下新建组件文件夹,这里以v-form为例:

image.pngv-form.vuev-form.ts中封装好组件,也可以先随便写点,方便测试,README.md中,写好参数说明。index.ts中:

import vform from "./src/v-form.vue"
import { withInstall } from "@vue3-components/utils/with-install"

const VForm = withInstall(vform)

export default VForm

packages\utils\with-install.ts:

import type { App, Plugin } from "vue" // 只导入类型,不是值

export type SFCWithInstall<T> = T & Plugin

export const withInstall = <T>(comp: T) => {
  (comp as SFCWithInstall<T>).install = function (app: App) {
    app.component((comp as any).name, comp)
  }
  return comp as SFCWithInstall<T>
}

验证封装组件是否生效

play\main.ts全局引入组件:

import { createApp } from "vue"
import App from "./app.vue"
import ElementPlus from "element-plus"
import "element-plus/dist/index.css"

import VForm from "@vue3-components/components/v-form"

const app = createApp(App)
app.use(ElementPlus)
app.use(VForm)
app.mount("#app")

play\app.vue中使用组件:

<template>
  <div>测试</div>
  <v-form :elements="forms" @search="search"></v-form>
</template>
<script lang="ts" setup>
const forms = [
  {
    label: "角色标识",
    prop: "roleCode",
    placeholder: "角色标识",
  },
  {
    label: "角色名称",
    prop: "roleName",
    placeholder: "分组名称",
  },
  {
    label: "产品",
    prop: "productCode",
    placeholder: "产品",
    type: "select",
    optionGroup: true,
    options: [],
    style: "width:100%;",
  },
  {
    label: "创建时间",
    prop: "create_at_start,create_at_end",
    type: "datetimerange",
    defaultValue: [],
    startPlaceholder: "选择开始时间",
    endPlaceholder: "选择结束时间",
    valueFormat: "yyyy-MM-dd HH:mm:ss",
    layout: {
      lg: {
        span: 8,
      },
      md: {
        span: 12,
      },
      sm: {
        span: 24,
      },
      xs: {
        span: 24,
      },
    },
  },
]

const search = (params) => {
  console.log(params)
}
</script>

至此,组件封装完成,接下来需要解决的问题是如何抽离公共样式,随着组件库中组件越来越多,一些重复的样式需要抽离出来,抽离完公共样式后,再解决打包和发布问题,发布后才能在其他项目中安装使用。