vueuse / vue-demi

🎩 Creates Universal Library for Vue 2 & 3
MIT License
2.97k stars 155 forks source link

TypeError: o.resolveComponent is not a function & 能否提供一个打包 vue2、vue3 组件库的 demo #80

Closed Murphycx94 closed 2 years ago

Murphycx94 commented 3 years ago

我想打包一个 vue2、vue3 都可用的组件库 打包完后的组件,在 vue3 项目中使用没有问题 但是在 vue2 项目中运行时报了如下错误

Uncaught TypeError: e.defineComponent is not a function
    at eval (index.js?dead:6)
    at eval (index.js?dead:6)
    at eval (index.js?dead:6)
    at Object.../../long-bridge/fe-toolbox/packages/vue3-components/lib/LbNoticeBar/index.js (app.js:937)
    at __webpack_require__ (app.js:849)
    at fn (app.js:151)
    at eval (cjs.js?!./node_modules/babel-loader/lib/index.js!./node_modules/cache-loader/dist/cjs.js?!./node_modules/vue-loader/lib/index.js?!./src/App.vue?vue&type=script&lang=js&:4)
    at Module../node_modules/cache-loader/dist/cjs.js?!./node_modules/babel-loader/lib/index.js!./node_modules/cache-loader/dist/cjs.js?!./node_modules/vue-loader/lib/index.js?!./src/App.vue?vue&type=script&lang=js& (app.js:960)
    at __webpack_require__ (app.js:849)
    at fn (app.js:151)

当我修改打包命令 vue-demi-switch 2 && yarn build 打包后

Uncaught TypeError: o.withScopeId is not a function
    at eval (index.js?dead:6)
    at eval (index.js?dead:6)
    at eval (index.js?dead:6)
    at Object.../../long-bridge/fe-toolbox/packages/vue3-components/lib/LbNoticeBar/index.js (app.js:937)
    at __webpack_require__ (app.js:849)
    at fn (app.js:151)
    at eval (cjs.js?!./node_modules/babel-loader/lib/index.js!./node_modules/cache-loader/dist/cjs.js?!./node_modules/vue-loader/lib/index.js?!./src/App.vue?vue&type=script&lang=js&:4)
    at Module../node_modules/cache-loader/dist/cjs.js?!./node_modules/babel-loader/lib/index.js!./node_modules/cache-loader/dist/cjs.js?!./node_modules/vue-loader/lib/index.js?!./src/App.vue?vue&type=script&lang=js& (app.js:960)
    at __webpack_require__ (app.js:849)
    at fn (app.js:151)

这是我其中的一个组件 Icon 组件

<template>
  <svg class="icon iconfont" aria-hidden="true" @click="e => $emit('click', e)">
    <use :xlink:href="`#icon-${name}`"></use>
  </svg>
</template>

<script>
import { defineComponent } from 'vue-demi'

export default defineComponent({
  name: 'LbIcon',
  props: {
    /**
     * isRequired.
     */
    name: {
      type: String,
      required: true
    }
  }
})
</script>

<style lang="scss" scoped>
.icon {
  width: 1em;
  height: 1em;
  overflow: hidden;
  vertical-align: -0.15em;
  cursor: pointer;
  fill: currentColor;
}
</style>

这是打包后的代码

/*!
 * @lb-public/vue3-components v0.5.0 Mon Jul 26 2021 19:07:24 GMT+0800 (中国标准时间)
 * (c) 2021 @lbf2e.
 * Released under the MIT License.
 */
!(function (e, n) {
  'object' == typeof exports && 'undefined' != typeof module
    ? (module.exports = n(require('vue-demi'), require('vue')))
    : 'function' == typeof define && define.amd
    ? define(['vue-demi', 'vue'], n)
    : ((e = 'undefined' != typeof globalThis ? globalThis : e || self).index = n(e.VueDemi, e.Vue))
})(this, function (e, n) {
  'use strict'
  const i = e.defineComponent({ name: 'LbIcon', props: { name: { type: String, required: !0 } } }),
    o = n.withScopeId('data-v-7a1e4f22')(
      (e, i, o, t, d, r) => (
        n.openBlock(),
        n.createBlock(
          'svg',
          { class: 'icon iconfont', 'aria-hidden': 'true', onClick: i[1] || (i[1] = n => e.$emit('click', n)) },
          [n.createVNode('use', { 'xlink:href': `#icon-${e.name}` }, null, 8, ['xlink:href'])]
        )
      )
    )
  return (i.render = o), (i.__scopeId = 'data-v-7a1e4f22'), i
})
francisZimo commented 3 years ago

我想打包一个 vue2、vue3 都可用的组件库 打包完后的组件,在 vue3 项目中使用没有问题 但是在 vue2 项目中运行时报了如下错误

Uncaught TypeError: e.defineComponent is not a function
    at eval (index.js?dead:6)
    at eval (index.js?dead:6)
    at eval (index.js?dead:6)
    at Object.../../long-bridge/fe-toolbox/packages/vue3-components/lib/LbNoticeBar/index.js (app.js:937)
    at __webpack_require__ (app.js:849)
    at fn (app.js:151)
    at eval (cjs.js?!./node_modules/babel-loader/lib/index.js!./node_modules/cache-loader/dist/cjs.js?!./node_modules/vue-loader/lib/index.js?!./src/App.vue?vue&type=script&lang=js&:4)
    at Module../node_modules/cache-loader/dist/cjs.js?!./node_modules/babel-loader/lib/index.js!./node_modules/cache-loader/dist/cjs.js?!./node_modules/vue-loader/lib/index.js?!./src/App.vue?vue&type=script&lang=js& (app.js:960)
    at __webpack_require__ (app.js:849)
    at fn (app.js:151)

当我修改打包命令 vue-demi-switch 2 && yarn build 打包后

Uncaught TypeError: o.withScopeId is not a function
    at eval (index.js?dead:6)
    at eval (index.js?dead:6)
    at eval (index.js?dead:6)
    at Object.../../long-bridge/fe-toolbox/packages/vue3-components/lib/LbNoticeBar/index.js (app.js:937)
    at __webpack_require__ (app.js:849)
    at fn (app.js:151)
    at eval (cjs.js?!./node_modules/babel-loader/lib/index.js!./node_modules/cache-loader/dist/cjs.js?!./node_modules/vue-loader/lib/index.js?!./src/App.vue?vue&type=script&lang=js&:4)
    at Module../node_modules/cache-loader/dist/cjs.js?!./node_modules/babel-loader/lib/index.js!./node_modules/cache-loader/dist/cjs.js?!./node_modules/vue-loader/lib/index.js?!./src/App.vue?vue&type=script&lang=js& (app.js:960)
    at __webpack_require__ (app.js:849)
    at fn (app.js:151)

这是我其中的一个组件 Icon 组件

<template>
  <svg class="icon iconfont" aria-hidden="true" @click="e => $emit('click', e)">
    <use :xlink:href="`#icon-${name}`"></use>
  </svg>
</template>

<script>
import { defineComponent } from 'vue-demi'

export default defineComponent({
  name: 'LbIcon',
  props: {
    /**
     * isRequired.
     */
    name: {
      type: String,
      required: true
    }
  }
})
</script>

<style lang="scss" scoped>
.icon {
  width: 1em;
  height: 1em;
  overflow: hidden;
  vertical-align: -0.15em;
  cursor: pointer;
  fill: currentColor;
}
</style>

这是打包后的代码

/*!
 * @lb-public/vue3-components v0.5.0 Mon Jul 26 2021 19:07:24 GMT+0800 (中国标准时间)
 * (c) 2021 @lbf2e.
 * Released under the MIT License.
 */
!(function (e, n) {
  'object' == typeof exports && 'undefined' != typeof module
    ? (module.exports = n(require('vue-demi'), require('vue')))
    : 'function' == typeof define && define.amd
    ? define(['vue-demi', 'vue'], n)
    : ((e = 'undefined' != typeof globalThis ? globalThis : e || self).index = n(e.VueDemi, e.Vue))
})(this, function (e, n) {
  'use strict'
  const i = e.defineComponent({ name: 'LbIcon', props: { name: { type: String, required: !0 } } }),
    o = n.withScopeId('data-v-7a1e4f22')(
      (e, i, o, t, d, r) => (
        n.openBlock(),
        n.createBlock(
          'svg',
          { class: 'icon iconfont', 'aria-hidden': 'true', onClick: i[1] || (i[1] = n => e.$emit('click', n)) },
          [n.createVNode('use', { 'xlink:href': `#icon-${e.name}` }, null, 8, ['xlink:href'])]
        )
      )
    )
  return (i.render = o), (i.__scopeId = 'data-v-7a1e4f22'), i
})

Have you solved it

kakajun commented 2 years ago

vue3-sketch-ruler contain template compile demo with vue-demi to vue2/3

KesionX commented 2 years ago

我想打包一个 vue2、vue3 都可用的组件库 打包完后的组件,在 vue3 项目中使用没有问题 但是在 vue2 项目中运行时报了如下错误

Uncaught TypeError: e.defineComponent is not a function
    at eval (index.js?dead:6)
    at eval (index.js?dead:6)
    at eval (index.js?dead:6)
    at Object.../../long-bridge/fe-toolbox/packages/vue3-components/lib/LbNoticeBar/index.js (app.js:937)
    at __webpack_require__ (app.js:849)
    at fn (app.js:151)
    at eval (cjs.js?!./node_modules/babel-loader/lib/index.js!./node_modules/cache-loader/dist/cjs.js?!./node_modules/vue-loader/lib/index.js?!./src/App.vue?vue&type=script&lang=js&:4)
    at Module../node_modules/cache-loader/dist/cjs.js?!./node_modules/babel-loader/lib/index.js!./node_modules/cache-loader/dist/cjs.js?!./node_modules/vue-loader/lib/index.js?!./src/App.vue?vue&type=script&lang=js& (app.js:960)
    at __webpack_require__ (app.js:849)
    at fn (app.js:151)

当我修改打包命令 vue-demi-switch 2 && yarn build 打包后

Uncaught TypeError: o.withScopeId is not a function
    at eval (index.js?dead:6)
    at eval (index.js?dead:6)
    at eval (index.js?dead:6)
    at Object.../../long-bridge/fe-toolbox/packages/vue3-components/lib/LbNoticeBar/index.js (app.js:937)
    at __webpack_require__ (app.js:849)
    at fn (app.js:151)
    at eval (cjs.js?!./node_modules/babel-loader/lib/index.js!./node_modules/cache-loader/dist/cjs.js?!./node_modules/vue-loader/lib/index.js?!./src/App.vue?vue&type=script&lang=js&:4)
    at Module../node_modules/cache-loader/dist/cjs.js?!./node_modules/babel-loader/lib/index.js!./node_modules/cache-loader/dist/cjs.js?!./node_modules/vue-loader/lib/index.js?!./src/App.vue?vue&type=script&lang=js& (app.js:960)
    at __webpack_require__ (app.js:849)
    at fn (app.js:151)

这是我其中的一个组件 Icon 组件

<template>
  <svg class="icon iconfont" aria-hidden="true" @click="e => $emit('click', e)">
    <use :xlink:href="`#icon-${name}`"></use>
  </svg>
</template>

<script>
import { defineComponent } from 'vue-demi'

export default defineComponent({
  name: 'LbIcon',
  props: {
    /**
     * isRequired.
     */
    name: {
      type: String,
      required: true
    }
  }
})
</script>

<style lang="scss" scoped>
.icon {
  width: 1em;
  height: 1em;
  overflow: hidden;
  vertical-align: -0.15em;
  cursor: pointer;
  fill: currentColor;
}
</style>

这是打包后的代码

/*!
 * @lb-public/vue3-components v0.5.0 Mon Jul 26 2021 19:07:24 GMT+0800 (中国标准时间)
 * (c) 2021 @lbf2e.
 * Released under the MIT License.
 */
!(function (e, n) {
  'object' == typeof exports && 'undefined' != typeof module
    ? (module.exports = n(require('vue-demi'), require('vue')))
    : 'function' == typeof define && define.amd
    ? define(['vue-demi', 'vue'], n)
    : ((e = 'undefined' != typeof globalThis ? globalThis : e || self).index = n(e.VueDemi, e.Vue))
})(this, function (e, n) {
  'use strict'
  const i = e.defineComponent({ name: 'LbIcon', props: { name: { type: String, required: !0 } } }),
    o = n.withScopeId('data-v-7a1e4f22')(
      (e, i, o, t, d, r) => (
        n.openBlock(),
        n.createBlock(
          'svg',
          { class: 'icon iconfont', 'aria-hidden': 'true', onClick: i[1] || (i[1] = n => e.$emit('click', n)) },
          [n.createVNode('use', { 'xlink:href': `#icon-${e.name}` }, null, 8, ['xlink:href'])]
        )
      )
    )
  return (i.render = o), (i.__scopeId = 'data-v-7a1e4f22'), i
})

Have you solved it

理论上是没法同时兼容vue2、vue3 但是可以做到一份代码分别打出vue2版本的包、与vue3版本的包

可以使用rollup实现

  1. 使用vue-demi开发
  2. rollup.config.js 自定义插件resolveId, vue2的vue-demi 指向vue2版本,vue3的vue-demi 指向vue3版本
  3. 同时要兼容 rollup-import-vue,vue2 的编译使用:https://github.com/KesionX/rollup-plugin-vue-2 vue3的编译使用:https://github.com/vuejs/rollup-plugin-vue

eg: 提供一个不算完整的rollup.config.js ,但能够表达我的意思

import commonjs from 'rollup-plugin-commonjs' 
import vue_2 from "rollup-plugin-ue2";
import vue_3 from "rollup-plugin-vue";

function vueTransformPlugin(isVue2){
    return {
        resolveId (source) {
            if (/vue-demi/.test(source)) {

                if (isVue2) {
                    return "./node_modules/vue-demi/lib/v2/index.mjs";
                } else {
                    return "./node_modules/vue-demi/lib/v3/index.mjs";
                }
            }
        }
    }
}
/**
* returns {import ('rollup' ).RollupOptions}
*/
function getBaseConfig(isVue2){
    const vueConfig = {
        css: true,
        style: {
            preprocessOptions:{
                less: {
                    javascriptEnabled: true,
                }
            }
        }
    }
    const vueComplier = isVue2 ? vue_2(vueConfig) : vue_3(vueConfig);
    return {
        external:[
            /@vue\/composition-api/,
            ...Object.keys (dependencies| {}),
            ... Object. keys (peerDependencies| {}),
        ],
        input: "./src/index.ts",
        output: {
            dir: `dist/${isVue2 ? "u2" : "'u3"}`,
            format: "esm",
            globals: { vue: "Vue" },
        },
        plugins: [
            commonjs(),
            vueComplier,
            vueTransformPlugin(isVue2)
        ]
    }
}

const config_ue2 = getBaseConfig(true);
const config_ue3 = getBaseConfig(false);
export default [config_ue2, config_ue3];
zss1004504439 commented 2 years ago

如果只使用 jsx 的 render ,不使用template语法可以吗

zss1004504439 commented 2 years ago

有示例吗,跑不起来

sxzz commented 2 years ago

This library is only compatible with the public API, the vnode-related API is not adapted. It is recommended to use template or JSX with different versions of Vite plugin to generate two versions of the bundle file.

本库仅抹平了公开 API,vnode 相关的 API 并没有做适配。建议使用 template 或 JSX并配合不同版本 Vite plugin 生成两个版本的打包文件。

angelanana commented 1 month ago

I found that the setup sfc syntax sugar of vue3 is incompatible. I use the setup syntax sugar to develop components. Finally, the package of vue2 version cannot be packaged successfully. It will prompt an error: "default" is not exported by "xxx", imported by "xxx"; error during build: RollupError: "default" is not exported by 'XXX' Is there a solution?