1. Convert CalendarFetcher from legacy constructor function pattern to
ES6 class (which simplifies future migration from CommonJS to ES
modules).
2. Implement targeted HTTP error handling with smart retry strategies
for common calendar feed issues:
- 401/403: Extended retry delay (5× interval, min 30 min)
- 429: Retry-After header parsing with 15 min fallback
- 5xx: Exponential backoff (2^count, max 3 retries)
- 4xx: Extended retry (2× interval, min 15 min)
- Add serverErrorCount tracking for exponential backoff
- Error messages now include specific HTTP status codes and calculated
retry delays for better debugging and user feedback
Previously, CalendarFetcher did not respond appropriately to HTTP
errors, continuing to hammer endpoints without backoff, potentially
overloading servers and triggering rate limits. This refactoring
implements respectful retry strategies that adapt to server responses
and reduce unnecessary load.
Maybe we could later centralize the HTTP error handling and use it for
weather and newsfeed as well.
The PR was inspired by having worked on the calendar fetcher for
MMM-CalendarExt2, where there was already better error handling.
### 1. Replace `XMLHttpRequest` with the modern `fetch` API for loading
translation files
#### Changes
- **translator.js**: Use `fetch` with `async/await` instead of XHR
callbacks
- **loader.js**: Align URL handling and add error handling (follow-up to
fetch migration)
- **Tests**: Update infrastructure for `fetch` compatibility
#### Benefits
- Modern standard API
- Cleaner, more readable code
- Better error handling and fallback mechanisms
### 2. Migrate e2e tests to Playwright
This wasn't originally planned for this PR, but is related. While
investigating suspicious log entries which surfaced after the fetch
migration I kept running into JSDOM’s limitations. That pushed me to
migrate the E2E suite to Playwright instead.
#### Changes
- switch e2e harness to Playwright (`tests/e2e/helpers/global-setup.js`)
- rewrite specs to use Playwright locators + shared `expectTextContent`
- install Chromium via `npx playwright install --with-deps` in CI
#### Benefits
- much closer to real browser behaviour
- and no more fighting JSDOM’s quirks
## CI Log Suppression
**Two-level approach for clean test output:**
1. **Suppress debug/info logs**: Call `logger.setLogLevel("ERROR")` in
CI to hide verbose logging
2. **Suppress intentional error logs**: Set `mmTestMode` flag and check
it before logging errors that are part of test assertions (e.g., testing
error handling in `git_helper.js` and `server_functions.js`)
This keeps CI output clean and makes genuine failures immediately
visible, while preserving full logging for local development.
**Before:** 1348 log lines with verbose debug/info output
**After:** 168 log clean lines with only test results
## Calendar Symbol Test Stability
Convert the calendar symbol test from external URL (`calendarlabs.com`)
to existing local mock file (`12_events.ics`). This eliminates CI
timeouts caused by external dependencies and improves test reliability.
The test still validates the same symbol array feature but now runs
faster and deterministically without network dependencies.
This is a big change, but I think it's a good move, as `vitest` is much
more modern than `jest`.
I'm excited about the UI watch feature (run `npm run test:ui`), for
example - it's really helpful and saves time when debugging tests. I had
to adjust a few tests because they had time related issues, but
basically we are now testing the same things - even a bit better and
less flaky (I hope).
What do you think?
## 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>
- Combine file existence and permission checks with better error
messages
- Replace thrown exceptions with clean error output (no stack traces)
- Support custom module positions by changing strict validation to
warnings
- Add missing process.exit(1) after validation errors
Users now see clear, actionable error messages without stack traces, and
custom region configurations work correctly.
## example before
```bash
$ npm run start
> magicmirror@2.34.0-develop start
> node --run start:x11
[2025-10-22 17:56:06.303] [LOG] Starting MagicMirror: v2.34.0-develop
[2025-10-22 17:56:06.304] [LOG] Loading config ...
[2025-10-22 17:56:06.304] [LOG] config template file not exists, no envsubst
[2025-10-22 17:56:06.356] [ERROR] File not found: /home/kristjan/MagicMirror/config/config.js
No config file present!
[2025-10-22 17:56:06.356] [ERROR] [checkconfig] Error: Error: ENOENT: no such file or directory, access '/home/kristjan/MagicMirror/config/config.js'
No permission to access config file!
at checkConfigFile (/home/kristjan/MagicMirror/js/check_config.js:43:9)
at Object.<anonymous> (/home/kristjan/MagicMirror/js/check_config.js:138:2)
at Module._compile (node:internal/modules/cjs/loader:1714:14)
at Module._extensions..js (node:internal/modules/cjs/loader:1848:10)
at Module.load (node:internal/modules/cjs/loader:1448:32)
at Module._load (node:internal/modules/cjs/loader:1270:12)
at c._load (node:electron/js2c/node_init:2:17993)
at TracingChannel.traceSync (node:diagnostics_channel:322:14)
at wrapModuleLoad (node:internal/modules/cjs/loader:244:24)
at Module.require (node:internal/modules/cjs/loader:1470:12)
at require (node:internal/modules/helpers:147:16)
at loadConfig (/home/kristjan/MagicMirror/js/app.js:126:3)
at App.start (/home/kristjan/MagicMirror/js/app.js:291:18)
at Object.<anonymous> (/home/kristjan/MagicMirror/js/electron.js:228:7)
at Module._compile (node:internal/modules/cjs/loader:1714:14)
at Module._extensions..js (node:internal/modules/cjs/loader:1848:10)
```
## example after
```bash
$ npm run start
> magicmirror@2.34.0-develop start
> node --run start:x11
[2025-10-22 21:33:27.930] [LOG] Starting MagicMirror: v2.34.0-develop
[2025-10-22 21:33:27.931] [LOG] Loading config ...
[2025-10-22 21:33:27.931] [LOG] config template file not exists, no envsubst
[2025-10-22 21:33:27.985] [ERROR] [check_config] File not found: /home/kristjan/MagicMirror/config/config.js
```
This fixes security issue
[CVE-2023-42282](https://github.com/advisories/GHSA-78xj-cgh5-2h22),
which is not very likely to be exploitable in MagicMirror² setups, but
still should be fixed.
The [express-ipfilter](https://www.npmjs.com/package/express-ipfilter)
package depends on the obviously unmaintained
[ip](https://github.com/indutny/node-ip) package, which has known
security vulnerabilities. Since no fix is available, this commit
replaces both dependencies with a custom middleware using the better
maintained [ipaddr.js](https://www.npmjs.com/package/ipaddr.js) library.
Changes:
- Add new `js/ip_access_control.js` with lightweight middleware
- Remove `express-ipfilter` dependency, add `ipaddr.js`
- Update `js/server.js` to use new middleware
- In addition, I have formulated the descriptions of the corresponding
tests a little more clearly.
Adding a rule to the config checker config so that unexpected commas in
the middle of arrays (reported in issue #3910) are better detected.
Two commas in a row inside the modules array create an empty entry
(`undefined`). JavaScript accepts that syntax, but MagicMirror would
later try to load that “module” and fail.
Alternatively, we could filter out undefined entries, but with this PR,
the user receives a clear message indicating where the error lies, can
easily fix it, and thus has a cleaner configuration.
## Before
```
[2025-10-10 19:33:30.874] [INFO] Checking config file /home/kristjan/MagicMirror/config/config.js ...
[2025-10-10 19:33:30.944] [INFO] Your configuration file doesn't contain syntax errors :)
[2025-10-10 19:33:30.945] [INFO] Checking modules structure configuration ...
[2025-10-10 19:33:31.027] [ERROR] This module configuration contains errors:
undefinedmust be object
```
## After
```
[2025-10-10 19:41:20.030] [INFO] Checking config file /home/kristjan/MagicMirror/config/config.js ...
[2025-10-10 19:41:20.107] [ERROR] Your configuration file contains syntax errors :(
Line 91 column 1: Unexpected comma in middle of array.
```
- removes the external unmaintained `module-alias` dependency ->
reducing complexity and risk
- introduces a small internal alias mechanism for `logger` and
`node_helper`
- preserves backward compatibility for existing 3rd‑party modules
- should simplify a future ESM migration of MagicMirror
I'm confident that it shouldn't cause any problems, but we could also
consider including it in the release after next. What do you think?
This PR is inspired by PR #2934 - so thanks to @thesebas! 🙇😃
Having repeatedly seen that users are unaware of the meaning of the
EADDRINUSE error message (see, for example, this [forum
thread](https://forum.magicmirror.builders/topic/19871/update-package-list/5)),
I thought we should intercept this message and provide clearer output.
This may help users identify the cause of the problem more quickly
themselves.
## before
```
[2025-09-13 09:54:32.903] [LOG] Starting MagicMirror: v2.33.0-develop
...
[2025-09-13 09:54:33.533] [LOG] Starting server on port 8080 ...
[2025-09-13 09:54:33.537] [WARN] You're using a full whitelist configuration to allow for all IPs
[2025-09-13 09:54:33.568] [ERROR] Whoops! There was an uncaught exception...
[2025-09-13 09:54:33.574] [ERROR] Error: listen EADDRINUSE: address already in use 0.0.0.0:8080
at Server.setupListenHandle [as _listen2] (node:net:1940:16)
at listenInCluster (node:net:1997:12)
at node:net:2206:7
at process.processTicksAndRejections (node:internal/process/task_queues:90:21) {
code: 'EADDRINUSE',
errno: -98,
syscall: 'listen',
address: '0.0.0.0',
port: 8080
}
[2025-09-13 09:54:33.574] [ERROR] MagicMirror² will not quit, but it might be a good idea to check why this happened. Maybe no internet connection?
[2025-09-13 09:54:33.574] [ERROR] If you think this really is an issue, please open an issue on GitHub: https://github.com/MagicMirrorOrg/MagicMirror/issues
[2025-09-13 09:54:35.235] [INFO]
#### System Information ####
...
```
## after
```
[2025-09-13 09:53:20.151] [LOG] Starting MagicMirror: v2.33.0-develop
...
[2025-09-13 09:53:20.928] [LOG] Starting server on port 8080 ...
[2025-09-13 09:53:20.931] [WARN] You're using a full whitelist configuration to allow for all IPs
[2025-09-13 09:53:20.970] [ERROR]
────────────────────────────────────────────────────────────────
PORT IN USE: 0.0.0.0:8080
Another process (most likely another MagicMirror instance)
is already using this port.
Stop the other process (free the port) or use a different port.
────────────────────────────────────────────────────────────────
[2025-09-13 09:53:22.471] [INFO]
#### System Information ####
...
```
socket.io times out and closes the client side socket without any
callback
sendSocntNotification() from the server side data is lost as the socket
is closed. but the client doesn't know
increase the timeout
fixes#3380
Fixes#3253
Adds a configuration option to overwrite the default `User-Agent` header
that is send at least by the calendar and news module. Allows other
modules to use the individual user agent as well.
The configuration accepts either a string or a function:
```
var config =
{
...
userAgent: 'Mozilla/5.0 (My User Agent)',
...
}
```
or
```
var config =
{
...
userAgent: () => 'Mozilla/5.0 (My User Agent)',
...
}
```
---------
Co-authored-by: Veeck <github@veeck.de>
Co-authored-by: veeck <gitkraken@veeck.de>
Co-authored-by: Karsten Hassel <hassel@gmx.de>
Co-authored-by: Kristjan ESPERANTO <35647502+KristjanESPERANTO@users.noreply.github.com>
Additionally to #3839 did some rework on the system logging.
- feat: include MagicMirror version (like Sam suggested in #3839)
- refactor: use more variables to get the string array less complex
- refactor: get `installedNodeVersion` from si.versions (with that it
was possible to drop the import of `execSync`)
- fix: `used node` was always the same as the installed one. Since
Electron comes with its own node version, this can differ. This is now
shown correctly (again?) with the use of `process.version`.
- a bit formatting
I think these changes make the code easier to understand and therefore
easier to maintain. Except for showing the MM version there is no big
difference for the user.
## before
```bash
##### System Information #####
- SYSTEM: manufacturer: Notebook; model: N650DU; virtual: false; timeZone: Europe/Berlin
- OS: platform: linux; distro: Debian GNU/Linux; release: 12; arch: x64; kernel: 5.10.0-20-amd64
- VERSIONS: electron: 36.3.2; used node: 22.15.0; installed node: 22.15.0; npm: 10.9.0; pm2: 6.0.6
- ENV: XDG_SESSION_TYPE: wayland; MM_CONFIG_FILE: config/config_MMM-PublicTransportHafas.js;
WAYLAND_DISPLAY: wayland-0; DISPLAY: :0; ELECTRON_ENABLE_GPU: undefined
- RAM: total: 15925.45 MB; free: 2716.90 MB; used: 13209.04 MB
- UPTIME: 259 minutes
```
## after
```bash
#### System Information ####
- SYSTEM: manufacturer: Notebook; model: N650DU; virtual: false; MM: 2.33.0-develop
- OS: platform: linux; distro: Debian GNU/Linux; release: 12; arch: x64; kernel: 5.10.0-20-amd64
- VERSIONS: electron: 36.3.2; used node: 22.15.1; installed node: 22.15.0; npm: 10.9.0; pm2: 6.0.6
- ENV: XDG_SESSION_TYPE: wayland; MM_CONFIG_FILE: config/config_MMM-PublicTransportHafas.js
WAYLAND_DISPLAY: wayland-0; DISPLAY: :0; ELECTRON_ENABLE_GPU: undefined
- RAM: total: 15925.45 MB; free: 2814.49 MB; used: 13110.96 MB
- OTHERS: uptime: 260 minutes; timeZone: Europe/Berlin
```
When we introduced the system information, I selected `###` as the
prefix for each line. While this doesn't cause any problems in the
terminal, when someone copies the output to an issue or the forum, every
line is formatted as a heading, which is not ideal. That's why I made
some rework and suggest these changes.
In addition to the formatting changes, I added some env and RAM details
plus the uptime. These are just suggestions – if you don't think they're
worth adding, I'm happy to remove them. We wanted to keep this block
compact.
@sdetweil, since you are often on the front line with the error messages
from users: Is there any information missing in the system block that
you often have to request additionally?
Feel free to request changes!
-----
## in the terminal
### before
```
[2025-07-09 21:58:36.943] [INFO] System information:
### SYSTEM: manufacturer: Notebook; model: N650DU; virtual: false
### OS: platform: linux; distro: Debian GNU/Linux; release: 12; arch: x64; kernel: 5.10.0-20-amd64
### VERSIONS: electron: 36.3.2; used node: 24.2.0; installed node: 24.2.0; npm: 10.9.0; pm2: 6.0.6
### OTHER: timeZone: Europe/Berlin; ELECTRON_ENABLE_GPU: undefined
```
-----
### after
```
[2025-07-09 21:57:47.604] [INFO]
##### System Information #####
- SYSTEM: manufacturer: Notebook; model: N650DU; virtual: false; timeZone: Europe/Berlin
- OS: platform: linux; distro: Debian GNU/Linux; release: 12; arch: x64; kernel: 5.10.0-20-amd64
- VERSIONS: electron: 36.3.2; used node: 24.2.0; installed node: 24.2.0; npm: 10.9.0; pm2: 6.0.6
- ENV: XDG_SESSION_TYPE: wayland; MM_CONFIG_FILE: undefined;
WAYLAND_DISPLAY: wayland-0; DISPLAY: :0; ELECTRON_ENABLE_GPU: undefined
- RAM: total: 15925.45 MB; free: 967.75 MB; used: 14957.70 MB
- UPTIME: 172 minutes
```
-----
## as markdown (in an issue or the forum)
### before
[2025-07-09 21:58:36.943] [INFO] System information:
### SYSTEM: manufacturer: Notebook; model: N650DU; virtual: false
### OS: platform: linux; distro: Debian GNU/Linux; release: 12; arch:
x64; kernel: 5.10.0-20-amd64
### VERSIONS: electron: 36.3.2; used node: 24.2.0; installed node:
24.2.0; npm: 10.9.0; pm2: 6.0.6
### OTHER: timeZone: Europe/Berlin; ELECTRON_ENABLE_GPU: undefined
-----
### after
[2025-07-09 21:57:47.604] [INFO]
##### System Information #####
- SYSTEM: manufacturer: Notebook; model: N650DU; virtual: false;
timeZone: Europe/Berlin
- OS: platform: linux; distro: Debian GNU/Linux; release: 12; arch: x64;
kernel: 5.10.0-20-amd64
- VERSIONS: electron: 36.3.2; used node: 24.2.0; installed node: 24.2.0;
npm: 10.9.0; pm2: 6.0.6
- ENV: XDG_SESSION_TYPE: wayland; MM_CONFIG_FILE: undefined;
WAYLAND_DISPLAY: wayland-0; DISPLAY: :0; ELECTRON_ENABLE_GPU: undefined
- RAM: total: 15925.45 MB; free: 967.75 MB; used: 14957.70 MB
- UPTIME: 172 minutes
In PR #3806 I noticed that ESLint did not complain about the use of
`console`. Then I realised that the rule `no-console` was not activated.
I have now changed this and replaced a few places where `console` was
used.
We can't apply the rule to all .js files because not all of them use our
logger. Therefore I had to add an extra config block for it.
I was always unhappy when maintaining dependency updates to have 3
`package.json` files.
This PR moves all deps into the main `package.json` and removes the
folders `fonts` and `vendor`.
If accepted I will update the docs too.
---------
Co-authored-by: Kristjan ESPERANTO <35647502+KristjanESPERANTO@users.noreply.github.com>
`fs.F_OK` and `fs.R_OK` are [deprecated since a while node
20.8.0](https://nodejs.org/api/deprecations.html#DEP0176).
Node 24 now complains about them when running server mode (`node --run
server`):
```bash
[2025-05-23 23:11:44.932] [ERROR] (node:37733) [DEP0176] DeprecationWarning: fs.F_OK is deprecated, use fs.constants.F_OK instead
(Use `node --trace-deprecation ...` to show where the warning was created)
```
The replacements have been in place for a while, and this change should
work without any issues.
My proposal for #3761
* I use `flex` box for create region container
* I have moved `container` definition to `main.css` (for css tunning,
maybe it can be useful)
* I create `order` in module config for define module order display from
position
# Advantage:
We don't have to move module config in another place in array of modules
# Another advantage that i did'nt think:
We can change dynamicaly module order of a container:
- So, in this case, for a module config builder, (I won't mention the
name because otherwise I'll get angry...)
It can be usefull for a config preview (before saving config)
--> just change style css `order` module value for see preview
- Or, change `order` value in dev console for testing
# Disadvantages
I don't see any ;)
This has the advantage that the package manager is no longer involved
after the installation process.
However, previous start commands such as `npm run start` continue to
work. So we don't even have to adapt the documentation.
While debugging a 3rd party module, I looked at how modules are loaded
and realized that the `loadModules` method can be implemented much
simpler. This refactor makes the method easier to understand and
maintain.
Since we don't use the `raspberry` information, calling it in `si.get`
is useless.
I also made the string construction in the code a bit more readable. The
output remains the same.
fixes#3267 AGAIN, correctly, add testcase
add testcase for #3679 , broadcast clipping incorrectly
I added a test module (tests/testNotification) to catch the notification
and check the count. (one way to configure)
i put this module in the tests folder, and added /tests to the server
paths.
(can't have a module in a nested folder, like tests/modules/xxx)
but I have a problem. i can run the test config (MM_CONFIG_FILE), and
the two modules work correctly,
but in the spec runner, the calendar module times out on the broadcast
test.. there is only local ics file access, no outside hosts
I forced my system date to 1/1/24 (same as runner) and again the manual
testcase works fine
I added two test config.js,(configs/calendar) one works great (symbols)
, one fails (broadcast test)
I added additional delay in the calendarspec runner to try to debug the
module, but it still not long enough.. no messages of trouble when I get
into the browser.. BUT, this may be because of the log being turned
off... (just thought of this)
I created a special ICS (in mocks) that has 12 events, 1 for each
month.. (so I can check clipping and broadcast) the US holidays one is
sensitive to the current date, and I couldn't get it to work on
1/1/2024..
also, in general, is there a mechanism to run test:just_one_runner?
waiting thru the electron test to get to one testcase.. ugh..
Main point was to enable ESLint `dot-notation` and `no-unneeded-ternary`
rules for more code consistency.
I took the occasion to add two minor commits:
- Fix a problem found by running `test:spelling
- Minor dependency update
It wouldn't be a problem if the PR didn't arrive in the next release,
the changes are cosmetic.
user reporting slow/no connection/timeout errors on armv6l for calendar,
and newsfeed
we can increase the timeout by adding calls to the undici lib, but it
requires node 20.18.1 or above.
this adds the support for timeout
(also environment variable to override if needed,, mmFetchTimeout
(default 30 seconds)
and updates the base node version
Fix:
- use `path.resolve` for `moduleFolder` and `defaultModuleFolder` path
- Fix module path in case of sub/sub folder is used (sample
`module/test/test`)
---
case of module installation on `module/test/test`:
config will be:
```js
{
module: "test/test",
...
}
```
module core will be:
```js
Module.register("test", {
...
```
`test.js` is used for module core (no change)
---
case of module installation on `module/test` (no change):
config will be:
```js
{
module: "test",
...
}
```
module core will be:
```js
Module.register("test", {
...
```
so `test.js` is used for module core
---
In reality, with this patch, `module` config feature have 2
functionalites:
- determinate module path with more precision
- allow to use sub/sub folder in modules folder
---------
Co-authored-by: Veeck <github@veeck.de>
if the MagicMirror js folder is not writable (synology nas created by
different user than docker container) there is an uncaught throw
```
[ERROR] EACCES: permission denied, open 'js/positions.js'
```
add try/catch, output new message, console.error
```text
unable to write js/positions.js with the discovered module positions
make the MagicMirror/js folder writeable by the user starting MagicMirror
```
MM will start, but no modules will show, as no positions were discovered
this file is used to pass the list from the server side to the browser
side
fixes#3651
I am adding the animateIn/Out support to MMM-Config, but I need the list
of animations..
but they are not visible in js/animateCSS.js (from require)
adding an export satisfies that
side issue, these would go in a dropdown list
what value can I use for the default behavior? none/default?
don't want an error produced..
should I add code to check for this value to prevent error?
in some cases the modulename.js may need to detect running in test mode
(compliments pr #3630)
window.name is not set web mode
add a new field to the index.html
window.intest
and use the server_function to replace the hard coded string like we do
for window.mmversion=#VERSION#
then change the two test helpers to set the env variable
app.js detects and sets global.intest=true
server func replace with value of global.intest
then module can use if(window.intest)
fixes#3597
Changes:
- electron tests: add mocking to `electron.js` for mocking the server
side, before only the browser side was mocked
- publish "/tests/configs" and "/tests/mocks" always in `server.js`,
this reverts a change done with latest release, we need this for
debugging (otherwise you get on the screen that your config has errors
but config check is successful ...)
- revert hotfix in
`tests/configs/modules/calendar/show-duplicates-in-calendar.js`
- fix `tests/configs/modules/calendar/custom.js` to allow events in the
past (~~I don't know how this could work before~~ when testing css
classes `yesterday` and `dayBeforeYesterday` --> it worked before
because the server side did not mock and therefore was not in the past)
When a library is missing on an 3rd party module, MM² stop loading and
display a black screen. (I'm sure it's happened to everyone.)
So, I have added a try/catch block and it's avoid black screen, display
errors and allow continue loading with next module
after adding check:config to the MM startup process, #3450, we
accidentally discover module positions more than once, and write the
file each time..
add a check to see if we have done this work already
Since PR #3551 was not yet complete, I made my own attempt.
1. Update to ESLint v9.
2. Replace deprecated `.eslintrc.json` and `.eslintignore` by flat
config `eslint.config.mjs`.
3. Adapt `check_config.js` to use flat config.
4. Since `eslint-plugin-import` still doesn't support ESLint v9 I
removed it. We can add it back when it does support v9.
5. Run tests `npm run check:js` and `npm run config:check`.
6. In order not to overload this PR, I have not yet activated more
additional rules - there are some useful ones in the new plugin
`@eslint/js`.
@bugsounet, please don't take it as an offence that I have created a
competing PR. The migration to ESLint v9 has been burning under my nails
for some time.