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,8 @@
/**
* in CacheComponents, `import(...)` will be transformed into `trackDynamicImport(import(...))`.
* A dynamic import is essentially a cached async function, except it's cached by the module system.
*
* The promises are tracked globally regardless of if the `import()` happens inside a render or outside of it.
* When rendering, we can make the `cacheSignal` wait for all pending promises via `trackPendingModules`.
* */
export declare function trackDynamicImport<TExports extends Record<string, any>>(modulePromise: Promise<TExports>): Promise<TExports>;

View File

@@ -0,0 +1,57 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
Object.defineProperty(exports, "trackDynamicImport", {
enumerable: true,
get: function() {
return trackDynamicImport;
}
});
const _invarianterror = require("../../../shared/lib/invariant-error");
const _isthenable = require("../../../shared/lib/is-thenable");
const _trackmoduleloadingexternal = require("./track-module-loading.external");
function trackDynamicImport(modulePromise) {
if (process.env.NEXT_RUNTIME === 'edge') {
throw Object.defineProperty(new _invarianterror.InvariantError("Dynamic imports should not be instrumented in the edge runtime, because `cacheComponents` doesn't support it"), "__NEXT_ERROR_CODE", {
value: "E687",
enumerable: false,
configurable: true
});
}
if (!(0, _isthenable.isThenable)(modulePromise)) {
// We're expecting `import()` to always return a promise. If it's not, something's very wrong.
throw Object.defineProperty(new _invarianterror.InvariantError('`trackDynamicImport` should always receive a promise. Something went wrong in the dynamic imports transform.'), "__NEXT_ERROR_CODE", {
value: "E677",
enumerable: false,
configurable: true
});
}
// Even if we're inside a prerender and have `workUnitStore.cacheSignal`, we always track the promise globally.
// (i.e. via the global `moduleLoadingSignal` that `trackPendingImport` uses internally).
//
// We do this because the `import()` promise might be cached in userspace:
// (which is quite common for e.g. lazy initialization in libraries)
//
// let promise;
// function doDynamicImportOnce() {
// if (!promise) {
// promise = import("...");
// // transformed into:
// // promise = trackDynamicImport(import("..."));
// }
// return promise;
// }
//
// If multiple prerenders (e.g. multiple pages) depend on `doDynamicImportOnce`,
// we have to wait for the import *in all of them*.
// If we only tracked it using `workUnitStore.cacheSignal.trackRead()`,
// then only the first prerender to call `doDynamicImportOnce` would wait --
// Subsequent prerenders would re-use the existing `promise`,
// and `trackDynamicImport` wouldn't be called again in their scope,
// so their respective CacheSignals wouldn't wait for the promise.
(0, _trackmoduleloadingexternal.trackPendingImport)(modulePromise);
return modulePromise;
}
//# sourceMappingURL=track-dynamic-import.js.map

View File

@@ -0,0 +1 @@
{"version":3,"sources":["../../../../src/server/app-render/module-loading/track-dynamic-import.ts"],"sourcesContent":["import { InvariantError } from '../../../shared/lib/invariant-error'\nimport { isThenable } from '../../../shared/lib/is-thenable'\nimport { trackPendingImport } from './track-module-loading.external'\n\n/**\n * in CacheComponents, `import(...)` will be transformed into `trackDynamicImport(import(...))`.\n * A dynamic import is essentially a cached async function, except it's cached by the module system.\n *\n * The promises are tracked globally regardless of if the `import()` happens inside a render or outside of it.\n * When rendering, we can make the `cacheSignal` wait for all pending promises via `trackPendingModules`.\n * */\nexport function trackDynamicImport<TExports extends Record<string, any>>(\n modulePromise: Promise<TExports>\n): Promise<TExports> {\n if (process.env.NEXT_RUNTIME === 'edge') {\n throw new InvariantError(\n \"Dynamic imports should not be instrumented in the edge runtime, because `cacheComponents` doesn't support it\"\n )\n }\n\n if (!isThenable(modulePromise)) {\n // We're expecting `import()` to always return a promise. If it's not, something's very wrong.\n throw new InvariantError(\n '`trackDynamicImport` should always receive a promise. Something went wrong in the dynamic imports transform.'\n )\n }\n\n // Even if we're inside a prerender and have `workUnitStore.cacheSignal`, we always track the promise globally.\n // (i.e. via the global `moduleLoadingSignal` that `trackPendingImport` uses internally).\n //\n // We do this because the `import()` promise might be cached in userspace:\n // (which is quite common for e.g. lazy initialization in libraries)\n //\n // let promise;\n // function doDynamicImportOnce() {\n // if (!promise) {\n // promise = import(\"...\");\n // // transformed into:\n // // promise = trackDynamicImport(import(\"...\"));\n // }\n // return promise;\n // }\n //\n // If multiple prerenders (e.g. multiple pages) depend on `doDynamicImportOnce`,\n // we have to wait for the import *in all of them*.\n // If we only tracked it using `workUnitStore.cacheSignal.trackRead()`,\n // then only the first prerender to call `doDynamicImportOnce` would wait --\n // Subsequent prerenders would re-use the existing `promise`,\n // and `trackDynamicImport` wouldn't be called again in their scope,\n // so their respective CacheSignals wouldn't wait for the promise.\n trackPendingImport(modulePromise)\n\n return modulePromise\n}\n"],"names":["trackDynamicImport","modulePromise","process","env","NEXT_RUNTIME","InvariantError","isThenable","trackPendingImport"],"mappings":";;;;+BAWgBA;;;eAAAA;;;gCAXe;4BACJ;4CACQ;AAS5B,SAASA,mBACdC,aAAgC;IAEhC,IAAIC,QAAQC,GAAG,CAACC,YAAY,KAAK,QAAQ;QACvC,MAAM,qBAEL,CAFK,IAAIC,8BAAc,CACtB,iHADI,qBAAA;mBAAA;wBAAA;0BAAA;QAEN;IACF;IAEA,IAAI,CAACC,IAAAA,sBAAU,EAACL,gBAAgB;QAC9B,8FAA8F;QAC9F,MAAM,qBAEL,CAFK,IAAII,8BAAc,CACtB,iHADI,qBAAA;mBAAA;wBAAA;0BAAA;QAEN;IACF;IAEA,+GAA+G;IAC/G,yFAAyF;IACzF,EAAE;IACF,0EAA0E;IAC1E,oEAAoE;IACpE,EAAE;IACF,iBAAiB;IACjB,qCAAqC;IACrC,sBAAsB;IACtB,iCAAiC;IACjC,6BAA6B;IAC7B,wDAAwD;IACxD,QAAQ;IACR,sBAAsB;IACtB,MAAM;IACN,EAAE;IACF,gFAAgF;IAChF,mDAAmD;IACnD,uEAAuE;IACvE,4EAA4E;IAC5E,6DAA6D;IAC7D,oEAAoE;IACpE,kEAAkE;IAClEE,IAAAA,8CAAkB,EAACN;IAEnB,OAAOA;AACT","ignoreList":[0]}

View File

@@ -0,0 +1,2 @@
import { trackPendingChunkLoad, trackPendingImport, trackPendingModules } from './track-module-loading.instance';
export { trackPendingChunkLoad, trackPendingImport, trackPendingModules };

View File

@@ -0,0 +1,32 @@
// NOTE: this is marked as shared/external because it's stateful
// and the state needs to be shared between app-render (which waits for pending imports)
// and helpers used in transformed page code (which register pending imports)
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
0 && (module.exports = {
trackPendingChunkLoad: null,
trackPendingImport: null,
trackPendingModules: null
});
function _export(target, all) {
for(var name in all)Object.defineProperty(target, name, {
enumerable: true,
get: all[name]
});
}
_export(exports, {
trackPendingChunkLoad: function() {
return _trackmoduleloadinginstance.trackPendingChunkLoad;
},
trackPendingImport: function() {
return _trackmoduleloadinginstance.trackPendingImport;
},
trackPendingModules: function() {
return _trackmoduleloadinginstance.trackPendingModules;
}
});
const _trackmoduleloadinginstance = require("./track-module-loading.instance");
//# sourceMappingURL=track-module-loading.external.js.map

View File

@@ -0,0 +1 @@
{"version":3,"sources":["../../../../src/server/app-render/module-loading/track-module-loading.external.ts"],"sourcesContent":["// NOTE: this is marked as shared/external because it's stateful\n// and the state needs to be shared between app-render (which waits for pending imports)\n// and helpers used in transformed page code (which register pending imports)\n\nimport {\n trackPendingChunkLoad,\n trackPendingImport,\n trackPendingModules,\n} from './track-module-loading.instance' with { 'turbopack-transition': 'next-shared' }\n\nexport { trackPendingChunkLoad, trackPendingImport, trackPendingModules }\n"],"names":["trackPendingChunkLoad","trackPendingImport","trackPendingModules"],"mappings":"AAAA,gEAAgE;AAChE,wFAAwF;AACxF,6EAA6E;;;;;;;;;;;;;;;;;IAQpEA,qBAAqB;eAArBA,iDAAqB;;IAAEC,kBAAkB;eAAlBA,8CAAkB;;IAAEC,mBAAmB;eAAnBA,+CAAmB;;;4CAFhE","ignoreList":[0]}

View File

@@ -0,0 +1,12 @@
import { CacheSignal } from '../cache-signal';
export declare function trackPendingChunkLoad(promise: Promise<unknown>): void;
export declare function trackPendingImport(exportsOrPromise: unknown): void;
/**
* A top-level dynamic import (or chunk load):
*
* 1. delays a prerender (potentially for a task or longer)
* 2. may reveal more caches that need be filled
*
* So if we see one, we want to extend the duration of `cacheSignal` at least until the import/chunk-load is done.
*/
export declare function trackPendingModules(cacheSignal: CacheSignal): void;

View File

@@ -0,0 +1,66 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
0 && (module.exports = {
trackPendingChunkLoad: null,
trackPendingImport: null,
trackPendingModules: null
});
function _export(target, all) {
for(var name in all)Object.defineProperty(target, name, {
enumerable: true,
get: all[name]
});
}
_export(exports, {
trackPendingChunkLoad: function() {
return trackPendingChunkLoad;
},
trackPendingImport: function() {
return trackPendingImport;
},
trackPendingModules: function() {
return trackPendingModules;
}
});
const _cachesignal = require("../cache-signal");
const _isthenable = require("../../../shared/lib/is-thenable");
/**
* Tracks all in-flight async imports and chunk loads.
* Initialized lazily, because we don't want this to error in case it gets pulled into an edge runtime module.
*/ let _moduleLoadingSignal;
function getModuleLoadingSignal() {
if (!_moduleLoadingSignal) {
_moduleLoadingSignal = new _cachesignal.CacheSignal();
}
return _moduleLoadingSignal;
}
function trackPendingChunkLoad(promise) {
const moduleLoadingSignal = getModuleLoadingSignal();
moduleLoadingSignal.trackRead(promise);
}
function trackPendingImport(exportsOrPromise) {
const moduleLoadingSignal = getModuleLoadingSignal();
// requiring an async module returns a promise.
// if it's sync, there's nothing to track.
if ((0, _isthenable.isThenable)(exportsOrPromise)) {
// A client reference proxy might look like a promise, but we can only call `.then()` on it, not e.g. `.finally()`.
// Turn it into a real promise to avoid issues elsewhere.
const promise = Promise.resolve(exportsOrPromise);
moduleLoadingSignal.trackRead(promise);
}
}
function trackPendingModules(cacheSignal) {
const moduleLoadingSignal = getModuleLoadingSignal();
// We can't just use `cacheSignal.trackRead(moduleLoadingSignal.cacheReady())`,
// because we might start and finish multiple batches of module loads while waiting for caches,
// and `moduleLoadingSignal.cacheReady()` would resolve after the first batch.
// Instead, we'll keep notifying `cacheSignal` of each import/chunk-load.
const unsubscribe = moduleLoadingSignal.subscribeToReads(cacheSignal);
// Later, when `cacheSignal` is no longer waiting for any caches (or imports that we've notified it of),
// we can unsubscribe it.
cacheSignal.cacheReady().then(unsubscribe);
}
//# sourceMappingURL=track-module-loading.instance.js.map

View File

@@ -0,0 +1 @@
{"version":3,"sources":["../../../../src/server/app-render/module-loading/track-module-loading.instance.ts"],"sourcesContent":["import { CacheSignal } from '../cache-signal'\nimport { isThenable } from '../../../shared/lib/is-thenable'\n\n/**\n * Tracks all in-flight async imports and chunk loads.\n * Initialized lazily, because we don't want this to error in case it gets pulled into an edge runtime module.\n */\nlet _moduleLoadingSignal: CacheSignal | null\nfunction getModuleLoadingSignal() {\n if (!_moduleLoadingSignal) {\n _moduleLoadingSignal = new CacheSignal()\n }\n return _moduleLoadingSignal\n}\n\nexport function trackPendingChunkLoad(promise: Promise<unknown>) {\n const moduleLoadingSignal = getModuleLoadingSignal()\n moduleLoadingSignal.trackRead(promise)\n}\n\nexport function trackPendingImport(exportsOrPromise: unknown) {\n const moduleLoadingSignal = getModuleLoadingSignal()\n\n // requiring an async module returns a promise.\n // if it's sync, there's nothing to track.\n if (isThenable(exportsOrPromise)) {\n // A client reference proxy might look like a promise, but we can only call `.then()` on it, not e.g. `.finally()`.\n // Turn it into a real promise to avoid issues elsewhere.\n const promise = Promise.resolve(exportsOrPromise)\n moduleLoadingSignal.trackRead(promise)\n }\n}\n\n/**\n * A top-level dynamic import (or chunk load):\n *\n * 1. delays a prerender (potentially for a task or longer)\n * 2. may reveal more caches that need be filled\n *\n * So if we see one, we want to extend the duration of `cacheSignal` at least until the import/chunk-load is done.\n */\nexport function trackPendingModules(cacheSignal: CacheSignal): void {\n const moduleLoadingSignal = getModuleLoadingSignal()\n\n // We can't just use `cacheSignal.trackRead(moduleLoadingSignal.cacheReady())`,\n // because we might start and finish multiple batches of module loads while waiting for caches,\n // and `moduleLoadingSignal.cacheReady()` would resolve after the first batch.\n // Instead, we'll keep notifying `cacheSignal` of each import/chunk-load.\n const unsubscribe = moduleLoadingSignal.subscribeToReads(cacheSignal)\n\n // Later, when `cacheSignal` is no longer waiting for any caches (or imports that we've notified it of),\n // we can unsubscribe it.\n cacheSignal.cacheReady().then(unsubscribe)\n}\n"],"names":["trackPendingChunkLoad","trackPendingImport","trackPendingModules","_moduleLoadingSignal","getModuleLoadingSignal","CacheSignal","promise","moduleLoadingSignal","trackRead","exportsOrPromise","isThenable","Promise","resolve","cacheSignal","unsubscribe","subscribeToReads","cacheReady","then"],"mappings":";;;;;;;;;;;;;;;;IAegBA,qBAAqB;eAArBA;;IAKAC,kBAAkB;eAAlBA;;IAqBAC,mBAAmB;eAAnBA;;;6BAzCY;4BACD;AAE3B;;;CAGC,GACD,IAAIC;AACJ,SAASC;IACP,IAAI,CAACD,sBAAsB;QACzBA,uBAAuB,IAAIE,wBAAW;IACxC;IACA,OAAOF;AACT;AAEO,SAASH,sBAAsBM,OAAyB;IAC7D,MAAMC,sBAAsBH;IAC5BG,oBAAoBC,SAAS,CAACF;AAChC;AAEO,SAASL,mBAAmBQ,gBAAyB;IAC1D,MAAMF,sBAAsBH;IAE5B,+CAA+C;IAC/C,0CAA0C;IAC1C,IAAIM,IAAAA,sBAAU,EAACD,mBAAmB;QAChC,mHAAmH;QACnH,yDAAyD;QACzD,MAAMH,UAAUK,QAAQC,OAAO,CAACH;QAChCF,oBAAoBC,SAAS,CAACF;IAChC;AACF;AAUO,SAASJ,oBAAoBW,WAAwB;IAC1D,MAAMN,sBAAsBH;IAE5B,+EAA+E;IAC/E,+FAA+F;IAC/F,8EAA8E;IAC9E,yEAAyE;IACzE,MAAMU,cAAcP,oBAAoBQ,gBAAgB,CAACF;IAEzD,wGAAwG;IACxG,yBAAyB;IACzBA,YAAYG,UAAU,GAAGC,IAAI,CAACH;AAChC","ignoreList":[0]}