feat(blog): add file-based blog with dynamic slugs, MDX content and layout shell

- Introduced blog routing using Next.js App Router
- Implemented dynamic [slug] pages for blog posts
- Added MDX-based content loading via lib/posts
- Integrated shared TopBar layout with navigation
- Established clear content, lib and component separation
This commit is contained in:
PascalSchattenburg
2026-01-22 14:14:15 +01:00
parent b717952234
commit d147843c76
10412 changed files with 2475583 additions and 0 deletions

View File

@@ -0,0 +1,35 @@
import type { ExportAppResult } from '../export/types';
interface BuildDiagnostics {
buildStage?: string;
buildOptions?: Record<string, string>;
}
/**
* Saves the exact version of Next.js that was used to build the app to a diagnostics file.
*/
export declare function recordFrameworkVersion(version: string): Promise<void>;
/**
* Saves build diagnostics information to a file. This method can be called
* multiple times during a build to save additional information that can help
* debug a build such as what stage the build was in when a failure happened.
* Each time this method is called, the new information will be merged with any
* existing build diagnostics that previously existed.
*/
export declare function updateBuildDiagnostics(diagnostics: BuildDiagnostics): Promise<void>;
/**
* Writes fetch metrics collected during static generation to a file.
*/
export declare function recordFetchMetrics(exportResult: ExportAppResult): Promise<void>;
interface IncrementalBuildDiagnostics {
changedAppPaths?: string[];
unchangedAppPaths?: string[];
changedPagePaths?: string[];
unchangedPagePaths?: string[];
changedDependencies?: Record<string, string>;
shuttleGitSha?: string;
currentGitSha?: string;
}
/**
* Writes incremental build metrics to a file.
*/
export declare function updateIncrementalBuildMetrics(diagnostics: IncrementalBuildDiagnostics): Promise<void>;
export {};

View File

@@ -0,0 +1,92 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
0 && (module.exports = {
recordFetchMetrics: null,
recordFrameworkVersion: null,
updateBuildDiagnostics: null,
updateIncrementalBuildMetrics: null
});
function _export(target, all) {
for(var name in all)Object.defineProperty(target, name, {
enumerable: true,
get: all[name]
});
}
_export(exports, {
recordFetchMetrics: function() {
return recordFetchMetrics;
},
recordFrameworkVersion: function() {
return recordFrameworkVersion;
},
updateBuildDiagnostics: function() {
return updateBuildDiagnostics;
},
updateIncrementalBuildMetrics: function() {
return updateIncrementalBuildMetrics;
}
});
const _promises = require("fs/promises");
const _path = require("path");
const _shared = require("../trace/shared");
const DIAGNOSTICS_DIR = 'diagnostics';
const DIAGNOSTICS_FILE = 'build-diagnostics.json';
const FETCH_METRICS_FILE = 'fetch-metrics.json';
const INCREMENTAL_BUILDS_FILE = 'incremental-build-diagnostics.json';
const FRAMEWORK_VERSION_FILE = 'framework.json';
async function getDiagnosticsDir() {
const distDir = _shared.traceGlobals.get('distDir');
const diagnosticsDir = (0, _path.join)(distDir, DIAGNOSTICS_DIR);
await (0, _promises.mkdir)(diagnosticsDir, {
recursive: true
});
return diagnosticsDir;
}
async function recordFrameworkVersion(version) {
const diagnosticsDir = await getDiagnosticsDir();
const frameworkVersionFile = (0, _path.join)(diagnosticsDir, FRAMEWORK_VERSION_FILE);
await (0, _promises.writeFile)(frameworkVersionFile, JSON.stringify({
name: 'Next.js',
version
}));
}
async function updateBuildDiagnostics(diagnostics) {
const diagnosticsDir = await getDiagnosticsDir();
const diagnosticsFile = (0, _path.join)(diagnosticsDir, DIAGNOSTICS_FILE);
const existingDiagnostics = JSON.parse(await (0, _promises.readFile)(diagnosticsFile, 'utf8').catch(()=>'{}'));
const updatedBuildOptions = {
...existingDiagnostics.buildOptions ?? {},
...diagnostics.buildOptions ?? {}
};
const updatedDiagnostics = {
...existingDiagnostics,
...diagnostics,
buildOptions: updatedBuildOptions
};
await (0, _promises.writeFile)(diagnosticsFile, JSON.stringify(updatedDiagnostics, null, 2));
}
async function recordFetchMetrics(exportResult) {
const diagnosticsDir = await getDiagnosticsDir();
const diagnosticsFile = (0, _path.join)(diagnosticsDir, FETCH_METRICS_FILE);
const fetchMetricsByPath = {};
for (const [appPath, { fetchMetrics }] of exportResult.byPath){
if (fetchMetrics) {
fetchMetricsByPath[appPath] = fetchMetrics;
}
}
return (0, _promises.writeFile)(diagnosticsFile, JSON.stringify(fetchMetricsByPath, null, 2));
}
async function updateIncrementalBuildMetrics(diagnostics) {
const diagnosticsDir = await getDiagnosticsDir();
const diagnosticsFile = (0, _path.join)(diagnosticsDir, INCREMENTAL_BUILDS_FILE);
const existingDiagnostics = JSON.parse(await (0, _promises.readFile)(diagnosticsFile, 'utf8').catch(()=>'{}'));
const updatedDiagnostics = {
...existingDiagnostics,
...diagnostics
};
await (0, _promises.writeFile)(diagnosticsFile, JSON.stringify(updatedDiagnostics, null, 2));
}
//# sourceMappingURL=build-diagnostics.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,59 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
const _promises = require("fs/promises");
const _os = require("os");
const _path = require("path");
const _shared = require("../trace/shared");
const _builddiagnostics = require("./build-diagnostics");
async function readBuildDiagnostics(dir) {
return JSON.parse(await (0, _promises.readFile)((0, _path.join)(dir, 'diagnostics', 'build-diagnostics.json'), 'utf8'));
}
describe('build-diagnostics', ()=>{
it('records framework version to framework.json correctly', async ()=>{
const tmpDir = await (0, _promises.mkdtemp)((0, _path.join)((0, _os.tmpdir)(), 'build-diagnostics'));
(0, _shared.setGlobal)('distDir', tmpDir);
// Record the initial diagnostics and make sure it's correct.
await (0, _builddiagnostics.recordFrameworkVersion)('14.2.3');
let diagnostics = JSON.parse(await (0, _promises.readFile)((0, _path.join)(tmpDir, 'diagnostics', 'framework.json'), 'utf8'));
expect(diagnostics.version).toEqual('14.2.3');
});
it('records build diagnostics to a file correctly', async ()=>{
const tmpDir = await (0, _promises.mkdtemp)((0, _path.join)((0, _os.tmpdir)(), 'build-diagnostics'));
(0, _shared.setGlobal)('distDir', tmpDir);
// Record the initial diagnostics and make sure it's correct.
await (0, _builddiagnostics.updateBuildDiagnostics)({
buildStage: 'compile'
});
let diagnostics = await readBuildDiagnostics(tmpDir);
expect(diagnostics.buildStage).toEqual('compile');
// Add a new build option. Make sure that existing fields are preserved.
await (0, _builddiagnostics.updateBuildDiagnostics)({
buildStage: 'compile-server',
buildOptions: {
useBuildWorker: String(false)
}
});
diagnostics = await readBuildDiagnostics(tmpDir);
expect(diagnostics.buildStage).toEqual('compile-server');
expect(diagnostics.buildOptions).toEqual({
useBuildWorker: 'false'
});
// Make sure that it keeps existing build options when adding a new one.
await (0, _builddiagnostics.updateBuildDiagnostics)({
buildStage: 'compile-client',
buildOptions: {
experimentalBuildMode: 'compile'
}
});
diagnostics = await readBuildDiagnostics(tmpDir);
expect(diagnostics.buildStage).toEqual('compile-client');
expect(diagnostics.buildOptions).toEqual({
experimentalBuildMode: 'compile',
useBuildWorker: 'false'
});
});
});
//# sourceMappingURL=build-diagnostics.test.js.map

View File

@@ -0,0 +1 @@
{"version":3,"sources":["../../src/diagnostics/build-diagnostics.test.ts"],"sourcesContent":["import { mkdtemp, readFile } from 'fs/promises'\nimport { tmpdir } from 'os'\nimport { join } from 'path'\nimport { setGlobal } from '../trace/shared'\nimport {\n recordFrameworkVersion,\n updateBuildDiagnostics,\n} from './build-diagnostics'\n\nasync function readBuildDiagnostics(dir: string) {\n return JSON.parse(\n await readFile(join(dir, 'diagnostics', 'build-diagnostics.json'), 'utf8')\n )\n}\n\ndescribe('build-diagnostics', () => {\n it('records framework version to framework.json correctly', async () => {\n const tmpDir = await mkdtemp(join(tmpdir(), 'build-diagnostics'))\n setGlobal('distDir', tmpDir)\n\n // Record the initial diagnostics and make sure it's correct.\n await recordFrameworkVersion('14.2.3')\n let diagnostics = JSON.parse(\n await readFile(join(tmpDir, 'diagnostics', 'framework.json'), 'utf8')\n )\n expect(diagnostics.version).toEqual('14.2.3')\n })\n\n it('records build diagnostics to a file correctly', async () => {\n const tmpDir = await mkdtemp(join(tmpdir(), 'build-diagnostics'))\n setGlobal('distDir', tmpDir)\n\n // Record the initial diagnostics and make sure it's correct.\n await updateBuildDiagnostics({\n buildStage: 'compile',\n })\n let diagnostics = await readBuildDiagnostics(tmpDir)\n expect(diagnostics.buildStage).toEqual('compile')\n\n // Add a new build option. Make sure that existing fields are preserved.\n await updateBuildDiagnostics({\n buildStage: 'compile-server',\n buildOptions: {\n useBuildWorker: String(false),\n },\n })\n diagnostics = await readBuildDiagnostics(tmpDir)\n expect(diagnostics.buildStage).toEqual('compile-server')\n expect(diagnostics.buildOptions).toEqual({\n useBuildWorker: 'false',\n })\n\n // Make sure that it keeps existing build options when adding a new one.\n await updateBuildDiagnostics({\n buildStage: 'compile-client',\n buildOptions: {\n experimentalBuildMode: 'compile',\n },\n })\n diagnostics = await readBuildDiagnostics(tmpDir)\n expect(diagnostics.buildStage).toEqual('compile-client')\n expect(diagnostics.buildOptions).toEqual({\n experimentalBuildMode: 'compile',\n useBuildWorker: 'false',\n })\n })\n})\n"],"names":["readBuildDiagnostics","dir","JSON","parse","readFile","join","describe","it","tmpDir","mkdtemp","tmpdir","setGlobal","recordFrameworkVersion","diagnostics","expect","version","toEqual","updateBuildDiagnostics","buildStage","buildOptions","useBuildWorker","String","experimentalBuildMode"],"mappings":";;;;0BAAkC;oBACX;sBACF;wBACK;kCAInB;AAEP,eAAeA,qBAAqBC,GAAW;IAC7C,OAAOC,KAAKC,KAAK,CACf,MAAMC,IAAAA,kBAAQ,EAACC,IAAAA,UAAI,EAACJ,KAAK,eAAe,2BAA2B;AAEvE;AAEAK,SAAS,qBAAqB;IAC5BC,GAAG,yDAAyD;QAC1D,MAAMC,SAAS,MAAMC,IAAAA,iBAAO,EAACJ,IAAAA,UAAI,EAACK,IAAAA,UAAM,KAAI;QAC5CC,IAAAA,iBAAS,EAAC,WAAWH;QAErB,6DAA6D;QAC7D,MAAMI,IAAAA,wCAAsB,EAAC;QAC7B,IAAIC,cAAcX,KAAKC,KAAK,CAC1B,MAAMC,IAAAA,kBAAQ,EAACC,IAAAA,UAAI,EAACG,QAAQ,eAAe,mBAAmB;QAEhEM,OAAOD,YAAYE,OAAO,EAAEC,OAAO,CAAC;IACtC;IAEAT,GAAG,iDAAiD;QAClD,MAAMC,SAAS,MAAMC,IAAAA,iBAAO,EAACJ,IAAAA,UAAI,EAACK,IAAAA,UAAM,KAAI;QAC5CC,IAAAA,iBAAS,EAAC,WAAWH;QAErB,6DAA6D;QAC7D,MAAMS,IAAAA,wCAAsB,EAAC;YAC3BC,YAAY;QACd;QACA,IAAIL,cAAc,MAAMb,qBAAqBQ;QAC7CM,OAAOD,YAAYK,UAAU,EAAEF,OAAO,CAAC;QAEvC,wEAAwE;QACxE,MAAMC,IAAAA,wCAAsB,EAAC;YAC3BC,YAAY;YACZC,cAAc;gBACZC,gBAAgBC,OAAO;YACzB;QACF;QACAR,cAAc,MAAMb,qBAAqBQ;QACzCM,OAAOD,YAAYK,UAAU,EAAEF,OAAO,CAAC;QACvCF,OAAOD,YAAYM,YAAY,EAAEH,OAAO,CAAC;YACvCI,gBAAgB;QAClB;QAEA,wEAAwE;QACxE,MAAMH,IAAAA,wCAAsB,EAAC;YAC3BC,YAAY;YACZC,cAAc;gBACZG,uBAAuB;YACzB;QACF;QACAT,cAAc,MAAMb,qBAAqBQ;QACzCM,OAAOD,YAAYK,UAAU,EAAEF,OAAO,CAAC;QACvCF,OAAOD,YAAYM,YAAY,EAAEH,OAAO,CAAC;YACvCM,uBAAuB;YACvBF,gBAAgB;QAClB;IACF;AACF","ignoreList":[0]}