eddev 2.3.31 → 2.4.0-beta.2

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.
Files changed (106) hide show
  1. package/dist/app/entry/ssr-root-client.d.ts +0 -2
  2. package/dist/app/entry/ssr-root-client.d.ts.map +1 -1
  3. package/dist/app/lib/blocks/block-debugger.d.ts.map +1 -1
  4. package/dist/app/lib/blocks/block-debugger.js +19 -2
  5. package/dist/app/lib/devtools/components/panels/StructurePanel.js +1 -1
  6. package/dist/app/server/assets.d.ts +45 -0
  7. package/dist/app/server/assets.d.ts.map +1 -0
  8. package/dist/app/server/assets.js +15 -0
  9. package/dist/app/server/index.d.ts +4 -0
  10. package/dist/app/server/index.d.ts.map +1 -1
  11. package/dist/app/server/index.js +3 -0
  12. package/dist/app/server/proxy-wp-admin.d.ts +6 -2
  13. package/dist/app/server/proxy-wp-admin.d.ts.map +1 -1
  14. package/dist/app/server/proxy-wp-admin.js +29 -57
  15. package/dist/app/server/render-ssr-page.d.ts +2 -6
  16. package/dist/app/server/render-ssr-page.d.ts.map +1 -1
  17. package/dist/app/server/render-ssr-page.js +9 -8
  18. package/dist/app/server/rpc-handler.d.ts +14 -0
  19. package/dist/app/server/rpc-handler.d.ts.map +1 -0
  20. package/dist/app/server/rpc-handler.js +63 -0
  21. package/dist/app/server/server-app.d.ts +22 -0
  22. package/dist/app/server/server-app.d.ts.map +1 -0
  23. package/dist/app/server/server-app.js +186 -0
  24. package/dist/app/server/server-context.d.ts +5 -5
  25. package/dist/app/server/server-context.d.ts.map +1 -1
  26. package/dist/app/server/server-context.js +21 -13
  27. package/dist/app/server/utils/fetch-origin.d.ts +13 -0
  28. package/dist/app/server/utils/fetch-origin.d.ts.map +1 -0
  29. package/dist/app/server/utils/fetch-origin.js +21 -0
  30. package/dist/app/server/utils/request.d.ts +20 -0
  31. package/dist/app/server/utils/request.d.ts.map +1 -0
  32. package/dist/app/server/utils/request.js +60 -0
  33. package/dist/node/cli/cli-worker.d.ts +10 -6
  34. package/dist/node/cli/cli-worker.d.ts.map +1 -1
  35. package/dist/node/cli/cli-worker.js +7 -14
  36. package/dist/node/cli/cli.js +37 -43
  37. package/dist/node/cli/display/CLIApp.d.ts +2 -4
  38. package/dist/node/cli/display/CLIApp.d.ts.map +1 -1
  39. package/dist/node/cli/display/CLIApp.js +2 -3
  40. package/dist/node/cli/version.d.ts +1 -1
  41. package/dist/node/cli/version.d.ts.map +1 -1
  42. package/dist/node/cli/version.js +1 -1
  43. package/dist/node/compiler/app-codegen.d.ts +18 -0
  44. package/dist/node/compiler/app-codegen.d.ts.map +1 -0
  45. package/dist/node/compiler/app-codegen.js +473 -0
  46. package/dist/node/compiler/build-serverless.d.ts +16 -0
  47. package/dist/node/compiler/build-serverless.d.ts.map +1 -0
  48. package/dist/node/compiler/build-serverless.js +40 -0
  49. package/dist/node/compiler/bundler.spa.d.ts +33 -0
  50. package/dist/node/compiler/bundler.spa.d.ts.map +1 -0
  51. package/dist/node/compiler/bundler.spa.js +59 -0
  52. package/dist/node/compiler/dev-css-links.d.ts +25 -0
  53. package/dist/node/compiler/dev-css-links.d.ts.map +1 -0
  54. package/dist/node/compiler/dev-css-links.js +87 -0
  55. package/dist/node/compiler/dev-server.d.ts +2 -0
  56. package/dist/node/compiler/dev-server.d.ts.map +1 -1
  57. package/dist/node/compiler/dev-server.js +43 -75
  58. package/dist/node/compiler/get-vite-config.d.ts +37 -6
  59. package/dist/node/compiler/get-vite-config.d.ts.map +1 -1
  60. package/dist/node/compiler/get-vite-config.js +113 -121
  61. package/dist/node/compiler/serverless-app.d.ts +35 -0
  62. package/dist/node/compiler/serverless-app.d.ts.map +1 -0
  63. package/dist/node/compiler/serverless-app.js +332 -0
  64. package/dist/node/compiler/transforms/block-meta.d.ts +10 -0
  65. package/dist/node/compiler/transforms/block-meta.d.ts.map +1 -0
  66. package/dist/node/compiler/transforms/block-meta.js +27 -0
  67. package/dist/node/compiler/transforms/component-names.d.ts +19 -0
  68. package/dist/node/compiler/transforms/component-names.d.ts.map +1 -0
  69. package/dist/node/compiler/transforms/component-names.js +45 -0
  70. package/dist/node/compiler/transforms/index.d.ts +36 -0
  71. package/dist/node/compiler/transforms/index.d.ts.map +1 -0
  72. package/dist/node/compiler/transforms/index.js +80 -0
  73. package/dist/node/compiler/transforms/types.d.ts +48 -0
  74. package/dist/node/compiler/transforms/types.d.ts.map +1 -0
  75. package/dist/node/compiler/transforms/types.js +1 -0
  76. package/dist/node/project/config.d.ts +1 -1
  77. package/dist/node/project/config.d.ts.map +1 -1
  78. package/dist/node/project/config.js +1 -1
  79. package/dist/node/project/env.js +1 -1
  80. package/dist/node/project/project-log.d.ts +7 -0
  81. package/dist/node/project/project-log.d.ts.map +1 -0
  82. package/dist/node/project/project-log.js +6 -0
  83. package/dist/node/project/project.d.ts +2 -2
  84. package/dist/node/project/project.d.ts.map +1 -1
  85. package/dist/node/project/project.js +3 -3
  86. package/dist/node/utils/fs.d.ts +70 -69
  87. package/dist/node/utils/fs.d.ts.map +1 -1
  88. package/package.json +12 -13
  89. package/skills/eddev/docs/devtool/cli.mdx +10 -8
  90. package/tsconfig.node.json +17 -5
  91. package/types.env.d.ts +1 -1
  92. package/dist/node/compiler/build-vinxi.d.ts +0 -9
  93. package/dist/node/compiler/build-vinxi.d.ts.map +0 -1
  94. package/dist/node/compiler/build-vinxi.js +0 -39
  95. package/dist/node/compiler/bundler.admin.d.ts +0 -14
  96. package/dist/node/compiler/bundler.admin.d.ts.map +0 -1
  97. package/dist/node/compiler/bundler.admin.js +0 -37
  98. package/dist/node/compiler/bundler.frontend.d.ts +0 -15
  99. package/dist/node/compiler/bundler.frontend.d.ts.map +0 -1
  100. package/dist/node/compiler/bundler.frontend.js +0 -51
  101. package/dist/node/compiler/vinxi-app.d.ts +0 -23
  102. package/dist/node/compiler/vinxi-app.d.ts.map +0 -1
  103. package/dist/node/compiler/vinxi-app.js +0 -261
  104. package/dist/node/compiler/vinxi-codegen.d.ts +0 -13
  105. package/dist/node/compiler/vinxi-codegen.d.ts.map +0 -1
  106. package/dist/node/compiler/vinxi-codegen.js +0 -764
@@ -0,0 +1,332 @@
1
+ import glsl from "vite-plugin-glsl";
2
+ import { nitro } from "nitro/vite";
3
+ import { join } from "node:path";
4
+ import { joinURL } from "ufo";
5
+ import { cliMode } from "../cli/cli-mode.js";
6
+ import { getAppFolder } from "./app-codegen.js";
7
+ import { getCacheConfig } from "./cache-config.js";
8
+ import { collectDevStylesheets, cssLinkHmrPlugin } from "./dev-css-links.js";
9
+ import { baseConfigPlugin, corePlugins, createBuildStatusTracker, envPlugin, ignoreRollupErrorsPlugin, loggerPlugin, reactPlugin, workersPlugin, } from "./get-vite-config.js";
10
+ /**
11
+ * The Vite environments that make up the serverless app (Nitro adds its own `nitro` environment):
12
+ * - `client`: the public site in the browser, served from `/_build/`
13
+ * - `admin`: the WordPress editor bundle for proxied wp-admin pages, served from `/_admin/`
14
+ * - `ssr`: the server entry, rendering pages and handling data/RPC requests
15
+ *
16
+ * In dev, `admin` runs as a separate Vite server mounted at `/_admin/` instead, because a dev server
17
+ * only serves its `client` environment to browsers (see `adminDevServerPlugin`).
18
+ */
19
+ export const SERVERLESS_ENVIRONMENTS = ["client", "admin", "ssr"];
20
+ /**
21
+ * Dev only: lets the server runtime (which runs in the same process, via Nitro's `self` runner) ask the
22
+ * admin dev server for the admin bundle's stylesheets. Read by the generated `manifest/assets.ts`.
23
+ */
24
+ export const ADMIN_DEV_STYLESHEETS_HOOK = "__EDDEV_ADMIN_DEV_STYLESHEETS__";
25
+ /** URL prefix for the admin bundle (`assetsDir` in builds, the admin dev server's `base` in dev). */
26
+ const ADMIN_BASE = "/_admin/";
27
+ /** The bundle settings used by eddev's shared plugins, per environment. */
28
+ function getEnvironmentArgs(args, environment) {
29
+ const shared = {
30
+ mode: args.mode,
31
+ serverless: true,
32
+ rootDir: args.rootDir,
33
+ publicUrl: args.publicUrl,
34
+ console: args.log,
35
+ };
36
+ switch (environment) {
37
+ case "client":
38
+ return { ...shared, target: "frontend", client: true };
39
+ case "admin":
40
+ return { ...shared, target: "cms", client: true };
41
+ case "ssr":
42
+ return { ...shared, target: "frontend", client: false };
43
+ default:
44
+ return null;
45
+ }
46
+ }
47
+ function getTransformTargetForEnvironment(environment) {
48
+ if (environment === "admin")
49
+ return "cms";
50
+ if (environment === "client")
51
+ return "frontend";
52
+ return "server";
53
+ }
54
+ /**
55
+ * Compile-time `env.*` values differ per environment (eg. `env.client`, `env.admin`), so the replace
56
+ * plugin is instantiated separately for each one. Nitro's own environment is left alone.
57
+ */
58
+ function environmentEnvPlugin(args) {
59
+ return {
60
+ name: "eddev:env-per-environment",
61
+ applyToEnvironment(environment) {
62
+ const envArgs = getEnvironmentArgs(args, environment.name);
63
+ return envArgs ? envPlugin(envArgs) : false;
64
+ },
65
+ };
66
+ }
67
+ /** Build status for the CLI, tracked per environment (production builds only). */
68
+ function environmentBuildStatusPlugin(status) {
69
+ return {
70
+ name: "eddev:build-status",
71
+ apply: "build",
72
+ buildStart() {
73
+ status.start(this.environment.name);
74
+ },
75
+ buildEnd(error) {
76
+ if (error)
77
+ status.end(this.environment.name, true);
78
+ },
79
+ writeBundle() {
80
+ status.end(this.environment.name);
81
+ },
82
+ };
83
+ }
84
+ /**
85
+ * In dev, serves the admin bundle from a second Vite server (in middleware mode) under `/_admin/`.
86
+ * It shares the main server's HTTP server for HMR, on its own websocket path.
87
+ */
88
+ function adminDevServerPlugin(args) {
89
+ let admin;
90
+ return {
91
+ name: "eddev:admin-dev-server",
92
+ apply: "serve",
93
+ async configureServer(server) {
94
+ const { createServer } = await import("vite");
95
+ const adminArgs = getEnvironmentArgs(args, "admin");
96
+ admin = await createServer({
97
+ configFile: false,
98
+ root: args.rootDir,
99
+ mode: args.mode,
100
+ base: ADMIN_BASE,
101
+ appType: "custom",
102
+ publicDir: false,
103
+ // A separate dependency cache, so the two dev servers don't overwrite each other's optimized deps
104
+ cacheDir: "node_modules/.vite/eddev-admin",
105
+ logLevel: cliMode.verbose ? "info" : "warn",
106
+ plugins: [...corePlugins({ ...adminArgs, logLabel: "admin" }), cssLinkHmrPlugin()],
107
+ server: {
108
+ middlewareMode: true,
109
+ hmr: server.httpServer ? { server: server.httpServer } : undefined,
110
+ allowedHosts: true,
111
+ cors: true,
112
+ },
113
+ });
114
+ server.middlewares.use((req, res, next) => {
115
+ if (req.url?.startsWith(ADMIN_BASE)) {
116
+ admin.middlewares(req, res, next);
117
+ }
118
+ else {
119
+ next();
120
+ }
121
+ });
122
+ // Link the admin bundle's stylesheets in the head of proxied wp-admin pages, so blocks don't
123
+ // render before their CSS. See cssLinkHmrPlugin() for how these links hot reload.
124
+ const entryUrl = `/.eddev/${getAppFolder({ mode: args.mode, serverless: true })}/entry.admin.tsx`;
125
+ globalThis[ADMIN_DEV_STYLESHEETS_HOOK] = async () => {
126
+ const stylesheets = await collectDevStylesheets(admin.environments.client, entryUrl);
127
+ return stylesheets.map((sheet) => ({ href: joinURL(ADMIN_BASE, sheet.url), "data-vite-dev-id": sheet.id }));
128
+ };
129
+ server.httpServer?.once("close", () => {
130
+ delete globalThis[ADMIN_DEV_STYLESHEETS_HOOK];
131
+ admin?.close();
132
+ });
133
+ },
134
+ };
135
+ }
136
+ /**
137
+ * Route rules for the Nitro server: WordPress proxies, and Vercel ISR for pages and data.
138
+ *
139
+ * Nitro's `cache`/`static` rules are deliberately not used. Under Vinxi (Nitro v2) they had no effect on
140
+ * eddev's handlers, but Nitro v3 applies them, which would add a server-side page cache and
141
+ * `Cache-Control: public` headers. Data caching is handled by eddev itself (see `serverless.dataCache`).
142
+ */
143
+ function getRouteRules(args) {
144
+ const cacheConfig = getCacheConfig(args.origin, args.config);
145
+ const serverlessDataRoute = (expiration) => cacheConfig.serverless.isr
146
+ ? {
147
+ isr: {
148
+ expiration,
149
+ allowQuery: [],
150
+ passQuery: false,
151
+ },
152
+ headers: {
153
+ "Vercel-Cache-Tag": "data",
154
+ },
155
+ }
156
+ : {
157
+ isr: false,
158
+ };
159
+ const serverlessPageRoute = (expiration) => cacheConfig.serverless.isr
160
+ ? {
161
+ isr: {
162
+ expiration,
163
+ allowQuery: [],
164
+ passQuery: false,
165
+ },
166
+ headers: {
167
+ "Vercel-Cache-Tag": "data",
168
+ },
169
+ }
170
+ : {
171
+ isr: false,
172
+ };
173
+ return {
174
+ "/wp-content/uploads/**": {
175
+ proxy: joinURL(args.origin, "wp-content/uploads/**"),
176
+ headers: {
177
+ "Cache-Control": "max-age=86400",
178
+ "CDN-Cache-Control": "max-age=86400",
179
+ "Vercel-CDN-Cache-Control": "max-age=86400",
180
+ },
181
+ },
182
+ "/wp-content/plugins/**": {
183
+ proxy: joinURL(args.origin, "wp-content/plugins/**"),
184
+ headers: {
185
+ "Cache-Control": "max-age=86400",
186
+ "CDN-Cache-Control": "max-age=86400",
187
+ "Vercel-CDN-Cache-Control": "max-age=86400",
188
+ },
189
+ },
190
+ "/wp-content/**": { proxy: joinURL(args.origin, "wp-content/**") },
191
+ "/wp-includes/**": { proxy: joinURL(args.origin, "wp-includes/**") },
192
+ "/_data/route/**": serverlessDataRoute(cacheConfig.pageDataTTL ?? 0),
193
+ "/_data/query/**": serverlessDataRoute(cacheConfig.queryHooksTTL ?? 0),
194
+ "/_data/mutation/**": { isr: false },
195
+ "/_data/submit-gf": { isr: false },
196
+ "/_bypass/**": { isr: false },
197
+ ...Object.fromEntries((args.rpcBases ?? []).map((base) => ["/" + base.replace(/(^\/|\/$)/g, "") + "/**", { isr: false }])),
198
+ "/": serverlessPageRoute(cacheConfig.pageDataTTL ?? 0),
199
+ "/**": serverlessPageRoute(cacheConfig.pageDataTTL ?? 0),
200
+ };
201
+ }
202
+ function getNitroConfig(args) {
203
+ // Builds are written inside `.eddev`, except for platforms that require a fixed location
204
+ // (Vercel's `.vercel/output`, Netlify's `.netlify`). Cloudflare finds its output through the
205
+ // `.wrangler/deploy/config.json` redirect that Nitro writes, so it can live in `.eddev` too.
206
+ const hasFixedOutput = !!args.preset && /^(vercel|netlify)/.test(args.preset);
207
+ return {
208
+ preset: args.preset,
209
+ compatibilityDate: "2026-09-01",
210
+ // eddev provides the server entry; don't scan `server/` (that's for RPC routes, handled by eddev).
211
+ serverDir: false,
212
+ buildDir: ".eddev/nitro",
213
+ ...(hasFixedOutput ? {} : { output: { dir: ".eddev/output" } }),
214
+ publicAssets: args.config.serverless.themeAssets.map((folder) => {
215
+ const folderName = folder
216
+ .split("/")
217
+ .filter((p) => !p.includes("*") && p !== ".")
218
+ .join("/");
219
+ return {
220
+ dir: join(args.rootDir, folderName),
221
+ baseURL: joinURL(args.publicUrl, folderName),
222
+ // As with Vinxi: missing files fall through to the app, and (since these files aren't
223
+ // content-hashed) they don't get long-lived `immutable` caching on Vercel.
224
+ fallthrough: true,
225
+ };
226
+ }),
227
+ routeRules: getRouteRules(args),
228
+ vercel: {
229
+ config: {
230
+ version: 3,
231
+ bypassToken: process.env.VERCEL_BYPASS_TOKEN,
232
+ },
233
+ // eddev sets its own (JS-readable) __vdpl cookie, see createServerApp()
234
+ skewProtection: false,
235
+ },
236
+ devServer: {
237
+ // Run the dev server in-process, so server logs go through the CLI's log display.
238
+ runner: "self",
239
+ },
240
+ };
241
+ }
242
+ /**
243
+ * The Vite config for the serverless app, used by both `eddev dev` and `eddev build --serverless`.
244
+ */
245
+ export function getServerlessViteConfig(args) {
246
+ const dev = args.mode === "development";
247
+ const folder = "./.eddev/" + getAppFolder({ mode: args.mode, serverless: true });
248
+ const status = createBuildStatusTracker(args.log);
249
+ const environmentsToBuild = SERVERLESS_ENVIRONMENTS.filter((name) => !(dev && name === "admin"));
250
+ const clientOptimizeDeps = {
251
+ include: ["valtio", "valtio/utils", "@tanstack/react-query", "qs", "react", "react-dom/client"],
252
+ exclude: ["eddev"],
253
+ };
254
+ const plugins = [
255
+ dev && adminDevServerPlugin(args),
256
+ nitro(getNitroConfig(args)),
257
+ glsl({ root: args.rootDir }),
258
+ baseConfigPlugin(),
259
+ environmentEnvPlugin(args),
260
+ reactPlugin({ target: getTransformTargetForEnvironment }),
261
+ ignoreRollupErrorsPlugin(),
262
+ workersPlugin(),
263
+ loggerPlugin({ console: args.log }),
264
+ !dev && environmentBuildStatusPlugin(status),
265
+ ];
266
+ return {
267
+ configFile: false,
268
+ root: args.rootDir,
269
+ mode: args.mode,
270
+ base: "/",
271
+ appType: "custom",
272
+ publicDir: false,
273
+ logLevel: cliMode.verbose ? "info" : "warn",
274
+ define: {
275
+ "process.env.NODE_ENV": JSON.stringify(args.mode),
276
+ },
277
+ plugins,
278
+ legacy: {
279
+ skipWebSocketTokenCheck: true,
280
+ },
281
+ server: {
282
+ allowedHosts: true,
283
+ cors: true,
284
+ },
285
+ environments: {
286
+ client: {
287
+ optimizeDeps: clientOptimizeDeps,
288
+ build: {
289
+ // Nitro reads `rollupOptions.input` to discover entries
290
+ rollupOptions: { input: `${folder}/entry.client.tsx` },
291
+ assetsDir: "_build",
292
+ sourcemap: true,
293
+ },
294
+ },
295
+ ...(dev
296
+ ? {}
297
+ : {
298
+ admin: {
299
+ consumer: "client",
300
+ optimizeDeps: clientOptimizeDeps,
301
+ build: {
302
+ rollupOptions: {
303
+ input: `${folder}/entry.admin.tsx`,
304
+ // Fixed name, so proxied wp-admin pages can load it without a manifest lookup
305
+ output: { entryFileNames: "_admin/entry.admin.js" },
306
+ },
307
+ assetsDir: "_admin",
308
+ sourcemap: true,
309
+ },
310
+ },
311
+ }),
312
+ ssr: {
313
+ resolve: {
314
+ // eddev relies on compile-time `env.*` replacement, so it must be bundled rather than externalized
315
+ noExternal: ["eddev", "react-use"],
316
+ },
317
+ build: {
318
+ rollupOptions: { input: `${folder}/entry.server.ts` },
319
+ // Keep the server's own copies of CSS/assets away from the theme's `/assets` folder
320
+ assetsDir: "_ssr",
321
+ sourcemap: true,
322
+ },
323
+ },
324
+ },
325
+ builder: {
326
+ // Build the client, admin and server bundles in parallel. Nitro then bundles the server output.
327
+ async buildApp(builder) {
328
+ await Promise.all(environmentsToBuild.map((name) => builder.build(builder.environments[name])));
329
+ },
330
+ },
331
+ };
332
+ }
@@ -0,0 +1,10 @@
1
+ import type { SourceTransform } from "./types.js";
2
+ /**
3
+ * Handles `export const meta = { ... }` in blocks and views.
4
+ *
5
+ * The meta object is consumed by the CLI at build time (block manifest, ed.dist.json), so it is
6
+ * normally stripped from bundles. In the `cms` target, block meta is kept and registered with
7
+ * `defineBlock.meta("<file name>", meta)` so the editor can read it at runtime.
8
+ */
9
+ export declare const blockMetaTransform: SourceTransform;
10
+ //# sourceMappingURL=block-meta.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"block-meta.d.ts","sourceRoot":"","sources":["../../../../src/node/compiler/transforms/block-meta.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAA;AAEjD;;;;;;GAMG;AACH,eAAO,MAAM,kBAAkB,EAAE,eAiBhC,CAAA"}
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Handles `export const meta = { ... }` in blocks and views.
3
+ *
4
+ * The meta object is consumed by the CLI at build time (block manifest, ed.dist.json), so it is
5
+ * normally stripped from bundles. In the `cms` target, block meta is kept and registered with
6
+ * `defineBlock.meta("<file name>", meta)` so the editor can read it at runtime.
7
+ */
8
+ export const blockMetaTransform = {
9
+ name: "block-meta",
10
+ visitor: ({ s, code, kind, name, target }) => ({
11
+ ExportNamedDeclaration(node) {
12
+ const decl = node.declaration;
13
+ if (decl?.type !== "VariableDeclaration")
14
+ return;
15
+ const declarator = decl.declarations[0];
16
+ if (declarator?.id?.type !== "Identifier" || declarator.id.name !== "meta")
17
+ return;
18
+ if (target === "cms" && kind === "block" && declarator.init) {
19
+ const init = code.slice(declarator.init.start, declarator.init.end);
20
+ s.overwrite(node.start, node.end, `defineBlock.meta(${JSON.stringify(name)}, ${init});`);
21
+ }
22
+ else {
23
+ s.remove(node.start, node.end);
24
+ }
25
+ },
26
+ }),
27
+ };
@@ -0,0 +1,19 @@
1
+ import type { SourceTransform } from "./types.js";
2
+ /**
3
+ * Rewrites `export default defineBlock("name", (props) => ...)` (and `defineView`) into a named
4
+ * function declaration with a `displayName`, so React DevTools and error stacks show
5
+ * `Block(name)` / `View(name)` instead of an anonymous component.
6
+ *
7
+ * ```tsx
8
+ * export default defineBlock("hero/main", (props) => <div />)
9
+ * // becomes
10
+ * export default function Block_hero_main(props) { return <div /> }
11
+ * Block_hero_main.displayName = "Block(hero/main)"
12
+ * ```
13
+ *
14
+ * Only the exact two-argument form with a string literal and an arrow function is rewritten.
15
+ * The arrow's return type annotation and type parameters are dropped, matching the previous Babel
16
+ * implementation.
17
+ */
18
+ export declare const componentNamesTransform: SourceTransform;
19
+ //# sourceMappingURL=component-names.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"component-names.d.ts","sourceRoot":"","sources":["../../../../src/node/compiler/transforms/component-names.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAA;AAEjD;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,uBAAuB,EAAE,eA+BrC,CAAA"}
@@ -0,0 +1,45 @@
1
+ import { pascalCase } from "change-case-all";
2
+ /**
3
+ * Rewrites `export default defineBlock("name", (props) => ...)` (and `defineView`) into a named
4
+ * function declaration with a `displayName`, so React DevTools and error stacks show
5
+ * `Block(name)` / `View(name)` instead of an anonymous component.
6
+ *
7
+ * ```tsx
8
+ * export default defineBlock("hero/main", (props) => <div />)
9
+ * // becomes
10
+ * export default function Block_hero_main(props) { return <div /> }
11
+ * Block_hero_main.displayName = "Block(hero/main)"
12
+ * ```
13
+ *
14
+ * Only the exact two-argument form with a string literal and an arrow function is rewritten.
15
+ * The arrow's return type annotation and type parameters are dropped, matching the previous Babel
16
+ * implementation.
17
+ */
18
+ export const componentNamesTransform = {
19
+ name: "component-names",
20
+ visitor: ({ s, code }) => ({
21
+ ExportDefaultDeclaration(node) {
22
+ const call = node.declaration;
23
+ if (call?.type !== "CallExpression" || call.callee?.type !== "Identifier")
24
+ return;
25
+ if (call.callee.name !== "defineBlock" && call.callee.name !== "defineView")
26
+ return;
27
+ if (call.arguments.length !== 2)
28
+ return;
29
+ const [nameArg, fn] = call.arguments;
30
+ if (nameArg.type !== "Literal" || typeof nameArg.value !== "string")
31
+ return;
32
+ if (fn.type !== "ArrowFunctionExpression")
33
+ return;
34
+ const type = pascalCase(call.callee.name.replace("define", ""));
35
+ const name = nameArg.value;
36
+ const componentName = type + "_" + name.replace(/[^a-z0-9]/g, "_").replace(/_+/g, "_");
37
+ const params = fn.params.length ? code.slice(fn.params[0].start, fn.params[fn.params.length - 1].end) : "";
38
+ const body = fn.body.type === "BlockStatement"
39
+ ? code.slice(fn.body.start, fn.body.end)
40
+ : `{\n return ${code.slice(fn.body.start, fn.body.end)}\n}`;
41
+ s.overwrite(node.start, node.end, `export default ${fn.async ? "async " : ""}function ${componentName}(${params}) ${body}\n` +
42
+ `${componentName}.displayName = ${JSON.stringify(type + "(" + name + ")")};`);
43
+ },
44
+ }),
45
+ };
@@ -0,0 +1,36 @@
1
+ import MagicString from "magic-string";
2
+ import type { Plugin } from "vite";
3
+ import type { SourceFileKind, SourceTransform, TransformTarget } from "./types.js";
4
+ export type { SourceTransform, SourceTransformContext, TransformTarget } from "./types.js";
5
+ /**
6
+ * The built-in transforms, in the order their handlers run for each node.
7
+ * Add new transforms here.
8
+ */
9
+ export declare const defaultTransforms: SourceTransform[];
10
+ /** Classify a module id as a block or view, using the last `/blocks/` or `/views/` segment. */
11
+ export declare function getSourceFileInfo(id: string): {
12
+ kind: SourceFileKind;
13
+ name: string;
14
+ } | null;
15
+ export type TransformResult = {
16
+ code: string;
17
+ map: ReturnType<MagicString["generateMap"]>;
18
+ } | null;
19
+ /**
20
+ * Run the transforms over a single block or view file. Returns null when nothing changed.
21
+ * Exposed separately from the plugin so it can be unit tested.
22
+ */
23
+ export declare function transformSource(id: string, code: string, target: TransformTarget, transforms?: SourceTransform[]): TransformResult;
24
+ export type TransformsPluginOptions = {
25
+ /**
26
+ * The target for the modules being compiled. Pass a function when one Vite instance builds
27
+ * several environments (eg. the serverless app, where `admin` is `cms` and `ssr` is `server`).
28
+ */
29
+ target: TransformTarget | ((environmentName: string) => TransformTarget);
30
+ transforms?: SourceTransform[];
31
+ };
32
+ /**
33
+ * Applies eddev's source transforms to block and view files, before JSX/TypeScript are compiled.
34
+ */
35
+ export declare function transformsPlugin(options: TransformsPluginOptions): Plugin;
36
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/node/compiler/transforms/index.ts"],"names":[],"mappings":"AAAA,OAAO,WAAW,MAAM,cAAc,CAAA;AAEtC,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,MAAM,CAAA;AAGlC,OAAO,KAAK,EAAE,cAAc,EAAE,eAAe,EAA0B,eAAe,EAAmB,MAAM,YAAY,CAAA;AAE3H,YAAY,EAAE,eAAe,EAAE,sBAAsB,EAAE,eAAe,EAAE,MAAM,YAAY,CAAA;AAE1F;;;GAGG;AACH,eAAO,MAAM,iBAAiB,EAAE,eAAe,EAAkD,CAAA;AAEjG,+FAA+F;AAC/F,wBAAgB,iBAAiB,CAAC,EAAE,EAAE,MAAM,GAAG;IAAE,IAAI,EAAE,cAAc,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAS3F;AAiBD,MAAM,MAAM,eAAe,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,UAAU,CAAC,WAAW,CAAC,aAAa,CAAC,CAAC,CAAA;CAAE,GAAG,IAAI,CAAA;AAElG;;;GAGG;AACH,wBAAgB,eAAe,CAC7B,EAAE,EAAE,MAAM,EACV,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,eAAe,EACvB,UAAU,GAAE,eAAe,EAAsB,GAChD,eAAe,CAqBjB;AAED,MAAM,MAAM,uBAAuB,GAAG;IACpC;;;OAGG;IACH,MAAM,EAAE,eAAe,GAAG,CAAC,CAAC,eAAe,EAAE,MAAM,KAAK,eAAe,CAAC,CAAA;IACxE,UAAU,CAAC,EAAE,eAAe,EAAE,CAAA;CAC/B,CAAA;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,uBAAuB,GAAG,MAAM,CAezE"}
@@ -0,0 +1,80 @@
1
+ import MagicString from "magic-string";
2
+ import { parseSync, Visitor } from "vite";
3
+ import { blockMetaTransform } from "./block-meta.js";
4
+ import { componentNamesTransform } from "./component-names.js";
5
+ /**
6
+ * The built-in transforms, in the order their handlers run for each node.
7
+ * Add new transforms here.
8
+ */
9
+ export const defaultTransforms = [blockMetaTransform, componentNamesTransform];
10
+ /** Classify a module id as a block or view, using the last `/blocks/` or `/views/` segment. */
11
+ export function getSourceFileInfo(id) {
12
+ const file = id.replace(/[?#].*$/, "");
13
+ if (file.includes("/node_modules/"))
14
+ return null;
15
+ // Greedy `.*` so the last matching folder wins, as the previous Babel implementation did.
16
+ const block = file.match(/.*\/blocks\/(.+)\.tsx$/);
17
+ if (block)
18
+ return { kind: "block", name: block[1] };
19
+ const view = file.match(/.*\/views\/(.+)\.tsx$/);
20
+ if (view)
21
+ return { kind: "view", name: view[1] };
22
+ return null;
23
+ }
24
+ function combineVisitors(handlerSets) {
25
+ const combined = {};
26
+ for (const handlers of handlerSets) {
27
+ for (const [type, handler] of Object.entries(handlers)) {
28
+ ;
29
+ (combined[type] ??= []).push(handler);
30
+ }
31
+ }
32
+ return Object.fromEntries(Object.entries(combined).map(([type, handlers]) => [
33
+ type,
34
+ handlers.length === 1 ? handlers[0] : (node) => handlers.forEach((handler) => handler(node)),
35
+ ]));
36
+ }
37
+ /**
38
+ * Run the transforms over a single block or view file. Returns null when nothing changed.
39
+ * Exposed separately from the plugin so it can be unit tested.
40
+ */
41
+ export function transformSource(id, code, target, transforms = defaultTransforms) {
42
+ const info = getSourceFileInfo(id);
43
+ if (!info)
44
+ return null;
45
+ const base = { id: id.replace(/[?#].*$/, ""), code, kind: info.kind, name: info.name, target };
46
+ const active = transforms.filter((t) => t.applies?.(base) ?? true);
47
+ if (!active.length)
48
+ return null;
49
+ const { program, errors } = parseSync(base.id, code, { sourceType: "module" });
50
+ const fatal = errors.filter((e) => e.severity === "Error");
51
+ if (fatal.length) {
52
+ // Leave the file untouched; the regular transform pipeline will report the syntax error.
53
+ return null;
54
+ }
55
+ const s = new MagicString(code);
56
+ const ctx = { ...base, ast: program, s };
57
+ new Visitor(combineVisitors(active.map((t) => t.visitor(ctx)))).visit(program);
58
+ if (!s.hasChanged())
59
+ return null;
60
+ return { code: s.toString(), map: s.generateMap({ hires: "boundary", source: base.id, includeContent: true }) };
61
+ }
62
+ /**
63
+ * Applies eddev's source transforms to block and view files, before JSX/TypeScript are compiled.
64
+ */
65
+ export function transformsPlugin(options) {
66
+ const transforms = options.transforms ?? defaultTransforms;
67
+ return {
68
+ name: "eddev:transforms",
69
+ enforce: "pre",
70
+ transform: {
71
+ filter: {
72
+ id: { include: [/\/(blocks|views)\/.+\.tsx(?:$|\?)/], exclude: [/\/node_modules\//] },
73
+ },
74
+ handler(code, id) {
75
+ const target = typeof options.target === "function" ? options.target(this.environment.name) : options.target;
76
+ return transformSource(id, code, target, transforms);
77
+ },
78
+ },
79
+ };
80
+ }
@@ -0,0 +1,48 @@
1
+ import type MagicString from "magic-string";
2
+ import type { ESTree } from "vite";
3
+ type Program = ESTree.Program;
4
+ /**
5
+ * Which bundle a module is being compiled for.
6
+ * - `cms`: the WordPress admin/editor bundle
7
+ * - `frontend`: the public site, in the browser
8
+ * - `server`: the public site, rendered on the server (SSR)
9
+ */
10
+ export type TransformTarget = "cms" | "frontend" | "server";
11
+ /** The kind of eddev source file being transformed. */
12
+ export type SourceFileKind = "block" | "view";
13
+ export type SourceTransformContext = {
14
+ /** Absolute module id, without any query string */
15
+ id: string;
16
+ /** The original source code */
17
+ code: string;
18
+ /** The parsed program (ESTree-compatible, with TypeScript nodes) */
19
+ ast: Program;
20
+ /**
21
+ * Shared output buffer. Transforms must only edit ranges they own, because
22
+ * MagicString cannot re-edit a range that another transform has overwritten.
23
+ */
24
+ s: MagicString;
25
+ kind: SourceFileKind;
26
+ /**
27
+ * The file-derived name, relative to the `blocks/` or `views/` folder and without extension.
28
+ * For example `blocks/hero/carousel.tsx` → `hero/carousel`.
29
+ */
30
+ name: string;
31
+ target: TransformTarget;
32
+ };
33
+ /** Handlers keyed by ESTree node type, as accepted by Vite's (oxc) `Visitor`. */
34
+ export type VisitorHandlers = Record<string, (node: any) => void>;
35
+ /**
36
+ * A small source transform, run as part of the `eddev:transforms` Vite plugin.
37
+ *
38
+ * Each file is parsed once and walked once; the visitors of every applicable
39
+ * transform are combined into a single walk.
40
+ */
41
+ export type SourceTransform = {
42
+ name: string;
43
+ /** Return false to skip this transform for a particular file/target. Defaults to always applying. */
44
+ applies?: (ctx: Omit<SourceTransformContext, "ast" | "s">) => boolean;
45
+ visitor: (ctx: SourceTransformContext) => VisitorHandlers;
46
+ };
47
+ export {};
48
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../src/node/compiler/transforms/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,WAAW,MAAM,cAAc,CAAA;AAC3C,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,MAAM,CAAA;AAElC,KAAK,OAAO,GAAG,MAAM,CAAC,OAAO,CAAA;AAE7B;;;;;GAKG;AACH,MAAM,MAAM,eAAe,GAAG,KAAK,GAAG,UAAU,GAAG,QAAQ,CAAA;AAE3D,uDAAuD;AACvD,MAAM,MAAM,cAAc,GAAG,OAAO,GAAG,MAAM,CAAA;AAE7C,MAAM,MAAM,sBAAsB,GAAG;IACnC,mDAAmD;IACnD,EAAE,EAAE,MAAM,CAAA;IACV,+BAA+B;IAC/B,IAAI,EAAE,MAAM,CAAA;IACZ,oEAAoE;IACpE,GAAG,EAAE,OAAO,CAAA;IACZ;;;OAGG;IACH,CAAC,EAAE,WAAW,CAAA;IACd,IAAI,EAAE,cAAc,CAAA;IACpB;;;OAGG;IACH,IAAI,EAAE,MAAM,CAAA;IACZ,MAAM,EAAE,eAAe,CAAA;CACxB,CAAA;AAED,iFAAiF;AACjF,MAAM,MAAM,eAAe,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,GAAG,KAAK,IAAI,CAAC,CAAA;AAEjE;;;;;GAKG;AACH,MAAM,MAAM,eAAe,GAAG;IAC5B,IAAI,EAAE,MAAM,CAAA;IACZ,qGAAqG;IACrG,OAAO,CAAC,EAAE,CAAC,GAAG,EAAE,IAAI,CAAC,sBAAsB,EAAE,KAAK,GAAG,GAAG,CAAC,KAAK,OAAO,CAAA;IACrE,OAAO,EAAE,CAAC,GAAG,EAAE,sBAAsB,KAAK,eAAe,CAAA;CAC1D,CAAA"}
@@ -0,0 +1 @@
1
+ export {};
@@ -1,5 +1,5 @@
1
1
  import { z } from "zod";
2
- import { Project } from "./project.js";
2
+ import type { Project } from "./project.js";
3
3
  export declare const EDCacheConfigSchema: z.ZodObject<{
4
4
  wordpress: z.ZodDefault<z.ZodObject<{
5
5
  cacheHeaders: z.ZodDefault<z.ZodBoolean>;
@@ -1 +1 @@
1
- {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../../src/node/project/config.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAIvB,OAAO,EAAE,OAAO,EAAyB,MAAM,cAAc,CAAA;AAE7D,eAAO,MAAM,mBAAmB;;;;;;;;;;;;;;;iBAmB9B,CAAA;AAqBF,eAAO,MAAM,qBAAqB;;;;;;;;;;;;2BAwChC,CAAA;AAEF,eAAO,MAAM,cAAc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAwHzB,CAAA;AAEF,MAAM,MAAM,QAAQ,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,cAAc,CAAC,CAAA;AACrD,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,mBAAmB,CAAC,CAAA;AAE/D,qBAAa,YAAY;IAGI,OAAO,EAAE,OAAO;IAF3C,MAAM,CAAC,EAAE,QAAQ,CAAA;IAEjB,OAAO;WAEM,MAAM,CAAC,OAAO,EAAE,OAAO;IAM9B,IAAI;YAQI,kBAAkB;YAclB,UAAU;IAiCxB,OAAO,CAAC,WAAW;IAOnB,MAAM,CAAC,cAAc,CAAC,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,OAAO;CAUzD"}
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../../src/node/project/config.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAIvB,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA;AAG3C,eAAO,MAAM,mBAAmB;;;;;;;;;;;;;;;iBAmB9B,CAAA;AAqBF,eAAO,MAAM,qBAAqB;;;;;;;;;;;;2BAwChC,CAAA;AAEF,eAAO,MAAM,cAAc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAwHzB,CAAA;AAEF,MAAM,MAAM,QAAQ,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,cAAc,CAAC,CAAA;AACrD,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,mBAAmB,CAAC,CAAA;AAE/D,qBAAa,YAAY;IAGI,OAAO,EAAE,OAAO;IAF3C,MAAM,CAAC,EAAE,QAAQ,CAAA;IAEjB,OAAO;WAEM,MAAM,CAAC,OAAO,EAAE,OAAO;IAM9B,IAAI;YAQI,kBAAkB;YAclB,UAAU;IAiCxB,OAAO,CAAC,WAAW;IAOnB,MAAM,CAAC,cAAc,CAAC,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,OAAO;CAUzD"}
@@ -4,7 +4,7 @@ import { z } from "zod";
4
4
  import { cliMode } from "../cli/cli-mode.js";
5
5
  import { fs } from "../utils/fs.js";
6
6
  import { isDeploying } from "../utils/is-deploying.js";
7
- import { projectLog as console } from "./project.js";
7
+ import { projectLog as console } from "./project-log.js";
8
8
  export const EDCacheConfigSchema = z.object({
9
9
  wordpress: z
10
10
  .object({
@@ -1,6 +1,6 @@
1
1
  import { z } from "zod";
2
2
  import { cliMode } from "../cli/cli-mode.js";
3
- import { projectLog as console } from "./project.js";
3
+ import { projectLog as console } from "./project-log.js";
4
4
  import { formatZodError } from "../utils/format-zod-error.js";
5
5
  const portNumber = z
6
6
  .string()