@timber-js/app 0.2.0-alpha.191 → 0.2.0-alpha.192
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-types.d.ts +24 -6
- package/dist/config-types.d.ts.map +1 -1
- package/dist/index.js +31 -28
- package/dist/index.js.map +1 -1
- package/dist/plugins/mdx.d.ts +17 -4
- package/dist/plugins/mdx.d.ts.map +1 -1
- package/dist/plugins/server-bundle.d.ts.map +1 -1
- package/docs/api/34-api-config.mdx +9 -8
- package/docs/more/04b-mdx.mdx +38 -18
- package/package.json +7 -3
- package/src/config-types.ts +27 -7
- package/src/plugins/mdx.ts +69 -35
- package/src/plugins/server-bundle.ts +2 -1
package/dist/plugins/mdx.d.ts
CHANGED
|
@@ -1,10 +1,22 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* timber-mdx — Vite sub-plugin for MDX
|
|
2
|
+
* timber-mdx — Vite sub-plugin for MDX and Markdown rendering.
|
|
3
3
|
*
|
|
4
|
-
* Wires
|
|
4
|
+
* Wires vite-plugin-satteri into the Vite pipeline when MDX is activated.
|
|
5
5
|
* MDX is activated when pageExtensions includes 'mdx' or 'md', or
|
|
6
6
|
* when a content/ directory exists at the project root.
|
|
7
7
|
*
|
|
8
|
+
* Satteri is a Rust-based Markdown/MDX compiler with a native Vite plugin:
|
|
9
|
+
* - `.mdx` files compile to React components (ES modules with real import
|
|
10
|
+
* statements, so @vitejs/plugin-rsc client-boundary detection works).
|
|
11
|
+
* - `.md` files compile to modules exporting a rendered HTML string.
|
|
12
|
+
* - Frontmatter (YAML/TOML) parses natively and is emitted as a
|
|
13
|
+
* `frontmatter` named export — no remark plugins needed.
|
|
14
|
+
* - GFM (tables, footnotes, strikethrough, task lists) is on by default.
|
|
15
|
+
*
|
|
16
|
+
* Extensibility is satteri's visitor-based plugin API (defineMdastPlugin /
|
|
17
|
+
* defineHastPlugin), not unified — the AST lives on the Rust side, so
|
|
18
|
+
* remark/rehype plugins cannot run. See design/20-content-collections.md.
|
|
19
|
+
*
|
|
8
20
|
* Design doc: 20-content-collections.md §"The timber-mdx Plugin"
|
|
9
21
|
*/
|
|
10
22
|
import type { Plugin } from 'vite';
|
|
@@ -19,9 +31,10 @@ export declare function findMdxComponents(root: string): string | undefined;
|
|
|
19
31
|
* Create the timber-mdx Vite plugin.
|
|
20
32
|
*
|
|
21
33
|
* Uses the transform and resolveId hooks to delegate MDX compilation
|
|
22
|
-
* to
|
|
34
|
+
* to vite-plugin-satteri. The inner plugin is loaded lazily on first
|
|
35
|
+
* activation.
|
|
23
36
|
*
|
|
24
|
-
* Hooks: buildStart (loads
|
|
37
|
+
* Hooks: buildStart (loads vite-plugin-satteri), resolveId, load, transform
|
|
25
38
|
*/
|
|
26
39
|
export declare function timberMdx(ctx: PluginContext): Plugin;
|
|
27
40
|
//# sourceMappingURL=mdx.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mdx.d.ts","sourceRoot":"","sources":["../../src/plugins/mdx.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"mdx.d.ts","sourceRoot":"","sources":["../../src/plugins/mdx.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,MAAM,CAAC;AAKnC,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAI1D;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAelE;AAqED;;;;;;;;GAQG;AACH,wBAAgB,SAAS,CAAC,GAAG,EAAE,aAAa,GAAG,MAAM,CA4HpD"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server-bundle.d.ts","sourceRoot":"","sources":["../../src/plugins/server-bundle.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAGH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"server-bundle.d.ts","sourceRoot":"","sources":["../../src/plugins/server-bundle.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAGH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,MAAM,CAAC;AAqCnC,wBAAgB,kBAAkB,IAAI,MAAM,EAAE,CAuK7C"}
|
|
@@ -39,11 +39,10 @@ interface TimberUserConfig {
|
|
|
39
39
|
firstLoadJs?: number;
|
|
40
40
|
};
|
|
41
41
|
appDir?: string;
|
|
42
|
-
mdx?: {
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
remarkRehypeOptions?: any;
|
|
42
|
+
mdx?: false | {
|
|
43
|
+
mdastPlugins?: any[];
|
|
44
|
+
hastPlugins?: any[];
|
|
45
|
+
features?: Record<string, any>;
|
|
47
46
|
};
|
|
48
47
|
actionEncryption?: {
|
|
49
48
|
disableInDev?: boolean;
|
|
@@ -226,15 +225,17 @@ Override the app directory location. Set to a relative path from the project roo
|
|
|
226
225
|
|
|
227
226
|
### `mdx`
|
|
228
227
|
|
|
229
|
-
MDX compilation options —
|
|
228
|
+
MDX compilation options — Satteri visitor plugins and parser feature toggles (GFM and frontmatter are on by default). Set `mdx: false` to disable timber's MDX support and bring your own compiler:
|
|
230
229
|
|
|
231
230
|
```ts
|
|
232
231
|
mdx: {
|
|
233
|
-
|
|
234
|
-
|
|
232
|
+
hastPlugins: [myCodeHighlighter],
|
|
233
|
+
features: { math: true },
|
|
235
234
|
}
|
|
236
235
|
```
|
|
237
236
|
|
|
237
|
+
See [MDX](/docs/mdx) for the plugin model and how it differs from remark/rehype.
|
|
238
|
+
|
|
238
239
|
### `actionEncryption`
|
|
239
240
|
|
|
240
241
|
Server action bound args encryption configuration. The RSC plugin encrypts closure variables captured by `'use server'` functions using AES-256-GCM so they are opaque and tamper-proof in the Flight payload. Encryption is always enabled in production.
|
package/docs/more/04b-mdx.mdx
CHANGED
|
@@ -17,10 +17,10 @@ export default {
|
|
|
17
17
|
};
|
|
18
18
|
```
|
|
19
19
|
|
|
20
|
-
Install the MDX compiler
|
|
20
|
+
Install the MDX compiler — timber.js uses [Satteri](https://satteri.bruits.org), a Rust-based Markdown/MDX compiler with a native Vite plugin:
|
|
21
21
|
|
|
22
22
|
```bash title="Terminal"
|
|
23
|
-
pnpm add -D
|
|
23
|
+
pnpm add -D vite-plugin-satteri satteri
|
|
24
24
|
```
|
|
25
25
|
|
|
26
26
|
That's it. Any `page.mdx` file in your `app/` directory is now a route.
|
|
@@ -57,7 +57,7 @@ This page is a **server component** — no JavaScript shipped to the browser.
|
|
|
57
57
|
|
|
58
58
|
## Frontmatter
|
|
59
59
|
|
|
60
|
-
|
|
60
|
+
Frontmatter parsing is built in — YAML between `---` fences or TOML between `+++` fences. Frontmatter is exported as a single `frontmatter` object:
|
|
61
61
|
|
|
62
62
|
````mdx title="app/blog/hello/page.mdx"
|
|
63
63
|
---
|
|
@@ -127,33 +127,52 @@ pnpm add @timber-js/app
|
|
|
127
127
|
|
|
128
128
|
Only the `CopyButton` ships JavaScript. The rest of the page renders as static HTML.
|
|
129
129
|
|
|
130
|
-
##
|
|
130
|
+
## Plugins and Features
|
|
131
131
|
|
|
132
|
-
|
|
132
|
+
GFM (tables, footnotes, strikethrough, task lists) and frontmatter are on by default. Additional syntax is enabled through `features`, and custom transforms are written as Satteri visitor plugins through the `mdx` key in your config:
|
|
133
133
|
|
|
134
134
|
```ts title="timber.config.ts"
|
|
135
|
-
import
|
|
136
|
-
|
|
135
|
+
import { defineHastPlugin } from 'satteri';
|
|
136
|
+
|
|
137
|
+
const externalLinks = defineHastPlugin({
|
|
138
|
+
name: 'external-links',
|
|
139
|
+
element: {
|
|
140
|
+
filter: ['a'],
|
|
141
|
+
visit(node, ctx) {
|
|
142
|
+
const href = node.properties.href;
|
|
143
|
+
if (typeof href === 'string' && href.startsWith('http')) {
|
|
144
|
+
ctx.setProperty(node, 'target', '_blank');
|
|
145
|
+
}
|
|
146
|
+
},
|
|
147
|
+
},
|
|
148
|
+
});
|
|
137
149
|
|
|
138
150
|
export default {
|
|
139
151
|
pageExtensions: ['tsx', 'ts', 'jsx', 'js', 'mdx'],
|
|
140
152
|
mdx: {
|
|
141
|
-
|
|
142
|
-
|
|
153
|
+
hastPlugins: [externalLinks],
|
|
154
|
+
features: { math: true },
|
|
143
155
|
},
|
|
144
156
|
};
|
|
145
157
|
```
|
|
146
158
|
|
|
147
|
-
The `mdx` config maps directly to
|
|
159
|
+
The `mdx` config maps directly to `vite-plugin-satteri` options. Available fields:
|
|
160
|
+
|
|
161
|
+
| Option | Type | Description |
|
|
162
|
+
| -------------- | -------------------- | ------------------------------------------------------------------------------- |
|
|
163
|
+
| `mdastPlugins` | `MdastPluginInput[]` | Markdown AST visitors (created with `defineMdastPlugin`) |
|
|
164
|
+
| `hastPlugins` | `HastPluginInput[]` | HTML AST visitors (created with `defineHastPlugin`) |
|
|
165
|
+
| `features` | `Features` | Parser toggles — `gfm`, `frontmatter`, `math`, `directive`, `wikilinks`, … |
|
|
148
166
|
|
|
149
|
-
|
|
150
|
-
| --------------------- | --------------- | ------------------------------------------ |
|
|
151
|
-
| `remarkPlugins` | `PluggableList` | remark plugins for Markdown AST transforms |
|
|
152
|
-
| `rehypePlugins` | `PluggableList` | rehype plugins for HTML AST transforms |
|
|
153
|
-
| `recmaPlugins` | `PluggableList` | recma plugins for ESTree transforms |
|
|
154
|
-
| `remarkRehypeOptions` | `object` | Options passed to `remark-rehype` |
|
|
167
|
+
Satteri plugins are filtered visitors, not unified plugins — **remark/rehype plugins do not run** on Satteri's Rust-side AST. Visitors can be async and can replace nodes, which is enough to build things like shiki-based syntax highlighting (shiki transformers such as `@shikijs/twoslash` still work, since they run inside shiki).
|
|
155
168
|
|
|
156
|
-
|
|
169
|
+
If you need the unified MDX pipeline (for example, CodeHike), bypass timber's MDX support entirely: set `mdx: false` in your config and register `@mdx-js/rollup` yourself in `vite.config.ts` with `enforce: 'pre'`:
|
|
170
|
+
|
|
171
|
+
```ts title="timber.config.ts"
|
|
172
|
+
export default {
|
|
173
|
+
mdx: false, // disable timber's built-in MDX — bring your own compiler
|
|
174
|
+
};
|
|
175
|
+
```
|
|
157
176
|
|
|
158
177
|
## Dynamic MDX Loading
|
|
159
178
|
|
|
@@ -205,5 +224,6 @@ For structured content outside the route tree (blog posts, docs, changelogs), us
|
|
|
205
224
|
| `@next/mdx` wrapper package | Built-in — just add `'mdx'` to pageExtensions |
|
|
206
225
|
| `next.config.mjs` `withMDX()` wrapper | `timber.config.ts` `mdx` key |
|
|
207
226
|
| MDX pages are client components by default | MDX pages are server components by default |
|
|
208
|
-
|
|
|
227
|
+
| unified (remark/rehype) plugins | Satteri visitor plugins + built-in features |
|
|
228
|
+
| Custom loader for `.md` files | Built in — `.md` imports export an HTML string |
|
|
209
229
|
| `mdx-components.tsx` at project root | Same convention |
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@timber-js/app",
|
|
3
|
-
"version": "0.2.0-alpha.
|
|
3
|
+
"version": "0.2.0-alpha.192",
|
|
4
4
|
"description": "Vite-native React framework built for Servers and Serverless Platforms — correct HTTP semantics, real status codes, pages that work without JavaScript",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"cloudflare-workers",
|
|
@@ -160,14 +160,15 @@
|
|
|
160
160
|
"@content-collections/core": "^0.14.0 || ^0.15.0",
|
|
161
161
|
"@content-collections/mdx": "^0.2.0",
|
|
162
162
|
"@content-collections/vite": "^0.2.0 || ^0.3.0",
|
|
163
|
-
"@mdx-js/rollup": "^3.0.0",
|
|
164
163
|
"@typescript/native-preview": "^7.0.0-dev.0",
|
|
165
164
|
"@vitejs/plugin-react": "^6.0.0",
|
|
166
165
|
"@vitejs/plugin-rsc": ">=0.5.28",
|
|
167
166
|
"nuqs": "^2.0.0",
|
|
168
167
|
"react": "19.2.7",
|
|
169
168
|
"react-dom": "19.2.7",
|
|
169
|
+
"satteri": "^0.9.5",
|
|
170
170
|
"vite": "^8.1.0",
|
|
171
|
+
"vite-plugin-satteri": "^0.2.15",
|
|
171
172
|
"wrangler": "^4.0.0",
|
|
172
173
|
"zod": "^3.22.0 || ^4.0.0"
|
|
173
174
|
},
|
|
@@ -181,7 +182,10 @@
|
|
|
181
182
|
"@content-collections/vite": {
|
|
182
183
|
"optional": true
|
|
183
184
|
},
|
|
184
|
-
"
|
|
185
|
+
"satteri": {
|
|
186
|
+
"optional": true
|
|
187
|
+
},
|
|
188
|
+
"vite-plugin-satteri": {
|
|
185
189
|
"optional": true
|
|
186
190
|
},
|
|
187
191
|
"@typescript/native-preview": {
|
package/src/config-types.ts
CHANGED
|
@@ -159,13 +159,33 @@ export interface TimberUserConfig {
|
|
|
159
159
|
* to use a custom location.
|
|
160
160
|
*/
|
|
161
161
|
appDir?: string;
|
|
162
|
-
/**
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
162
|
+
/**
|
|
163
|
+
* MDX/Markdown compilation options passed to vite-plugin-satteri.
|
|
164
|
+
*
|
|
165
|
+
* Satteri's plugin API is visitor-based (`defineMdastPlugin` /
|
|
166
|
+
* `defineHastPlugin` from the `satteri` package) — unified
|
|
167
|
+
* remark/rehype plugins are not supported.
|
|
168
|
+
*
|
|
169
|
+
* Set to `false` to disable timber's MDX support entirely — even when a
|
|
170
|
+
* `content/` directory exists. Use this when registering your own MDX
|
|
171
|
+
* compiler (e.g. `@mdx-js/rollup` for the unified pipeline) directly in
|
|
172
|
+
* `vite.config.ts`.
|
|
173
|
+
*
|
|
174
|
+
* See design/20-content-collections.md.
|
|
175
|
+
*/
|
|
176
|
+
mdx?:
|
|
177
|
+
| false
|
|
178
|
+
| {
|
|
179
|
+
/** MDAST-stage plugins (created with satteri's `defineMdastPlugin`). */
|
|
180
|
+
mdastPlugins?: unknown[];
|
|
181
|
+
/** HAST-stage plugins (created with satteri's `defineHastPlugin`). */
|
|
182
|
+
hastPlugins?: unknown[];
|
|
183
|
+
/**
|
|
184
|
+
* Parser feature toggles. Defaults: `gfm: true`, `frontmatter: true`,
|
|
185
|
+
* everything else (math, directive, wikilinks, …) off.
|
|
186
|
+
*/
|
|
187
|
+
features?: Record<string, unknown>;
|
|
188
|
+
};
|
|
169
189
|
/**
|
|
170
190
|
* Server action bound args encryption configuration.
|
|
171
191
|
*
|
package/src/plugins/mdx.ts
CHANGED
|
@@ -1,10 +1,22 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* timber-mdx — Vite sub-plugin for MDX
|
|
2
|
+
* timber-mdx — Vite sub-plugin for MDX and Markdown rendering.
|
|
3
3
|
*
|
|
4
|
-
* Wires
|
|
4
|
+
* Wires vite-plugin-satteri into the Vite pipeline when MDX is activated.
|
|
5
5
|
* MDX is activated when pageExtensions includes 'mdx' or 'md', or
|
|
6
6
|
* when a content/ directory exists at the project root.
|
|
7
7
|
*
|
|
8
|
+
* Satteri is a Rust-based Markdown/MDX compiler with a native Vite plugin:
|
|
9
|
+
* - `.mdx` files compile to React components (ES modules with real import
|
|
10
|
+
* statements, so @vitejs/plugin-rsc client-boundary detection works).
|
|
11
|
+
* - `.md` files compile to modules exporting a rendered HTML string.
|
|
12
|
+
* - Frontmatter (YAML/TOML) parses natively and is emitted as a
|
|
13
|
+
* `frontmatter` named export — no remark plugins needed.
|
|
14
|
+
* - GFM (tables, footnotes, strikethrough, task lists) is on by default.
|
|
15
|
+
*
|
|
16
|
+
* Extensibility is satteri's visitor-based plugin API (defineMdastPlugin /
|
|
17
|
+
* defineHastPlugin), not unified — the AST lives on the Rust side, so
|
|
18
|
+
* remark/rehype plugins cannot run. See design/20-content-collections.md.
|
|
19
|
+
*
|
|
8
20
|
* Design doc: 20-content-collections.md §"The timber-mdx Plugin"
|
|
9
21
|
*/
|
|
10
22
|
|
|
@@ -43,6 +55,12 @@ export function findMdxComponents(root: string): string | undefined {
|
|
|
43
55
|
* Determine if MDX should be activated based on config and project structure.
|
|
44
56
|
*/
|
|
45
57
|
function shouldActivate(ctx: PluginContext): boolean {
|
|
58
|
+
// Explicit opt-out — the escape hatch for apps that register their own
|
|
59
|
+
// MDX compiler (e.g. @mdx-js/rollup for the unified pipeline) in
|
|
60
|
+
// vite.config.ts. Without this, a content/ directory would force
|
|
61
|
+
// activation no matter what pageExtensions says.
|
|
62
|
+
if (ctx.config.mdx === false) return false;
|
|
63
|
+
|
|
46
64
|
const exts = ctx.config.pageExtensions;
|
|
47
65
|
if (exts && exts.some((ext) => MDX_EXTENSIONS.includes(ext))) {
|
|
48
66
|
return true;
|
|
@@ -61,13 +79,11 @@ function shouldActivate(ctx: PluginContext): boolean {
|
|
|
61
79
|
*
|
|
62
80
|
* Why this matters: pnpm only hoists declared (peer) dependencies into a
|
|
63
81
|
* package's resolution scope. The MDX integration's optional companions
|
|
64
|
-
* — `
|
|
65
|
-
*
|
|
66
|
-
*
|
|
67
|
-
*
|
|
68
|
-
*
|
|
69
|
-
* `undefined` and skipped frontmatter parsing entirely — leaving MDX to
|
|
70
|
-
* choke on YAML as JS expressions (TIM-840).
|
|
82
|
+
* — `vite-plugin-satteri` and `satteri` — are installed as direct deps of
|
|
83
|
+
* the consumer (e.g. `packages/website`), not `@timber-js/app`. A bare
|
|
84
|
+
* `import('vite-plugin-satteri')` from inside this file resolves against
|
|
85
|
+
* `packages/timber-app/node_modules` and silently fails with
|
|
86
|
+
* `ERR_MODULE_NOT_FOUND` (TIM-840).
|
|
71
87
|
*
|
|
72
88
|
* Resolving relative to `projectRoot` (via `createRequire`) makes the
|
|
73
89
|
* lookup walk the consumer's `node_modules` tree first, which is where
|
|
@@ -106,9 +122,10 @@ async function tryImport(name: string, projectRoot: string): Promise<unknown | u
|
|
|
106
122
|
* Create the timber-mdx Vite plugin.
|
|
107
123
|
*
|
|
108
124
|
* Uses the transform and resolveId hooks to delegate MDX compilation
|
|
109
|
-
* to
|
|
125
|
+
* to vite-plugin-satteri. The inner plugin is loaded lazily on first
|
|
126
|
+
* activation.
|
|
110
127
|
*
|
|
111
|
-
* Hooks: buildStart (loads
|
|
128
|
+
* Hooks: buildStart (loads vite-plugin-satteri), resolveId, load, transform
|
|
112
129
|
*/
|
|
113
130
|
export function timberMdx(ctx: PluginContext): Plugin {
|
|
114
131
|
let innerPlugin: Plugin | null = null;
|
|
@@ -116,50 +133,60 @@ export function timberMdx(ctx: PluginContext): Plugin {
|
|
|
116
133
|
async function activate(): Promise<void> {
|
|
117
134
|
if (innerPlugin !== null || !shouldActivate(ctx)) return;
|
|
118
135
|
|
|
119
|
-
|
|
136
|
+
// Satteri compiles .md to an HTML string, not a component — a page.md
|
|
137
|
+
// route would make the renderer invoke a string as a component and
|
|
138
|
+
// TypeError at request time. Fail at startup instead. Imported .md
|
|
139
|
+
// files work without listing 'md' in pageExtensions.
|
|
140
|
+
if (ctx.config.pageExtensions?.includes('md')) {
|
|
141
|
+
throw new Error(
|
|
142
|
+
[
|
|
143
|
+
"[timber] pageExtensions includes 'md', but .md route pages are not supported:",
|
|
144
|
+
'Markdown files compile to HTML strings, not components.',
|
|
145
|
+
'',
|
|
146
|
+
"Use .mdx for pages (pageExtensions: ['tsx', 'ts', 'mdx']).",
|
|
147
|
+
'.md files can still be imported as HTML strings — no pageExtensions entry needed.',
|
|
148
|
+
].join('\n')
|
|
149
|
+
);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
const createSatteriPlugin = (await tryImport('vite-plugin-satteri', ctx.root)) as
|
|
120
153
|
| ((options?: Record<string, unknown>) => Plugin)
|
|
121
154
|
| undefined;
|
|
122
155
|
|
|
123
|
-
if (!
|
|
156
|
+
if (!createSatteriPlugin) {
|
|
124
157
|
throw new Error(
|
|
125
158
|
[
|
|
126
|
-
'[timber] MDX is enabled but
|
|
159
|
+
'[timber] MDX is enabled but vite-plugin-satteri is not installed.',
|
|
127
160
|
'',
|
|
128
161
|
'Install it:',
|
|
129
|
-
' pnpm add -D
|
|
162
|
+
' pnpm add -D vite-plugin-satteri satteri',
|
|
130
163
|
'',
|
|
131
164
|
'MDX is activated because pageExtensions includes "mdx"/"md" or a content/ directory exists.',
|
|
132
165
|
].join('\n')
|
|
133
166
|
);
|
|
134
167
|
}
|
|
135
168
|
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
// so pnpm finds packages declared in the user's package.json (TIM-840).
|
|
140
|
-
const remarkPlugins: unknown[] = [];
|
|
141
|
-
const remarkFrontmatter = await tryImport('remark-frontmatter', ctx.root);
|
|
142
|
-
const remarkMdxFrontmatter = await tryImport('remark-mdx-frontmatter', ctx.root);
|
|
143
|
-
if (remarkFrontmatter) remarkPlugins.push(remarkFrontmatter);
|
|
144
|
-
if (remarkMdxFrontmatter) remarkPlugins.push(remarkMdxFrontmatter);
|
|
145
|
-
|
|
146
|
-
if (mdxConfig.remarkPlugins) {
|
|
147
|
-
remarkPlugins.push(...mdxConfig.remarkPlugins);
|
|
148
|
-
}
|
|
169
|
+
// `|| {}` (not `??`): mdx can be `false`, though shouldActivate() has
|
|
170
|
+
// already bailed in that case.
|
|
171
|
+
const mdxConfig = ctx.config.mdx || {};
|
|
149
172
|
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
};
|
|
173
|
+
// We pass `development` explicitly (satteri otherwise infers it from
|
|
174
|
+
// Vite's command via its own configResolved hook, which we don't
|
|
175
|
+
// delegate) and control providerImportSource — the mdx-components.tsx
|
|
176
|
+
// convention belongs to the framework, not the user config.
|
|
177
|
+
const mdxOptions: Record<string, unknown> = { development: ctx.dev };
|
|
156
178
|
|
|
157
179
|
const mdxComponentsPath = findMdxComponents(ctx.root);
|
|
158
180
|
if (mdxComponentsPath) {
|
|
159
181
|
mdxOptions.providerImportSource = mdxComponentsPath;
|
|
160
182
|
}
|
|
161
183
|
|
|
162
|
-
innerPlugin =
|
|
184
|
+
innerPlugin = createSatteriPlugin({
|
|
185
|
+
mdx: mdxOptions,
|
|
186
|
+
...(mdxConfig.mdastPlugins ? { mdastPlugins: mdxConfig.mdastPlugins } : {}),
|
|
187
|
+
...(mdxConfig.hastPlugins ? { hastPlugins: mdxConfig.hastPlugins } : {}),
|
|
188
|
+
...(mdxConfig.features ? { features: mdxConfig.features } : {}),
|
|
189
|
+
});
|
|
163
190
|
}
|
|
164
191
|
|
|
165
192
|
return {
|
|
@@ -208,6 +235,13 @@ export function timberMdx(ctx: PluginContext): Plugin {
|
|
|
208
235
|
|
|
209
236
|
async transform(code, id) {
|
|
210
237
|
if (!innerPlugin) return null;
|
|
238
|
+
// Ids with a Vite query (?raw, ?url, ?import) are asset requests, not
|
|
239
|
+
// modules to compile. vite-plugin-satteri's id regexes match them, but
|
|
240
|
+
// by the time this transform runs the code is already the asset module
|
|
241
|
+
// (e.g. `export default "<file text>"` for ?raw) — compiling that as
|
|
242
|
+
// markdown corrupts it. @mdx-js/rollup matched by extname and skipped
|
|
243
|
+
// queried ids; preserve that behavior.
|
|
244
|
+
if (id.includes('?')) return null;
|
|
211
245
|
const envName = (this as unknown as { environment?: { name?: string } }).environment?.name;
|
|
212
246
|
if (envName && envName !== 'rsc') return null;
|
|
213
247
|
if (typeof innerPlugin.transform === 'function') {
|