沉淀自己的pro-table组件,并发布到npm(Vue3、element-plus)

沉淀自己的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
yarn add vue3-el-pro-table
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');
import 'vue3-el-pro-table/dist/vue3-el-pro-table.css';
import Vue3ProTable from 'vue3-el-pro-table';



createApp(App)
  .use(Vue3ProTable)
  .mount('#app');
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 <vue3-pro-table /> directly in .vue file.

Import interface:

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

Plz refer to github.com/huzhushan/v… 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 };
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 };
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
},
}
{





  "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
  },
}
{ "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",
}
{





  "main": "dist/vue3-el-pro-table.umd.js",
}
{ "main": "dist/vue3-el-pro-table.umd.js", }

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

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

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

Cannot read properties of null (reading 'isCE')
Cannot read properties of null (reading 'isCE')
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,
});
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,
});
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"
}
{





  "types": "dist/global.d.ts"
}
{ "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 组件的类型提示
],
}
}
{





  "compilerOptions": {
    "types": [
      "webpack-env",
      "jest",
      "vue3-el-pro-table/dist/global.d.ts", // 获取 vue3-el-pro-table 注册的全局组件的类型提示
      "element-plus/global.d.ts" // 获取 element-plus 组件的类型提示
    ],
  }
}
{ "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,
});
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,
});
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 CVue3ProTable
TestHelloWorld: typeof CHelloWorld
}
}
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 CVue3ProTable
    TestHelloWorld: typeof CHelloWorld
  }
}
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 CVue3ProTable TestHelloWorld: typeof CHelloWorld } }

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

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





  "gen-declaration": "vue-tsc -p tsconfig.declaration.json"
}
{ "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"]
}
{





  "extends": "./tsconfig.json",
  "compilerOptions": {
    "outDir": "es",
    "declaration": true,
    "emitDeclarationOnly": true
  },
  "include": ["src"],
  "exclude": ["node_modules", "**/__tests__/**", "**/__demos__/**", "**/*.md"]
}
{ "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 介绍:flutter.cn/docs/get-st…
  2. Cannot read properties of null (reading ‘isCE’):stackoverflow.com/questions/7…
  3. 在 NPM 上创建并发布您的第一个 Vue.JS 插件:5balloons.info/create-publ…
  4. 全局组件类型声明的最佳实践 (Vue3+TS+Volar):juejin.cn/post/706673…

© 版权声明
THE END
喜欢就支持一下吧
点赞0

Warning: mysqli_query(): (HY000/3): Error writing file '/tmp/MYSBXY6j' (Errcode: 28 - No space left on device) in /www/wwwroot/583.cn/wp-includes/class-wpdb.php on line 2345
admin的头像-五八三
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

图形验证码
取消
昵称代码图片