Merge branch 'build/enforce_node_version' into 'v3'

ui_migration upgrade NodeJS version 26 and configurations

Closes #732

See merge request openflexure/openflexure-microscope-server!550
This commit is contained in:
Julian Stirling 2026-05-23 17:18:32 +00:00
commit 710883cff5
7 changed files with 951 additions and 2016 deletions

View file

@ -18,7 +18,7 @@ include:
.javascript_webapp:
extends: .javascript
variables:
JS_IMAGE: node:20
JS_IMAGE: node:26
JS_PATH: webapp
JS_CACHE_PATH: webapp/node_modules

View file

@ -11,11 +11,22 @@
_Note: If you are using a Windows OS, the following commands must be executed in a Powershell terminal._
* Install Node.js v18 (and npm)
* [Get Node.js v26 using the official installation scripts for your operating system.](https://nodejs.org/en/download/current)
* [Get Node.js v26 using the official installation scripts for your operating system.](https://nodejs.org/en/download/current) *(Optionally, you can instead install NVM as explained below)*.
* Navigate into the webapp directory with `cd webapp`
* Install dependencies with `npm install`
* Build the static web app with `npm run build`
#### ( Optional ) Using NVM "Node-Version-Manager"
If you have multiple projects that use different versions of Node.JS you can install Node Version Manager (NVM) to allow you to switch version from the terminal. To use NVM:
* [Install NVM](https://www.nvmnode.com/guide/installation.html)
* Install Node.js v26 with `nvm install 26`
* Set the Node.js to version 26 with `nvm use 26`
## Live Server
When developing it is useful to use the development server so Vue changes happen instantly without the need to rebuild. To start the development server run:

2874
webapp/package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -5,7 +5,7 @@
"description": "User interface for the OpenFlexure Microscope Server",
"author": "OpenFlexure <contact@openflexure.org> (https://www.openflexure.org)",
"engines": {
"node": ">=20.0.0"
"node": ">=26.0.0"
},
"scripts": {
"gv": "genversion src/version.js",
@ -19,44 +19,47 @@
"test:unit": "NODE_OPTIONS=--expose-gc vitest run src/tests/unit/ --no-cache --mode test --detectAsyncLeaks --coverage --isolate=true --pool=forks --silent --logHeapUsage"
},
"dependencies": {
"@vueuse/core": "^14.1.0",
"axios": "^1.7.7",
"material-design-icons": "^3.0",
"@vueuse/core": "^14.3.0",
"axios": "^1.16.1",
"material-symbols": "^0.44.8",
"mitt": "^3.0.1",
"mousetrap": "^1.6.5",
"openseadragon": "^5.0.0",
"pinia": "^3.0.4",
"pinia-plugin-persistedstate": "^4.7.1",
"uikit": "^3.24.2",
"vue": "^3.4.0"
"uikit": "^3.25.16",
"vue": "^3.5.34"
},
"devDependencies": {
"@babel/eslint-parser": "^7.28.5",
"@eslint/js": "^10.0.1",
"@pinia/testing": "^1.0.3",
"@vitejs/plugin-vue": "^6.0.6",
"@vitest/coverage-v8": "^4.1.6",
"@vue/eslint-config-prettier": "9.0.0",
"@vitejs/plugin-vue": "^6.0.7",
"@vitest/coverage-v8": "^4.1.7",
"@vue/eslint-config-prettier": "10.2.0",
"@vue/test-utils": "^2.4.10",
"autoprefixer": "^10.4.24",
"core-js": "^3.46.0",
"autoprefixer": "^10.5.0",
"core-js": "^3.49.0",
"cross-env": "^10.1.0",
"eslint": "^9.39.2",
"eslint": "^10.4.0",
"eslint-config-prettier": "^10.1.8",
"eslint-plugin-pinia": "^0.4.2",
"eslint-plugin-prettier": "^5.5.5",
"eslint-plugin-vue": "^9.20.0",
"eslint-plugin-vue": "^10.9.1",
"globals": "^17.6.0",
"happy-dom": "^20.9.0",
"less": "^4.5.1",
"material-symbols": "^0.39.1",
"less": "^4.6.4",
"postcss-html": "^1.8.1",
"postcss-less": "^6.0.0",
"prettier": "^3.2.8",
"stylelint": "^17.11.0",
"prettier": "^3.8.3",
"stylelint": "^17.12.0",
"stylelint-config-standard": "^40.0.0",
"stylelint-config-standard-less": "^4.1.0",
"typescript-eslint": "^8.59.0",
"vite": "^7.3.1",
"vitest": "^4.1.6"
"typescript-eslint": "^8.59.4",
"vite": "^8.0.13",
"vitest": "^4.1.7"
},
"overrides": {
"glob": "12.0"
},
"postcss": {
"plugins": {

View file

@ -58,7 +58,7 @@ export default {
...mapActions(useSettingsStore, ["resetState"]),
...mapActions(useWotStore, ["deleteAllThingDescriptions"]),
systemRequest: function (action) {
let message = "";
let message;
if (action == "reboot") {
message = "Restart microscope?";
} else {

View file

@ -40,6 +40,9 @@ export default defineConfig(({ command, mode }) => {
? [
(node) => {
// Check if the current AST node is an HTML element
// Node.type 1 is equal to node.type ELEMENT
// https://developer.mozilla.org/es/docs/Web/API/Node/nodeType
// https://developer.mozilla.org/es/docs/Web/API/Element
if (node.type === 1) {
// Filter out any property named "data-test-id"
node.props = node.props.filter((prop) => prop.name !== "data-test-id");
@ -60,11 +63,27 @@ export default defineConfig(({ command, mode }) => {
chunkSizeWarningLimit: 400,
rollupOptions: {
output: {
manualChunks: {
"vue-vendor": ["vue", "pinia", "pinia-plugin-persistedstate"],
openseadragon: ["openseadragon"],
uikit: ["uikit"],
utils: ["axios", "mitt", "mousetrap", "@vueuse/core"],
manualChunks(id) {
// Only split out third-party dependencies from node_modules
if (id.includes("node_modules")) {
if (id.includes("vue") || id.includes("pinia")) {
return "vue-vendor";
}
if (id.includes("openseadragon")) {
return "openseadragon";
}
if (id.includes("uikit")) {
return "uikit";
}
if (
id.includes("axios") ||
id.includes("mitt") ||
id.includes("mousetrap") ||
id.includes("@vueuse")
) {
return "utils";
}
}
},
},
},

View file

@ -61,7 +61,7 @@ export default defineConfig({
optimizer: {
web: {
enabled: true,
include: ["uikit", "openseadragon", "material-design-icons"],
include: ["uikit", "openseadragon", "material-symbols"],
},
},
},