vue-demi
vue-demi copied to clipboard
vue-demi setup in monorepos
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!
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:
- Create two different version-specific packages, each with a version-specific build process
- Point each package's build tool 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 you will publish, 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.
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
Issue Description
Hello! We encountered a problem when adding a [email protected] 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 [email protected] 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
During the build vue-demi tried to use vue@3 from its node_modules instead of using vue@2 from vue2-app1.
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