vueuse / vue-demi

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

vue-demi setup in monorepos #138

Open zeusdeux opened 2 years ago

zeusdeux commented 2 years ago

Hi folks!

We are using vue-demi in a monorepo where we have a components package that uses vue-demi and has vue 3 as a devDependency. Alongside that, in the same monorepo, have vue 2 and vue 3 apps that consume the components package. We declare a dependency on the components package in the various vue apps using the workspace: protocol.

We use pnpm as our package manager. Upon running pnpm install in the root of monorepo, vue 3 devDependency of the components package is installed and the post install script of vue-demi sets up its exports for vue 3 since it finds the local vue 3 dependency when running require('vue'). In the apps, a link is created to the components package which results in vue-demi being hard configured for vue 3 and fails to work when a component coming from the components package is used in a vue 2 app.

How should one use vue-demi in a monorepo to have it work across vue 2 and vue 3 apps in the same monorepo?

Thanks for the work put into this package btw! It's a blessing!

phobetron commented 2 years ago

Are your components compiled from SFCs, or include any sort of Vue version-specific compilation?

No, the components are developed in a way that does not require any Vue version-specific compilation

You could solve your problem simply by reducing hoisting from your package manager. You may have to prevent any kind of hoisting, which could slow down development processes due to bloat.

You may also need to ensure you switch Vue versions during the development process using vue-demi-switch. This should have no effect on the final package, but allows you to compile and test with the expected version.

Yes, the components need to be compiled (SFCs or something similar)

There doesn't seem to be a straightforward way to create a universal package for SFCs. The reason for this is that SFC compilers are also dev dependencies of the shared component package. The compilation process runs during the build of the package, using the Vue version that is detected at that time. The end-user's Vue version at build-time is still an unknown. The numerous differences between possible build tools makes it impossible for a single library to handle multiple compilers and versions within the same process seamlessly.

This is a process I've implemented that works:

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.

Gumball12 commented 1 year ago

README and the answers above provide enough information, but if you need a working example, you can see this repository:

https://github.com/Gumball12/vitest-vue-demi-pnpm-monorepo

KirIIISolovyov commented 1 year ago

Issue Description

Hello! We encountered a problem when adding a vue@2.7 app to our yarn workspace monorepo, which consists of vue@3 apps using Vite. Both the vue@3 and vue@2 apps rely on a shared-library from npm, which uses vue-demi to support both versions.

In our case the problem was because of hoisting of vue-demi to the root. When we attempted to switch to vue@2.7 using vue-demi-switch, it changed the Vue version for all apps in the monorepo, causing the dev and build commands to fail.

Monorepo Structure

/apps
--/vue3-app1
--/vue3-app2
--/vue3-app3
--/vue2-app1

/node_modules
--/shared-library
--/vue-demi # vue-demi-switch changes version of the root package

Attempted Solution

We solved the problem adding nohoist to the vue2-app1/package.json and switch vue version:

{
  "private": true,
  "workspaces": {
    "hohoist": ["**/shared-library", "**/shared-library/**"]
  },
  "scripts": {
    "dev": "vue-demi-switch 2.7 && vite",
    "build": "vue-demi-switch 2.7 && vite build"
  }
}

Updated Monorepo Structure with Nohoist

/apps
--/vue3-app1
--/vue3-app2
--/vue3-app3
--/vue2-app1
  --/node_modules
   --/shared-library
   --/vue-demi # vue-demi for vue2-app1. Now vue-demi-switch changes version only for vue2-app1, not the root

/node_modules
--/shared-library
--/vue-demi

Issue with build Command

However, the problem persisted when running the build command. For some reason, vue2-app1/node_modules/vue-demi contained vue@3 inside its node_modules, while vue2-app1 had vue@2

image
image

During the build vue-demi tried to use vue@3 from its node_modules instead of using vue@2 fromvue2-app1.
image

Solution

We managed to resolve the problem via vite aliases. We explicitly set path to vue2-app1/node_modules/vue vite-config.js

export default defineConfig({
  resolve: {
    vue: fileURLToPath(new URL('./node_modules/vue', import.meta.url))
  },
  optimizeDeps: {
    exclude: ['vue-demi'] // It seems to solve the imports problem for dev, but does not work for build
  }
});

I hope this solution will help you with the same problem and save time