Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Shared vue-demi SFC Library & Yarn 3 Workspace Compatibility Issues #139

Open
phobetron opened this issue Mar 4, 2022 · 4 comments
Open

Comments

@phobetron
Copy link

I've been having a difficult time working out how to build a universal component library with SFCs that can be used by both Vue2 and Vue3 apps bundled together in a Yarn 3 workspaces monorepo.

I have created a (failing) proof of concept project. The library builds, and the Vue3 app renders it correctly. However, the Vue 2 app will not build, and gives the following error:

failed to load config from <path to>demi-components-poc/packages/example-vue2/vite.config.ts
error when starting dev server:
Error:

Vue packages version mismatch:

- vue@3.2.31 (<path to>demi-components-poc/node_modules/vue/index.js)
- vue-template-compiler@2.6.14 (<path to>demi-components-poc/node_modules/vue-template-compiler/package.json)

This may cause things to work incorrectly. Make sure to use the same version for both.
If you are using vue-loader@>=10.0, simply update vue-template-compiler.
If you are using vue-loader@<10.0 or vueify, re-installing vue-loader/vueify should bump vue-template-compiler to the latest.

    at Object.<anonymous> (<path to>demi-components-poc/node_modules/vue-template-compiler/index.js:10:9)
    at Module._compile (node:internal/modules/cjs/loader:1101:14)
    at Object.Module._extensions..js (node:internal/modules/cjs/loader:1153:10)
    at Module.load (node:internal/modules/cjs/loader:981:32)
    at Function.Module._load (node:internal/modules/cjs/loader:822:12)
    at Module.require (node:internal/modules/cjs/loader:1005:19)
    at require (node:internal/modules/cjs/helpers:102:18)
    at Object.<anonymous> (<path to>demi-components-poc/node_modules/vite-plugin-vue2/dist/utils/descriptorCache.js:30:42)
    at Module._compile (node:internal/modules/cjs/loader:1101:14)
    at Object.Module._extensions..js (node:internal/modules/cjs/loader:1153:10)
    at Module.load (node:internal/modules/cjs/loader:981:32)
    at Function.Module._load (node:internal/modules/cjs/loader:822:12)
    at Module.require (node:internal/modules/cjs/loader:1005:19)
    at require (node:internal/modules/cjs/helpers:102:18)
    at Object.<anonymous> (<path to>demi-components-poc/node_modules/vite-plugin-vue2/dist/main.js:29:27)
    at Module._compile (node:internal/modules/cjs/loader:1101:14)

I've attempted various arrangements of vue-demi-switch calls, but this exact error occurs regardless, so I've left that out of the PoC.

The library, as well as both Vue apps, are built using Vite. Is there an incompatibility with vue-demi SFCs and Yarn workspaces, or maybe in how Vite loads Vue?

@phobetron
Copy link
Author

phobetron commented Mar 4, 2022

Here's the compiled JS:

import { defineComponent } from "vue-demi";
import { openBlock, createElementBlock } from "vue";
var _export_sfc = (sfc, props) => {
  const target = sfc.__vccOpts || sfc;
  for (const [key, val] of props) {
    target[key] = val;
  }
  return target;
};
const _sfc_main = defineComponent({
  methods: {
    action() {
      console.log("Button Clicked");
    }
  }
});
function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) {
  return openBlock(), createElementBlock("button", {
    onClick: _cache[0] || (_cache[0] = (...args) => _ctx.action && _ctx.action(...args))
  }, "Click");
}
var HelloWorld = /* @__PURE__ */ _export_sfc(_sfc_main, [["render", _sfc_render]]);
export { HelloWorld };

But I'm not sure this has any bearing on anything. It seems to be more of a Vite and/or Yarn workspace dependency issue.

@antfu
Copy link
Member

antfu commented Mar 5, 2022

I think it more likely that vue-template-compiler is grabing the v3 of vue due to the yarn workspace hoisting. Maybe you can try adding this to your package.json

  "installConfig": {
    "hoistingLimits": "workspaces"
  }

@phobetron
Copy link
Author

phobetron commented Mar 5, 2022

@antfu For some reason, that had no effect, but placing nmHoistingLimits: workspaces in .yarnrc.yml worked. After also adding a missing dependency, the Vue2 app builds and loads in the browser. However, the dependency from line 2 in the compiled JS causes an error, as it is still Vue3-specific.

The new error in the browser is:

Uncaught SyntaxError: The requested module '/node_modules/.vite/vue.js?v=c2bff7da' does not provide an export named 'createElementBlock'

Here's the new JS after adding the hoisting limits:

import { defineComponent } from "/node_modules/.vite/vue-demi.js?v=c2bff7da";
import { openBlock, createElementBlock } from "/node_modules/.vite/vue.js?v=c2bff7da";
var _export_sfc = (sfc, props) => {
  const target = sfc.__vccOpts || sfc;
  for (const [key, val] of props) {
    target[key] = val;
  }
  return target;
};
const _sfc_main = defineComponent({
  methods: {
    action() {
      console.log("Button Clicked");
    }
  }
});
function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) {
  return openBlock(), createElementBlock("button", {
    onClick: _cache[0] || (_cache[0] = (...args) => _ctx.action && _ctx.action(...args))
  }, "Click");
}
var HelloWorld = /* @__PURE__ */ _export_sfc(_sfc_main, [["render", _sfc_render]]);
export { HelloWorld };

I think these are referenced in the Vue SFC compiler. Is there any way to get vue-demi to pick these up during the compilation process, or is it not possible to use SFCs in a vue-demi project?

I've updated the PoC repo, if you would like to poke at it.

@phobetron
Copy link
Author

phobetron commented Mar 5, 2022

I just found one project, vue3-sketch-ruler, uses a build process that creates separate libraries for 2 & 3, combined into a single package with a postinstall process that determines which library should be used.

My best current working solution is in the PoC repo. It has the following:

  • Two different version-specific packages, each with a version-specific build process
  • Each package's build tool is pointed to an external, shared source directory, containing components that use vue-demi
  • Each package outputs their build artifacts to a third package
  • The third package, which is the one that will be published, builds functionality that conditionally switches between the two versions at run-time

My only other thought to simplify this process is to have one library package that uses multiple build files, but that would require additional tooling like yarn-plugin-conditions (which currently does to seem to work with Vue3) to switch dependencies in the package manager itself.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants