metaowl 0.2.11 → 0.2.13

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/index.js CHANGED
@@ -1,6 +1,7 @@
1
1
  import { mountApp } from './modules/app-mounter.js'
2
2
  import { buildRoutes } from './modules/file-router.js'
3
3
  import { processRoutes } from './modules/router.js'
4
+ import { discoverLayouts } from './modules/layouts.js'
4
5
 
5
6
  export { default as Fetch } from './modules/fetch.js'
6
7
  export { default as Cache } from './modules/cache.js'
@@ -170,7 +171,21 @@ export {
170
171
  *
171
172
  * @param {Record<string, object>|object[]} [routesOrModules]
172
173
  */
173
- export async function boot(routesOrModules = {}) {
174
+ export async function boot(routesOrModules = {}, layoutsOrModules = null) {
175
+ // Auto-discover layouts
176
+ try {
177
+ if (layoutsOrModules) {
178
+ // Use layouts provided by Vite plugin transformation
179
+ const { buildLayouts, setDefaultLayout } = await import('./modules/layouts.js')
180
+ buildLayouts(layoutsOrModules)
181
+ setDefaultLayout('default')
182
+ } else {
183
+ await discoverLayouts()
184
+ }
185
+ } catch (e) {
186
+ console.warn('[metaowl] Could not auto-discover layouts:', e.message)
187
+ }
188
+
174
189
  const routes = Array.isArray(routesOrModules)
175
190
  ? routesOrModules
176
191
  : buildRoutes(routesOrModules)
@@ -2,17 +2,43 @@
2
2
  * @module TemplatesManager
3
3
  *
4
4
  * Template loading and merging utilities for OWL applications.
5
+ * Supports both runtime loading (legacy) and build-time inlined templates.
5
6
  */
6
7
  import { loadFile } from '@odoo/owl'
7
8
 
9
+ /**
10
+ * Try to import inlined templates from build time.
11
+ * Returns null if not available (dev mode without inline plugin or legacy setup).
12
+ */
13
+ async function getInlinedTemplates() {
14
+ try {
15
+ // In production (build), templates are inlined via Vite plugin
16
+ const { TEMPLATES } = await import('/src/templates.js')
17
+ return TEMPLATES
18
+ } catch (e) {
19
+ // In development or legacy setup, templates are loaded at runtime
20
+ return null
21
+ }
22
+ }
23
+
8
24
  /**
9
25
  * Loads and concatenates a list of OWL XML template files into a single
10
26
  * `<templates>` string ready to be passed to OWL's mount() options.
11
27
  *
12
- * @param {string[]} files - Array of URL-style XML paths, e.g. ['/owl/components/Header/Header.xml']
28
+ * If inlined templates are available (from build time), those are used directly.
29
+ * Otherwise, falls back to runtime loading of individual XML files.
30
+ *
31
+ * @param {string[]} [files] - Array of URL-style XML paths (ignored if inlined templates exist)
13
32
  * @returns {Promise<string>}
14
33
  */
15
- export async function mergeTemplates(files) {
34
+ export async function mergeTemplates(files = []) {
35
+ // Try to get inlined templates first (production build)
36
+ const inlined = await getInlinedTemplates()
37
+ if (inlined) {
38
+ return inlined
39
+ }
40
+
41
+ // Fallback: load templates at runtime (development or legacy)
16
42
  let templates = '<templates>'
17
43
  for (const file of files) {
18
44
  try {
@@ -23,3 +49,12 @@ export async function mergeTemplates(files) {
23
49
  }
24
50
  return templates + '</templates>'
25
51
  }
52
+
53
+ /**
54
+ * Check if inlined templates are available.
55
+ * @returns {Promise<boolean>}
56
+ */
57
+ export async function hasInlinedTemplates() {
58
+ const templates = await getInlinedTemplates()
59
+ return templates !== null
60
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "metaowl",
3
- "version": "0.2.11",
3
+ "version": "0.2.13",
4
4
  "description": "Lightweight meta-framework for Odoo OWL — file-based routing, app mounting, Fetch helper, Cache, Meta tags, SSG generator, and a Vite plugin.",
5
5
  "type": "module",
6
6
  "main": "index.js",
package/vite/plugin.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { fileURLToPath } from 'node:url'
2
2
  import { resolve, dirname } from 'node:path'
3
- import { mkdirSync, copyFileSync, cpSync, existsSync } from 'node:fs'
3
+ import { mkdirSync, copyFileSync, cpSync, existsSync, readFileSync, writeFileSync } from 'node:fs'
4
4
  import { createRequire } from 'node:module'
5
5
  import { globSync } from 'glob'
6
6
  import { config as dotenvConfig } from 'dotenv'
@@ -63,7 +63,7 @@ export async function metaowlPlugin(options = {}) {
63
63
  const componentXml = collectXml(`${componentsDir}/**/*.xml`)
64
64
  const pageXml = collectXml(`${pagesDir}/**/*.xml`)
65
65
  const layoutXml = collectXml(`${layoutsDir}/**/*.xml`)
66
- const allComponents = [...pageXml, ...componentXml, ...layoutXml]
66
+ const allComponents = [...layoutXml, ...pageXml, ...componentXml]
67
67
 
68
68
  const defaultRestartGlobs = [
69
69
  `${root}/**/*.[jt]s`,
@@ -191,10 +191,7 @@ export async function metaowlPlugin(options = {}) {
191
191
  return {
192
192
  code: code.replace(
193
193
  /boot\(\s*\)/,
194
- `boot(import.meta.glob('./${pagesRel}/**/*.js', { eager: true }))`
195
- ).replace(
196
- /discoverLayouts\(\s*\)/,
197
- `discoverLayouts(import.meta.glob('./${layoutsRel}/**/*.js', { eager: true }))`
194
+ `boot(import.meta.glob('./${pagesRel}/**/*.js', { eager: true }), import.meta.glob('./${layoutsRel}/**/*.js', { eager: true }))`
198
195
  ),
199
196
  map: null
200
197
  }
@@ -222,20 +219,37 @@ export async function metaowlPlugin(options = {}) {
222
219
  closeBundle() {
223
220
  const projectRoot = process.cwd()
224
221
 
225
- // Copy OWL XML templates (loaded at runtime via fetch — not processed by Vite)
226
- const xmlFiles = globSync([`${componentsDir}/**/*.xml`, `${pagesDir}/**/*.xml`, `${layoutsDir}/**/*.xml`])
227
- for (const xmlFile of xmlFiles) {
228
- const relPath = xmlFile.replace(new RegExp(`^${root}[\\/]`), '')
229
- const dest = resolve(_outDirResolved, relPath)
230
- mkdirSync(dirname(dest), { recursive: true })
231
- copyFileSync(resolve(projectRoot, xmlFile), dest)
232
- }
222
+ // Collect and inline all XML templates into a single JS file
223
+ const xmlFiles = [
224
+ ...globSync(`${root}/${layoutsDir}/**/*.xml`),
225
+ ...globSync(`${root}/${pagesDir}/**/*.xml`),
226
+ ...globSync(`${root}/${componentsDir}/**/*.xml`)
227
+ ]
233
228
 
234
- // Copy assets/images (referenced via absolute URLs in XML — not processed by Vite)
235
- const srcImages = resolve(projectRoot, root, 'assets', 'images')
236
- if (existsSync(srcImages)) {
237
- cpSync(srcImages, resolve(_outDirResolved, 'assets', 'images'), { recursive: true })
229
+ let templates = '<templates>'
230
+ for (const file of xmlFiles) {
231
+ try {
232
+ templates += readFileSync(file, 'utf-8')
233
+ } catch (e) {
234
+ console.warn(`[metaowl] Failed to read template: ${file}`)
235
+ }
238
236
  }
237
+ templates += '</templates>'
238
+
239
+ // Escape for JavaScript string
240
+ const escaped = templates
241
+ .replace(/\\/g, '\\\\')
242
+ .replace(/'/g, "\\'")
243
+ .replace(/\n/g, '\\n')
244
+ .replace(/\r/g, '')
245
+
246
+ // Write templates.js
247
+ const templatesJs = `export const TEMPLATES = '${escaped}';\n`
248
+ const templatesDir = resolve(_outDirResolved, root)
249
+ mkdirSync(templatesDir, { recursive: true })
250
+ writeFileSync(resolve(templatesDir, 'templates.js'), templatesJs)
251
+
252
+ console.log(`[metaowl] Inlined ${xmlFiles.length} XML templates into templates.js`)
239
253
  }
240
254
  }
241
255
  ]