@backmatter/next 0.0.15 → 0.0.17
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/config.cjs +44 -6
- package/dist/loader.cjs +47 -5
- package/package.json +2 -2
- package/src/config.ts +6 -2
- package/src/loader.ts +11 -3
- package/src/routes.ts +11 -7
package/dist/config.cjs
CHANGED
|
@@ -84,8 +84,10 @@ var import_node_path2 = __toESM(require("node:path"));
|
|
|
84
84
|
var DEFAULT_DIRS = {
|
|
85
85
|
models: "models",
|
|
86
86
|
blocks: "blocks",
|
|
87
|
+
richtext: "richtext",
|
|
87
88
|
mdx: "mdx",
|
|
88
|
-
layouts: "layouts"
|
|
89
|
+
layouts: "layouts",
|
|
90
|
+
objects: "objects"
|
|
89
91
|
};
|
|
90
92
|
|
|
91
93
|
// ../core/src/node/discover.ts
|
|
@@ -146,6 +148,9 @@ function listBlockFallbackFiles(root, blocksDir = "blocks") {
|
|
|
146
148
|
function listLayoutFiles(root, layoutsDir = "layouts") {
|
|
147
149
|
return listModelFiles(root, layoutsDir);
|
|
148
150
|
}
|
|
151
|
+
function listObjectFiles(root, objectsDir = "objects") {
|
|
152
|
+
return listModelFiles(root, objectsDir);
|
|
153
|
+
}
|
|
149
154
|
function listBlockFiles(root, blocksDir = "blocks") {
|
|
150
155
|
const { files, skipped } = listPascalCaseFiles(root, blocksDir);
|
|
151
156
|
return { blocks: files, skipped };
|
|
@@ -182,7 +187,7 @@ function detectSdk(root) {
|
|
|
182
187
|
}
|
|
183
188
|
function renderCachedCmsClient() {
|
|
184
189
|
return [
|
|
185
|
-
"const raw = createBackmatter({ ...config, models });",
|
|
190
|
+
"const raw = createBackmatter({ ...config, models, sync: false });",
|
|
186
191
|
"",
|
|
187
192
|
"async function getDoc(locale: string, type: string, slug: string) {",
|
|
188
193
|
' "use cache";',
|
|
@@ -237,6 +242,8 @@ function renderModelsBarrel(input) {
|
|
|
237
242
|
`;
|
|
238
243
|
}
|
|
239
244
|
function renderSyncBarrel(input) {
|
|
245
|
+
const objects = input.objects ?? [];
|
|
246
|
+
const richtext = input.richtext ?? [];
|
|
240
247
|
const lines = [GENERATED_HEADER, `import { createBackmatter } from "${input.sdk}";`];
|
|
241
248
|
if (input.configFile) {
|
|
242
249
|
lines.push(`import config from "${importSpecifier(input.outDir, input.configFile)}";`);
|
|
@@ -249,14 +256,24 @@ function renderSyncBarrel(input) {
|
|
|
249
256
|
for (const b of input.blocks) {
|
|
250
257
|
lines.push(`import ${b.name} from "${importSpecifier(input.outDir, b.file)}";`);
|
|
251
258
|
}
|
|
259
|
+
for (const b of richtext) {
|
|
260
|
+
lines.push(`import richtext${b.name} from "${importSpecifier(input.outDir, b.file)}";`);
|
|
261
|
+
}
|
|
262
|
+
for (const object of objects) {
|
|
263
|
+
lines.push(`import ${object.importName} from "${importSpecifier(input.outDir, object.file)}";`);
|
|
264
|
+
}
|
|
252
265
|
lines.push("");
|
|
253
266
|
lines.push(`export const models = [${input.models.map((m) => m.importName).join(", ")}] as const;`);
|
|
254
267
|
lines.push("export type Models = typeof models;");
|
|
255
268
|
lines.push("");
|
|
256
269
|
lines.push(`export const blocks = [${input.blocks.map((b) => b.name).join(", ")}] as const;`);
|
|
257
270
|
lines.push("");
|
|
271
|
+
lines.push(`export const richtext = [${richtext.map((b) => `richtext${b.name}`).join(", ")}] as const;`);
|
|
272
|
+
lines.push("");
|
|
273
|
+
lines.push(`export const objects = [${objects.map((o) => o.importName).join(", ")}] as const;`);
|
|
274
|
+
lines.push("");
|
|
258
275
|
lines.push("/** Typed content client: cms.query.{type}, cms.getDoc, cms.listDocs. */");
|
|
259
|
-
lines.push("export const cms = createBackmatter({ ...config, models, blocks });");
|
|
276
|
+
lines.push("export const cms = createBackmatter({ ...config, models, blocks, richtext, objects, sync: true });");
|
|
260
277
|
return `${lines.join(`
|
|
261
278
|
`)}
|
|
262
279
|
`;
|
|
@@ -274,6 +291,19 @@ function renderMdxBarrel(input) {
|
|
|
274
291
|
`)}
|
|
275
292
|
`;
|
|
276
293
|
}
|
|
294
|
+
function renderRichtextBarrel(input) {
|
|
295
|
+
const lines = [GENERATED_HEADER];
|
|
296
|
+
for (const b of input.richtext) {
|
|
297
|
+
lines.push(`import ${b.name} from "${importSpecifier(input.outDir, b.file)}";`);
|
|
298
|
+
}
|
|
299
|
+
lines.push("");
|
|
300
|
+
lines.push("/** In-content blocks: <Image /> in MDX resolves to richtext/Image.tsx. */");
|
|
301
|
+
const entries = input.richtext.map((b) => `${b.name}: ${b.name}.component`);
|
|
302
|
+
lines.push(`export const richtextComponents = ${entries.length ? `{ ${entries.join(", ")} }` : "{}"};`);
|
|
303
|
+
return `${lines.join(`
|
|
304
|
+
`)}
|
|
305
|
+
`;
|
|
306
|
+
}
|
|
277
307
|
function renderBlocksBarrel(input) {
|
|
278
308
|
const lines = [GENERATED_HEADER, ""];
|
|
279
309
|
lines.push('/** Composer loaders: JSON `{ type: "Hero" }` → dynamic import of blocks/Hero.tsx. */');
|
|
@@ -316,6 +346,7 @@ var REGISTRY_FILES = [
|
|
|
316
346
|
"blocks.ts",
|
|
317
347
|
"block-fallbacks.ts",
|
|
318
348
|
"mdx.ts",
|
|
349
|
+
"richtext.ts",
|
|
319
350
|
"layouts.ts",
|
|
320
351
|
"sync.ts"
|
|
321
352
|
];
|
|
@@ -324,9 +355,11 @@ function generate(options) {
|
|
|
324
355
|
const outDir = import_node_path2.default.resolve(root, options.outDir ?? DEFAULT_OUT_DIR);
|
|
325
356
|
const models = listModelFiles(root, options.modelsDir ?? DEFAULT_DIRS.models);
|
|
326
357
|
const { blocks, skipped: skippedBlocks } = listBlockFiles(root, options.blocksDir ?? DEFAULT_DIRS.blocks);
|
|
358
|
+
const { blocks: richtext, skipped: skippedRichtext } = listBlockFiles(root, options.richtextDir ?? DEFAULT_DIRS.richtext);
|
|
327
359
|
const fallbacks = listBlockFallbackFiles(root, options.blocksDir ?? DEFAULT_DIRS.blocks);
|
|
328
360
|
const { blocks: mdx, skipped: skippedMdx } = listMdxFiles(root, options.mdxDir ?? DEFAULT_DIRS.mdx);
|
|
329
361
|
const layouts = listLayoutFiles(root, options.layoutsDir ?? DEFAULT_DIRS.layouts);
|
|
362
|
+
const objects = listObjectFiles(root, options.objectsDir ?? DEFAULT_DIRS.objects);
|
|
330
363
|
const sdk = options.sdk ?? detectSdk(root);
|
|
331
364
|
const configFile = findConfigFile(root);
|
|
332
365
|
const write = options.write ?? true;
|
|
@@ -335,8 +368,9 @@ function generate(options) {
|
|
|
335
368
|
"blocks.ts": renderBlocksBarrel({ outDir, blocks }),
|
|
336
369
|
"block-fallbacks.ts": renderBlockFallbacksBarrel({ outDir, fallbacks }),
|
|
337
370
|
"mdx.ts": renderMdxBarrel({ outDir, mdx }),
|
|
371
|
+
"richtext.ts": renderRichtextBarrel({ outDir, richtext }),
|
|
338
372
|
"layouts.ts": renderLayoutsBarrel({ outDir, layouts }),
|
|
339
|
-
"sync.ts": renderSyncBarrel({ outDir, models, blocks, configFile, sdk })
|
|
373
|
+
"sync.ts": renderSyncBarrel({ outDir, models, blocks, richtext, objects, configFile, sdk })
|
|
340
374
|
};
|
|
341
375
|
const outputs = REGISTRY_FILES.map((name) => {
|
|
342
376
|
const file = import_node_path2.default.join(outDir, name);
|
|
@@ -354,9 +388,11 @@ function generate(options) {
|
|
|
354
388
|
changed: outputs.filter((o) => o.changed).map((o) => o.rel),
|
|
355
389
|
models,
|
|
356
390
|
blocks,
|
|
391
|
+
richtext,
|
|
357
392
|
mdx,
|
|
358
393
|
layouts,
|
|
359
|
-
|
|
394
|
+
objects,
|
|
395
|
+
skippedBlocks: [...skippedBlocks, ...skippedRichtext],
|
|
360
396
|
skippedMdx,
|
|
361
397
|
configFile
|
|
362
398
|
};
|
|
@@ -391,8 +427,10 @@ function resolveLoaderOptions(options = {}) {
|
|
|
391
427
|
outDir: options.outDir ?? DEFAULT_OUT_DIR,
|
|
392
428
|
modelsDir: options.modelsDir ?? DEFAULT_DIRS.models,
|
|
393
429
|
blocksDir: options.blocksDir ?? DEFAULT_DIRS.blocks,
|
|
430
|
+
richtextDir: options.richtextDir ?? DEFAULT_DIRS.richtext,
|
|
394
431
|
mdxDir: options.mdxDir ?? DEFAULT_DIRS.mdx,
|
|
395
432
|
layoutsDir: options.layoutsDir ?? DEFAULT_DIRS.layouts,
|
|
433
|
+
objectsDir: options.objectsDir ?? DEFAULT_DIRS.objects,
|
|
396
434
|
sdk: SDK
|
|
397
435
|
};
|
|
398
436
|
}
|
|
@@ -408,7 +446,7 @@ function registryMatchers(loaderOptions) {
|
|
|
408
446
|
const escaped = rel.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
409
447
|
return {
|
|
410
448
|
glob: `**/${rel}/*.ts`,
|
|
411
|
-
test: new RegExp(`(^|[\\\\/])${escaped.replace(/\//g, "[\\\\/]")}[\\\\/](index|blocks|block-fallbacks|mdx|layouts|sync)\\.ts$`)
|
|
449
|
+
test: new RegExp(`(^|[\\\\/])${escaped.replace(/\//g, "[\\\\/]")}[\\\\/](index|blocks|block-fallbacks|mdx|richtext|layouts|sync)\\.ts$`)
|
|
412
450
|
};
|
|
413
451
|
}
|
|
414
452
|
function withBackmatter(nextConfig = {}, options = {}) {
|
package/dist/loader.cjs
CHANGED
|
@@ -78,8 +78,10 @@ var import_node_path2 = __toESM(require("node:path"));
|
|
|
78
78
|
var DEFAULT_DIRS = {
|
|
79
79
|
models: "models",
|
|
80
80
|
blocks: "blocks",
|
|
81
|
+
richtext: "richtext",
|
|
81
82
|
mdx: "mdx",
|
|
82
|
-
layouts: "layouts"
|
|
83
|
+
layouts: "layouts",
|
|
84
|
+
objects: "objects"
|
|
83
85
|
};
|
|
84
86
|
|
|
85
87
|
// ../core/src/node/discover.ts
|
|
@@ -140,6 +142,9 @@ function listBlockFallbackFiles(root, blocksDir = "blocks") {
|
|
|
140
142
|
function listLayoutFiles(root, layoutsDir = "layouts") {
|
|
141
143
|
return listModelFiles(root, layoutsDir);
|
|
142
144
|
}
|
|
145
|
+
function listObjectFiles(root, objectsDir = "objects") {
|
|
146
|
+
return listModelFiles(root, objectsDir);
|
|
147
|
+
}
|
|
143
148
|
function listBlockFiles(root, blocksDir = "blocks") {
|
|
144
149
|
const { files, skipped } = listPascalCaseFiles(root, blocksDir);
|
|
145
150
|
return { blocks: files, skipped };
|
|
@@ -176,7 +181,7 @@ function detectSdk(root) {
|
|
|
176
181
|
}
|
|
177
182
|
function renderCachedCmsClient() {
|
|
178
183
|
return [
|
|
179
|
-
"const raw = createBackmatter({ ...config, models });",
|
|
184
|
+
"const raw = createBackmatter({ ...config, models, sync: false });",
|
|
180
185
|
"",
|
|
181
186
|
"async function getDoc(locale: string, type: string, slug: string) {",
|
|
182
187
|
' "use cache";',
|
|
@@ -231,6 +236,8 @@ function renderModelsBarrel(input) {
|
|
|
231
236
|
`;
|
|
232
237
|
}
|
|
233
238
|
function renderSyncBarrel(input) {
|
|
239
|
+
const objects = input.objects ?? [];
|
|
240
|
+
const richtext = input.richtext ?? [];
|
|
234
241
|
const lines = [GENERATED_HEADER, `import { createBackmatter } from "${input.sdk}";`];
|
|
235
242
|
if (input.configFile) {
|
|
236
243
|
lines.push(`import config from "${importSpecifier(input.outDir, input.configFile)}";`);
|
|
@@ -243,14 +250,24 @@ function renderSyncBarrel(input) {
|
|
|
243
250
|
for (const b of input.blocks) {
|
|
244
251
|
lines.push(`import ${b.name} from "${importSpecifier(input.outDir, b.file)}";`);
|
|
245
252
|
}
|
|
253
|
+
for (const b of richtext) {
|
|
254
|
+
lines.push(`import richtext${b.name} from "${importSpecifier(input.outDir, b.file)}";`);
|
|
255
|
+
}
|
|
256
|
+
for (const object of objects) {
|
|
257
|
+
lines.push(`import ${object.importName} from "${importSpecifier(input.outDir, object.file)}";`);
|
|
258
|
+
}
|
|
246
259
|
lines.push("");
|
|
247
260
|
lines.push(`export const models = [${input.models.map((m) => m.importName).join(", ")}] as const;`);
|
|
248
261
|
lines.push("export type Models = typeof models;");
|
|
249
262
|
lines.push("");
|
|
250
263
|
lines.push(`export const blocks = [${input.blocks.map((b) => b.name).join(", ")}] as const;`);
|
|
251
264
|
lines.push("");
|
|
265
|
+
lines.push(`export const richtext = [${richtext.map((b) => `richtext${b.name}`).join(", ")}] as const;`);
|
|
266
|
+
lines.push("");
|
|
267
|
+
lines.push(`export const objects = [${objects.map((o) => o.importName).join(", ")}] as const;`);
|
|
268
|
+
lines.push("");
|
|
252
269
|
lines.push("/** Typed content client: cms.query.{type}, cms.getDoc, cms.listDocs. */");
|
|
253
|
-
lines.push("export const cms = createBackmatter({ ...config, models, blocks });");
|
|
270
|
+
lines.push("export const cms = createBackmatter({ ...config, models, blocks, richtext, objects, sync: true });");
|
|
254
271
|
return `${lines.join(`
|
|
255
272
|
`)}
|
|
256
273
|
`;
|
|
@@ -268,6 +285,19 @@ function renderMdxBarrel(input) {
|
|
|
268
285
|
`)}
|
|
269
286
|
`;
|
|
270
287
|
}
|
|
288
|
+
function renderRichtextBarrel(input) {
|
|
289
|
+
const lines = [GENERATED_HEADER];
|
|
290
|
+
for (const b of input.richtext) {
|
|
291
|
+
lines.push(`import ${b.name} from "${importSpecifier(input.outDir, b.file)}";`);
|
|
292
|
+
}
|
|
293
|
+
lines.push("");
|
|
294
|
+
lines.push("/** In-content blocks: <Image /> in MDX resolves to richtext/Image.tsx. */");
|
|
295
|
+
const entries = input.richtext.map((b) => `${b.name}: ${b.name}.component`);
|
|
296
|
+
lines.push(`export const richtextComponents = ${entries.length ? `{ ${entries.join(", ")} }` : "{}"};`);
|
|
297
|
+
return `${lines.join(`
|
|
298
|
+
`)}
|
|
299
|
+
`;
|
|
300
|
+
}
|
|
271
301
|
function renderBlocksBarrel(input) {
|
|
272
302
|
const lines = [GENERATED_HEADER, ""];
|
|
273
303
|
lines.push('/** Composer loaders: JSON `{ type: "Hero" }` → dynamic import of blocks/Hero.tsx. */');
|
|
@@ -310,6 +340,7 @@ var REGISTRY_FILES = [
|
|
|
310
340
|
"blocks.ts",
|
|
311
341
|
"block-fallbacks.ts",
|
|
312
342
|
"mdx.ts",
|
|
343
|
+
"richtext.ts",
|
|
313
344
|
"layouts.ts",
|
|
314
345
|
"sync.ts"
|
|
315
346
|
];
|
|
@@ -318,9 +349,11 @@ function generate(options) {
|
|
|
318
349
|
const outDir = import_node_path2.default.resolve(root, options.outDir ?? DEFAULT_OUT_DIR);
|
|
319
350
|
const models = listModelFiles(root, options.modelsDir ?? DEFAULT_DIRS.models);
|
|
320
351
|
const { blocks, skipped: skippedBlocks } = listBlockFiles(root, options.blocksDir ?? DEFAULT_DIRS.blocks);
|
|
352
|
+
const { blocks: richtext, skipped: skippedRichtext } = listBlockFiles(root, options.richtextDir ?? DEFAULT_DIRS.richtext);
|
|
321
353
|
const fallbacks = listBlockFallbackFiles(root, options.blocksDir ?? DEFAULT_DIRS.blocks);
|
|
322
354
|
const { blocks: mdx, skipped: skippedMdx } = listMdxFiles(root, options.mdxDir ?? DEFAULT_DIRS.mdx);
|
|
323
355
|
const layouts = listLayoutFiles(root, options.layoutsDir ?? DEFAULT_DIRS.layouts);
|
|
356
|
+
const objects = listObjectFiles(root, options.objectsDir ?? DEFAULT_DIRS.objects);
|
|
324
357
|
const sdk = options.sdk ?? detectSdk(root);
|
|
325
358
|
const configFile = findConfigFile(root);
|
|
326
359
|
const write = options.write ?? true;
|
|
@@ -329,8 +362,9 @@ function generate(options) {
|
|
|
329
362
|
"blocks.ts": renderBlocksBarrel({ outDir, blocks }),
|
|
330
363
|
"block-fallbacks.ts": renderBlockFallbacksBarrel({ outDir, fallbacks }),
|
|
331
364
|
"mdx.ts": renderMdxBarrel({ outDir, mdx }),
|
|
365
|
+
"richtext.ts": renderRichtextBarrel({ outDir, richtext }),
|
|
332
366
|
"layouts.ts": renderLayoutsBarrel({ outDir, layouts }),
|
|
333
|
-
"sync.ts": renderSyncBarrel({ outDir, models, blocks, configFile, sdk })
|
|
367
|
+
"sync.ts": renderSyncBarrel({ outDir, models, blocks, richtext, objects, configFile, sdk })
|
|
334
368
|
};
|
|
335
369
|
const outputs = REGISTRY_FILES.map((name) => {
|
|
336
370
|
const file = import_node_path2.default.join(outDir, name);
|
|
@@ -348,9 +382,11 @@ function generate(options) {
|
|
|
348
382
|
changed: outputs.filter((o) => o.changed).map((o) => o.rel),
|
|
349
383
|
models,
|
|
350
384
|
blocks,
|
|
385
|
+
richtext,
|
|
351
386
|
mdx,
|
|
352
387
|
layouts,
|
|
353
|
-
|
|
388
|
+
objects,
|
|
389
|
+
skippedBlocks: [...skippedBlocks, ...skippedRichtext],
|
|
354
390
|
skippedMdx,
|
|
355
391
|
configFile
|
|
356
392
|
};
|
|
@@ -362,20 +398,26 @@ function backmatterLoader(source) {
|
|
|
362
398
|
const root = import_node_path3.default.resolve(options.root);
|
|
363
399
|
const modelsDir = import_node_path3.default.resolve(root, options.modelsDir);
|
|
364
400
|
const blocksDir = import_node_path3.default.resolve(root, options.blocksDir);
|
|
401
|
+
const richtextDir = import_node_path3.default.resolve(root, options.richtextDir);
|
|
365
402
|
const mdxDir = import_node_path3.default.resolve(root, options.mdxDir);
|
|
366
403
|
const layoutsDir = import_node_path3.default.resolve(root, options.layoutsDir);
|
|
404
|
+
const objectsDir = import_node_path3.default.resolve(root, options.objectsDir);
|
|
367
405
|
this.addContextDependency(modelsDir);
|
|
368
406
|
this.addContextDependency(blocksDir);
|
|
407
|
+
this.addContextDependency(richtextDir);
|
|
369
408
|
this.addContextDependency(mdxDir);
|
|
370
409
|
this.addContextDependency(layoutsDir);
|
|
410
|
+
this.addContextDependency(objectsDir);
|
|
371
411
|
this.cacheable?.(true);
|
|
372
412
|
const result = generate({
|
|
373
413
|
root,
|
|
374
414
|
outDir: options.outDir,
|
|
375
415
|
modelsDir: options.modelsDir,
|
|
376
416
|
blocksDir: options.blocksDir,
|
|
417
|
+
richtextDir: options.richtextDir,
|
|
377
418
|
mdxDir: options.mdxDir,
|
|
378
419
|
layoutsDir: options.layoutsDir,
|
|
420
|
+
objectsDir: options.objectsDir,
|
|
379
421
|
sdk: options.sdk
|
|
380
422
|
});
|
|
381
423
|
if (result.configFile)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@backmatter/next",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.17",
|
|
4
4
|
"description": "Experimental Next.js adapter for Backmatter. APIs will break. Not ready for production.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"publishConfig": {
|
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
"test": "bun test"
|
|
39
39
|
},
|
|
40
40
|
"dependencies": {
|
|
41
|
-
"@backmatter/core": "^0.0.
|
|
41
|
+
"@backmatter/core": "^0.0.16",
|
|
42
42
|
"@mdx-js/mdx": "^3.1.1",
|
|
43
43
|
"remark-gfm": "^4.0.1"
|
|
44
44
|
},
|
package/src/config.ts
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
// resolve `import { cms } from ".backmatter"`.
|
|
6
6
|
// 2. Registers `@backmatter/next/loader` for the registry files with Turbopack
|
|
7
7
|
// (Next 16 default) and webpack (`next build --webpack`). The loader declares
|
|
8
|
-
// `models/`, `blocks/`, and `mdx/` as context dependencies, so the bundler's
|
|
8
|
+
// `models/`, `blocks/`, `richtext/`, and `mdx/` as context dependencies, so the bundler's
|
|
9
9
|
// own file watcher keeps the registry fresh — no polling, no second watcher process.
|
|
10
10
|
import { existsSync } from "node:fs";
|
|
11
11
|
import path from "node:path";
|
|
@@ -24,8 +24,10 @@ export type WithBackmatterOptions = {
|
|
|
24
24
|
outDir?: string;
|
|
25
25
|
modelsDir?: string;
|
|
26
26
|
blocksDir?: string;
|
|
27
|
+
richtextDir?: string;
|
|
27
28
|
mdxDir?: string;
|
|
28
29
|
layoutsDir?: string;
|
|
30
|
+
objectsDir?: string;
|
|
29
31
|
/** Called after the boot-time generation. Default: log what changed. */
|
|
30
32
|
onGenerate?: (result: GenerateResult) => void;
|
|
31
33
|
};
|
|
@@ -80,8 +82,10 @@ export function resolveLoaderOptions(options: WithBackmatterOptions = {}): Backm
|
|
|
80
82
|
outDir: options.outDir ?? DEFAULT_OUT_DIR,
|
|
81
83
|
modelsDir: options.modelsDir ?? DEFAULT_DIRS.models,
|
|
82
84
|
blocksDir: options.blocksDir ?? DEFAULT_DIRS.blocks,
|
|
85
|
+
richtextDir: options.richtextDir ?? DEFAULT_DIRS.richtext,
|
|
83
86
|
mdxDir: options.mdxDir ?? DEFAULT_DIRS.mdx,
|
|
84
87
|
layoutsDir: options.layoutsDir ?? DEFAULT_DIRS.layouts,
|
|
88
|
+
objectsDir: options.objectsDir ?? DEFAULT_DIRS.objects,
|
|
85
89
|
sdk: SDK,
|
|
86
90
|
};
|
|
87
91
|
}
|
|
@@ -104,7 +108,7 @@ export function registryMatchers(loaderOptions: BackmatterLoaderOptions): { glob
|
|
|
104
108
|
const escaped = rel.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
105
109
|
return {
|
|
106
110
|
glob: `**/${rel}/*.ts`,
|
|
107
|
-
test: new RegExp(`(^|[\\\\/])${escaped.replace(/\//g, "[\\\\/]")}[\\\\/](index|blocks|block-fallbacks|mdx|layouts|sync)\\.ts$`),
|
|
111
|
+
test: new RegExp(`(^|[\\\\/])${escaped.replace(/\//g, "[\\\\/]")}[\\\\/](index|blocks|block-fallbacks|mdx|richtext|layouts|sync)\\.ts$`),
|
|
108
112
|
};
|
|
109
113
|
}
|
|
110
114
|
|
package/src/loader.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
// packages/next/src/loader.ts
|
|
2
|
-
// Bundler loader for `.backmatter/index.ts`, `.backmatter/blocks.ts`,
|
|
3
|
-
// and `.backmatter/layouts.ts`.
|
|
2
|
+
// Bundler loader for `.backmatter/index.ts`, `.backmatter/blocks.ts`,
|
|
3
|
+
// `.backmatter/mdx.ts`, `.backmatter/richtext.ts`, and `.backmatter/layouts.ts`.
|
|
4
4
|
//
|
|
5
5
|
// This is the Tailwind-JIT mechanism: instead of running our own watcher we
|
|
6
6
|
// tell the bundler that these modules depend on the `models/`, `blocks/`,
|
|
7
|
-
// `mdx/`, and `layouts/` directories. webpack and Turbopack already watch the filesystem;
|
|
7
|
+
// `richtext/`, `mdx/`, and `layouts/` directories. webpack and Turbopack already watch the filesystem;
|
|
8
8
|
// when a file is added, removed or renamed there they invalidate the module,
|
|
9
9
|
// re-run this loader, and we regenerate the barrel from a fresh `readdir`.
|
|
10
10
|
import path from "node:path";
|
|
@@ -15,8 +15,10 @@ export type BackmatterLoaderOptions = {
|
|
|
15
15
|
outDir: string;
|
|
16
16
|
modelsDir: string;
|
|
17
17
|
blocksDir: string;
|
|
18
|
+
richtextDir: string;
|
|
18
19
|
mdxDir: string;
|
|
19
20
|
layoutsDir: string;
|
|
21
|
+
objectsDir: string;
|
|
20
22
|
sdk: string;
|
|
21
23
|
};
|
|
22
24
|
|
|
@@ -34,13 +36,17 @@ export default function backmatterLoader(this: BackmatterLoaderContext, source:
|
|
|
34
36
|
const root = path.resolve(options.root);
|
|
35
37
|
const modelsDir = path.resolve(root, options.modelsDir);
|
|
36
38
|
const blocksDir = path.resolve(root, options.blocksDir);
|
|
39
|
+
const richtextDir = path.resolve(root, options.richtextDir);
|
|
37
40
|
const mdxDir = path.resolve(root, options.mdxDir);
|
|
38
41
|
const layoutsDir = path.resolve(root, options.layoutsDir);
|
|
42
|
+
const objectsDir = path.resolve(root, options.objectsDir);
|
|
39
43
|
|
|
40
44
|
this.addContextDependency(modelsDir);
|
|
41
45
|
this.addContextDependency(blocksDir);
|
|
46
|
+
this.addContextDependency(richtextDir);
|
|
42
47
|
this.addContextDependency(mdxDir);
|
|
43
48
|
this.addContextDependency(layoutsDir);
|
|
49
|
+
this.addContextDependency(objectsDir);
|
|
44
50
|
this.cacheable?.(true);
|
|
45
51
|
|
|
46
52
|
const result = generate({
|
|
@@ -48,8 +54,10 @@ export default function backmatterLoader(this: BackmatterLoaderContext, source:
|
|
|
48
54
|
outDir: options.outDir,
|
|
49
55
|
modelsDir: options.modelsDir,
|
|
50
56
|
blocksDir: options.blocksDir,
|
|
57
|
+
richtextDir: options.richtextDir,
|
|
51
58
|
mdxDir: options.mdxDir,
|
|
52
59
|
layoutsDir: options.layoutsDir,
|
|
60
|
+
objectsDir: options.objectsDir,
|
|
53
61
|
sdk: options.sdk,
|
|
54
62
|
});
|
|
55
63
|
if (result.configFile) this.addDependency(result.configFile);
|
package/src/routes.ts
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
// `route` template (including `/` via indexSlug), loads it and renders MDX
|
|
5
5
|
// or JSON pages. An optional catch-all is required so `/` is a CMS route.
|
|
6
6
|
import { Fragment, Suspense, createElement, type ReactNode } from "react";
|
|
7
|
-
import { matchRoute, modelFormat, PREVIEW_CHECKOUT_QUERY, PREVIEW_COOKIE, readPreviewCookie, routeSegments, type BackmatterDoc, type ModelDef } from "@backmatter/core";
|
|
7
|
+
import { isRoutable, matchRoute, modelFormat, PREVIEW_CHECKOUT_QUERY, PREVIEW_COOKIE, readPreviewCookie, routeSegments, type BackmatterDoc, type ModelDef } from "@backmatter/core";
|
|
8
8
|
import type { BackmatterClient } from "@backmatter/core/node/create-backmatter";
|
|
9
9
|
import { fetchPreviewDoc } from "@backmatter/core/preview";
|
|
10
10
|
import { renderDoc, type MdxComponents } from "./mdx-compile";
|
|
@@ -63,7 +63,7 @@ export type CatchAllRoute = {
|
|
|
63
63
|
Page: (props: {
|
|
64
64
|
params: Promise<CatchAllParams>;
|
|
65
65
|
searchParams?: Promise<CatchAllSearchParams>;
|
|
66
|
-
}) =>
|
|
66
|
+
}) => ReactNode;
|
|
67
67
|
CmsRoute: (props: {
|
|
68
68
|
params: Promise<CatchAllParams> | CatchAllParams;
|
|
69
69
|
searchParams?: Promise<CatchAllSearchParams> | CatchAllSearchParams;
|
|
@@ -162,7 +162,7 @@ export function createCatchAll<Models extends readonly ModelDef[]>(
|
|
|
162
162
|
const params: CatchAllParams[] = [];
|
|
163
163
|
for (const doc of docs) {
|
|
164
164
|
const model = byType.get(doc.type);
|
|
165
|
-
if (!model) continue;
|
|
165
|
+
if (!model || !isRoutable(model)) continue;
|
|
166
166
|
params.push({ [CATCH_ALL_PARAM]: routeSegments(model, doc.locale, doc.slug) });
|
|
167
167
|
}
|
|
168
168
|
return params;
|
|
@@ -248,7 +248,7 @@ export function createCatchAll<Models extends readonly ModelDef[]>(
|
|
|
248
248
|
params: Promise<CatchAllParams> | CatchAllParams;
|
|
249
249
|
searchParams?: Promise<CatchAllSearchParams> | CatchAllSearchParams;
|
|
250
250
|
}) => {
|
|
251
|
-
const resolved = await
|
|
251
|
+
const resolved = await params;
|
|
252
252
|
const hit = resolve(resolved[CATCH_ALL_PARAM]);
|
|
253
253
|
if (!hit) return failFor();
|
|
254
254
|
const doc = await cms.getDoc(hit.locale, hit.type, hit.slug);
|
|
@@ -267,7 +267,7 @@ export function createCatchAll<Models extends readonly ModelDef[]>(
|
|
|
267
267
|
params: Promise<CatchAllParams> | CatchAllParams;
|
|
268
268
|
searchParams?: Promise<CatchAllSearchParams> | CatchAllSearchParams;
|
|
269
269
|
}) => {
|
|
270
|
-
const resolved = await
|
|
270
|
+
const resolved = await params;
|
|
271
271
|
const hit = resolve(resolved[CATCH_ALL_PARAM]);
|
|
272
272
|
if (!hit) return null;
|
|
273
273
|
const preview = await resolvePreviewState(cms, options.preview, searchParams);
|
|
@@ -284,11 +284,15 @@ export function createCatchAll<Models extends readonly ModelDef[]>(
|
|
|
284
284
|
);
|
|
285
285
|
};
|
|
286
286
|
|
|
287
|
-
const Page: CatchAllRoute["Page"] =
|
|
287
|
+
const Page: CatchAllRoute["Page"] = (props) =>
|
|
288
288
|
createElement(
|
|
289
289
|
Fragment,
|
|
290
290
|
null,
|
|
291
|
-
|
|
291
|
+
createElement(
|
|
292
|
+
Suspense,
|
|
293
|
+
{ fallback: createElement("div", { "aria-busy": "true", style: { minHeight: "100vh" } }) },
|
|
294
|
+
createElement(PublishedRoute, props),
|
|
295
|
+
),
|
|
292
296
|
createElement(Suspense, { fallback: null }, createElement(PreviewBranch, props)),
|
|
293
297
|
);
|
|
294
298
|
|