文章目录

    • 沉淀自己的pro-table组件,并发布到npm
      • Quick Start
      • 开发过程笔记
      • add TS Support
    • 参考资料

沉淀自己的pro-table组件,并发布到npm

传送门

约定:npm包名vue3-el-pro-table,引用vue3-el-pro-table的包名为“本项目”。

声明:Vue3ProTable.vue代码是在这个项目的基础上进行修改的。

作者:hans774882968以及hans774882968以及hans774882968

Quick Start

yarn add vue3-el-pro-table

src/main.ts

import 'vue3-el-pro-table/dist/vue3-el-pro-table.css';import Vue3ProTable from 'vue3-el-pro-table';createApp(App).use(Vue3ProTable).mount('#app');

Then use directly in .vue file.

Import interface:

import { Vue3ProTableProps } from 'vue3-el-pro-table';

Component props definition:

export declare interface Vue3ProTableProps {request: (...args: any[]) => Promise<{ data: object[], total: number }>// 表格标题title?: string// 是否隐藏标题栏hideTitleBar?: boolean// 搜索表单配置,false表示不显示搜索表单search?: boolean | objectborder?: boolean// 表头配置columns?: object[]// 行数据的Key,同elementUI的table组件的row-keyrowKey?: string// 分页配置,false表示不显示分页pagination?: boolean | objecttree?: object// The above attributes are all from https://github.com/huzhushan/vue3-pro-table. The following properties are added by me.loadTableDataBeforeMount?: booleanblockRedundantRequestOnReset?: booleanpaddingLeft?: string | numberpaddingRight?: string | number}

Plz refer to https://github.com/huzhushan/vue3-pro-table for instructions on how to use vue3-el-pro-table.

开发过程笔记

根据参考链接3,实际上我们只需要提供一个符合Vue插件格式的入口install.js,和一个Vue组件。但为了满足npm包迭代过程中的预览、测试等需求,我们仍然需要以组件库的标准来开发这个npm包。因此我采用的方案是:先使用vue-cli快速创建一个项目,满足组件的预览、测试等需求,在此基础上再新增一个构建流程。

  1. 使用vue-cli创建一个普通的Vue3 + TS项目。
  2. 新增组件src/components/Vue3ProTable.vue
  3. 新增Vue插件入口src/install.js
import HelloWorld from './components/HelloWorld.vue';import Vue3ProTable from './components/Vue3ProTable.vue';function install(app) {if (install.installed) return;install.installed = true;app.component('test-hello-world', HelloWorld); // 顺便把脚手架生成的组件也注册为全局组件app.component('vue3-pro-table', Vue3ProTable);}Vue3ProTable.install = install;export default { install };
  1. 新增build-lib命令并运行yarn build-lib——这就是vue3-el-pro-table生成Vue插件的构建命令:
{"scripts": {"build": "vue-cli-service build", // 作为对比"build-lib": "vue-cli-service build --target lib --name vue3-el-pro-table ./src/install.js" // 参考:https://cli.vuejs.org/guide/build-targets.html#library},}
  1. 构建成功后修改package.json修改下入口:
{"main": "dist/vue3-el-pro-table.umd.js",}

在另一个项目(即本项目)预览最新改动:

yarn add file:../vue3-el-pro-table

接下来开始踩坑了。当引入的组件使用slot的时候会报错:

Cannot read properties of null (reading 'isCE')

根据参考链接2,原因是本项目和vue3-el-pro-table各有一个vue,即使它们版本相同也会引起冲突。虽然参考链接2的提问说给webpack添加vue配置无济于事,但我的项目用这个配置是可以解决问题的。

在本项目的vue.config.js禁用symlinks并alias vue:

const { defineConfig } = require('@vue/cli-service');const path = require('path');module.exports = defineConfig({chainWebpack(config) {config.resolve.symlinks(false);config.resolve.alias.set('vue', path.resolve('./node_modules/vue'));},devServer: {port: 8090,},transpileDependencies: true,});

add TS Support

为了防止本项目报TS错误,我们的npm包vue3-el-pro-table需要给出.d.ts文件。

  1. 本项目package.json指定类型定义文件路径:
{"types": "dist/global.d.ts"}
  1. 本项目tsconfig.json新增配置:
{"compilerOptions": {"types": ["webpack-env","jest","vue3-el-pro-table/dist/global.d.ts", // 获取 vue3-el-pro-table 注册的全局组件的类型提示"element-plus/global.d.ts" // 获取 element-plus 组件的类型提示],}}

global.d.ts不应该放在dist目录,因此我把它放到了src/global.d.ts,并配置CopyWebpackPluginvue3-el-pro-tablevue.config.js

const { defineConfig } = require('@vue/cli-service');const path = require('path');const CopyWebpackPlugin = require('copy-webpack-plugin');module.exports = defineConfig({configureWebpack: {plugins: [new CopyWebpackPlugin({patterns: [{from: path.resolve(__dirname, 'src', 'global.d.ts'),to: path.resolve(__dirname, 'dist'),},],}),],},transpileDependencies: true,});

最理想的情况下dist/global.d.ts能在编译时直接生成,但可惜我们参考的Vue3ProTable.vue不是一个TS组件,且改造为TS组件的工作量过大,因此global.d.ts是手动维护的,传送门。

我们期望dist/global.d.ts能够给组件提供类型提示。根据参考链接4,需要以下代码:

declare const CVue3ProTable: import('vue').DefineComponent<......>;declare const CHelloWorld: import('vue').DefineComponent<{msg: StringConstructor;}, unknown, unknown, object, object, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, object, string, import('vue').VNodeProps & import('vue').AllowedComponentProps & import('vue').ComponentCustomProps, Readonly<import('vue').ExtractPropTypes<{msg: StringConstructor;}>>, object, object>;declare module 'vue' {export interface GlobalComponents {Vue3ProTable: typeof CVue3ProTableTestHelloWorld: typeof CHelloWorld}}

这里的CVue3ProTable, CHelloWorld看上去很复杂,不会是手写的吧?的确不是手写的,可以让vue-tsc生成。首先安装vue-tsc并新增命令:

{"gen-declaration": "vue-tsc -p tsconfig.declaration.json"}

然后新增tsconfig.declaration.json

{"extends": "./tsconfig.json","compilerOptions": {"outDir": "es","declaration": true,"emitDeclarationOnly": true},"include": ["src"],"exclude": ["node_modules", "**/__tests__/**", "**/__demos__/**", "**/*.md"]}

最后执行yarn gen-declaration,把组件的类型定义复制到global.d.ts即可。

参考资料

  1. 声明式 UI 介绍:https://flutter.cn/docs/get-started/flutter-for/declarative
  2. Cannot read properties of null (reading ‘isCE’):https://stackoverflow.com/questions/71063992/when-importing-self-made-vue-3-library-into-vue-3-project-uncaught-typeerror
  3. 在 NPM 上创建并发布您的第一个 Vue.JS 插件:https://5balloons.info/create-publish-you-first-vue-plugin-on-npm-the-right-way/
  4. 全局组件类型声明的最佳实践 (Vue3+TS+Volar):https://juejin.cn/post/7066730414626308103