'How can I get live-reload on a local npm package in a monorepo?

I'm setting up a monorepo workspace for a Vue 3 (vite + ts), cloud functions, & shared-lib (shared functions and ts interfaces etc.).

I can get the import of my local shared-lib folder to work. I get live type-checking in my front-end project by doing a npm run build -- -- watch on my shared-lib.

Yet for some reason, everything that is transpiled to Javascript, doesn't update unless I uninstall and then install the shared-lib package.

So for instance: creating a const in the shared-lib, doesnt make it usable in the front-end / back-end projects where I'm importing the shared-lib. But creating an interface, IS.

I tried a couple of things and searched a large part of the internet 😂. I tried to play around with the vite.config since I thought that it might do some sort of caching on the packages.

For now, this is what my vite.config.ts looks like:

import { defineConfig } from "vite"
import vue from "@vitejs/plugin-vue"

// https://vitejs.dev/config/
export default defineConfig({
  server: {
    host: true,
  },
  plugins: [vue()],
  resolve: {
    preserveSymlinks: true,
  },
  optimizeDeps: {
    include: ["shared-lib"],
  },
})

This is the index.ts in my shared-lib:

// this is not usable / doesn't update live.
export const sharedConst = () => console.log("testing shared functionality")

// this updates live in other projects.
export interface TestInterface {
  name: {
    firstName: string
    lastName: string
  }
}

This is what my package.json dependencies look like in my front-end:

  "dependencies": {
    ...

    "shared-lib": "file:../backend/functions/dist/shared-lib"
  },

I build the shared-lib to the dist folder of my cloud functions in order to have it be packaged when I upload it. Vue/vite doesn't care where it's packages reside.



Solution 1:[1]

Not sure if you still need an answer to this question, but after a couple of hours I've managed to get my shared library working for my Vue/Vite project.

I made sure my shared library was built as ESM in stead of CJS.

tsconfig.json:

{
    "compilerOptions": {
        "module": "ES2020",
        "moduleResolution": "node",
        "allowSyntheticDefaultImports": true
        ...
    }
}

package.json:

{
    "type": "module"
    ...
}

Then you can add the module to optimizeDeps.exclude as described here: https://vitejs.dev/config/#server-watch. This prevents the shared library from being prebuilt and not rebuilt without forcing a rebuild manually.

I've set up vite.config.js as follows:

{
    server: {
        watch: {
            usePolling: true, // For Docker.
            ignored: ['!**/node_modules/shared-lib/**'],
        },
    },
    optimizeDeps: {
        exclude: ['shared-lib']
    },
    ...
}

For me to get this working it was important to leave resolve.preserveSymlinks and server.watch.followSymlinks at their defaults.

Lastly it's important to run tsc in watch mode (--watch) on the shared library to make sure the sources get recompiled when they get edited:

Using this setup I can get my Vue/Vite project to hot reload changes to the shared library just fine.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Juulloo