Plugin does not support multiple livereload instances at once
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
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;
}
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.
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.
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.
It's ok to remove compatibility, just make sure to cut a major release and note both versions in the README.
Yes, I think we'll end up doing a major release either way 👍
@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!