继上一篇创建项目以及ESLint+Prettier配置,今天是第二篇,组件库基础结构搭建,以及一些配置项配置情况。

八、搭建组件库基础结构

步骤1:创建目录结构

在src下创建以下目录:

src/
├── components/       # 公共组件目录
│   ├── Button/       # 示例组件(按钮)
│   │   ├── index.ts  # 组件导出
│   │   ├── Button.vue # 组件源码
│   ├── index.ts      # 所有组件统一导出
├── types/            # 类型定义目录
│   ├── index.d.ts    # 全局类型
├── styles/           # 全局样式
│   ├── index.scss    # 样式入口(可安装sass支持)
├── index.ts          # 组件库入口(供外部引入)

步骤2:安装Sass(这里我使用得是Sass,可以根据自己喜好选择样式预处理)

pnpm add -D sass@latest

步骤3:编写示例组件(Button)

  • src/components/Button/Button.vue:
<template>
  <button
    class="v-btn"
    :class="[{ 'v-btn--primary': type === 'primary' }, { 'v-btn--default': type === 'default' }]"
    :disabled="disabled"
    @click="handleClick"
  >
    <slot />
  </button>
</template>

<script setup lang="ts">
//定义Props
const props = defineProps({
  type: {
    type: String,
    default: 'default',
    validator: (val: string) => ['primary', 'default'].includes(val),
  },
  disabled: {
    type: Boolean,
    default: false,
  },
});

//定义事件
const emit = defineEmits<{
  click: [e: MouseEvent];
}>();

//点击事件
const handleClick = (e: MouseEvent) => {
  if (!props.disabled) {
    emit('click', e);
  }
};

</script>

<style scoped lang="scss">
.v-btn {
  padding: 8px 16px;
  border: none;
  border-radius: 4px;
  cursor: pointer;
  transition: background-color 0.2s;

  &--default {
    background: #f5f5f5;
    color: #333;

    &:hover {
      background: #e5e5e5;
    }
  }

  &--primary {
    background: #409eff;
    color: #fff;

    &:hover {
      background: #66b1ff;
    }
  }

  &:disabled {
    opacity: 0.6;
    cursor: not-allowed;
  }
}
</style>
  • src/components/Button/index.ts:
import Button from './Button.vue';
import type { App } from 'vue';

//注册组件
Button.install = (app: App) => {
  app.component(Button.name || 'VButton', Button);
};

export default Button;
  • src/components/index.ts(统一导出所有组件):
import Button from './Button';
import type { App, Component } from 'vue';

// 组件列表
const components: Component[] = [Button];

// 全局注册插件
const install = (app: App) => {
  components.forEach((component) => {
    app.component(component.name || component.__name || '', component);
  });
};

// 导出单个组件 + 全局安装方法
export { Button };
export default { install };
  • src/index.ts(组件库入口):
import * as components from './components';
import './styles/index.scss';

export * from './components';

//全局安装方法
const install = (app: any) => {
  Object.values(components).forEach((component) => {
    if (component.install) {
      app.use(component);
    }
  });
};

export default { install };

九、添加脚本命令(package.json)

修改package.json得scripts:

{
  "name": "@bruce_cao/vue3-component-library",
  "private": false,
  "version": "0.0.9",
  "type": "module",
  "scripts": {
    "dev": "vite",
    "build": "vite build && echo '开始生成类型声明' && vue-tsc",
    "build:types": "vue-tsc --noEmit false --declaration true --emitDeclarationOnly true",
    "preview": "vite preview",
    "lint": "eslint . --fix --debug",
    "lint:check": "eslint .",
    "format": "prettier --write \"src/**/*.{vue,ts,scss}\"",
    "test": "vitest run",
    "test:watch": "vitest",
    "test:coverage": "vitest run --coverage",
    "docs:dev": "vitepress dev docs",
    "docs:build": "vitepress build docs",
    "docs:preview": "vitepress preview docs"
  },
  "dependencies": {
    "vue": "^3.5.24"
  },
  "devDependencies": {
    "@eslint/js": "^9.39.2",
    "@types/jest": "^30.0.0",
    "@types/node": "^25.0.3",
    "@typescript-eslint/eslint-plugin": "^8.50.0",
    "@typescript-eslint/parser": "^8.50.0",
    "@vitejs/plugin-vue": "^6.0.1",
    "@vitest/coverage-v8": "^4.0.16",
    "@vue/test-utils": "^2.4.6",
    "@vue/tsconfig": "^0.8.1",
    "eslint": "^9.39.2",
    "eslint-config-prettier": "^10.1.8",
    "eslint-plugin-prettier": "^5.5.4",
    "eslint-plugin-vue": "^10.6.2",
    "happy-dom": "^20.0.11",
    "markdown-it": "^14.1.0",
    "markdown-it-container": "^4.0.0",
    "prettier": "^3.7.4",
    "sass": "^1.97.0",
    "typescript": "~5.9.3",
    "vite": "^7.2.4",
    "vitepress": "^1.6.4",
    "vitest": "^4.0.16",
    "vue-eslint-parser": "^10.2.0",
    "vue-tsc": "^3.1.4"
  },
  "main": "./dist/vue3-component-library.umd.js",
  "module": "./dist/vue3-component-library.es.js",
  "types": "./dist/types/index.d.ts",
  "files": [
    "dist"
  ],
  "peerDependencies": {
    "vue": "^3.0.0"
  },
  "license": "MIT",
  "repository": {
    "type": "git",
    "url": "https://jihulab.com/chj_158-group/vue3-component-library.git"
  },
  "keywords": ["vue3", "Component library", "ts", "vite"],
  "author": "bruce_cao 15833355879@163.com"
}

tips:上图包含了之后项目文档,以及单元测试,eslint等相关命令,在这我先统一把所有命令放出来,后期逐个命令都会有解释作用得。

十、测试项目

步骤1:开发模式运行

pnpm dev
  • 修改src/App.vue引入Button组件测试:
<script setup lang="ts">
import { Button as VButton } from '@/components';

const handleClick = () => {
  console.log('按钮点击');
};
</script>

<template>
  <div>
    <VButton type="primary" @click="handleClick">主要按钮</VButton>
    <VButton type="default" disabled>禁用按钮</VButton>
  </div>
</template>

步骤2:代码检查与格式化

pnpm lint # 检查并修复ESLint错误
pnpm format # 格式化代码

步骤3:打包组件库

pnpm build
  • 打包完成后会生成dist目录,包含:
  1. ES模块版本(*.es.js)
  2. UMD版本(*.umd.js)
  3. 类型声明文件(若配置了vue-tsc)

常见问题解决:

        1、如果ESLint报错“parserOptions.parser”无效:确保eslint.config.js中parser为vue-eslint-parser, parserOptions.parser为@typescript-eslint/parser.

        2、路径别名不生效:Vite 和 TS 的paths配置需一致,且安装@types/node。

        3、Prettier格式化不生效:检查.preitterrc.cjs配置,确保eslint-plugin-prettier已安装并加入extends。

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐