metaowl 0.1.0
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/CONTRIBUTING.md +49 -0
- package/LICENSE +147 -0
- package/README.md +543 -0
- package/bin/metaowl-build.js +12 -0
- package/bin/metaowl-create.js +270 -0
- package/bin/metaowl-dev.js +12 -0
- package/bin/metaowl-generate.js +176 -0
- package/bin/metaowl-lint.js +71 -0
- package/bin/utils.js +61 -0
- package/config/jsconfig.base.json +3 -0
- package/config/tsconfig.base.json +18 -0
- package/eslint.js +49 -0
- package/index.js +32 -0
- package/modules/app-mounter.js +40 -0
- package/modules/cache.js +57 -0
- package/modules/fetch.js +44 -0
- package/modules/file-router.js +60 -0
- package/modules/meta.js +119 -0
- package/modules/router.js +62 -0
- package/modules/templates-manager.js +20 -0
- package/package.json +68 -0
- package/postcss.cjs +43 -0
- package/test/cache.test.js +55 -0
- package/test/fetch.test.js +100 -0
- package/test/file-router.test.js +55 -0
- package/test/meta.test.js +146 -0
- package/test/router.test.js +77 -0
- package/test/templates-manager.test.js +62 -0
- package/vite/plugin.js +216 -0
- package/vitest.config.js +8 -0
package/README.md
ADDED
|
@@ -0,0 +1,543 @@
|
|
|
1
|
+
# metaowl
|
|
2
|
+
|
|
3
|
+
> A lightweight meta-framework for [Odoo OWL](https://github.com/odoo/owl), built on top of [Vite](https://vitejs.dev).
|
|
4
|
+
|
|
5
|
+
[](https://www.npmjs.com/package/metaowl)
|
|
6
|
+
[](LICENSE)
|
|
7
|
+
[](https://nodejs.org)
|
|
8
|
+
[](https://github.com/dennisschott/metaowl/issues)
|
|
9
|
+
|
|
10
|
+
metaowl gives you everything you need to ship production-ready OWL applications — file-based routing, app mounting, a fetch helper, `localStorage` cache, meta tag management, an SSG generator, and a batteries-included Vite plugin — so you can focus on building components instead of wiring infrastructure.
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## Table of Contents
|
|
15
|
+
|
|
16
|
+
- [Features](#features)
|
|
17
|
+
- [Requirements](#requirements)
|
|
18
|
+
- [Installation](#installation)
|
|
19
|
+
- [Create a New Project](#create-a-new-project)
|
|
20
|
+
- [Manual Setup](#manual-setup)
|
|
21
|
+
- [File-based Routing](#file-based-routing)
|
|
22
|
+
- [CLI Reference](#cli-reference)
|
|
23
|
+
- [API Reference](#api-reference)
|
|
24
|
+
- [boot](#bootroutes)
|
|
25
|
+
- [Fetch](#fetch)
|
|
26
|
+
- [Cache](#cache)
|
|
27
|
+
- [Meta](#meta)
|
|
28
|
+
- [configureOwl](#configureowlconfig)
|
|
29
|
+
- [buildRoutes](#buildroutesmodules)
|
|
30
|
+
- [Vite Plugin](#vite-plugin)
|
|
31
|
+
- [metaowlPlugin](#metaowlpluginoptions)
|
|
32
|
+
- [metaowlConfig](#metaowlconfigoptions)
|
|
33
|
+
- [ESLint Config](#eslint-config)
|
|
34
|
+
- [PostCSS Config](#postcss-config)
|
|
35
|
+
- [TypeScript / jsconfig](#typescript--jsconfig)
|
|
36
|
+
- [Contributing](#contributing)
|
|
37
|
+
- [License](#license)
|
|
38
|
+
|
|
39
|
+
---
|
|
40
|
+
|
|
41
|
+
## Features
|
|
42
|
+
|
|
43
|
+
- **File-based routing** — mirrors Nuxt/Next.js conventions out of the box
|
|
44
|
+
- **App mounting** — zero-config OWL component mounting with template merging
|
|
45
|
+
- **Fetch helper** — thin wrapper around the Fetch API with a configurable base URL and error handler
|
|
46
|
+
- **Cache** — async-style `localStorage` wrapper (`get`, `set`, `remove`, `clear`, `keys`)
|
|
47
|
+
- **Meta tags** — programmatic control over `<title>`, Open Graph, Twitter Card, canonical, and more
|
|
48
|
+
- **SSG generator** — statically pre-renders HTML pages with correct meta tags at build time
|
|
49
|
+
- **Vite plugin** — handles `COMPONENTS` injection, XML template copying, CSS auto-import, chunk splitting, and env filtering
|
|
50
|
+
- **ESLint & PostCSS** — shareable configs included; no extra dev-dependencies needed in your project
|
|
51
|
+
|
|
52
|
+
---
|
|
53
|
+
|
|
54
|
+
## Requirements
|
|
55
|
+
|
|
56
|
+
| Dependency | Version |
|
|
57
|
+
|---|---|
|
|
58
|
+
| Node.js | `>=18` |
|
|
59
|
+
| `@odoo/owl` | bundled |
|
|
60
|
+
|
|
61
|
+
---
|
|
62
|
+
|
|
63
|
+
## Installation
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
npm install metaowl
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
`@odoo/owl` is bundled with metaowl and resolved automatically — no separate installation required.
|
|
70
|
+
|
|
71
|
+
---
|
|
72
|
+
|
|
73
|
+
## Create a New Project
|
|
74
|
+
|
|
75
|
+
The fastest way to get started is the `metaowl-create` scaffolder:
|
|
76
|
+
|
|
77
|
+
```bash
|
|
78
|
+
npx metaowl-create my-app
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
Or install metaowl globally and run it interactively:
|
|
82
|
+
|
|
83
|
+
```bash
|
|
84
|
+
npm install -g metaowl
|
|
85
|
+
metaowl-create
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
This generates a ready-to-run project:
|
|
89
|
+
|
|
90
|
+
```
|
|
91
|
+
my-app/
|
|
92
|
+
├── package.json
|
|
93
|
+
├── vite.config.js
|
|
94
|
+
├── eslint.config.js
|
|
95
|
+
├── postcss.config.cjs
|
|
96
|
+
├── jsconfig.json
|
|
97
|
+
├── .gitignore
|
|
98
|
+
└── src/
|
|
99
|
+
├── index.html
|
|
100
|
+
├── metaowl.js
|
|
101
|
+
├── css.js
|
|
102
|
+
├── components/
|
|
103
|
+
│ ├── AppHeader/
|
|
104
|
+
│ │ ├── AppHeader.js
|
|
105
|
+
│ │ ├── AppHeader.xml
|
|
106
|
+
│ │ └── AppHeader.css
|
|
107
|
+
│ └── AppFooter/
|
|
108
|
+
│ ├── AppFooter.js
|
|
109
|
+
│ ├── AppFooter.xml
|
|
110
|
+
│ └── AppFooter.css
|
|
111
|
+
└── pages/
|
|
112
|
+
└── index/
|
|
113
|
+
├── Index.js
|
|
114
|
+
├── Index.xml
|
|
115
|
+
└── index.css
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
Then:
|
|
119
|
+
|
|
120
|
+
```bash
|
|
121
|
+
cd my-app
|
|
122
|
+
npm install
|
|
123
|
+
npm run dev
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
---
|
|
127
|
+
|
|
128
|
+
## Manual Setup
|
|
129
|
+
|
|
130
|
+
### 1. `vite.config.js`
|
|
131
|
+
|
|
132
|
+
Use the convenience wrapper for a sensible default configuration:
|
|
133
|
+
|
|
134
|
+
```js
|
|
135
|
+
import { metaowlConfig } from 'metaowl/vite'
|
|
136
|
+
|
|
137
|
+
export default metaowlConfig({
|
|
138
|
+
componentsDir: 'src/owl/components',
|
|
139
|
+
pagesDir: 'src/owl/pages',
|
|
140
|
+
server: { port: 3000 },
|
|
141
|
+
preview: { port: 4173 }
|
|
142
|
+
})
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
Or compose the plugin into your own config:
|
|
146
|
+
|
|
147
|
+
```js
|
|
148
|
+
import { defineConfig } from 'vite'
|
|
149
|
+
import { metaowlPlugin } from 'metaowl/vite'
|
|
150
|
+
|
|
151
|
+
export default defineConfig({
|
|
152
|
+
plugins: [
|
|
153
|
+
metaowlPlugin({
|
|
154
|
+
componentsDir: 'src/owl/components',
|
|
155
|
+
pagesDir: 'src/owl/pages'
|
|
156
|
+
})
|
|
157
|
+
]
|
|
158
|
+
})
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
### 2. `src/metaowl.js`
|
|
162
|
+
|
|
163
|
+
```js
|
|
164
|
+
import { boot, Fetch } from 'metaowl'
|
|
165
|
+
|
|
166
|
+
Fetch.configure({
|
|
167
|
+
baseUrl: import.meta.env.VITE_API_URL ?? ''
|
|
168
|
+
})
|
|
169
|
+
|
|
170
|
+
// File-based routing — boot() with no args is the recommended convention.
|
|
171
|
+
// The metaowl Vite plugin expands it to import.meta.glob at build time.
|
|
172
|
+
boot()
|
|
173
|
+
|
|
174
|
+
// — or — manual route table
|
|
175
|
+
// import routes from './routes.js'
|
|
176
|
+
// boot(routes)
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
### 3. `src/index.html`
|
|
180
|
+
|
|
181
|
+
```html
|
|
182
|
+
<!doctype html>
|
|
183
|
+
<html lang="en">
|
|
184
|
+
<head>
|
|
185
|
+
<meta charset="UTF-8" />
|
|
186
|
+
<title>My App</title>
|
|
187
|
+
</head>
|
|
188
|
+
<body>
|
|
189
|
+
<div id="metaowl"></div>
|
|
190
|
+
<script type="module" src="/metaowl.js"></script>
|
|
191
|
+
</body>
|
|
192
|
+
</html>
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
---
|
|
196
|
+
|
|
197
|
+
## File-based Routing
|
|
198
|
+
|
|
199
|
+
Pages placed in `pagesDir` are automatically mapped to URL paths using the same conventions as Nuxt and Next.js:
|
|
200
|
+
|
|
201
|
+
| File | URL |
|
|
202
|
+
|---|---|
|
|
203
|
+
| `pages/index/Index.js` | `/` |
|
|
204
|
+
| `pages/about/About.js` | `/about` |
|
|
205
|
+
| `pages/blog/post/Post.js` | `/blog/post` |
|
|
206
|
+
|
|
207
|
+
**Rules:**
|
|
208
|
+
- The *directory* path relative to `pages/` becomes the URL segment.
|
|
209
|
+
- A top-level directory named `index` maps to `/`.
|
|
210
|
+
- The component must be the `default` export, or the first function export in the module.
|
|
211
|
+
|
|
212
|
+
Enable file-based routing by passing `import.meta.glob` to `boot()`:
|
|
213
|
+
|
|
214
|
+
```js
|
|
215
|
+
boot(import.meta.glob('./pages/**/*.js', { eager: true }))
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
SSG path variants (`.html`, trailing slash, `index.html`) are added automatically so your builds work with any static host.
|
|
219
|
+
|
|
220
|
+
---
|
|
221
|
+
|
|
222
|
+
## CLI Reference
|
|
223
|
+
|
|
224
|
+
metaowl ships four CLI commands that use its own bundled Vite, Prettier, and ESLint binaries — no need to install them separately in your project.
|
|
225
|
+
|
|
226
|
+
| Command | Description |
|
|
227
|
+
|---|---|
|
|
228
|
+
| `metaowl-create` | Scaffold a new project interactively |
|
|
229
|
+
| `metaowl-dev` | Start the Vite development server |
|
|
230
|
+
| `metaowl-build` | Lint then production build (Rollup via Vite) |
|
|
231
|
+
| `metaowl-generate` | Lint, build, then SSG — pre-renders every page to static HTML |
|
|
232
|
+
| `metaowl-lint` | Run Prettier + ESLint across project source files |
|
|
233
|
+
|
|
234
|
+
Add them to your `package.json` scripts:
|
|
235
|
+
|
|
236
|
+
```json
|
|
237
|
+
{
|
|
238
|
+
"scripts": {
|
|
239
|
+
"dev": "metaowl-dev",
|
|
240
|
+
"build": "metaowl-build",
|
|
241
|
+
"generate": "metaowl-generate",
|
|
242
|
+
"lint": "metaowl-lint"
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
### Configuring lint targets
|
|
248
|
+
|
|
249
|
+
By default, `metaowl-lint` targets `src/metaowl.js`, `src/css.js`, `src/owl/pages/**`, and `src/owl/components/**`. Override in `package.json`:
|
|
250
|
+
|
|
251
|
+
```json
|
|
252
|
+
{
|
|
253
|
+
"metaowl": {
|
|
254
|
+
"lint": ["src/metaowl.js", "src/pages/**", "src/components/**"]
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
### Configuring SSG output
|
|
260
|
+
|
|
261
|
+
`metaowl-generate` reads `pagesDir` and `outDir` from `package.json`:
|
|
262
|
+
|
|
263
|
+
```json
|
|
264
|
+
{
|
|
265
|
+
"metaowl": {
|
|
266
|
+
"pagesDir": "src/pages",
|
|
267
|
+
"outDir": "dist"
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
---
|
|
273
|
+
|
|
274
|
+
## API Reference
|
|
275
|
+
|
|
276
|
+
### `boot(routes)`
|
|
277
|
+
|
|
278
|
+
Resolves the current URL against a route table and mounts the matching OWL component into `#app`.
|
|
279
|
+
|
|
280
|
+
```ts
|
|
281
|
+
boot(routesOrModules: Record<string, object> | RouteDefinition[]): Promise<void>
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
Accepts either:
|
|
285
|
+
- An `import.meta.glob` result (file-based routing, recommended)
|
|
286
|
+
- A manual array of route objects: `{ name, path: string[], component }`
|
|
287
|
+
|
|
288
|
+
---
|
|
289
|
+
|
|
290
|
+
### `Fetch`
|
|
291
|
+
|
|
292
|
+
A static class wrapping the Fetch API with a shared base URL and error handler.
|
|
293
|
+
|
|
294
|
+
#### `Fetch.configure(options)`
|
|
295
|
+
|
|
296
|
+
Call once before `boot()`.
|
|
297
|
+
|
|
298
|
+
```ts
|
|
299
|
+
Fetch.configure({
|
|
300
|
+
baseUrl?: string, // Prepended to every internal request
|
|
301
|
+
onError?: Function // Invoked on network errors
|
|
302
|
+
})
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
#### `Fetch.url(url, method?, data?, internal?, triggerErrorHandler?)`
|
|
306
|
+
|
|
307
|
+
```ts
|
|
308
|
+
Fetch.url(
|
|
309
|
+
url: string,
|
|
310
|
+
method: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' = 'GET',
|
|
311
|
+
data: object | null = null,
|
|
312
|
+
internal: boolean = true,
|
|
313
|
+
triggerErrorHandler: boolean = true
|
|
314
|
+
): Promise<any | null>
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
When `internal` is `true` (default), `baseUrl` is prepended to `url`. Returns the parsed JSON response, or `null` on error.
|
|
318
|
+
|
|
319
|
+
---
|
|
320
|
+
|
|
321
|
+
### `Cache`
|
|
322
|
+
|
|
323
|
+
A static async-style `localStorage` wrapper. Values are automatically JSON-serialised.
|
|
324
|
+
|
|
325
|
+
```ts
|
|
326
|
+
Cache.get(key: string): Promise<any>
|
|
327
|
+
Cache.set(key: string, value: any): Promise<void>
|
|
328
|
+
Cache.remove(key: string): Promise<void>
|
|
329
|
+
Cache.clear(): Promise<void>
|
|
330
|
+
Cache.keys(): Promise<string[]>
|
|
331
|
+
```
|
|
332
|
+
|
|
333
|
+
---
|
|
334
|
+
|
|
335
|
+
### `Meta`
|
|
336
|
+
|
|
337
|
+
Programmatically set document meta tags. Each function is idempotent — the tag is created if it does not already exist.
|
|
338
|
+
|
|
339
|
+
```ts
|
|
340
|
+
import { Meta } from 'metaowl'
|
|
341
|
+
|
|
342
|
+
Meta.title('My Page')
|
|
343
|
+
Meta.description('Page description')
|
|
344
|
+
Meta.keywords('owl, odoo, framework')
|
|
345
|
+
Meta.author('Jane Doe')
|
|
346
|
+
Meta.canonical('https://example.com/page')
|
|
347
|
+
|
|
348
|
+
// Open Graph
|
|
349
|
+
Meta.ogTitle('My Page')
|
|
350
|
+
Meta.ogDescription('Page description')
|
|
351
|
+
Meta.ogImage('https://example.com/og.png')
|
|
352
|
+
Meta.ogUrl('https://example.com/page')
|
|
353
|
+
|
|
354
|
+
// Twitter Card
|
|
355
|
+
Meta.twitterCard('summary_large_image')
|
|
356
|
+
Meta.twitterTitle('My Page')
|
|
357
|
+
Meta.twitterDescription('Page description')
|
|
358
|
+
Meta.twitterImage('https://example.com/og.png')
|
|
359
|
+
```
|
|
360
|
+
|
|
361
|
+
The full list of helpers: `title`, `description`, `keywords`, `author`, `canonical`, `ogTitle`, `ogDescription`, `ogImage`, `ogUrl`, `ogLocale`, `ogImageWidth`, `ogImageHeight`, `twitterCard`, `twitterSite`, `twitterCreator`, `twitterTitle`, `twitterDescription`, `twitterImage`, `twitterImageAlt`, `twitterUrl`, `twitterSiteId`, `twitterCreatorId`.
|
|
362
|
+
|
|
363
|
+
---
|
|
364
|
+
|
|
365
|
+
### `configureOwl(config)`
|
|
366
|
+
|
|
367
|
+
Override the default OWL `mount()` options before calling `boot()`.
|
|
368
|
+
|
|
369
|
+
```ts
|
|
370
|
+
configureOwl(config: Partial<OwlMountConfig>): void
|
|
371
|
+
```
|
|
372
|
+
|
|
373
|
+
**Defaults:**
|
|
374
|
+
|
|
375
|
+
```js
|
|
376
|
+
{
|
|
377
|
+
warnIfNoStaticProps: true,
|
|
378
|
+
willStartTimeout: 10000,
|
|
379
|
+
translatableAttributes: ['title', 'placeholder', 'label', 'alt']
|
|
380
|
+
}
|
|
381
|
+
```
|
|
382
|
+
|
|
383
|
+
---
|
|
384
|
+
|
|
385
|
+
### `buildRoutes(modules)`
|
|
386
|
+
|
|
387
|
+
Converts an `import.meta.glob` result into a metaowl route table. Called automatically by `boot()` when a glob result is passed.
|
|
388
|
+
|
|
389
|
+
```ts
|
|
390
|
+
buildRoutes(modules: Record<string, object>): RouteDefinition[]
|
|
391
|
+
```
|
|
392
|
+
|
|
393
|
+
---
|
|
394
|
+
|
|
395
|
+
## Vite Plugin
|
|
396
|
+
|
|
397
|
+
### `metaowlPlugin(options)`
|
|
398
|
+
|
|
399
|
+
Returns an array of Vite plugins that configure the full metaowl build pipeline.
|
|
400
|
+
|
|
401
|
+
| Option | Default | Description |
|
|
402
|
+
|---|---|---|
|
|
403
|
+
| `root` | `'src'` | Vite root directory |
|
|
404
|
+
| `outDir` | `'../dist'` | Build output directory |
|
|
405
|
+
| `publicDir` | `'../public'` | Public assets directory |
|
|
406
|
+
| `componentsDir` | `'src/components'` | OWL components directory (glob base) |
|
|
407
|
+
| `pagesDir` | `'src/pages'` | OWL pages directory (glob base) |
|
|
408
|
+
| `vendorPackages` | `['@odoo/owl']` | npm packages bundled into the `vendor` chunk |
|
|
409
|
+
| `frameworkEntry` | `'./node_modules/metaowl/index.js'` | Entry for the `framework` chunk |
|
|
410
|
+
| `restartGlobs` | `[]` | Additional globs that trigger dev-server restart |
|
|
411
|
+
| `envPrefix` | `undefined` | Only expose `process.env` vars with this prefix (plus `NODE_ENV`) |
|
|
412
|
+
|
|
413
|
+
**What the plugin does:**
|
|
414
|
+
|
|
415
|
+
- Injects `COMPONENTS` (array of XML template paths) and `DEV_MODE` as global defines
|
|
416
|
+
- Filters `process.env` to prevent accidental secret leakage
|
|
417
|
+
- Copies OWL XML templates and `assets/images` to the output directory after build
|
|
418
|
+
- Auto-imports CSS/SCSS files from `componentsDir` and `pagesDir`
|
|
419
|
+
- Configures Rollup chunk splitting (`vendor` + `framework`)
|
|
420
|
+
- Resolves `@odoo/owl` to the bundled ES module
|
|
421
|
+
- Enables TypeScript path aliases via `vite-tsconfig-paths`
|
|
422
|
+
|
|
423
|
+
---
|
|
424
|
+
|
|
425
|
+
### `metaowlConfig(options)`
|
|
426
|
+
|
|
427
|
+
A convenience wrapper that returns a complete `vite.UserConfig` with sensible defaults.
|
|
428
|
+
|
|
429
|
+
```js
|
|
430
|
+
import { metaowlConfig } from 'metaowl/vite'
|
|
431
|
+
|
|
432
|
+
export default metaowlConfig({
|
|
433
|
+
componentsDir: 'src/owl/components',
|
|
434
|
+
pagesDir: 'src/owl/pages',
|
|
435
|
+
vendorPackages: ['@odoo/owl', 'apexcharts'],
|
|
436
|
+
envPrefix: 'APP_',
|
|
437
|
+
server: { port: 3333 },
|
|
438
|
+
preview: { port: 8080 }
|
|
439
|
+
})
|
|
440
|
+
```
|
|
441
|
+
|
|
442
|
+
`server`, `preview`, and `build` are applied directly to the Vite config; all other options are forwarded to `metaowlPlugin`.
|
|
443
|
+
|
|
444
|
+
---
|
|
445
|
+
|
|
446
|
+
## ESLint Config
|
|
447
|
+
|
|
448
|
+
metaowl ships a ready-to-use flat ESLint config. No additional ESLint packages are needed in your project.
|
|
449
|
+
|
|
450
|
+
```js
|
|
451
|
+
// eslint.config.js
|
|
452
|
+
import { eslintConfig } from 'metaowl/eslint'
|
|
453
|
+
export default eslintConfig
|
|
454
|
+
```
|
|
455
|
+
|
|
456
|
+
Extend or override rules:
|
|
457
|
+
|
|
458
|
+
```js
|
|
459
|
+
import { eslintConfig } from 'metaowl/eslint'
|
|
460
|
+
|
|
461
|
+
export default [
|
|
462
|
+
...eslintConfig,
|
|
463
|
+
{
|
|
464
|
+
rules: {
|
|
465
|
+
'no-console': 'warn'
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
]
|
|
469
|
+
```
|
|
470
|
+
|
|
471
|
+
---
|
|
472
|
+
|
|
473
|
+
## PostCSS Config
|
|
474
|
+
|
|
475
|
+
metaowl ships a PostCSS config factory that enables [PurgeCSS](https://purgecss.com) in production builds to eliminate unused styles.
|
|
476
|
+
|
|
477
|
+
```js
|
|
478
|
+
// postcss.config.cjs
|
|
479
|
+
const { createPostcssConfig } = require('metaowl/postcss')
|
|
480
|
+
module.exports = createPostcssConfig()
|
|
481
|
+
```
|
|
482
|
+
|
|
483
|
+
Extend with a custom safelist or additional content globs:
|
|
484
|
+
|
|
485
|
+
```js
|
|
486
|
+
module.exports = createPostcssConfig({
|
|
487
|
+
safelist: [/^my-custom-/, 'another-class'],
|
|
488
|
+
content: ['./templates/**/*.html']
|
|
489
|
+
})
|
|
490
|
+
```
|
|
491
|
+
|
|
492
|
+
PurgeCSS scans `.xml`, `.html`, and `src/**/*.js` files by default.
|
|
493
|
+
|
|
494
|
+
---
|
|
495
|
+
|
|
496
|
+
## TypeScript / jsconfig
|
|
497
|
+
|
|
498
|
+
Extend from the included base configs to get sensible defaults:
|
|
499
|
+
|
|
500
|
+
**`jsconfig.json`** (JavaScript projects):
|
|
501
|
+
|
|
502
|
+
```json
|
|
503
|
+
{
|
|
504
|
+
"extends": "./node_modules/metaowl/config/jsconfig.base.json",
|
|
505
|
+
"compilerOptions": {
|
|
506
|
+
"baseUrl": "src",
|
|
507
|
+
"paths": {
|
|
508
|
+
"@pages/*": ["owl/pages/*"],
|
|
509
|
+
"@components/*": ["owl/components/*"]
|
|
510
|
+
}
|
|
511
|
+
},
|
|
512
|
+
"include": ["src"]
|
|
513
|
+
}
|
|
514
|
+
```
|
|
515
|
+
|
|
516
|
+
**`tsconfig.json`** (TypeScript projects):
|
|
517
|
+
|
|
518
|
+
```json
|
|
519
|
+
{
|
|
520
|
+
"extends": "./node_modules/metaowl/config/tsconfig.base.json",
|
|
521
|
+
"compilerOptions": {
|
|
522
|
+
"baseUrl": "src"
|
|
523
|
+
},
|
|
524
|
+
"include": ["src"]
|
|
525
|
+
}
|
|
526
|
+
```
|
|
527
|
+
|
|
528
|
+
---
|
|
529
|
+
|
|
530
|
+
## Contributing
|
|
531
|
+
|
|
532
|
+
Contributions are welcome! Please open an issue before submitting a pull request so we can discuss the change.
|
|
533
|
+
|
|
534
|
+
1. Fork the repository
|
|
535
|
+
2. Create a feature branch: `git checkout -b feat/my-feature`
|
|
536
|
+
3. Commit your changes following [Conventional Commits](https://www.conventionalcommits.org)
|
|
537
|
+
4. Open a pull request
|
|
538
|
+
|
|
539
|
+
---
|
|
540
|
+
|
|
541
|
+
## License
|
|
542
|
+
|
|
543
|
+
[LGPL v3](LICENSE) © [Dennis Schott](https://github.com/dennisschott)
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* metaowl build — lint then production build.
|
|
4
|
+
*/
|
|
5
|
+
import { banner, bin, cwd, metaowlRoot, run, success } from './utils.js'
|
|
6
|
+
|
|
7
|
+
banner('build')
|
|
8
|
+
run('Linting', `node "${metaowlRoot}/bin/metaowl-lint.js"`)
|
|
9
|
+
run('Building', `"${bin}/vite" build`)
|
|
10
|
+
success('Build complete')
|
|
11
|
+
console.log()
|
|
12
|
+
|