From 41c0fc314740c2da0ccf2164b2d8aa233b47466e Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 23 Oct 2026 12:09:07 +0000 Subject: [PATCH 1/2] chore(deps): require @bquery/bquery ^1.18.0 bQuery 1.18.0 compiles bq-on handlers with several `;`-separated statements: compileViews() returns { expressions, statements, stats } and emitModule() passes the statement map as the second argument of registerCompiledExpressions(). The plugin hands the whole compile result to emitModule(), so it needed no code change; with 1.18 as the floor the "1.17.2 leaves them to the runtime evaluator and warns" case no longer exists for supported versions. - Peer and dev dependency ^1.17.2 -> ^1.18.0 (package is unreleased, so its first release can require 1.18); bun.lock updated. - README and CHANGELOG drop the 1.17.2 caveat. - The version-tolerant unit test is replaced by one that runs the emitted module against a stub registry and checks that the handler lands in the statements map and runs both statements in order (fails on 1.17.2), plus one for a statement list outside bq-on falling back to the runtime. - The SSR dev-server test asserts the doctype of a full-page template rendered with renderToResponse(), which bQuery keeps since 1.18. The SSR middleware only renders GET/HEAD navigations and never forwards a request body, so 1.18's body limits and single-read ctx.body() do not affect it; the file-route, i18n extract and generateNonce APIs the plugin uses are unchanged. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_018Ju3jbgag99iuxndoJTrgM --- CHANGELOG.md | 6 +++++- README.md | 9 ++++----- bun.lock | 6 +++--- package.json | 4 ++-- test/unit.test.ts | 50 +++++++++++++++++++++++++++++++++++++---------- test/vite.test.ts | 2 ++ 6 files changed, 56 insertions(+), 21 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e841c6a..a1b7f40 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,4 +8,8 @@ project uses [Semantic Versioning](https://semver.org/). ### Added -- `@bquery/unplugin` — a bundler plugin for Vite, Rollup, webpack, Rspack and esbuild ([bQuery/bQuery#224](https://github.com/bQuery/bQuery/issues/224), developed in [bQuery/bQuery#278](https://github.com/bQuery/bQuery/pull/278)). It compiles `*.view.html` imports with the view compiler (HMR in Vite), generates the file-route manifest as `virtual:bquery/routes`, extracts i18n messages into the catalogs in watch mode (`virtual:bquery/messages` hot-reloads them), and in Vite dev adds a CSP nonce and an SSR middleware for a `render(request, ctx)` server entry. Requires `@bquery/bquery` 1.17.2 or later. +- `@bquery/unplugin` — a bundler plugin for Vite, Rollup, webpack, Rspack and esbuild ([bQuery/bQuery#224](https://github.com/bQuery/bQuery/issues/224), developed in [bQuery/bQuery#278](https://github.com/bQuery/bQuery/pull/278)). It compiles `*.view.html` imports with the view compiler (HMR in Vite), generates the file-route manifest as `virtual:bquery/routes`, extracts i18n messages into the catalogs in watch mode (`virtual:bquery/messages` hot-reloads them), and in Vite dev adds a CSP nonce and an SSR middleware for a `render(request, ctx)` server entry. Requires `@bquery/bquery` 1.18.0 or later. + +### Changed + +- Requires `@bquery/bquery` 1.18.0 or later (peer and dev dependency `^1.18.0`, was `^1.17.2`). `bq-on` handlers with several `;`-separated statements (`$event.preventDefault(); add()`) now always compile: the view compiler puts them in a separate statements map that the emitted module passes to `registerCompiledExpressions(expressions, statements)`, instead of leaving them to the runtime evaluator with a warning as 1.17.2 did. bQuery 1.18 also keeps the `` of full-page templates in its SSR renderers, so pages served by the SSR dev middleware no longer fall into quirks mode. diff --git a/README.md b/README.md index 6038587..6ecd0a5 100644 --- a/README.md +++ b/README.md @@ -31,7 +31,7 @@ bun add -d @bquery/unplugin pnpm add -D @bquery/unplugin ``` -`@bquery/bquery` (`^1.17.2`) is a peer dependency. Install the bundler you use; +`@bquery/bquery` (`^1.18.0`) is a peer dependency. Install the bundler you use; each one (`vite`, `rollup`, `webpack`, `@rspack/core`, `esbuild`) is an optional peer dependency. @@ -174,10 +174,9 @@ with the render contract and the limitations. ## Compatibility - Node.js 24+ or Bun 1.4+. -- `@bquery/bquery` 1.17.2 or later. `bq-on` handlers with several - `;`-separated statements (`$event.preventDefault(); add()`) are compiled only - by bQuery releases after 1.17.2, which also accept them at runtime. With - 1.17.2 the plugin leaves them to the runtime evaluator and warns. +- `@bquery/bquery` 1.18.0 or later. `bq-on` handlers with several + `;`-separated statements (`$event.preventDefault(); add()`) are compiled + like single expressions. - `csp` and `ssr` need the Vite dev server; other bundlers ignore them with one warning per build. webpack and Rspack use the same code paths through unplugin's adapters but are not covered by this package's test suite. diff --git a/bun.lock b/bun.lock index 15f0c05..300789b 100644 --- a/bun.lock +++ b/bun.lock @@ -8,7 +8,7 @@ "unplugin": "^3.4.0", }, "devDependencies": { - "@bquery/bquery": "^1.17.2", + "@bquery/bquery": "^1.18.0", "@types/bun": "^1.4.3", "@typescript-eslint/eslint-plugin": "^8.72.0", "@typescript-eslint/parser": "^8.72.0", @@ -22,7 +22,7 @@ "vite": "^8.3.5", }, "peerDependencies": { - "@bquery/bquery": "^1.17.2", + "@bquery/bquery": "^1.18.0", "@rspack/core": ">=1.0.0", "esbuild": ">=0.18.0", "rollup": ">=3.0.0", @@ -39,7 +39,7 @@ }, }, "packages": { - "@bquery/bquery": ["@bquery/bquery@1.17.2", "", { "bin": { "bquery-i18n": "bin/bquery-i18n.mjs", "bquery-view-compile": "bin/bquery-view-compile.mjs" } }, "sha512-An8W68G5AXZbRXjaZTEWTz+EWWPE3n7ySIbCRYu0xgsBJ1pD3svemGXOXtwDlEd5BXsYMx3Y2yuXCxFoGoyPHQ=="], + "@bquery/bquery": ["@bquery/bquery@1.18.0", "", { "bin": { "bquery-i18n": "bin/bquery-i18n.mjs", "create-bquery": "bin/create-bquery.mjs", "bquery-view-compile": "bin/bquery-view-compile.mjs" } }, "sha512-8rR0q4SXRccs/TsdB5IOh2y/4dS7+AYsXvUrOnhouJ81l8nSzPegzx/dJ41Blj3oPq+CpcuRLNa9NSBSXc7skg=="], "@cacheable/memory": ["@cacheable/memory@2.2.0", "", { "dependencies": { "@cacheable/utils": "^2.5.0", "@keyv/bigmap": "^1.3.1", "hookified": "^1.15.1", "keyv": "^5.6.0" } }, "sha512-CTLKqLItRCEixEAewD3/j9DB3/o96gpTPD4eJ1v+DGOlxZRZncRQkGYqqnAGCscYd6RNeXfGeiuCphsPtqyIfQ=="], diff --git a/package.json b/package.json index 1fbff8c..c9f7713 100644 --- a/package.json +++ b/package.json @@ -97,7 +97,7 @@ "unplugin": "^3.4.0" }, "peerDependencies": { - "@bquery/bquery": "^1.17.2", + "@bquery/bquery": "^1.18.0", "@rspack/core": ">=1.0.0", "esbuild": ">=0.18.0", "rollup": ">=3.0.0", @@ -122,7 +122,7 @@ } }, "devDependencies": { - "@bquery/bquery": "^1.17.2", + "@bquery/bquery": "^1.18.0", "@types/bun": "^1.4.3", "@typescript-eslint/eslint-plugin": "^8.72.0", "@typescript-eslint/parser": "^8.72.0", diff --git a/test/unit.test.ts b/test/unit.test.ts index c767122..6c18fd9 100644 --- a/test/unit.test.ts +++ b/test/unit.test.ts @@ -147,17 +147,47 @@ describe('generators', () => { expect(stats).toEqual({ total: 1, compiled: 1, skipped: [] }); }); - it('handles bq-on statement lists with any supported @bquery/bquery', async () => { - // `a(); b()` in bq-on compiles with bQuery releases after 1.17.2 (which - // register it in a separate statements map); 1.17.2 skips it (runtime - // fallback + warning). Either way the module is valid. + it('compiles bq-on statement lists into the statements map', async () => { const handler = '$event.preventDefault(); add()'; - const { code, stats } = buildViewModule(`
`, {}, false); - await transform(code, { format: 'esm', loader: 'js' }); - const skipped = stats.skipped.some((entry) => entry.expression === handler); - const registration = code.slice(0, code.indexOf('const template')); - expect(registration.includes(JSON.stringify(handler))).toBe(!skipped); - expect(stats.total).toBe(1); + const { code, stats } = buildViewModule( + `

`, + {}, + false + ); + expect(stats).toEqual({ total: 2, compiled: 2, skipped: [] }); + + // Run the emitted module against a stub registry to see what it registers. + const calls: Array unknown>>> = []; + const { code: cjs } = await transform(code, { format: 'cjs', loader: 'js' }); + const run = new Function('require', 'module', 'exports', cjs); + const module = { exports: {} as Record }; + run( + () => ({ + registerCompiledExpressions: (...args: (typeof calls)[number]) => calls.push(args), + }), + module, + module.exports + ); + expect(calls).toHaveLength(1); + const [expressions, statements] = calls[0]!; + expect(Object.keys(expressions!)).toEqual(['count']); + expect(Object.keys(statements!)).toEqual([handler]); + + // Both statements run in order; the last one's value is the handler's value. + const order: string[] = []; + const ctx = { + $event: { preventDefault: () => order.push('preventDefault') }, + add: () => (order.push('add'), 'added'), + }; + expect(statements![handler]!(ctx)).toBe('added'); + expect(order).toEqual(['preventDefault', 'add']); + expect(module.exports.default).toContain(`bq-on:submit="${handler}"`); + }); + + it('leaves a statement list outside bq-on to the runtime evaluator', () => { + const { stats } = buildViewModule('

', {}, false); + expect(stats.compiled).toBe(0); + expect(stats.skipped.map((entry) => entry.expression)).toEqual(['a(); b()']); }); it('compiles only bare view imports or the view marker', () => { diff --git a/test/vite.test.ts b/test/vite.test.ts index ce5fea9..bf902c3 100644 --- a/test/vite.test.ts +++ b/test/vite.test.ts @@ -304,6 +304,8 @@ describe('vite dev server', () => { const res = await get('/bquery'); expect(res.status).toBe(200); const html = await res.text(); + // A full-page template keeps its doctype (bQuery 1.18+), so no quirks mode. + expect(html).toMatch(/^/i); expect(html).toMatch(/]*>Rendered by bQuery<\/h1>/); expect(html).toContain('/@vite/client'); }); From c06112460ac29ac36a483ebca879956d95b3c0e0 Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 23 Oct 2026 12:09:52 +0000 Subject: [PATCH 2/2] docs: add the client entry through the SSR context bQuery's SSR renderers drop every