rollup-plugin-livereload icon indicating copy to clipboard operation
rollup-plugin-livereload copied to clipboard

Plugin does not support multiple livereload instances at once

Open leumasme opened this issue 2 years ago • 7 comments

Rollup supports producing multiple bundles at once by exporting multiple configs in an array from the rollup config script, e.g.

import livereload from "rollup-plugin-livereload";

export default [{
{
        input: `modA/src/main.js`,
        output: {
            sourcemap: true,
            format: "iife",
            name: "app",
            file: `modA/public/build/bundle.js`
        },
        plugins: [
            livereload("modA/public"),
        ]
    }
},{
{
        input: `modB/src/main.js`,
        output: {
            sourcemap: true,
            format: "iife",
            name: "app",
            file: `modB/public/build/bundle.js`
        },
        plugins: [
            livereload("modB/public"),
        ]
    }
}]

Using this rollup feature however breaks this plugin. The livereload server is kept in a global state variable PLUGIN_LIVERELOAD https://github.com/thgh/rollup-plugin-livereload/blob/0f0b30c8cd1dbd6754e041dfcfd65ed8d5ae6d98/src/index.js#L5-L7 If livereload is instantiated multiple times in the same rollup process, they clash and the variable will be overwritten. When reloading the rollup config, this leads to multiple livereload instances trying to close the same server https://github.com/thgh/rollup-plugin-livereload/blob/0f0b30c8cd1dbd6754e041dfcfd65ed8d5ae6d98/src/index.js#L20-L22 which results in a crash, as closing the same server multiple times is not supported by livereload

[!] TypeError: Cannot read properties of null (reading 'close')
    at Server.close (PROJECT\node_modules\livereload\lib\livereload.js:227:27)
    at livereload (PROJECT\node_modules\rollup-plugin-livereload\dist\index.cjs.js:104:18)
    at constructConfig (file:///PROJECT/rollup.config.mjs?1683999555521:92:28)
    at file:///PROJECT/rollup.config.mjs?1683999555521:109:5
    at ModuleJob.run (node:internal/modules/esm/module_job:194:25

leumasme avatar May 13 '23 17:05 leumasme

Since the author of this plugin seems to no longer be maintaining it, a workaround is to put this in your rollup.config.js before any livereload() calls:

// Live reload plugin is broken with multiple rollup configs, so we need to close the server manually
if (global.PLUGIN_LIVERELOAD?.server) {
    console.log("Closing old live reload server");
    global.PLUGIN_LIVERELOAD.server.close();
    global.PLUGIN_LIVERELOAD.server = null;
} 

leumasme avatar May 13 '23 18:05 leumasme

Hi @leumasme, thanks for reporting this issue. I think we might have to see if there is another way we can keep track of the server and when it's connection should be closed. Perhaps there are some life-cycle hooks from Rollup that we can use to accomplish this, rather than keeping things in a global.

jonkoops avatar Aug 07 '23 09:08 jonkoops

For context, the global was introduced for after rollup config watch (when you change rollup.config.js). There were no hooks at the time, so we landed on that approach.

Each time livereload() is called, looks like it could be related to multiple entries or updating rollup.config.js.

One thing that could definitely help is a little state machine that keeps track of init->started->restarting so it doesn't try to double close a server.

thgh avatar Aug 07 '23 10:08 thgh

Since Rollup 3 was released a while ago we might consider using the build hooks and remove compatibility with Rollup 2, or perhaps we can keep things compatible while using this API.

jonkoops avatar Aug 07 '23 19:08 jonkoops

It's ok to remove compatibility, just make sure to cut a major release and note both versions in the README.

thgh avatar Aug 07 '23 20:08 thgh

Yes, I think we'll end up doing a major release either way 👍

jonkoops avatar Aug 14 '23 17:08 jonkoops

@leumasme in the mean time, you could add this to the first bundle livereload(["modA/public", "modB/public"]), and don't call livereload in the second. I'm curious to see solutions for this usecase!

thgh avatar Aug 15 '23 08:08 thgh