How do I get HMR (Hot Module Replacement) working with a TypeScript React Monorepo in Vite
Asked Answered
P

0

6

I've got a React monorepo (build in TypeScript) and I've recently been switching over from Webpack to Vite. However I'm having real difficult in getting HMR working correctly within Vite (I believe because we separately build our packages).

I'm open to options to get this working (although I think I still need to be able to build my packages, for Jest/ESLint performance).

Project Structure

\apps
  \main
\packages
  \domainA
    \foo
      \package.json
      \build
      \src

At the moment each package gets build using tsc "tsc --project tsconfig.lib.json" into the build directory. The package.json defines the following:

"name": "@ig/foo",
"main": "./build/index.js",
"types": "./build/index.d.ts",
"files": [
    "/build"
],

I can spin up the main application and if I make a change in /packages/domainA/foo/src/index.ts then it'll build (currently using a watcher) and I get a full page reload.

I'd like to eliminate the page reload and instead use HMR. I don't think changing the entry point to "main": "./src/index.ts" will work for my use-case due to the slowness in the other tools unfortunately. However I'm happy to try and bypass this and re-point Vite to the source files if necessary.

I've tried all sorts of permutations, having looked at a few sample repos. But not managed to get anything working, e.g.

resolve: {
  alias: [{
    find: '@ig/foo',
    replacement: '../packages/domainA/foo/src/index.ts',
  },
}

Here is my current Vite config:

import react from '@vitejs/plugin-react';
import fs from 'fs';
import path, { resolve } from 'path';
import { defineConfig } from 'vite';
import mkcert from 'vite-plugin-mkcert';
import svgrPlugin from 'vite-plugin-svgr';

export default defineConfig({
    // optimizeDeps: {
    //     include: ['@infogrid/solution-views-occupancy'],
    // },
    build: {
        outDir: 'build/public',
        sourcemap: true,
        rollupOptions: {
            input: {
                main: resolve(__dirname, 'index.html'),
                base: resolve(__dirname, 'index_base.html'),
            },
         }
     },
     server: {
        port: Number(process.env.PORT),
        // setting to true allows external ip
        host: true,
     },
     plugins: [
        react({ fastRefresh: true }), // Primarily used for HMR
        svgrPlugin({ svgrOptions: { icon: true } }), // Turns svgs into react components
        mkcert(), // Allows for HTTPS during local development
     ]
}
Procedure answered 11/11, 2022 at 17:43 Comment(4)
Did you manage to get this working? I pretty much have the same issue.Mcquoid
@Mcquoid yes and no. The only way we got it working was to remap the package JSON files (in the vite config) to point at source instead rather than build output. That fixes HMR while still allows things like Jest to consume built output.Procedure
Was this mapping done using alias in vite config (keeping two package.json files for every package, one for vite, one for everything else)?Mcquoid
@Mcquoid no, we added { resolve: alias: [ ...rewritePkgs() ] } to our vite.config file. Trying to work out what that function does (I didn't write it) as it's a little cryptic.Procedure

© 2022 - 2024 — McMap. All rights reserved.