Vue3.x基于TSX封装组件发布npm问题

darkCode
  • 1.8k

公司一个项目是基于vue3.x+ant-design-vue+typescript去做开发,而且是基于微前端框架,很多子应用都会公用一些常用的公共组件。所以就想着将这些公共组件封装起来发布到npm进行管理,更加方便些。

二次封装的库名叫hc-ui-cli。相关目录文件如下:

vue.config.js代码内容如下:

const path = require('path');
module.exports = {
  pages: {
    index: {
      // page 的入口
      entry: 'examples/main.ts',
      // 模板来源
      template: 'examples/index.html',
      // 在 dist/index.html 的输出
      filename: 'index.html',
    },
  },
    css: {
    loaderOptions: {
      less: {
        lessOptions: {
          modifyVars: {
          },
          javascriptEnabled: true,
        },
      }
    }
  },
  // 扩展 webpack 配置
  chainWebpack: (config) => {
    config.resolve.alias.set("~", path.resolve("components"));
    // 没有任何具名导出并直接暴露默认导出
    config.output.libraryExport('default');
  },
}

package.json文件代码如下:

{
  "name": "hc-ui-cli",
  "version": "0.1.8",
  "private": false,
  "main": "./dist/hc-ui-cli.umd.min.js",
  "scripts": {
    "serve": "vue-cli-service serve",
    "build": "vue-cli-service build",
    "lib": "vue-cli-service build --target lib --name hc-ui-cli components/index.ts",
    "lint": "vue-cli-service lint"
  },
  "dependencies": {
    "core-js": "^3.6.5",
    "hc-ui-cli": "./hc-ui-cli-0.1.8.tgz",
    "vue": "^3.0.0"
  },
  "devDependencies": {
    "@typescript-eslint/eslint-plugin": "^4.18.0",
    "@typescript-eslint/parser": "^4.18.0",
    "@vue/babel-plugin-jsx": "^1.0.6",
    "@vue/cli-plugin-babel": "~4.5.0",
    "@vue/cli-plugin-eslint": "~4.5.0",
    "@vue/cli-plugin-typescript": "~4.5.0",
    "@vue/cli-service": "~4.5.0",
    "@vue/compiler-sfc": "^3.0.0",
    "@vue/eslint-config-typescript": "^7.0.0",
    "ant-design-vue": "^2.2.4",
    "babel-eslint": "^10.1.0",
    "babel-plugin-import": "^1.13.3",
    "eslint": "^6.7.2",
    "eslint-plugin-vue": "^7.0.0",
    "less": "^3.13.0",
    "less-loader": "^7.1.0",
    "typescript": "~4.1.5",
    "vue-types": "^4.0.3"
  }
}

components目录下新建了xhPagnition(分页组件)目录,用来存放分页组件。组件名index.tsx。代码如下:

import { defineComponent, ref, Ref, ExtractPropTypes } from "vue";
import PropTypes from "../_utils/vue-types";
import { withInstall } from "../_utils/type";
const xhPaginationProps = {
  pageSize: PropTypes.number.def(20).isRequired,
  total: PropTypes.number.def(0).isRequired,
};
const XhPagination = defineComponent({
  name: "XhPagination",
  props: xhPaginationProps,
  setup(props, { emit }) {
    const pageNum: Ref<number> = ref<number>(1);
    const pageSizeOptions: Ref<string[]> = ref<string[]>(["10", "20", "50"]);
    const onShowSizeChange = (page: number, size: number) => {
      emit("onShowSizeChange", page, size);
    };
    const onChangePage = (pageNumber: number) => {
      emit("onChangePage", pageNumber);
    };
    return {
      pageSizeOptions,
      pageNum,
      onShowSizeChange,
      onChangePage,
    };
  },
  render() {
    const { pageSizeOptions, onChangePage, pageNum, onShowSizeChange } = this;
    return (
      <div class="xh-pagination-wrapper">
        <a-pagination
          {...this.$props}
          show-quick-jumper
          show-size-changer
          page-size-options={pageSizeOptions}
          v-model={pageNum}
          show-total={(total) => `共 ${total} 条数据`}
          onChange={onChangePage}
          onShowSizeChange={onShowSizeChange}
        />
      </div>
    );
  },
});
export type XhPaginationProps = Partial<
  ExtractPropTypes<typeof xhPaginationProps>
>;

export default withInstall(XhPagination);

这里工具函数withInstall代码如下:

import type { App, Plugin } from 'vue';
export const withInstall = <T>(comp: T) => {
  const c = comp as any;
  c.install = function (app: App) {
    app.component(c.displayName || c.name, comp);
  };

  return comp as T & Plugin;
};

然后自己通过npm pack命令生成对应的tgz文件,然后通过yarn进行安装,在测试文件中引入看是否打包正常。

这样是可以的:

import { createApp } from "vue";
import { useComponent } from "../components/_utils/antdv-registry";
import App from "./App.vue";
import { XhPagination } from "hc-ui-cli/components";

let app: any;
// eslint-disable-next-line prefer-const
app = createApp(App);
useComponent(app);
app.use(XhPagination);
app.mount("#app");

问题点:如果import { XhPagination } from "hc-ui-cli";这样按需引入就不行,报XhPaginationundefined
所以上来问下大佬该怎么处理这种情况。

PS: 测试的时候直接用import { XhPagination } from "components";是可以的.

回复
阅读 623
2 个回答
✓ 已被采纳

已经解决。将主入口文件导出install方法的同时。分别对应导出对应的组件。简单代码如下:

import type { App, DefineComponent } from 'vue';
import XhPagination from './xhPagination';
import XhTable from './xhTable';
const wrapComponents:Array<DefineComponent | any>  = [XhPagination, XhTable]
export const install = function (app: App) {
  wrapComponents.forEach(cpm => {
    if (cpm.install) {
      app.use(cpm);
    }
  })
  return app;
};

export default {
  install,
  XhPagination,
  XhTable
};

export {
  XhPagination,
  XhTable
}

试试在package.json中定义一下exports

你知道吗?

宣传栏