@zenithbuild/core 1.2.8 → 1.2.10

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.
@@ -26,6 +26,7 @@ import * as logger from '../utils/logger'
26
26
  import * as brand from '../utils/branding'
27
27
  import {
28
28
  compileZenSource,
29
+ discoverComponents,
29
30
  discoverLayouts,
30
31
  processLayout,
31
32
  generateBundleJS,
@@ -90,8 +91,10 @@ export async function dev(options: DevOptions = {}): Promise<void> {
90
91
 
91
92
  // Let plugin register its CLI hooks (if it wants to)
92
93
  // CLI does NOT check what the plugin is - it just offers the API
94
+ console.log('[Zenith] About to call registerCLI for:', plugin.name)
93
95
  if (plugin.registerCLI) {
94
96
  plugin.registerCLI(bridgeAPI)
97
+ console.log('[Zenith] registerCLI completed for:', plugin.name)
95
98
  }
96
99
  }
97
100
 
@@ -100,16 +103,20 @@ export async function dev(options: DevOptions = {}): Promise<void> {
100
103
  // ============================================
101
104
  // Initialize ALL plugins unconditionally.
102
105
  // If no plugins, this is a no-op. CLI doesn't branch on plugin presence.
106
+ console.log('[Zenith] About to call registry.initAll...')
103
107
  await registry.initAll(createPluginContext(rootDir))
108
+ console.log('[Zenith] registry.initAll completed')
104
109
 
105
110
  // Create hook context - CLI provides this but NEVER uses getPluginData itself
106
111
  const hookCtx: HookContext = {
107
112
  projectRoot: rootDir,
108
113
  getPluginData: getPluginDataByNamespace
109
114
  }
115
+ console.log('[Zenith] hookCtx created, calling runPluginHooks...')
110
116
 
111
117
  // Dispatch lifecycle hook - plugins decide if they care
112
118
  await runPluginHooks('cli:dev:start', hookCtx)
119
+ console.log('[Zenith] runPluginHooks completed')
113
120
 
114
121
  // ============================================
115
122
  // CSS Compilation (Compiler-Owned)
@@ -150,21 +157,59 @@ export async function dev(options: DevOptions = {}): Promise<void> {
150
157
  */
151
158
  async function compilePageInMemory(pagePath: string): Promise<CompiledPage | null> {
152
159
  try {
153
- const layoutsDir = path.join(pagesDir, '../layouts')
154
160
  const componentsDir = path.join(pagesDir, '../components')
161
+ const layoutsDir = path.join(pagesDir, '../layouts')
162
+
163
+ // Discover layouts for wrapping logic
155
164
  const layouts = discoverLayouts(layoutsDir)
156
- const source = fs.readFileSync(pagePath, 'utf-8')
157
165
 
166
+ // Discover components for resolution logic
167
+ // We need layouts to be available as components too (e.g. <DefaultLayout>)
168
+ const componentsMap = new Map()
169
+
170
+ if (fs.existsSync(componentsDir)) {
171
+ const comps = discoverComponents(componentsDir)
172
+ for (const [k, v] of comps) componentsMap.set(k, v)
173
+ }
174
+
175
+ if (fs.existsSync(layoutsDir)) {
176
+ const layoutComps = discoverComponents(layoutsDir)
177
+ for (const [k, v] of layoutComps) {
178
+ // Start with uppercase = component
179
+ if (k[0] === k[0]?.toUpperCase()) {
180
+ componentsMap.set(k, v)
181
+ }
182
+ }
183
+ }
184
+
185
+ const source = fs.readFileSync(pagePath, 'utf-8')
158
186
  let processedSource = source
159
- let layoutToUse = layouts.get('DefaultLayout')
160
187
 
161
- if (layoutToUse) processedSource = processLayout(source, layoutToUse)
188
+ // Legacy layout wrapping (implicit)
189
+ // If the page doesn't explicitly use the layout, we might wrap it?
190
+ // But if users use <DefaultLayout>, that's handled by component resolution.
191
+
192
+ let layoutToUse = layouts.get('DefaultLayout')
193
+ if (layoutToUse && !source.includes('<DefaultLayout')) {
194
+ // only wrap if not already used?
195
+ // actually processLayout is usually for "implicit" layout application
196
+ // If the user manually wraps, processLayout might double wrap?
197
+ // Let's assume processLayout logic is correct for now or minimal.
198
+ // processLayout(source, layoutToUse) checks if it should wrap.
199
+ processedSource = processLayout(source, layoutToUse)
200
+ } else if (layoutToUse) {
201
+ // If it IS used explicitly, we treat it as a component.
202
+ // We don't wrap it.
203
+ }
162
204
 
163
205
  const result = await compileZenSource(processedSource, pagePath, {
164
- componentsDir: fs.existsSync(componentsDir) ? componentsDir : undefined
206
+ components: componentsMap
165
207
  })
166
208
  if (!result.finalized) throw new Error('Compilation failed')
167
209
 
210
+ console.log('[Dev] Finalized JS Length:', result.finalized.js.length)
211
+ console.log('[Dev] Finalized JS Preview:', result.finalized.js.substring(0, 500))
212
+
168
213
  const routeDef = generateRouteDefinition(pagePath, pagesDir)
169
214
 
170
215
 
@@ -251,23 +296,26 @@ export async function dev(options: DevOptions = {}): Promise<void> {
251
296
  * It serializes blindly - never inspecting what's inside.
252
297
  */
253
298
  async function generateDevHTML(page: CompiledPage): Promise<string> {
254
- // Single neutral injection point
255
- const runtimeTag = `<script type="module" src="/runtime.js"></script>`
299
+ // Runtime MUST be a regular script (not module) to execute synchronously
300
+ // before the page module script runs and needs its globals
301
+ const runtimeTag = `<script src="/runtime.js"></script>`
256
302
  const scriptTag = `<script type="module">\n${page.script}\n</script>`
257
303
  const allScripts = `${runtimeTag}\n${scriptTag}`
258
304
 
259
- let html = page.html.includes('</head>')
260
- ? page.html.replace('</head>', `${allScripts}\n</head>`)
261
- : page.html.includes('</body>')
262
- ? page.html.replace('</body>', `${allScripts}\n</body>`)
263
- : `${page.html}\n${allScripts}`
305
+ let html = page.html;
306
+ if (html.includes('</head>')) {
307
+ html = html.replace('</head>', `${allScripts}\n</head>`);
308
+ } else if (html.includes('</body>')) {
309
+ html = html.replace('</body>', `${allScripts}\n</body>`);
310
+ } else {
311
+ html = `${html}\n${allScripts}`;
312
+ }
264
313
 
265
- // Ensure DOCTYPE is present to prevent Quirks Mode (critical for SVG namespace)
266
314
  if (!html.trimStart().toLowerCase().startsWith('<!doctype')) {
267
- html = `<!DOCTYPE html>\n${html}`
315
+ html = `<!DOCTYPE html>\n<html lang="en">\n${html}\n</html>`;
268
316
  }
269
317
 
270
- return html
318
+ return html;
271
319
  }
272
320
 
273
321
  // ============================================
@@ -407,7 +455,7 @@ export async function dev(options: DevOptions = {}): Promise<void> {
407
455
  const renderTime = Math.round(renderEnd - renderStart)
408
456
 
409
457
  logger.route('GET', pathname, 200, totalTime, compileTime, renderTime)
410
- return new Response(html, { headers: { 'Content-Type': 'text/html' } })
458
+ return new Response(html, { headers: { 'Content-Type': 'text/html; charset=utf-8' } })
411
459
  }
412
460
  }
413
461
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zenithbuild/core",
3
- "version": "1.2.8",
3
+ "version": "1.2.10",
4
4
  "description": "Core library for the Zenith framework",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -56,16 +56,16 @@
56
56
  },
57
57
  "private": false,
58
58
  "devDependencies": {
59
- "@types/bun": "latest",
60
- "@types/node": "latest",
61
- "prettier": "^3.7.4"
59
+ "@types/bun": "^1.3.6",
60
+ "@types/node": "^25.0.10",
61
+ "prettier": "^3.8.1"
62
62
  },
63
63
  "peerDependencies": {
64
- "typescript": "^5"
64
+ "typescript": "^5.9.3"
65
65
  },
66
66
  "dependencies": {
67
- "@zenithbuild/compiler": "latest",
68
- "@zenithbuild/router": "latest",
67
+ "@zenithbuild/compiler": "^1.0.12",
68
+ "@zenithbuild/router": "^1.0.4",
69
69
  "picocolors": "^1.1.1"
70
70
  }
71
- }
71
+ }
Binary file