基于Vite搭建Vue3.x组件库

310 阅读2分钟

简介

本文主要讲述如何使用 Vite + Vue3.x + Typescript 从零搭建组件库。

仓库地址 - github,欢迎使用和点亮小星星。

yoo-ui-pro - npm

初始化项目

通过 vue3-base-project 快速搭建项目,详细过程可看之前的文章 从零搭建Vue3.x项目工程环境

调整目录结构

增加 examples文件夹

用于本地开发时预览使用。

增加 packages文件夹

用于放置具体封装的组件。

修改 vite.config.json配置

export default defineConfig({
  base: './',
  root: join(__dirname, '../examples'),
  resolve: {
    alias: {
      '@': resolve(__dirname, '../'),
      '@packages': resolve(__dirname, '../packages'),
      '@examples': resolve(__dirname, '../examples'),
      '@yui': resolve(__dirname, '../packages'),
    },
  },
});

编写组件

单个组件目录结构

packages/components目录下创建一个 FullScreenIcon组件,结构如下

├── FullScreenIcon
│   ├── index.ts
│   └── src
│       ├── index.less
│       └── index.vue

具体代码如下

编写 packages/components/FullScreenIcon/src/index.vue文件

<script lang="tsx">
import { defineComponent } from 'vue';
import { FullScreen } from '@element-plus/icons-vue';
import { ElMessage } from 'element-plus';
import screenfull from 'screenfull';
​
export default defineComponent({
  name: 'FullScreenIcon',
  components: {
    FullScreen,
  },
  setup() {
    // 全屏
    const onFullScreen = () => {
      if (screenfull.isEnabled) {
        screenfull.toggle();
      } else {
        ElMessage.warning({
          message: '抱歉,当前浏览器不支持该全屏功能,可尝试使用F11触发全屏',
          type: 'warning',
        });
      }
    };
​
    return () => {
      return (
        <el-icon onClick={onFullScreen}>
          <full-screen />
        </el-icon>
      );
    };
  },
});
</script><style lang="less">
@import url('./index.less');
</style>

编写公共install方法packages/utils/install.ts

import type { App, Plugin } from 'vue';
​
export const install = <T>(main: T) => {
  (main as T & Plugin).install = (Vue: App) => {
    // @ts-ignore
    Vue.component(main.name, main);
  };
  return main;
};
​

编写组件导出 packages/components/FullScreenIcon/index.ts

import { install } from '@yui/utils/install';
import FullScreenIcon from './src/index.vue';
​
export const YFullScreenIcon = install(FullScreenIcon);
export default YFullScreenIcon;
​
export * from './src/index.vue';

导出所有组件

新建并编写 packages/index.ts文件

import components, { ProTable, FullScreenIcon } from './components';
import type { App } from 'vue';
const pkg = require('../package.json');
​
interface OptsType {}
​
/**
 * 全局注册使用
 * @param Vue Vue
 * @param opts 配置项参数
 */
const install = (Vue: App, opts?: OptsType) => {
  // @ts-ignore
  if (install.installed) return;
​
  Object.keys(components).forEach((key: string) => {
    Vue.component(key, components[key]);
  });
};
​
// script标签引入
// @ts-ignore
if (typeof window !== 'undefined' && window.Vue) {
  // @ts-ignore
  install(window.Vue);
}
​
export { ProTable, FullScreenIcon };
​
export default {
  version: pkg.version,
  install,
};

打包组件库

编写打包配置

import { defineConfig } from 'vite';
import vue from '@vitejs/plugin-vue';
import { resolve } from 'path';
import Components from 'unplugin-vue-components/vite';
import { ElementPlusResolver } from 'unplugin-vue-components/resolvers';
import vueJsx from '@vitejs/plugin-vue-jsx';
import dts from 'vite-plugin-dts';
​
const pkg = require('../package.json');
​
export default defineConfig({
  build: {
    outDir: 'lib',
    minify: true,
    lib: {
      name: 'yoo-ui-pro',
      entry: resolve(__dirname, '../packages/index.ts'),
      // formats: ['es', 'cjs', 'umd'],
      formats: ['es', 'umd'],
      fileName: (format) => `${pkg.name}.${format}.js`,
    },
    rollupOptions: {
      external: ['vue', 'vue-router'],
      input: [resolve(__dirname, '../packages/index.ts')],
      output: {
        globals: {
          vue: 'Vue',
        },
      },
    },
  },
  resolve: {
    alias: {
      '@yui': resolve(__dirname, '../packages'),
    },
  },
  plugins: [
    vue(),
    vueJsx(),
    Components({
      resolvers: [ElementPlusResolver()],
      directoryAsNamespace: true,
    }),
    dts({
      entryRoot: resolve(__dirname, '../packages'),
    }),
  ],
});
​

修改 package.json

{
  "name": "yoo-ui-pro",
  "version": "0.20.0",
  "keywords": [
    "component library",
    "ui",
    "vue",
    "yoo-ui"
  ],
  "main": "lib/yoo-ui-pro.umd.js",
  "module": "lib/yoo-ui-pro.es.js",
  "exports": {
    ".": {
      "require": "./lib/yoo-ui-pro.umd.js",
      "import": "./lib/yoo-ui-pro.es.js",
      "types": "./lib/index.d.ts"
    },
    "./*": "./*"
  },
  "types": "lib/index.d.ts",
  "files": [
    "lib",
    "README",
    "LICENSE",
    "CHANGELOG.md"
  ],
  "scripts": {
    "dev": "vite -c ./build/dev.config.ts",
    "build": "vue-tsc --noEmit && vite build",
    "build:lib": "vite build -c ./build/lib.build.ts",
    "serve": "vite preview",
    "lint": "eslint . --ext .js,.ts,.tsx,.vue --ignore-path .eslintignore",
    "prepare": "husky install",
    "lint:style": "stylelint "src/**/*.(less|css)" --customSyntax postcss-less",
    "prepublishOnly": "npm run build:lib"
  }
}

执行打包

# 执行命令
npm run build:lib

# 成功后会在根目录生成 lib 文件夹,结构如下
.
├── components
│   ├── FullScreenIcon
│   │   ├── index.d.ts
│   │   └── src
│   │       └── index.vue.d.ts
│   └── index.d.ts
├── favicon.ico
├── index.d.ts
├── style.css
├── utils
│   └── install.d.ts
├── yoo-ui-pro.es.js
└── yoo-ui-pro.umd.js

发布到npm

注册npm账号

npm官网

登陆

npm login 

发布包

npm publish

总结

到此讲完了如何搭建属于自己的组件库的过程,目前组件文档还是单纯的Markdown进行编写记录,后续将会增加 vitepress生成组件库文档。

本文有错误的地方欢迎大家指正哈,谢谢大家的支持!