fix: upgrade Next.js and refresh Docker runtime

This commit is contained in:
joshuafhiggins committed 2026-10-22 17:09:03 -04:00 Verified
1 parent 60934ea1d6
commit d66a428ad7
7 files changed
+358 -288

No files matched your search

+7
View File
@@ -0,0 +1,7 @@
.git
.next
node_modules
.idea
.env*
npm-debug.log*
*.tsbuildinfo
+4 -4
View File
@@ -3,9 +3,9 @@
# ============================================ # ============================================
# IMPORTANT: Node.js Version Maintenance # IMPORTANT: Node.js Version Maintenance
# This Dockerfile uses Node.js 24.13.0-slim, which was the latest LTS version at the time of writing. # This Dockerfile uses Node.js 24.22.1-slim, which was the latest LTS version at the time of writing.
# To ensure security and compatibility, regularly update the NODE_VERSION ARG to the latest LTS version. # To ensure security and compatibility, regularly update the NODE_VERSION ARG to the latest LTS version.
ARG NODE_VERSION=24.13.0-slim ARG NODE_VERSION=24.22.1-slim
FROM node:${NODE_VERSION} AS dependencies FROM node:${NODE_VERSION} AS dependencies
@@ -13,7 +13,7 @@ FROM node:${NODE_VERSION} AS dependencies
WORKDIR /app WORKDIR /app
# Copy package-related files first to leverage Docker's caching mechanism # Copy package-related files first to leverage Docker's caching mechanism
COPY package.json yarn.lock* package-lock.json* pnpm-lock.yaml* .npmrc* ./ COPY package.json yarn.lock* package-lock.json* pnpm-lock.yaml* pnpm-workspace.yaml* .npmrc* ./
# Install project dependencies with frozen lockfile for reproducible builds # Install project dependencies with frozen lockfile for reproducible builds
RUN --mount=type=cache,target=/root/.npm \ RUN --mount=type=cache,target=/root/.npm \
@@ -109,4 +109,4 @@ USER node
EXPOSE 3000 EXPOSE 3000
# Start Next.js standalone server # Start Next.js standalone server
CMD ["node", "server.js"] CMD ["node", "server.js"]
+8 -15
View File
@@ -1,16 +1,9 @@
import { dirname } from "path"; import { defineConfig, globalIgnores } from "eslint/config";
import { fileURLToPath } from "url"; import nextVitals from "eslint-config-next/core-web-vitals";
import { FlatCompat } from "@eslint/eslintrc"; import nextTs from "eslint-config-next/typescript";
const __filename = fileURLToPath(import.meta.url); export default defineConfig([
const __dirname = dirname(__filename); ...nextVitals,
...nextTs,
const compat = new FlatCompat({ globalIgnores([".next/**", "out/**", "build/**", "next-env.d.ts"]),
baseDirectory: __dirname, ]);
});
const eslintConfig = [
...compat.extends("next/core-web-vitals", "next/typescript"),
];
export default eslintConfig;
+4 -5
View File
@@ -1,12 +1,11 @@
import type { NextConfig } from "next"; import type { NextConfig } from "next";
const nextConfig: NextConfig = { const nextConfig: NextConfig = {
/* config options here */
};
module.exports = {
// ... rest of the configuration.
output: "standalone", output: "standalone",
outputFileTracingIncludes: {
"/api/posts": ["./posts/**/*"],
"/posts/*": ["./posts/**/*"],
},
}; };
export default nextConfig; export default nextConfig;
+307 -236
View File
File diff suppressed because it is too large. Load diff
+3 -4
View File
@@ -6,26 +6,25 @@
"dev": "next dev --turbopack", "dev": "next dev --turbopack",
"build": "next build", "build": "next build",
"start": "next start", "start": "next start",
"lint": "next lint" "lint": "eslint ."
}, },
"dependencies": { "dependencies": {
"cookies-next": "^6.0.0", "cookies-next": "^6.0.0",
"gray-matter": "^4.0.3", "gray-matter": "^4.0.3",
"lucide-react": "^0.511.0", "lucide-react": "^0.511.0",
"next": "16.2.4", "next": "16.4.2",
"react": "19.2.5", "react": "19.2.5",
"react-audio-player": "^0.17.0", "react-audio-player": "^0.17.0",
"react-dom": "19.2.5", "react-dom": "19.2.5",
"react-markdown": "^10.1.0" "react-markdown": "^10.1.0"
}, },
"devDependencies": { "devDependencies": {
"@eslint/eslintrc": "^3",
"@tailwindcss/postcss": "^4", "@tailwindcss/postcss": "^4",
"@types/node": "^20", "@types/node": "^20",
"@types/react": "19.2.14", "@types/react": "19.2.14",
"@types/react-dom": "19.2.3", "@types/react-dom": "19.2.3",
"eslint": "^9", "eslint": "^9",
"eslint-config-next": "16.2.4", "eslint-config-next": "16.4.2",
"tailwindcss": "^4", "tailwindcss": "^4",
"typescript": "^5" "typescript": "^5"
}, },
+25 -24
View File
@@ -2,21 +2,22 @@
import Image from "next/image"; import Image from "next/image";
import ReactAudioPlayer from "react-audio-player"; import ReactAudioPlayer from "react-audio-player";
import {useEffect, useState} from "react"; import {useEffect, useRef} from "react";
import { getCookie, setCookie } from "cookies-next"; import { getCookie, setCookie } from "cookies-next";
export default function RecordBox() { export default function RecordBox() {
let player: ReactAudioPlayer | null = null; const player = useRef<ReactAudioPlayer>(null);
let notes: HTMLImageElement | null = null; const notes = useRef<HTMLImageElement>(null);
const shouldAutoPlay = useRef(true);
const [firstSong, setFirstSong] = useState<string | undefined>();
const [shouldAutoPlay, setShouldAutoPlay] = useState<boolean>(true);
useEffect(() => { useEffect(() => {
setFirstSong(randomSong());
// Get autoplay preference from cookie
const autoplayCookie = getCookie('jukebox-autoplay'); const autoplayCookie = getCookie('jukebox-autoplay');
setShouldAutoPlay(autoplayCookie === 'true' || autoplayCookie === undefined); shouldAutoPlay.current = autoplayCookie === 'true' || autoplayCookie === undefined;
const audio = player.current?.audioEl.current;
if (audio) {
audio.autoplay = shouldAutoPlay.current;
audio.src = randomSong();
}
}, []); }, []);
return <div> return <div>
@@ -24,38 +25,38 @@ export default function RecordBox() {
className="hidden bottom-23 right-0 fixed z-50 pb-2 pr-2" className="hidden bottom-23 right-0 fixed z-50 pb-2 pr-2"
alt={"It's Playing"} width={100} height={100} src={"/musical_notes_final.gif"} alt={"It's Playing"} width={100} height={100} src={"/musical_notes_final.gif"}
unoptimized={true} unoptimized={true}
ref={(ref) => { notes = ref; }} ref={notes}
/> />
<button> <button>
<Image className="bottom-0 right-0 fixed z-50 pb-2 pr-2 cursor-pointer" <Image className="bottom-0 right-0 fixed z-50 pb-2 pr-2 cursor-pointer"
src={"/record_player.svg"} width={100} height={100} alt={"Player"} src={"/record_player.svg"} width={100} height={100} alt={"Player"}
onClick={() => { onClick={() => {
if (player != null && notes != null) { const audio = player.current?.audioEl.current;
if (player.audioEl.current.paused) { if (audio && notes.current) {
player.audioEl.current.play().then(); if (audio.paused) {
notes.className = "bottom-23 right-0 fixed z-50 pb-2 pr-2"; audio.play().then();
notes.current.className = "bottom-23 right-0 fixed z-50 pb-2 pr-2";
// Save preference for autoplay ON // Save preference for autoplay ON
setCookie('jukebox-autoplay', 'true'); setCookie('jukebox-autoplay', 'true');
setShouldAutoPlay(true); shouldAutoPlay.current = true;
} else { } else {
player.audioEl.current.pause(); audio.pause();
notes.className = "hidden bottom-23 right-0 fixed z-50 pb-2 pr-2"; notes.current.className = "hidden bottom-23 right-0 fixed z-50 pb-2 pr-2";
// Save preference for autoplay OFF // Save preference for autoplay OFF
setCookie('jukebox-autoplay', 'false'); setCookie('jukebox-autoplay', 'false');
setShouldAutoPlay(false); shouldAutoPlay.current = false;
} }
} }
}} }}
/> />
</button> </button>
<ReactAudioPlayer <ReactAudioPlayer
autoPlay={shouldAutoPlay} controls={false} className="" controls={false} className=""
volume={0.2} volume={0.2}
ref={(element) => { player = element; }} ref={player}
src={firstSong} onPlay={() => {started(player.current, notes.current)}}
onPlay={() => {started(player, notes)}} onEnded={() => {ended(player.current, notes.current, shouldAutoPlay.current)}}
onEnded={() => {ended(player, notes, shouldAutoPlay)}} onPause={() => {stopped(player.current, notes.current)}}
onPause={() => {stopped(player, notes)}}
/> />
</div> </div>
} }