metaowl 0.2.14 → 0.2.16

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/README.md CHANGED
@@ -63,6 +63,7 @@ All powered by a batteries-included Vite plugin that handles the build pipeline,
63
63
  - [ESLint Config](#eslint-config)
64
64
  - [PostCSS Config](#postcss-config)
65
65
  - [TypeScript / jsconfig](#typescript--jsconfig)
66
+ - [Deployment](#deployment)
66
67
  - [Contributing](#contributing)
67
68
  - [License](#license)
68
69
 
@@ -1370,6 +1371,69 @@ Extend from the included base configs to get sensible defaults:
1370
1371
 
1371
1372
  ---
1372
1373
 
1374
+ ## Deployment
1375
+
1376
+ MetaOWL provides two ways to build your application for production:
1377
+
1378
+ ### Option 1: `npm run generate` (Recommended)
1379
+
1380
+ ```bash
1381
+ npm run generate
1382
+ ```
1383
+
1384
+ This command generates static HTML files for all routes. The result works **without any server configuration** on all web hosts:
1385
+
1386
+ - GitHub Pages
1387
+ - Vercel
1388
+ - Netlify
1389
+ - Cloudflare Pages
1390
+ - Any traditional web host
1391
+
1392
+ All pages are generated as separate HTML files at build time, so every route can be accessed directly.
1393
+
1394
+ ### Option 2: `npm run build`
1395
+
1396
+ ```bash
1397
+ npm run build
1398
+ ```
1399
+
1400
+ This command creates a Single Page Application (SPA). Since all routes are handled client-side, the web server must **forward all requests to `index.html`** (SPA fallback).
1401
+
1402
+ #### Web Server Configuration by Host:
1403
+
1404
+ **Vercel, Netlify, Cloudflare Pages:**
1405
+ Create a `public/serve.json` file before building:
1406
+
1407
+ ```json
1408
+ {
1409
+ "rewrites": [
1410
+ { "source": "**", "destination": "/index.html" }
1411
+ ]
1412
+ }
1413
+ ```
1414
+
1415
+ **Apache (.htaccess):**
1416
+ ```apache
1417
+ RewriteEngine On
1418
+ RewriteCond %{REQUEST_FILENAME} !-f
1419
+ RewriteCond %{REQUEST_FILENAME} !-d
1420
+ RewriteRule ^ /index.html [L]
1421
+ ```
1422
+
1423
+ **nginx:**
1424
+ ```nginx
1425
+ location / {
1426
+ try_files $uri $uri/ /index.html;
1427
+ }
1428
+ ```
1429
+
1430
+ **Node.js (with serve):**
1431
+ ```bash
1432
+ npx serve -s dist
1433
+ ```
1434
+
1435
+ ---
1436
+
1373
1437
  ## Contributing
1374
1438
 
1375
1439
  Contributions are welcome! Please open an issue before submitting a pull request so we can discuss the change.
@@ -2,68 +2,26 @@
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.
6
5
  */
7
6
  import { loadFile } from '@odoo/owl'
8
7
 
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
- // Skip in test environment (Vitest doesn't have the same import.meta behavior)
15
- // Also skip if we're not in a browser environment
16
- if (typeof window === 'undefined' && typeof globalThis.importMeta === 'undefined') {
17
- return null
18
- }
19
-
20
- try {
21
- // In production (build), templates are inlined via Vite plugin
22
- // Use dynamic import with a path that Vite can resolve at runtime
23
- // The templates.js is generated in the output directory
24
- // Using eval to prevent Vite's static analysis from failing
25
- const templatesModule = await new Function('return import("/templates.js")')()
26
- return templatesModule.TEMPLATES
27
- } catch (e) {
28
- // In development or legacy setup, templates are loaded at runtime
29
- return null
30
- }
31
- }
32
-
33
8
  /**
34
9
  * Loads and concatenates a list of OWL XML template files into a single
35
10
  * `<templates>` string ready to be passed to OWL's mount() options.
36
11
  *
37
- * If inlined templates are available (from build time), those are used directly.
38
- * Otherwise, falls back to runtime loading of individual XML files.
39
- *
40
- * @param {string[]} [files] - Array of URL-style XML paths (ignored if inlined templates exist)
12
+ * @param {string[]} files - Array of URL-style XML paths, e.g. ['/owl/components/Header/Header.xml']
41
13
  * @returns {Promise<string>}
42
14
  */
43
- export async function mergeTemplates(files = []) {
44
- // Try to get inlined templates first (production build)
45
- const inlined = await getInlinedTemplates()
46
- if (inlined) {
47
- return inlined
48
- }
49
-
50
- // Fallback: load templates at runtime (development or legacy)
51
- let templates = '<templates>'
52
- for (const file of files) {
53
- try {
54
- templates += await loadFile(file)
55
- } catch (e) {
56
- console.error(`[metaowl] Failed to load template: ${file}`, e)
57
- }
58
- }
59
- return templates + '</templates>'
60
- }
61
-
62
- /**
63
- * Check if inlined templates are available.
64
- * @returns {Promise<boolean>}
65
- */
66
- export async function hasInlinedTemplates() {
67
- const templates = await getInlinedTemplates()
68
- return templates !== null
15
+ export async function mergeTemplates(files) {
16
+ const results = await Promise.all(
17
+ files.map(async (file) => {
18
+ try {
19
+ return await loadFile(file)
20
+ } catch (e) {
21
+ console.error(`[metaowl] Failed to load template: ${file}`, e)
22
+ return ''
23
+ }
24
+ })
25
+ )
26
+ return '<templates>' + results.join('') + '</templates>'
69
27
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "metaowl",
3
- "version": "0.2.14",
3
+ "version": "0.2.16",
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, readFileSync, writeFileSync } from 'node:fs'
3
+ import { mkdirSync, copyFileSync, cpSync, existsSync } from 'node:fs'
4
4
  import { createRequire } from 'node:module'
5
5
  import { globSync } from 'glob'
6
6
  import { config as dotenvConfig } from 'dotenv'
@@ -219,36 +219,16 @@ export async function metaowlPlugin(options = {}) {
219
219
  closeBundle() {
220
220
  const projectRoot = process.cwd()
221
221
 
222
- // Collect and inline all XML templates into a single JS file
223
- // Use already collected XML arrays to avoid duplicate glob operations
224
- const xmlFiles = [
225
- ...layoutXml,
226
- ...pageXml,
227
- ...componentXml
228
- ]
229
-
230
- let templates = '<templates>'
231
- for (const file of xmlFiles) {
232
- try {
233
- templates += readFileSync(file, 'utf-8')
234
- } catch (e) {
235
- console.warn(`[metaowl] Failed to read template: ${file}`)
236
- }
222
+ // Copy OWL XML templates (loaded at runtime via fetch — not processed by Vite)
223
+ const xmlFiles = globSync([`${componentsDir}/**/*.xml`, `${pagesDir}/**/*.xml`, `${layoutsDir}/**/*.xml`])
224
+ for (const xmlFile of xmlFiles) {
225
+ const relPath = xmlFile.replace(new RegExp(`^${root}[\\/]`), '')
226
+ const dest = resolve(_outDirResolved, relPath)
227
+ mkdirSync(dirname(dest), { recursive: true })
228
+ copyFileSync(resolve(projectRoot, xmlFile), dest)
237
229
  }
238
- templates += '</templates>'
239
-
240
- // Escape for JavaScript string using JSON encoding for safety
241
- const escaped = JSON.stringify(templates).slice(1, -1)
242
-
243
- // Write templates.js to the output root (accessible as /templates.js)
244
- const templatesJs = `export const TEMPLATES = '${escaped}';\n`
245
- const templatesDir = _outDirResolved
246
- mkdirSync(templatesDir, { recursive: true })
247
- writeFileSync(resolve(templatesDir, 'templates.js'), templatesJs)
248
-
249
- console.log(`[metaowl] Inlined ${xmlFiles.length} XML templates into templates.js`)
250
230
 
251
- // Restore: Copy assets/images (referenced via absolute URLs in XML)
231
+ // Copy assets/images (referenced via absolute URLs in XML — not processed by Vite)
252
232
  const srcImages = resolve(projectRoot, root, 'assets', 'images')
253
233
  if (existsSync(srcImages)) {
254
234
  cpSync(srcImages, resolve(_outDirResolved, 'assets', 'images'), { recursive: true })