zero-query 0.9.8 → 1.0.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/README.md +55 -31
- package/cli/args.js +1 -1
- package/cli/commands/build.js +2 -2
- package/cli/commands/bundle.js +15 -15
- package/cli/commands/create.js +41 -7
- package/cli/commands/dev/devtools/index.js +1 -1
- package/cli/commands/dev/devtools/js/core.js +14 -14
- package/cli/commands/dev/devtools/js/elements.js +4 -4
- package/cli/commands/dev/devtools/js/stats.js +1 -1
- package/cli/commands/dev/devtools/styles.css +2 -2
- package/cli/commands/dev/index.js +2 -2
- package/cli/commands/dev/logger.js +1 -1
- package/cli/commands/dev/overlay.js +21 -14
- package/cli/commands/dev/server.js +5 -5
- package/cli/commands/dev/validator.js +7 -7
- package/cli/commands/dev/watcher.js +6 -6
- package/cli/help.js +4 -2
- package/cli/index.js +2 -2
- package/cli/scaffold/default/app/app.js +17 -18
- package/cli/scaffold/default/app/components/about.js +9 -9
- package/cli/scaffold/default/app/components/api-demo.js +6 -6
- package/cli/scaffold/default/app/components/contact-card.js +4 -4
- package/cli/scaffold/default/app/components/contacts/contacts.css +2 -2
- package/cli/scaffold/default/app/components/contacts/contacts.html +3 -3
- package/cli/scaffold/default/app/components/contacts/contacts.js +11 -11
- package/cli/scaffold/default/app/components/counter.js +8 -8
- package/cli/scaffold/default/app/components/home.js +13 -13
- package/cli/scaffold/default/app/components/not-found.js +1 -1
- package/cli/scaffold/default/app/components/playground/playground.css +1 -1
- package/cli/scaffold/default/app/components/playground/playground.html +11 -11
- package/cli/scaffold/default/app/components/playground/playground.js +11 -11
- package/cli/scaffold/default/app/components/todos.js +8 -8
- package/cli/scaffold/default/app/components/toolkit/toolkit.css +1 -1
- package/cli/scaffold/default/app/components/toolkit/toolkit.html +4 -4
- package/cli/scaffold/default/app/components/toolkit/toolkit.js +7 -7
- package/cli/scaffold/default/app/routes.js +1 -1
- package/cli/scaffold/default/app/store.js +1 -1
- package/cli/scaffold/default/global.css +2 -2
- package/cli/scaffold/default/index.html +2 -2
- package/cli/scaffold/minimal/app/app.js +6 -7
- package/cli/scaffold/minimal/app/components/about.js +5 -5
- package/cli/scaffold/minimal/app/components/counter.js +6 -6
- package/cli/scaffold/minimal/app/components/home.js +8 -8
- package/cli/scaffold/minimal/app/components/not-found.js +1 -1
- package/cli/scaffold/minimal/app/routes.js +1 -1
- package/cli/scaffold/minimal/app/store.js +1 -1
- package/cli/scaffold/minimal/global.css +2 -2
- package/cli/scaffold/minimal/index.html +1 -1
- package/cli/scaffold/ssr/app/app.js +29 -0
- package/cli/scaffold/ssr/app/components/about.js +28 -0
- package/cli/scaffold/ssr/app/components/home.js +37 -0
- package/cli/scaffold/ssr/app/components/not-found.js +15 -0
- package/cli/scaffold/ssr/app/routes.js +6 -0
- package/cli/scaffold/ssr/global.css +113 -0
- package/cli/scaffold/ssr/index.html +31 -0
- package/cli/scaffold/ssr/package.json +8 -0
- package/cli/scaffold/ssr/server/index.js +118 -0
- package/cli/utils.js +6 -6
- package/dist/zquery.dist.zip +0 -0
- package/dist/zquery.js +565 -228
- package/dist/zquery.min.js +2 -2
- package/index.d.ts +25 -12
- package/index.js +11 -7
- package/package.json +9 -3
- package/src/component.js +64 -63
- package/src/core.js +15 -15
- package/src/diff.js +38 -38
- package/src/errors.js +72 -18
- package/src/expression.js +15 -17
- package/src/http.js +4 -4
- package/src/package.json +1 -0
- package/src/reactive.js +75 -9
- package/src/router.js +104 -24
- package/src/ssr.js +133 -39
- package/src/store.js +103 -21
- package/src/utils.js +64 -12
- package/tests/audit.test.js +143 -15
- package/tests/cli.test.js +20 -20
- package/tests/component.test.js +121 -121
- package/tests/core.test.js +56 -56
- package/tests/diff.test.js +42 -42
- package/tests/errors.test.js +425 -147
- package/tests/expression.test.js +58 -53
- package/tests/http.test.js +20 -20
- package/tests/reactive.test.js +185 -24
- package/tests/router.test.js +501 -74
- package/tests/ssr.test.js +444 -10
- package/tests/store.test.js +264 -23
- package/tests/utils.test.js +163 -26
- package/types/collection.d.ts +2 -2
- package/types/component.d.ts +5 -5
- package/types/errors.d.ts +36 -4
- package/types/http.d.ts +3 -3
- package/types/misc.d.ts +9 -9
- package/types/reactive.d.ts +25 -3
- package/types/router.d.ts +10 -6
- package/types/ssr.d.ts +22 -2
- package/types/store.d.ts +40 -5
- package/types/utils.d.ts +1 -1
package/README.md
CHANGED
|
@@ -15,21 +15,23 @@
|
|
|
15
15
|
|
|
16
16
|
</p>
|
|
17
17
|
|
|
18
|
-
> **Lightweight, zero-dependency frontend library that combines jQuery-style DOM manipulation with a modern reactive component system, SPA router, global state management, HTTP client, and utility toolkit
|
|
18
|
+
> **Lightweight, zero-dependency frontend library that combines jQuery-style DOM manipulation with a modern reactive component system, SPA router, global state management, HTTP client, and utility toolkit - all in a single ~91 KB minified browser bundle. Works out of the box with ES modules. An optional CLI bundler is available for single-file production builds.**
|
|
19
19
|
|
|
20
20
|
## Features
|
|
21
21
|
|
|
22
22
|
| Module | Highlights |
|
|
23
23
|
| --- | --- |
|
|
24
|
-
| **Components** | Reactive state, template literals, `@event` delegation (22 modifiers
|
|
25
|
-
| **Router** | History & hash mode, route params (`:id`), wildcards, guards (`beforeEach`/`afterEach`), lazy loading, `z-link` navigation
|
|
26
|
-
| **Directives** | `z-if`, `z-for`, `z-model`, `z-show`, `z-bind`, `z-class`, `z-style`, `z-text`, `z-html`, `z-ref`, `z-cloak`, `z-pre`, `z-key`, `z-skip` — 17 built-in template directives |
|
|
27
|
-
| **Reactive** | Deep proxy reactivity, Signals (`.value`, `.peek()`), computed values, effects (auto-tracked with dispose) |
|
|
28
|
-
| **Store** | Reactive global state, named actions, computed getters, middleware, subscriptions, action history, snapshots |
|
|
24
|
+
| **Components** | Reactive state, template literals, `@event` delegation (22 modifiers - key filters, system keys, `.outside`, timing, and more), `z-model` two-way binding (with `z-trim`, `z-number`, `z-lazy`, `z-debounce`, `z-uppercase`, `z-lowercase`), computed properties, watch callbacks, slot-based content projection, directives (`z-if`/`z-else-if`/`z-else`, `z-for`, `z-show`, `z-bind`/`:attr`, `z-class`, `z-style`, `z-text`, `z-html`, `z-ref`, `z-cloak`, `z-pre`, `z-key`, `z-skip`), DOM morphing engine with LIS-based keyed reconciliation (no innerHTML rebuild), CSP-safe expression evaluation with AST caching, scoped styles, external templates (`templateUrl` / `styleUrl`), lifecycle hooks, auto-injected base styles |
|
|
25
|
+
| **Router** | History & hash mode, route params (`:id`), wildcards, guards (`beforeEach`/`afterEach`), lazy loading, `z-link` navigation with `z-link-params`, `z-to-top` scroll modifier (`instant`/`smooth`), `z-active-route` active-link class directive, `<z-outlet>` declarative mount point, sub-route history substates (`pushSubstate`/`onSubstate`) |
|
|
26
|
+
| **Directives** | `z-if`, `z-else-if`, `z-else`, `z-for`, `z-model`, `z-show`, `z-bind`/`:attr`, `z-class`, `z-style`, `z-text`, `z-html`, `z-ref`, `z-cloak`, `z-pre`, `z-key`, `z-skip`, `@event`/`z-on` — 17 built-in template directives |
|
|
27
|
+
| **Reactive** | Deep proxy reactivity, Signals (`.value`, `.peek()`), computed values, effects (auto-tracked with dispose), `batch()` for deferred notifications, `untracked()` for dependency-free reads |
|
|
28
|
+
| **Store** | Reactive global state, named actions, computed getters, middleware, subscriptions, `batch()` grouped mutations, `checkpoint()`/`undo()`/`redo()` with configurable stack, action history, snapshots |
|
|
29
29
|
| **Selectors & DOM** | jQuery-like chainable selectors, traversal, DOM manipulation, events, animation |
|
|
30
30
|
| **HTTP** | Fetch wrapper with auto-JSON, interceptors (with unsubscribe & clear), HEAD requests, parallel requests (`http.all`), config inspection (`getConfig`), timeout/abort, base URL |
|
|
31
|
-
| **Utils** | debounce, throttle, pipe, once, sleep, memoize, escapeHtml, stripHtml, uuid, capitalize, truncate, range, chunk, groupBy, unique, pick, omit, getPath/setPath, isEmpty, clamp, retry, timeout, deepClone, deepMerge, storage/session wrappers, event bus |
|
|
31
|
+
| **Utils** | debounce, throttle, pipe, once, sleep, memoize (LRU), escapeHtml, stripHtml, uuid, capitalize, truncate, range, chunk, groupBy, unique, pick, omit, getPath/setPath, isEmpty, clamp, retry, timeout, deepClone (enhanced fallback), deepMerge (prototype-pollution safe), storage/session wrappers, event bus |
|
|
32
|
+
| **Security** | XSS-safe template expressions (`{{}}` auto-escaping), sandboxed expression evaluator (blocks `window`, `Function`, `eval`, `RegExp`, `Error`, prototype chains), prototype pollution prevention in `deepMerge`/`setPath`, `z-link` protocol validation, SSR error sanitization |
|
|
32
33
|
| **Dev Tools** | CLI dev server with live-reload, CSS hot-swap, full-screen error overlay, floating toolbar, dark-themed inspector panel (Router view, DOM tree, network log, component viewer, performance dashboard), fetch interceptor, render instrumentation, CLI bundler for single-file production builds |
|
|
34
|
+
| **SSR** | Server-side rendering to HTML strings in Node.js - `createSSRApp()`, `renderToString()`, `renderPage()` with SEO/Open Graph support, `renderBatch()` for parallel rendering, fragment mode, hydration markers, graceful error handling, `escapeHtml()` utility |
|
|
33
35
|
|
|
34
36
|
---
|
|
35
37
|
|
|
@@ -37,7 +39,7 @@
|
|
|
37
39
|
|
|
38
40
|
### Recommended: CLI Dev Server
|
|
39
41
|
|
|
40
|
-
The fastest way to develop with zQuery is via the built-in **CLI dev server** with **live-reload**. It serves your ES modules as-is and automatically resolves the library
|
|
42
|
+
The fastest way to develop with zQuery is via the built-in **CLI dev server** with **live-reload**. It serves your ES modules as-is and automatically resolves the library - no manual downloads required.
|
|
41
43
|
|
|
42
44
|
```bash
|
|
43
45
|
# Install (per-project or globally)
|
|
@@ -53,29 +55,29 @@ npx zquery dev my-app
|
|
|
53
55
|
|
|
54
56
|
> **Tip:** Stay in the project root (where `node_modules` lives) instead of `cd`-ing into `my-app`. This keeps `index.d.ts` accessible to your IDE for full type/intellisense support.
|
|
55
57
|
|
|
56
|
-
The `create` command generates a ready-to-run project with a sidebar layout, router, multiple components (including folder components with external templates and styles), and responsive styles. Use `--minimal` (or `-m`) to scaffold a lightweight 3-page starter instead. The dev server watches for file changes, hot-swaps CSS in-place, full-reloads on other changes, and handles SPA fallback routing.
|
|
58
|
+
The `create` command generates a ready-to-run project with a sidebar layout, router, multiple components (including folder components with external templates and styles), and responsive styles. Use `--minimal` (or `-m`) to scaffold a lightweight 3-page starter instead. Use `--ssr` (or `-s`) to scaffold a project with a Node.js server-side rendering example. The dev server watches for file changes, hot-swaps CSS in-place, full-reloads on other changes, and handles SPA fallback routing.
|
|
57
59
|
|
|
58
60
|
#### Error Overlay
|
|
59
61
|
|
|
60
|
-
The dev server includes a **full-screen error overlay** that surfaces errors directly in the browser
|
|
62
|
+
The dev server includes a **full-screen error overlay** that surfaces errors directly in the browser - similar to Vite or Angular:
|
|
61
63
|
|
|
62
|
-
- **Syntax errors**
|
|
63
|
-
- **Runtime errors**
|
|
64
|
+
- **Syntax errors** - JS files are validated on every save *before* the reload is triggered. If a syntax error is found the page stays intact and a dark overlay appears with the error message, file path, line:column, and a code frame pointing to the exact location.
|
|
65
|
+
- **Runtime errors** - uncaught exceptions and unhandled promise rejections are captured and displayed in the same overlay with a cleaned-up stack trace.
|
|
64
66
|
- The overlay **auto-clears** when you fix the error and save. Press `Esc` or click `×` to dismiss manually.
|
|
65
67
|
|
|
66
68
|
#### Floating Toolbar & Inspector
|
|
67
69
|
|
|
68
|
-
A compact expandable toolbar appears in the bottom-right corner. In its **collapsed** state it shows live render and request counters. Click the chevron to **expand** and reveal the route indicator (color-coded by the last navigation event
|
|
70
|
+
A compact expandable toolbar appears in the bottom-right corner. In its **collapsed** state it shows live render and request counters. Click the chevron to **expand** and reveal the route indicator (color-coded by the last navigation event - navigate, pop, replace, hashchange, substate), registered component count, and DOM element count. Click any stat to open a **dark-themed DevTools inspector** as a popup - or visit `http://localhost:<port>/_devtools` for a standalone split-view panel with five tabs: **Router** (live route state, guards, history timeline), **Components** (live state cards), **Performance** (render timeline with timing metrics), **Network** (fetch log with JSON viewer), and **Elements** (live DOM tree with component badges, source viewer, expand/collapse).
|
|
69
71
|
|
|
70
72
|
### Alternative: Manual Setup (No npm)
|
|
71
73
|
|
|
72
|
-
If you prefer **zero tooling**, download `dist/zquery.min.js` from the [dist/ folder](https://github.com/tonywied17/zero-query/tree/main/dist) and drop it into your project root or `assets/scripts/`. Then open `index.html` directly in a browser
|
|
74
|
+
If you prefer **zero tooling**, download `dist/zquery.min.js` from the [dist/ folder](https://github.com/tonywied17/zero-query/tree/main/dist) and drop it into your project root or `assets/scripts/`. Then open `index.html` directly in a browser - no Node.js required.
|
|
73
75
|
|
|
74
76
|
```bash
|
|
75
77
|
git clone https://github.com/tonywied17/zero-query.git
|
|
76
78
|
cd zero-query
|
|
77
79
|
npx zquery build
|
|
78
|
-
# → dist/zquery.min.js (~
|
|
80
|
+
# → dist/zquery.min.js (~91 KB)
|
|
79
81
|
```
|
|
80
82
|
|
|
81
83
|
### Include in HTML
|
|
@@ -109,7 +111,7 @@ import './components/about.js';
|
|
|
109
111
|
import './components/contacts/contacts.js';
|
|
110
112
|
import { routes } from './routes.js';
|
|
111
113
|
|
|
112
|
-
$.router({
|
|
114
|
+
$.router({ routes, fallback: 'not-found' });
|
|
113
115
|
```
|
|
114
116
|
|
|
115
117
|
### Define a Component
|
|
@@ -129,7 +131,7 @@ $.component('home-page', {
|
|
|
129
131
|
});
|
|
130
132
|
```
|
|
131
133
|
|
|
132
|
-
That's it
|
|
134
|
+
That's it - a fully working SPA with the dev server's live-reload.
|
|
133
135
|
|
|
134
136
|
---
|
|
135
137
|
|
|
@@ -186,10 +188,30 @@ my-app/ ← minimal scaffold (npx zquery create my-app
|
|
|
186
188
|
assets/
|
|
187
189
|
```
|
|
188
190
|
|
|
191
|
+
Use `--ssr` for a project with server-side rendering:
|
|
192
|
+
|
|
193
|
+
```
|
|
194
|
+
my-app/ ← SSR scaffold (npx zquery create my-app --ssr)
|
|
195
|
+
index.html ← client HTML shell
|
|
196
|
+
global.css
|
|
197
|
+
app/
|
|
198
|
+
app.js ← client entry - registers shared components
|
|
199
|
+
routes.js ← shared route definitions
|
|
200
|
+
components/
|
|
201
|
+
home.js ← shared component (SSR + client)
|
|
202
|
+
about.js
|
|
203
|
+
not-found.js
|
|
204
|
+
server/
|
|
205
|
+
index.js ← SSR HTTP server
|
|
206
|
+
assets/
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
Components in `app/components/` export plain definition objects - the client registers them with `$.component()`, the server with `app.component()`. The `--ssr` flag handles everything automatically - installs dependencies, starts the server at `http://localhost:3000`, and opens the browser.
|
|
210
|
+
|
|
189
211
|
- One component per file inside `components/`.
|
|
190
212
|
- Names **must contain a hyphen** (Web Component convention): `home-page`, `app-counter`, etc.
|
|
191
213
|
- Components with external templates or styles can use a subfolder (e.g. `contacts/contacts.js` + `contacts.html` + `contacts.css`).
|
|
192
|
-
- `app.js` is the single entry point
|
|
214
|
+
- `app.js` is the single entry point - import components, create the store, and boot the router.
|
|
193
215
|
- `global.css` lives next to `index.html` for easy access; the bundler hashes it into `global.<hash>.min.css` for production.
|
|
194
216
|
- `assets/` holds static files that get copied to `dist/` as-is.
|
|
195
217
|
|
|
@@ -197,7 +219,7 @@ my-app/ ← minimal scaffold (npx zquery create my-app
|
|
|
197
219
|
|
|
198
220
|
## CLI Bundler
|
|
199
221
|
|
|
200
|
-
The CLI compiles your entire app
|
|
222
|
+
The CLI compiles your entire app - ES modules, the library, external templates, and assets - into a **single production-ready bundle**. It outputs two builds in one step: a `server/` build for deploying to any web server, and a `local/` build that works straight from disk. No config, no flags - just point it at your app.
|
|
201
223
|
|
|
202
224
|
```bash
|
|
203
225
|
# Auto-detect entry from any .html with a module script
|
|
@@ -219,7 +241,7 @@ dist/
|
|
|
219
241
|
z-app.<hash>.min.js
|
|
220
242
|
global.<hash>.min.css
|
|
221
243
|
assets/
|
|
222
|
-
local/ ← open from disk (file://)
|
|
244
|
+
local/ ← open from disk (file://) - no server needed
|
|
223
245
|
index.html
|
|
224
246
|
z-app.<hash>.min.js
|
|
225
247
|
...
|
|
@@ -236,11 +258,11 @@ dist/
|
|
|
236
258
|
|
|
237
259
|
### What the Bundler Does
|
|
238
260
|
|
|
239
|
-
1. **Entry detection**
|
|
240
|
-
1. **HTML files**
|
|
241
|
-
2. **Module scripts within HTML**
|
|
242
|
-
3. **JS file scan**
|
|
243
|
-
4. **Convention fallbacks**
|
|
261
|
+
1. **Entry detection** - a strict precedence order ensures the correct file is chosen:
|
|
262
|
+
1. **HTML files** - `index.html` is checked first, then other `.html` files (root + one level deep).
|
|
263
|
+
2. **Module scripts within HTML** - within each HTML file, a `<script type="module">` whose `src` resolves to `app.js` wins; otherwise the first module script tag is used.
|
|
264
|
+
3. **JS file scan** - if no HTML match, JS files (up to 2 levels deep) are scanned in two passes: first for `$.router(` (the canonical app entry point), then for `$.mount(`, `$.store(`, or `mountAll(`.
|
|
265
|
+
4. **Convention fallbacks** - `app/app.js`, `scripts/app.js`, `src/app.js`, `js/app.js`, `app.js`, `main.js`.
|
|
244
266
|
2. Resolves all `import` statements and topologically sorts dependencies
|
|
245
267
|
3. Strips `import`/`export` syntax, wraps in an IIFE
|
|
246
268
|
4. Embeds zQuery library and inlines `templateUrl` / `styleUrl` files
|
|
@@ -268,7 +290,7 @@ location / {
|
|
|
268
290
|
}
|
|
269
291
|
```
|
|
270
292
|
|
|
271
|
-
**Sub-path deployment** (e.g. `/my-app/`): set `<base href="/my-app/">` in your HTML
|
|
293
|
+
**Sub-path deployment** (e.g. `/my-app/`): set `<base href="/my-app/">` in your HTML - the router auto-detects it.
|
|
272
294
|
|
|
273
295
|
---
|
|
274
296
|
|
|
@@ -277,13 +299,13 @@ location / {
|
|
|
277
299
|
| Namespace | Methods |
|
|
278
300
|
| --- | --- |
|
|
279
301
|
| `$()` | Chainable selector → `ZQueryCollection` (CSS selectors, elements, NodeLists, HTML strings) |
|
|
280
|
-
| `$.all()` | Alias for `$()`
|
|
302
|
+
| `$.all()` | Alias for `$()` - identical behavior |
|
|
281
303
|
| `$.id` `$.class` `$.classes` `$.tag` `$.name` `$.children` `$.qs` `$.qsa` | Quick DOM refs |
|
|
282
304
|
| `$.create` | Element factory |
|
|
283
305
|
| `$.ready` `$.on` `$.off` | DOM ready, global event delegation & direct listeners |
|
|
284
306
|
| `$.fn` | Collection prototype (extend it) |
|
|
285
307
|
| `$.component` `$.mount` `$.mountAll` `$.getInstance` `$.destroy` `$.components` `$.prefetch` | Component system |
|
|
286
|
-
| `$.morph` `$.morphElement` | DOM morphing engine
|
|
308
|
+
| `$.morph` `$.morphElement` | DOM morphing engine - LIS-based keyed reconciliation, `isEqualNode()` bail-outs, `z-skip` opt-out. Patches existing DOM to match new HTML without destroying unchanged nodes. Auto-key detection (`id`, `data-id`, `data-key`) - no `z-key` required. `$().html()` and `$().replaceWith()` auto-morph existing content; `$().morph()` for explicit morph |
|
|
287
309
|
| `$.safeEval` | CSP-safe expression evaluator (replaces `eval` / `new Function`) |
|
|
288
310
|
| `$.style` | Dynamically load global stylesheet file(s) at runtime |
|
|
289
311
|
| `$.router` `$.getRouter` | SPA router |
|
|
@@ -298,14 +320,16 @@ location / {
|
|
|
298
320
|
| `$.retry` `$.timeout` | Async utils |
|
|
299
321
|
| `$.param` `$.parseQuery` | URL utils |
|
|
300
322
|
| `$.storage` `$.session` | Storage wrappers |
|
|
301
|
-
| `$.EventBus` `$.bus` | Event bus
|
|
323
|
+
| `$.EventBus` `$.bus` | Event bus |
|
|
324
|
+
| `$.onError` `$.ZQueryError` `$.ErrorCode` `$.guardCallback` `$.guardAsync` `$.formatError` `$.validate` | Error handling |
|
|
325
|
+
| `$.version` | Library version |\n| `$.libSize` | Minified bundle size string (e.g. `\"~91 KB\"`) |
|
|
302
326
|
| `$.unitTests` | Build-time test results `{ passed, failed, total, suites, duration, ok }` |
|
|
303
327
|
| `$.meta` | Build metadata (populated by CLI bundler) |
|
|
304
328
|
| `$.noConflict` | Release `$` global |
|
|
305
329
|
|
|
306
330
|
| CLI Command | Description |
|
|
307
331
|
| --- | --- |
|
|
308
|
-
| `zquery create [dir]` | Scaffold a new project. Default: full-featured app. `--minimal` / `-m`: lightweight 3-page starter with
|
|
332
|
+
| `zquery create [dir]` | Scaffold a new project. Default: full-featured app. `--minimal` / `-m`: lightweight 3-page starter. `--ssr` / `-s`: SSR project with shared components and HTTP server. |
|
|
309
333
|
| `zquery dev [root]` | Dev server with live-reload, CSS hot-swap, error overlay, expandable floating toolbar & five-tab inspector panel (port 3100). Visit `/_devtools` for the standalone panel. `--index` for custom HTML, `--bundle` for bundled mode, `--no-intercept` to skip CDN intercept. |
|
|
310
334
|
| `zquery bundle [dir\|file]` | Bundle app into a single IIFE file. Accepts dir or direct entry file. |
|
|
311
335
|
| `zquery build` | Build the zQuery library (`dist/zquery.min.js`) |
|
|
@@ -323,4 +347,4 @@ The official **[zQuery for VS Code](https://marketplace.visualstudio.com/items?i
|
|
|
323
347
|
|
|
324
348
|
## License
|
|
325
349
|
|
|
326
|
-
MIT
|
|
350
|
+
MIT - [Anthony Wiedman / Molex](https://github.com/tonywied17)
|
package/cli/args.js
CHANGED
package/cli/commands/build.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* cli/commands/build.js
|
|
2
|
+
* cli/commands/build.js - library build command
|
|
3
3
|
*
|
|
4
4
|
* Concatenates the zQuery source modules into dist/zquery.js and
|
|
5
5
|
* dist/zquery.min.js.
|
|
@@ -208,7 +208,7 @@ function buildLibrary() {
|
|
|
208
208
|
const zipBuf = buildZip(entries);
|
|
209
209
|
const zipPath = path.join(DIST, 'zquery.dist.zip');
|
|
210
210
|
fs.writeFileSync(zipPath, zipBuf);
|
|
211
|
-
console.log(` ✓ dist/zquery.dist.zip (${sizeKB(zipBuf)} KB)
|
|
211
|
+
console.log(` ✓ dist/zquery.dist.zip (${sizeKB(zipBuf)} KB) - ${entries.length} files`);
|
|
212
212
|
|
|
213
213
|
return { DIST, OUT_FILE, MIN_FILE };
|
|
214
214
|
}
|
package/cli/commands/bundle.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* cli/commands/bundle.js
|
|
2
|
+
* cli/commands/bundle.js - app bundler command
|
|
3
3
|
*
|
|
4
4
|
* Walks the ES module import graph starting from an entry file,
|
|
5
5
|
* strips import/export syntax, concatenates everything into a single
|
|
@@ -59,7 +59,7 @@ function extractImports(code) {
|
|
|
59
59
|
return specifiers;
|
|
60
60
|
}
|
|
61
61
|
|
|
62
|
-
/** Walk the import graph
|
|
62
|
+
/** Walk the import graph - topological sort (leaves first). */
|
|
63
63
|
function walkImportGraph(entry) {
|
|
64
64
|
const visited = new Set();
|
|
65
65
|
const order = [];
|
|
@@ -119,7 +119,7 @@ function rewriteResourceUrls(code, filePath, projectRoot) {
|
|
|
119
119
|
(match, prefix, quote, url) => {
|
|
120
120
|
if (url.startsWith('/') || url.includes('://')) return match;
|
|
121
121
|
const abs = path.resolve(fileDir, url);
|
|
122
|
-
// Only rewrite if the file actually exists
|
|
122
|
+
// Only rewrite if the file actually exists - avoids mangling code examples
|
|
123
123
|
if (!fs.existsSync(abs)) return match;
|
|
124
124
|
const rel = path.relative(projectRoot, abs).replace(/\\/g, '/');
|
|
125
125
|
return `${prefix}${quote}${rel}${quote}`;
|
|
@@ -128,7 +128,7 @@ function rewriteResourceUrls(code, filePath, projectRoot) {
|
|
|
128
128
|
}
|
|
129
129
|
|
|
130
130
|
/**
|
|
131
|
-
* Minify HTML for inlining
|
|
131
|
+
* Minify HTML for inlining - strips indentation and collapses whitespace
|
|
132
132
|
* between tags. Preserves content inside <pre>, <code>, and <textarea>
|
|
133
133
|
* blocks verbatim so syntax-highlighted code samples survive.
|
|
134
134
|
*/
|
|
@@ -164,7 +164,7 @@ function minifyHTML(html) {
|
|
|
164
164
|
}
|
|
165
165
|
|
|
166
166
|
/**
|
|
167
|
-
* Minify CSS for inlining
|
|
167
|
+
* Minify CSS for inlining - strips comments, collapses whitespace,
|
|
168
168
|
* removes unnecessary spaces around punctuation.
|
|
169
169
|
*/
|
|
170
170
|
function minifyCSS(css) {
|
|
@@ -396,7 +396,7 @@ function collectInlineResources(files, projectRoot) {
|
|
|
396
396
|
inlineMap[relKey] = fs.readFileSync(tmplPath, 'utf-8');
|
|
397
397
|
}
|
|
398
398
|
} else if (/templateUrl\s*:/.test(code)) {
|
|
399
|
-
// Dynamic templateUrl (e.g. Object.fromEntries, computed map)
|
|
399
|
+
// Dynamic templateUrl (e.g. Object.fromEntries, computed map) -
|
|
400
400
|
// inline all .html files in the component's directory tree so
|
|
401
401
|
// the runtime __zqInline lookup can resolve them by suffix.
|
|
402
402
|
(function scanHtml(dir) {
|
|
@@ -412,7 +412,7 @@ function collectInlineResources(files, projectRoot) {
|
|
|
412
412
|
scanHtml(full);
|
|
413
413
|
}
|
|
414
414
|
}
|
|
415
|
-
} catch { /* permission error
|
|
415
|
+
} catch { /* permission error - skip */ }
|
|
416
416
|
})(fileDir);
|
|
417
417
|
}
|
|
418
418
|
}
|
|
@@ -429,7 +429,7 @@ function collectInlineResources(files, projectRoot) {
|
|
|
429
429
|
/**
|
|
430
430
|
* Auto-detect the app entry point.
|
|
431
431
|
*
|
|
432
|
-
* Strategy
|
|
432
|
+
* Strategy - ordered by precedence (first match wins):
|
|
433
433
|
* 1. HTML discovery: index.html first, then other .html files
|
|
434
434
|
* (root level + one directory deep).
|
|
435
435
|
* 2. Within each HTML file, prefer a module <script> whose src
|
|
@@ -456,7 +456,7 @@ function detectEntry(projectRoot) {
|
|
|
456
456
|
htmlFiles.push(path.join(sub, child.name));
|
|
457
457
|
}
|
|
458
458
|
}
|
|
459
|
-
} catch { /* permission error
|
|
459
|
+
} catch { /* permission error - skip */ }
|
|
460
460
|
}
|
|
461
461
|
}
|
|
462
462
|
|
|
@@ -490,8 +490,8 @@ function detectEntry(projectRoot) {
|
|
|
490
490
|
}
|
|
491
491
|
|
|
492
492
|
// 2. Search JS files for entry-point patterns.
|
|
493
|
-
// Pass 1
|
|
494
|
-
// Pass 2
|
|
493
|
+
// Pass 1 - $.router (the canonical entry point).
|
|
494
|
+
// Pass 2 - $.mount, $.store, mountAll (component-level, lower confidence).
|
|
495
495
|
const routerRe = /\$\.router\s*\(/;
|
|
496
496
|
const otherRe = /\$\.(mount|store)\s*\(|mountAll\s*\(/;
|
|
497
497
|
|
|
@@ -541,8 +541,8 @@ function detectEntry(projectRoot) {
|
|
|
541
541
|
/**
|
|
542
542
|
* Rewrite an HTML file to replace the module <script> with the bundle.
|
|
543
543
|
* Produces two variants:
|
|
544
|
-
* server/index.html
|
|
545
|
-
* local/index.html
|
|
544
|
+
* server/index.html - <base href="/"> for SPA deep routes
|
|
545
|
+
* local/index.html - relative paths for file:// access
|
|
546
546
|
*/
|
|
547
547
|
function rewriteHtml(projectRoot, htmlRelPath, bundleFile, includeLib, bundledFiles, serverDir, localDir, globalCssOrigHref, globalCssHash) {
|
|
548
548
|
const htmlPath = path.resolve(projectRoot, htmlRelPath);
|
|
@@ -737,7 +737,7 @@ function bundleApp() {
|
|
|
737
737
|
const minimal = flag('minimal', 'm');
|
|
738
738
|
const globalCssOverride = option('global-css', null, null);
|
|
739
739
|
|
|
740
|
-
// Entry point
|
|
740
|
+
// Entry point - positional arg (directory or file) or auto-detection
|
|
741
741
|
let entry = null;
|
|
742
742
|
let targetDir = null;
|
|
743
743
|
for (let i = 1; i < args.length; i++) {
|
|
@@ -984,7 +984,7 @@ function bundleApp() {
|
|
|
984
984
|
console.log(`\n ✓ ${minBase} (${sizeKB(fs.readFileSync(minFile))} KB)`);
|
|
985
985
|
|
|
986
986
|
// ------------------------------------------------------------------
|
|
987
|
-
// Global CSS bundling
|
|
987
|
+
// Global CSS bundling - extract from index.html <link> or --global-css
|
|
988
988
|
// ------------------------------------------------------------------
|
|
989
989
|
let globalCssHash = null;
|
|
990
990
|
let globalCssOrigHref = null;
|
package/cli/commands/create.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// cli/commands/create.js
|
|
1
|
+
// cli/commands/create.js - scaffold a new zQuery project
|
|
2
2
|
//
|
|
3
3
|
// Templates live in cli/scaffold/<variant>/ (default or minimal).
|
|
4
4
|
// Reads template files, replaces {{NAME}} with the project name,
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
const fs = require('fs');
|
|
8
8
|
const path = require('path');
|
|
9
|
+
const { execSync, spawn } = require('child_process');
|
|
9
10
|
const { flag } = require('../args');
|
|
10
11
|
|
|
11
12
|
/**
|
|
@@ -30,11 +31,15 @@ function createProject(args) {
|
|
|
30
31
|
const target = dirArg ? path.resolve(dirArg) : process.cwd();
|
|
31
32
|
const name = path.basename(target);
|
|
32
33
|
|
|
33
|
-
// Determine scaffold variant: --minimal / -m or default
|
|
34
|
-
const variant = flag('minimal', 'm') ? 'minimal'
|
|
34
|
+
// Determine scaffold variant: --minimal / -m or --ssr / -s or default
|
|
35
|
+
const variant = flag('minimal', 'm') ? 'minimal'
|
|
36
|
+
: flag('ssr', 's') ? 'ssr'
|
|
37
|
+
: 'default';
|
|
35
38
|
|
|
36
39
|
// Guard: refuse to overwrite existing files
|
|
37
|
-
const
|
|
40
|
+
const checkFiles = ['index.html', 'global.css', 'app', 'assets'];
|
|
41
|
+
if (variant === 'ssr') checkFiles.push('server');
|
|
42
|
+
const conflicts = checkFiles.filter(f =>
|
|
38
43
|
fs.existsSync(path.join(target, f))
|
|
39
44
|
);
|
|
40
45
|
if (conflicts.length) {
|
|
@@ -43,7 +48,7 @@ function createProject(args) {
|
|
|
43
48
|
process.exit(1);
|
|
44
49
|
}
|
|
45
50
|
|
|
46
|
-
console.log(`\n zQuery
|
|
51
|
+
console.log(`\n zQuery - Create Project (${variant})\n`);
|
|
47
52
|
console.log(` Scaffolding into ${target}\n`);
|
|
48
53
|
|
|
49
54
|
// Resolve the scaffold template directory for the chosen variant
|
|
@@ -70,11 +75,40 @@ function createProject(args) {
|
|
|
70
75
|
console.log(` ✓ ${rel}`);
|
|
71
76
|
}
|
|
72
77
|
|
|
73
|
-
|
|
78
|
+
const devCmd = `npx zquery dev${target !== process.cwd() ? ` ${dirArg}` : ''}`;
|
|
79
|
+
|
|
80
|
+
if (variant === 'ssr') {
|
|
81
|
+
console.log(`\n Installing dependencies...\n`);
|
|
82
|
+
// Install zero-query from the same package that provides this CLI
|
|
83
|
+
// (works both in local dev and when installed from npm)
|
|
84
|
+
const zqRoot = path.resolve(__dirname, '..', '..');
|
|
85
|
+
try {
|
|
86
|
+
execSync(`npm install "${zqRoot}"`, { cwd: target, stdio: 'inherit' });
|
|
87
|
+
} catch {
|
|
88
|
+
console.error(`\n ✗ npm install failed. Run it manually:\n\n cd ${dirArg || '.'}\n npm install\n node server/index.js\n`);
|
|
89
|
+
process.exit(1);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
console.log(`\n Starting SSR server...\n`);
|
|
93
|
+
const child = spawn('node', ['server/index.js'], { cwd: target, stdio: 'inherit' });
|
|
94
|
+
|
|
95
|
+
setTimeout(() => {
|
|
96
|
+
const open = process.platform === 'win32' ? 'start'
|
|
97
|
+
: process.platform === 'darwin' ? 'open' : 'xdg-open';
|
|
98
|
+
try { execSync(`${open} http://localhost:3000`, { stdio: 'ignore' }); } catch {}
|
|
99
|
+
}, 500);
|
|
100
|
+
|
|
101
|
+
process.on('SIGINT', () => { child.kill(); process.exit(); });
|
|
102
|
+
process.on('SIGTERM', () => { child.kill(); process.exit(); });
|
|
103
|
+
child.on('exit', (code) => process.exit(code || 0));
|
|
104
|
+
return; // keep process alive for the server
|
|
105
|
+
} else {
|
|
106
|
+
console.log(`
|
|
74
107
|
Done! Next steps:
|
|
75
108
|
|
|
76
|
-
|
|
109
|
+
${devCmd}
|
|
77
110
|
`);
|
|
111
|
+
}
|
|
78
112
|
}
|
|
79
113
|
|
|
80
114
|
module.exports = createProject;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* cli/commands/dev/devtools/index.js
|
|
2
|
+
* cli/commands/dev/devtools/index.js - DevTools HTML assembler
|
|
3
3
|
*
|
|
4
4
|
* Reads CSS, HTML, and JS partials from this folder and concatenates them
|
|
5
5
|
* into a single self-contained HTML page served at /_devtools.
|
|
@@ -39,7 +39,7 @@ function formatTime(ts) {
|
|
|
39
39
|
}
|
|
40
40
|
|
|
41
41
|
// ===================================================================
|
|
42
|
-
// Connection
|
|
42
|
+
// Connection - find target window (opener popup → iframe fallback)
|
|
43
43
|
// ===================================================================
|
|
44
44
|
function isConnected() {
|
|
45
45
|
try { return targetWin && (targetWin === window.opener ? !targetWin.closed : true) && targetWin.document; }
|
|
@@ -48,11 +48,11 @@ function isConnected() {
|
|
|
48
48
|
|
|
49
49
|
function detectMode() {
|
|
50
50
|
if (window.opener) {
|
|
51
|
-
// Opened as popup
|
|
51
|
+
// Opened as popup - hide iframe, use opener
|
|
52
52
|
mode = 'popup';
|
|
53
53
|
targetWin = window.opener;
|
|
54
54
|
} else {
|
|
55
|
-
// Standalone tab
|
|
55
|
+
// Standalone tab - embed app in iframe
|
|
56
56
|
mode = 'split-h';
|
|
57
57
|
targetWin = null; // will set from iframe.contentWindow
|
|
58
58
|
}
|
|
@@ -110,11 +110,11 @@ var tbDragging = false;
|
|
|
110
110
|
|
|
111
111
|
var isH = mode === 'split-h';
|
|
112
112
|
if (isH) {
|
|
113
|
-
// Vertical column divider
|
|
113
|
+
// Vertical column divider - drag toolbar up/down
|
|
114
114
|
startPos = e.clientY;
|
|
115
115
|
startOffset = parseInt(toolbar.style.top, 10) || toolbar.offsetTop;
|
|
116
116
|
} else {
|
|
117
|
-
// Horizontal row divider
|
|
117
|
+
// Horizontal row divider - drag toolbar left/right
|
|
118
118
|
startPos = e.clientX;
|
|
119
119
|
startOffset = parseInt(toolbar.style.left, 10) || toolbar.offsetLeft;
|
|
120
120
|
}
|
|
@@ -180,7 +180,7 @@ divider.addEventListener('mousedown', function(e) {
|
|
|
180
180
|
});
|
|
181
181
|
|
|
182
182
|
// ===================================================================
|
|
183
|
-
// Refresh button
|
|
183
|
+
// Refresh button - reload the embedded iframe
|
|
184
184
|
// ===================================================================
|
|
185
185
|
document.getElementById('btn-refresh').addEventListener('click', function(e) {
|
|
186
186
|
e.stopPropagation();
|
|
@@ -192,7 +192,7 @@ document.getElementById('btn-refresh').addEventListener('click', function(e) {
|
|
|
192
192
|
});
|
|
193
193
|
|
|
194
194
|
// ===================================================================
|
|
195
|
-
// Viewport preset buttons
|
|
195
|
+
// Viewport preset buttons - resize browser pane to mobile/tablet/desktop
|
|
196
196
|
// ===================================================================
|
|
197
197
|
var viewportBtns = document.querySelectorAll('.viewport-btn');
|
|
198
198
|
|
|
@@ -219,10 +219,10 @@ viewportBtns.forEach(function(btn) {
|
|
|
219
219
|
var total = rootEl.offsetWidth;
|
|
220
220
|
|
|
221
221
|
if (targetWidth === 0) {
|
|
222
|
-
// Desktop
|
|
222
|
+
// Desktop - reset to default CSS proportions
|
|
223
223
|
rootEl.style.gridTemplateColumns = '';
|
|
224
224
|
} else {
|
|
225
|
-
// Mobile/Tablet
|
|
225
|
+
// Mobile/Tablet - set iframe column to exact pixel width
|
|
226
226
|
var pct = Math.min(85, Math.max(15, (targetWidth / total) * 100));
|
|
227
227
|
rootEl.style.gridTemplateColumns = pct.toFixed(1) + '% 4px 1fr';
|
|
228
228
|
}
|
|
@@ -233,7 +233,7 @@ viewportBtns.forEach(function(btn) {
|
|
|
233
233
|
});
|
|
234
234
|
|
|
235
235
|
// ===================================================================
|
|
236
|
-
// Route indicator
|
|
236
|
+
// Route indicator - toggle label showing current path + hash
|
|
237
237
|
// ===================================================================
|
|
238
238
|
var routeBtn = document.getElementById('btn-route');
|
|
239
239
|
var routeLabel = document.getElementById('route-label');
|
|
@@ -266,7 +266,7 @@ setInterval(function() {
|
|
|
266
266
|
}, 500);
|
|
267
267
|
|
|
268
268
|
// ===================================================================
|
|
269
|
-
// init
|
|
269
|
+
// init - connect to target window (popup or iframe)
|
|
270
270
|
// ===================================================================
|
|
271
271
|
function init() {
|
|
272
272
|
// If popup mode, targetWin is already set
|
|
@@ -310,7 +310,7 @@ function init() {
|
|
|
310
310
|
}
|
|
311
311
|
|
|
312
312
|
// ===================================================================
|
|
313
|
-
// connectToTarget
|
|
313
|
+
// connectToTarget - read existing data, start listeners, periodic sync
|
|
314
314
|
// ===================================================================
|
|
315
315
|
function connectToTarget() {
|
|
316
316
|
|
|
@@ -372,7 +372,7 @@ function connectToTarget() {
|
|
|
372
372
|
// Periodic refresh for components + perf (fast when tab is visible)
|
|
373
373
|
setInterval(function() {
|
|
374
374
|
if (!isConnected()) {
|
|
375
|
-
// Retry connection
|
|
375
|
+
// Retry connection - opener may be mid-mutation, not truly gone
|
|
376
376
|
try {
|
|
377
377
|
if (mode === 'popup' && window.opener && !window.opener.closed) {
|
|
378
378
|
targetWin = window.opener;
|
|
@@ -389,7 +389,7 @@ function connectToTarget() {
|
|
|
389
389
|
return;
|
|
390
390
|
}
|
|
391
391
|
}
|
|
392
|
-
// Keep targetDoc fresh
|
|
392
|
+
// Keep targetDoc fresh - the opener may have reloaded (live-reload)
|
|
393
393
|
try {
|
|
394
394
|
var freshDoc = targetWin.document;
|
|
395
395
|
if (freshDoc !== targetDoc) {
|
|
@@ -72,7 +72,7 @@ function buildNode(node, depth) {
|
|
|
72
72
|
var nodePath = getNodePath(node);
|
|
73
73
|
var hasChildren = false;
|
|
74
74
|
var childNodes = node.childNodes;
|
|
75
|
-
// style/script content is shown inline via the peek button
|
|
75
|
+
// style/script content is shown inline via the peek button - treat as leaf
|
|
76
76
|
if (tag !== 'style' && tag !== 'script') {
|
|
77
77
|
for (var i = 0; i < childNodes.length; i++) {
|
|
78
78
|
var cn = childNodes[i];
|
|
@@ -238,7 +238,7 @@ function buildNode(node, depth) {
|
|
|
238
238
|
toggleNested(childContainer, 0);
|
|
239
239
|
});
|
|
240
240
|
|
|
241
|
-
// Row click
|
|
241
|
+
// Row click - select element (not toggle)
|
|
242
242
|
row.addEventListener('click', function(e) {
|
|
243
243
|
// Don't select when clicking toggle arrow, badge, action buttons, or peek
|
|
244
244
|
if (e.target.closest('.tree-toggle') || e.target.closest('.tree-badge') || e.target.closest('.tree-action') || e.target.closest('.tree-peek')) return;
|
|
@@ -351,7 +351,7 @@ function showDetail(node) {
|
|
|
351
351
|
}
|
|
352
352
|
|
|
353
353
|
// ===================================================================
|
|
354
|
-
// MutationObserver
|
|
354
|
+
// MutationObserver - watch target document for live DOM changes
|
|
355
355
|
// ===================================================================
|
|
356
356
|
function startObserver() {
|
|
357
357
|
if (!targetDoc || observer) return;
|
|
@@ -394,7 +394,7 @@ function startObserver() {
|
|
|
394
394
|
}
|
|
395
395
|
}
|
|
396
396
|
|
|
397
|
-
if (!dominated) return; // All mutations were from devtools highlight
|
|
397
|
+
if (!dominated) return; // All mutations were from devtools highlight - skip rebuild
|
|
398
398
|
|
|
399
399
|
// Debounce tree rebuild
|
|
400
400
|
clearTimeout(startObserver._timer);
|
|
@@ -9,7 +9,7 @@ function updateStats() {
|
|
|
9
9
|
document.getElementById('morph-count').textContent = morphCount + ' renders';
|
|
10
10
|
document.getElementById('req-count').textContent = requests.length + ' requests';
|
|
11
11
|
|
|
12
|
-
// Route stat
|
|
12
|
+
// Route stat - show current path
|
|
13
13
|
try {
|
|
14
14
|
var router = targetWin && targetWin.$ && targetWin.$.getRouter();
|
|
15
15
|
var routeStat = document.getElementById('route-stat');
|
|
@@ -20,7 +20,7 @@ button{font:inherit;cursor:pointer;border:none;background:none;color:inherit}
|
|
|
20
20
|
.divider:hover{background:var(--accent)}
|
|
21
21
|
|
|
22
22
|
/* Divider toolbar */
|
|
23
|
-
/* split-h: divider is a tall 4px column
|
|
23
|
+
/* split-h: divider is a tall 4px column - toolbar sits to its LEFT, overlaying the browser */
|
|
24
24
|
.divider-toolbar{position:absolute;display:flex;flex-direction:column;align-items:center;gap:2px;
|
|
25
25
|
padding:4px 2px;background:var(--bg2);border:1px solid var(--border);border-radius:6px;
|
|
26
26
|
z-index:11;top:12px;right:100%;margin-right:2px;cursor:grab}
|
|
@@ -36,7 +36,7 @@ border:1px solid var(--border);border-radius:4px;font-size:11px;color:var(--acce
|
|
|
36
36
|
max-width:0;overflow:hidden;opacity:0;transition:max-width .25s ease,opacity .2s ease,padding .2s ease;
|
|
37
37
|
padding:0;pointer-events:none;line-height:22px;text-overflow:ellipsis}
|
|
38
38
|
.route-label.open{max-width:50vw;opacity:1;padding:2px 8px;pointer-events:auto}
|
|
39
|
-
/* split-v: divider is a wide 4px row
|
|
39
|
+
/* split-v: divider is a wide 4px row - toolbar sits ABOVE it as a horizontal bar */
|
|
40
40
|
#root.split-v .divider-toolbar{flex-direction:row;gap:4px;padding:2px 4px;
|
|
41
41
|
top:auto;right:auto;bottom:100%;left:12px;margin-right:0;margin-bottom:2px}
|
|
42
42
|
#root.split-v .divider-sep{width:1px;height:14px;margin:0 1px}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* cli/commands/dev/index.js
|
|
2
|
+
* cli/commands/dev/index.js - Dev server orchestrator
|
|
3
3
|
*
|
|
4
4
|
* Ties together the HTTP server, file watcher, logger, and overlay
|
|
5
5
|
* to provide a complete development environment with live-reload,
|
|
@@ -44,7 +44,7 @@ function resolveRoot(htmlEntry) {
|
|
|
44
44
|
}
|
|
45
45
|
|
|
46
46
|
// ---------------------------------------------------------------------------
|
|
47
|
-
// devServer
|
|
47
|
+
// devServer - main entry point (called from cli/index.js)
|
|
48
48
|
// ---------------------------------------------------------------------------
|
|
49
49
|
|
|
50
50
|
async function devServer() {
|