chore(next): upgrade preview and isolate dev services

This commit is contained in:
ajnart committed 2026-07-29 06:47:07 +02:00
1 parent ac73b9d891
commit 4ca0b747bb
9 files changed
+1651 -1437

No files matched your search

@@ -14,8 +14,8 @@ This guide will help you set up your development environment to start contributi
### Prerequisites
- **Node.js (lts)**: You can download it from the [official website](https://nodejs.org/).
- **pnpm (latest)**: You can install it by running `npm install -g pnpm`.
- **Node.js 24.18 or newer**: You can download it from the [official website](https://nodejs.org/).
- **Corepack**: Run `corepack enable` so the repository selects its pinned pnpm version.
- **Git**: You can download it from the [official website](https://git-scm.com/).
- **Docker or Docker Desktop**: You can download it from the [official website](https://www.docker.com/).
- **A GitHub account**: You can create one on the [official website](https://github.com/).
@@ -48,7 +48,11 @@ This guide will help you set up your development environment to start contributi
#### During development
- `pnpm dev`: Start the development server.
- `pnpm dev`: Start Next.js, the task runner, and the WebSocket server as separate development processes.
- `pnpm -F nextjs dev`: Start only the Next.js UI when background services are not needed.
- `pnpm dev:benchmark`: Run the local authenticated-board benchmark. Set `DEV_BENCHMARK_BOARD_URL` and
`DEV_BENCHMARK_STORAGE_STATE`; readiness-only measurements require the explicit `--smoke` flag and are not
suitable for performance claims.
- `pnpm cli`: Run cli commands.
- `pnpm db:migration:sqlite:run`: Run the migrations to create or update the sqlite db file.
- `pnpm db:migration:sqlite:generate`: Generate a new migration file for the sqlite db. Also works with `mysql`.
@@ -63,6 +67,7 @@ This guide will help you set up your development environment to start contributi
- `pnpm typecheck`: Run the typescript type checker.
#### Building the project
- `pnpm build`: Build the project for production.
- `docker build -t homarr .`: Build a docker image for the project.
- `docker run -p 7575:7575 -e SECRET_ENCRYPTION_KEY='your_64_character_hex_string' homarr:latest`: Run the created docker image.
- `docker run -p 7575:7575 -e SECRET_ENCRYPTION_KEY='your_64_character_hex_string' homarr:latest`: Run the created docker image.
+21 -11
View File
@@ -1,4 +1,6 @@
// Importing env files here to validate on build
import path from "node:path";
import "@homarr/auth/env";
import "@homarr/core/infrastructure/db/env";
import "@homarr/common/env";
@@ -13,7 +15,21 @@ const withNextIntl = createNextIntlPlugin({
requestConfig: "../../packages/translation/src/request.ts",
});
const getDevelopmentServiceAliases = () => {
if (process.env.NODE_ENV !== "development") {
return undefined;
}
return {
"@homarr/tasks": "./src/instrumentation-noop.ts",
"@homarr/websocket": "./src/instrumentation-noop.ts",
};
};
const nextConfig: NextConfig = {
// Next previews otherwise create agent instruction files in the application
// directory during development.
agentRules: false,
env: {
HOMARR_VERSION: process.env.HOMARR_VERSION ?? "unknown",
},
@@ -30,19 +46,13 @@ const nextConfig: NextConfig = {
serverExternalPackages: ["dockerode", "isomorphic-dompurify", "jsdom", "better-sqlite3"],
experimental: {
optimizePackageImports: ["@mantine/core", "@mantine/hooks", "@tabler/icons-react"],
turbopackFileSystemCacheForDev: true,
webpackMemoryOptimizations: true,
useTypeScriptCli: true,
},
turbopack: {
// ponytail: known Turbopack NFT warning from path.join(process.cwd(), …) in
// src/app/api/backup/{route,shared}.ts. No working placement in 16.2.x
// (see vercel/next.js#95125). Suppress until upstream fix lands.
ignoreIssue: [
{
path: "**/*",
title: "Encountered unexpected file in NFT list",
},
],
root: path.resolve(import.meta.dirname, "../.."),
// Development runs tasks and WebSocket as separate processes. These aliases
// keep their production-only instrumentation imports out of the dev graph.
resolveAlias: getDevelopmentServiceAliases(),
},
transpilePackages: ["@homarr/ui", "@homarr/notifications", "@homarr/modals", "@homarr/spotlight", "@homarr/widgets"],
images: {
+3
View File
@@ -0,0 +1,3 @@
// Development runs background services as separate processes. The aliases in
// next.config.ts keep production-only instrumentation imports out of the graph.
export const instrumentationNoop = true;
+55
View File
@@ -0,0 +1,55 @@
// @vitest-environment node
import { afterEach, beforeEach, describe, expect, test, vi } from "vitest";
const registerAsync = async (nodeEnv: string, nextRuntime: string) => {
const tasksStarted = vi.fn();
const websocketStarted = vi.fn();
vi.stubEnv("NODE_ENV", nodeEnv);
vi.stubEnv("NEXT_RUNTIME", nextRuntime);
vi.doMock("@homarr/tasks", () => {
tasksStarted();
return {};
});
vi.doMock("@homarr/websocket", () => {
websocketStarted();
return {};
});
const { register } = await import("./instrumentation");
await register();
return { tasksStarted, websocketStarted };
};
describe("Next instrumentation", () => {
beforeEach(() => {
vi.resetModules();
});
afterEach(() => {
vi.doUnmock("@homarr/tasks");
vi.doUnmock("@homarr/websocket");
vi.unstubAllEnvs();
});
test("embeds background services in the production Node runtime", async () => {
const { tasksStarted, websocketStarted } = await registerAsync("production", "nodejs");
expect(tasksStarted).toHaveBeenCalledOnce();
expect(websocketStarted).toHaveBeenCalledOnce();
});
test("does not embed background services in the development server", async () => {
const { tasksStarted, websocketStarted } = await registerAsync("development", "nodejs");
expect(tasksStarted).not.toHaveBeenCalled();
expect(websocketStarted).not.toHaveBeenCalled();
});
test("does not embed Node services in the edge runtime", async () => {
const { tasksStarted, websocketStarted } = await registerAsync("production", "edge");
expect(tasksStarted).not.toHaveBeenCalled();
expect(websocketStarted).not.toHaveBeenCalled();
});
});
+5 -4
View File
@@ -1,6 +1,7 @@
export async function register() {
if (process.env.NEXT_RUNTIME === "nodejs") {
await import("@homarr/tasks");
await import("@homarr/websocket");
}
if (process.env.NEXT_RUNTIME !== "nodejs") return;
if (process.env.NODE_ENV !== "production") return;
await import("@homarr/tasks");
await import("@homarr/websocket");
}
+3 -2
View File
@@ -19,7 +19,8 @@
"db:migration:sqlite:run": "pnpm -F db migration:sqlite:run",
"db:push": "pnpm -F db push:sqlite",
"db:studio": "pnpm -F db studio",
"dev": "pnpm -F nextjs dev",
"dev": "concurrently \"pnpm -F nextjs dev\" \"pnpm -F @homarr/tasks dev\" \"pnpm -F @homarr/websocket dev\"",
"dev:benchmark": "node --experimental-strip-types scripts/benchmarks/dev-board.mts",
"dev:docs": "pnpm -F @homarr/docs dev",
"docker:dev": "docker compose -f ./development/development.docker-compose.yml up",
"format": "turbo format --continue -- --check",
@@ -30,7 +31,7 @@
"release": "semantic-release",
"scripts:update-bug-report-template": "tsx ./scripts/update-bug-report-template.mts",
"scripts:update-readme-integrations": "tsx ./scripts/update-integration-list.mts",
"start": "concurrently \"pnpm with-env node apps/tasks/tasks.cjs\" \"pnpm with-env node apps/websocket/wssServer.cjs\" \"pnpm -F nextjs start\"",
"start": "pnpm -F nextjs start",
"test": "cross-env NODE_ENV=development CI=true vitest run --exclude e2e --coverage.enabled ",
"test:e2e": "cross-env NODE_ENV=development CI=true vitest e2e",
"test:ui": "cross-env NODE_ENV=development CI=true vitest --exclude e2e --ui --coverage.enabled",
+1 -1
View File
@@ -4,5 +4,5 @@
"tsBuildInfoFile": "node_modules/.cache/tsbuildinfo.json"
},
"include": ["."],
"exclude": ["node_modules"]
"exclude": ["node_modules", "migrations/*/migrate.cjs"]
}
+1551 -1413
View File
File diff suppressed because it is too large. Load diff
+3 -2
View File
@@ -146,7 +146,7 @@ catalog:
mcp-handler: ^1.1.0
maria2: ^0.4.1
mysql2: 3.22.6
next: 16.2.10
next: 16.3.0-preview.9
next-auth: 5.0.0-beta.31
next-intl: 4.13.1
node-loader: ^2.1.0
@@ -177,7 +177,7 @@ catalog:
tsdav: ^2.3.0
tsx: 4.20.4
turbo: ^2.10.4
typescript: "npm:@typescript/typescript6@^6.0.2"
typescript: 7.0.2
vite: ^8.1.4
undici: 7.28.0
use-deep-compare-effect: ^1.8.1
@@ -201,6 +201,7 @@ minimumReleaseAge: 4320
minimumReleaseAgeExclude:
- next
- "@next/*"
- "typescript@7.0.2"
- "@immich/sdk@3.0.0"
# Renovate security update: turbo@2.9.14
- turbo@2.9.14