Using Webpack's Watch option and UDT watch causes increasing reload times

I have an InDesign UXP React plugin based on the React Starter kit, in which nodemon was used to watch the src folder and then run webpack to build to the dist folder. This worked ok but sometimes the nodemon was slow to rebuild and I found that webpack had a watch option that wasn’t being used. I switched to using the webpack watch option while excluding the node_modules and dist folders and found that the rebuilds were much faster, from around 10000ms (build) or 2200ms (rebuild) with nodemon to around 100-200ms with just the webpack watch.

This issue is that the UXP Dev Tools when in watch mode and the using debugger becomes progressively slower each save and update, causing it to freeze for up to a minute after 20+ reloads. I’ve included the relevant webpack config below, and i saw other mention this issue but didn’t see any relevant resolution. I know I can not use the watch mode and use CMD+R to reload the UDT debugger, but that’s suboptimal for me. Does anyone know a solution for improving this?

I am on:

  • MacOS
  • UDT Version 2.1.0 (2.1.0.30)
  • InDesign 20.4
  • webpack 5.97.1
  • react 18.3.1

npm script:

"dev:plugin": "webpack --config-name plugin --mode development",

webpack config:

const config = (_env, argv) => {
    const isDev = argv.mode === "development"

    return [
        {
            name: "plugin",
            entry: "./src/index.jsx",
            output: {
                path: path.resolve(process.cwd(), "dist"),
                filename: "index.js",
                clean: true,
            },
            watch: isDev,
            watchOptions: {
                ignored: ["**/node_modules/**", "**/dist/**"],
            },

            devtool: "eval-cheap-source-map", // won't work on XD due to lack of eval
            externals: {
                uxp: "commonjs2 uxp",
                indesign: "commonjs2 indesign",
                os: "commonjs2 os",
                fs: "commonjs2 fs",
            },
            resolve: {
                extensions: [".js", ".jsx", ".idjs"],
            },
            module: {
                rules: [
                    {
                        test: /\.jsx?$/,
                        exclude: /node_modules/,
                        loader: "babel-loader",
                        options: {
                            plugins: [
                                "@babel/transform-react-jsx",
                                "@babel/proposal-object-rest-spread",
                                "@babel/plugin-syntax-class-properties",
                            ],
                        },
                    },
                    {
                        test: /\.png$/,
                        exclude: /node_modules/,
                        loader: "file-loader",
                    },
                    {
                        test: /\.css$/,
                        use: ["style-loader", "css-loader"],
                    },
                ],
            },
            plugins: [
                new CopyPlugin(["plugin", "in5_export_resources/Export-Resources"], {
                    copyUnmodified: true,
                }),
            ],
        }, ... ]}

Watch mode in UDT is not great. Sometimes it reloaded half-bundled plugin.

What I did instead was to add custom plugin into Webpack bundler and when webpack signals that bundling is finished then plugin sends signal to UXP plugin to reload itself.

This is much better because UDT simply cannot know when is the best time to reload… you can also generate thousand of files and still not being done… and you can’t reload it 1000× in 3 seconds… so additionally there are some waiting times. But it does not work as well even with waiting times.

Is your custom plugin available anywhere?

Do you use custom listener?

No. It is proprietary. But I think Bolt created custom selection as well.