Skip to content

Conversation

@jboucly
Copy link
Contributor

@jboucly jboucly commented Oct 19, 2025

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:

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.

@sdetweil
Copy link
Collaborator

You can reload the browser side anytime, ctl-r, or f5

it only loads the web side. You have to stop server and start to reload node_helpers

@sdetweil
Copy link
Collaborator

What does server dev do? dev was only for web side

if you open your own browser it doesn’t get that parm

@sdetweil
Copy link
Collaborator

The scripted installer handles node install plus other things

@jboucly
Copy link
Contributor Author

jboucly commented Oct 19, 2025

Yes, but stopping the server and then restarting it quickly becomes redundant when we make a lot of modifications and tests on the module side in development....

@jboucly
Copy link
Contributor Author

jboucly commented Oct 19, 2025

You can reload the browser side anytime, ctl-r, or f5

it only loads the web side. You have to stop server and start to reload node_helpers

Yes, but stopping the server and then restarting it quickly becomes redundant when we make a lot of modifications and tests on the module side in development....

What does server dev do? dev was only for web side

if you open your own browser it doesn’t get that parm

I don't understand

@sdetweil
Copy link
Collaborator

sdetweil commented Oct 19, 2025

So again, change module, ctrl-r if cursor is over web side, f5 if over dev window side

what does server:dev do?
The dev parm is only used when electron is the browser in full mode, npm run start:dev

in run server mode
You have to start your own browser. Chrome/firefox/surf/safari pointing at the MagicMirror address and port

dev mode curl-shift-I , toggles the dev window open or closed

@KristjanESPERANTO
Copy link
Collaborator

what does server:dev do?

To start MagicMirror in server mode + Nodemon keeps an eye on server-side files, and whenever a change is detected the server restarts automatically.

@sdetweil
Copy link
Collaborator

Ah

@jboucly jboucly changed the title Create .nvmrc file and create server:dev script Create server:dev script Oct 21, 2025
@jboucly jboucly changed the title Create server:dev script Create server:watch script Oct 21, 2025
@KristjanESPERANTO
Copy link
Collaborator

Thanks for the changes 🙂 I would like to test something relevant. Give me some time for the review.

Jboucly and others added 10 commits October 22, 2025 13:26
…g and port management

- Add port availability checks before restart to prevent race conditions
- Add error handler for spawn failures
- Extract hardcoded values to constants (RESTART_DELAY_MS, PORT_CHECK_*)
- Add getConfigFilePath() helper for cleaner config path resolution
- Watch js/ and serveronly/ directories in addition to modules/ and config/
- Watch all JS files (.js, .mjs, .cjs) instead of just node_helper.js
- Improve restart mechanism with isRestarting flag
- Better error messages for watcher and spawn failures
- Remove unused app.restart() method from app.js

These changes make the watcher more robust and easier to maintain.
@KristjanESPERANTO KristjanESPERANTO force-pushed the feat/add-server-auto-reload-and-nvm-config branch from 206421c to c2103f5 Compare October 22, 2025 12:54
@KristjanESPERANTO KristjanESPERANTO changed the title Create server:watch script feat(core): add server:watch script with automatic restart on file changes Oct 22, 2025
@KristjanESPERANTO
Copy link
Collaborator

KristjanESPERANTO commented Oct 22, 2025

I have re-based the branch.

During my tests, I encountered various issues. For example, the restart was triggered by files that my editor created temporarily when saving. Furthermore, the restart did not wait until the old instance released the port, so the new instance could not use it. I have adjusted this and other details in one commit.

Please feel free to give feedback on my changes.

From my point of view, everything looks good now 😃 However, I would wait for the opinion of at least one other contributor on the current status.

Edit: I removed the manual restart option since it would be another feature. One feature per PR is easier to handle.

@jboucly
Copy link
Contributor Author

jboucly commented Oct 22, 2025

I have re-based the branch.

During my tests, I encountered various issues. For example, the restart was triggered by files that my editor created temporarily when saving. Furthermore, the restart did not wait until the old instance released the port, so the new instance could not use it. I have adjusted this and other details in one commit.

Please feel free to give feedback on my changes.

From my point of view, everything looks good now 😃 However, I would wait for the opinion of at least one other contributor on the current status.

Edit: I removed the manual restart option since it would be another feature. One feature per PR is easier to handle.

Nice jobs ! Thanks for the changes ! I see that I don't have the whole history of the project when I see all the changes you made 🫣

Ok for the removal of manual reload and sorry for my english in changelog file x')

But i don't understand why on your local you have this bug with my version of watcher 🤔

Edit: I change the description of the PR

- allow `config.watchTargets` to opt into additional files while falling back to the active config and custom CSS
- expose `/reload` in server.js that emits `RELOAD` so connected clients refresh automatically

The watcher runs outside server.js and previously had no socket.io access, so browser reloads were impossible; the new endpoint bridges that gap.
- Use existing getConfigFilePath() in getServerPort()
- Remove hardcoded 127.0.0.1 from isPortAvailable() for container compatibility
- Move getConfigFilePath() to server_functions.js
- Use in app.js and watcher.js to avoid duplication
@khassel
Copy link
Collaborator

khassel commented Oct 27, 2025

From my side this can be merged. Will wait until tomorrow to give others a chance to comment/review.

Copy link
Collaborator

@KristjanESPERANTO KristjanESPERANTO left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've changed the PR text to reflect the current approach.

@khassel khassel merged commit 961b3c9 into MagicMirrorOrg:develop Oct 28, 2025
9 checks passed
KristjanESPERANTO added a commit to KristjanESPERANTO/MagicMirror-Documentation that referenced this pull request Nov 4, 2025
rejas pushed a commit to MagicMirrorOrg/MagicMirror-Documentation that referenced this pull request Nov 4, 2025
@sdetweil sdetweil mentioned this pull request Jan 1, 2026
sdetweil added a commit that referenced this pull request Jan 1, 2026
Thanks to: @Blackspirits, @Crazylegstoo, @jarnoml, @jboucly, @JHWelch,
@khassel, @KristjanESPERANTO, @rejas, @sdetweil, @xsorifc28

⚠️ This release needs nodejs version >=22.21.1 <23 || >=24

[Compare to previous Release
v2.33.0](v2.33.0...develop)

[core]
Prepare Release 2.34.0
(#3998)
dependency update + adjust Playwright setup + fix linter issue
(#3994)
demo with gif (#3995)
[core] fix: allow browser globals in config files
(#3992)
[core] fix: restore --ozone-platform=wayland flag for reliable Wayland
support (#3989)
[core] auto create release notes with every push on develop
(#3985)
[core] chore: simplify Wayland start script
(#3974)
[gitignore] restore the old Git behavior for the default modules
(#3968)
[core] configure cspell to check default modules only and fix typos
(#3955)
[gitignore] restoring the old Git behavior for the CSS directory
(#3954)
feat(core): add server:watch script with automatic restart on file
changes (#3920)
[check_config] refactor: improve error handling
(#3927)
refactor: replace express-ipfilter with lightweight custom middleware
(#3917)
refactor: replace module-alias dependency with internal alias resolver
(#3893)

[dependencies]

[chore] update dependencies and min. node version
(#3986)
[core] bump dependencies into december
(#3982)
Bump actions/checkout from 5 to 6
(#3972)
Update deps, unpin parse5
(#3934)
[core] Update deps and pin jsdom to v27.0.0
(#3925)
chore: update dependencies
(#3921)
update deps, exclude node v23
(#3916)
remove eslint warnings, add npm publish process to Collaboration.md
(#3913)
feat: add ESlint rule no-sparse-arrays for config check
(#3911)
chore: bump dependencies into october
(#3909)

[logging]

logger: add calling filename as prefix on server side
(#3926)
[logger] Add prefixes to most Log messages
(#3923)

[modules/alert]
Add new pt and pt-BR translations for Alert module and update global PT
strings (#3965)

[modules/calendar]
add checksum to test whether calendar event list changed
(#3988)
[calendar] fix: prevent excessive fetching on client reload and refactor
calendarfetcherutils.js
(#3976)
[calendar] refactor: migrate CalendarFetcher to ES6 class and improve
error handling (#3959)
[calendar] Show repeatingCountTitle only if yearDiff > 0
(#3949)
[tests] suppress debug logs in CI environment + improve calendar symbol
test stability (#3941)
[calendar] chore: remove requiresVersion: "2.1.0"
(#3932)
[calendar] test: remove "Recurring event per timezone" test
(#3929)

[modules/compliments]
[compliments] refactor: optimize loadComplimentFile method and add unit
tests (#3969)
fix: set compliments remote file minimum delay to 15 minutes
(#3970)
[compliments] fix: duplicate query param "?" in compliments module
refresh url (#3967)

[modules/newsfeed]
[newsfeed] fix header layout issue
(#3946)

[modules/weather]
[weatherprovider] update subclass language use override
(#3914)
[weather] fix wind-icon not showing in pirateweather
(#3957)
[weather] add error handling to weather fetch functions, including cors
(#3791)
remove deprecated ukmetoffice datapoint provider, cleanup .gitignore
(#3952)
fixes problems with daylight-saving-time in weather provider openmeteo
(#3931)
Fix for envcanada Provider to use updated Env Canada URL
(#3919)
[weather] feat: add configurable forecast date format option
(#3918)

[testing]
testing: update "Enforce Pull-Request Rules" workflow
(#3987)
[core] refactor: replace XMLHttpRequest with fetch and migrate e2e tests
to Playwright (#3950)
[test] replace node-libgpiod with serialport in electron-rebuild
workflow (#3945)
[ci] Add concurrency to automated tests workflow to cancel outdated runs
(#3943)
[tests] migrate from jest to vitest
(#3940)

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: Karsten Hassel <hassel@gmx.de>
Co-authored-by: Kristjan ESPERANTO <35647502+KristjanESPERANTO@users.noreply.github.com>
Co-authored-by: Ryan Williams <65094007+ryan-d-williams@users.noreply.github.com>
Co-authored-by: Veeck <github@veeck.de>
Co-authored-by: Bugsounet - Cédric <github@bugsounet.fr>
Co-authored-by: Marc Landis <dirk.rettschlag@gmail.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: HeikoGr <20295490+HeikoGr@users.noreply.github.com>
Co-authored-by: Pedro Lamas <pedrolamas@gmail.com>
Co-authored-by: veeck <gitkraken@veeck.de>
Co-authored-by: Magnus <34011212+MagMar94@users.noreply.github.com>
Co-authored-by: Ikko Eltociear Ashimine <eltociear@gmail.com>
Co-authored-by: DevIncomin <56730075+Developer-Incoming@users.noreply.github.com>
Co-authored-by: Nathan <n8nyoung@gmail.com>
Co-authored-by: mixasgr <mixasgr@users.noreply.github.com>
Co-authored-by: Savvas Adamtziloglou <savvas-gr@greeklug.gr>
Co-authored-by: Konstantinos <geraki@gmail.com>
Co-authored-by: OWL4C <124401812+OWL4C@users.noreply.github.com>
Co-authored-by: BugHaver <43462320+bughaver@users.noreply.github.com>
Co-authored-by: BugHaver <43462320+lsaadeh@users.noreply.github.com>
Co-authored-by: Koen Konst <koenspero@gmail.com>
Co-authored-by: Koen Konst <c.h.konst@avisi.nl>
Co-authored-by: dathbe <github@beffa.us>
Co-authored-by: Marcel <m-idler@users.noreply.github.com>
Co-authored-by: Kevin G. <crazylegstoo@gmail.com>
Co-authored-by: Jboucly <33218155+jboucly@users.noreply.github.com>
Co-authored-by: Jboucly <contact@jboucly.fr>
Co-authored-by: Jarno <54169345+jarnoml@users.noreply.github.com>
Co-authored-by: Jordan Welch <JordanHWelch@gmail.com>
Co-authored-by: Blackspirits <blackspirits@gmail.com>
Co-authored-by: Samed Ozdemir <samed@xsor.io>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants