mirror of
https://github.com/MichMich/MagicMirror.git
synced 2025-12-01 02:21:39 +00:00
feat(core): add server:watch script with automatic restart on file changes (#3920)
## Description
This PR adds a new `server:watch` script that runs MagicMirror² in
server-only mode with automatic restart and browser reload capabilities.
Particularly helpful for:
- **Developers** who need to see changes immediately without manual
restarts.
- **Users setting up their mirror** who make many changes to `config.js`
or `custom.css` and need quick feedback.
### What it does
When you run `npm run server:watch`, the watcher monitors files you
specify in `config.watchTargets`. Whenever a monitored file changes:
1. The server automatically restarts
2. Waits for the port to become available
3. Sends a reload notification to all connected browsers via Socket.io
4. Browsers automatically refresh to show the changes
This creates a seamless development experience where you can edit code,
save, and see the results within seconds.
### Implementation highlights
**Zero dependencies:** Uses only Node.js built-ins (`fs.watch`,
`child_process.spawn`, `net`, `http`) - no nodemon or external watchers
needed.
**Smart file watching:** Monitors parent directories instead of files
directly to handle atomic writes from modern editors (VSCode, etc.) that
create temporary files during save operations.
**Port management:** Waits for the old server instance to fully release
the port before starting a new one, preventing "port already in use"
errors.
### Configuration
Users explicitly define which files to monitor in their `config.js`:
```js
let config = {
watchTargets: [
"config/config.js",
"css/custom.css",
"modules/MMM-MyModule/MMM-MyModule.js",
"modules/MMM-MyModule/node_helper.js"
],
// ... rest of config
};
```
This explicit approach keeps the implementation simple (~260 lines)
while giving users full control over what triggers restarts. If
`watchTargets` is empty or undefined, the watcher starts but monitors
nothing, logging a clear warning message.
---
**Note:** This PR description has been updated to reflect the final
implementation. During the review process, we refined the approach
multiple times based on feedback.
---------
Co-authored-by: Jboucly <contact@jboucly.fr>
Co-authored-by: Kristjan ESPERANTO <35647502+KristjanESPERANTO@users.noreply.github.com>
This commit is contained in:
14
js/main.js
14
js/main.js
@@ -1,4 +1,4 @@
|
||||
/* global Loader, defaults, Translator, addAnimateCSS, removeAnimateCSS, AnimateCSSIn, AnimateCSSOut, modulePositions */
|
||||
/* global Loader, defaults, Translator, addAnimateCSS, removeAnimateCSS, AnimateCSSIn, AnimateCSSOut, modulePositions, io */
|
||||
|
||||
const MM = (function () {
|
||||
let modules = [];
|
||||
@@ -605,6 +605,18 @@ const MM = (function () {
|
||||
|
||||
createDomObjects();
|
||||
|
||||
// Setup global socket listener for RELOAD event (watch mode)
|
||||
if (typeof io !== "undefined") {
|
||||
const socket = io("/", {
|
||||
path: `${config.basePath || "/"}socket.io`
|
||||
});
|
||||
|
||||
socket.on("RELOAD", () => {
|
||||
Log.warn("Reload notification received from server");
|
||||
window.location.reload(true);
|
||||
});
|
||||
}
|
||||
|
||||
if (config.reloadAfterServerRestart) {
|
||||
setInterval(async () => {
|
||||
// if server startup time has changed (which means server was restarted)
|
||||
|
||||
Reference in New Issue
Block a user