@b9g/shovel 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/CHANGELOG.md CHANGED
@@ -2,6 +2,45 @@
2
2
 
3
3
  All notable changes to Shovel will be documented in this file.
4
4
 
5
+ ## [0.2.16] - 2026-02-26
6
+
7
+ ### Bug Fixes
8
+
9
+ - **`@b9g/shovel`** - `build.minify` config in `shovel.json` now propagates to client asset builds. Previously client JS/CSS was always minified regardless of the setting (closes #67)
10
+
11
+ ## @b9g/router 0.2.5 - 2026-02-25
12
+
13
+ ### Bug Fixes
14
+
15
+ - **`@b9g/router`** - Trailing slash middleware now also redirects when a catch-all route or error-handling middleware returns a 404 Response (not just thrown `NotFound` errors). In 0.2.4 the middleware only caught thrown errors, so catch-all routes returning 404 responses would not trigger the redirect
16
+
17
+ ## @b9g/router 0.2.4 - 2026-02-25
18
+
19
+ ### Bug Fixes
20
+
21
+ - **`@b9g/router`** - Trailing slash middleware now only redirects as a last resort. Previously it eagerly redirected before route matching, so routes explicitly defined with (or without) a trailing slash would always be redirected. Now the middleware yields to route matching first and only redirects on 404
22
+ - **`@b9g/router`** - Added `"append"` as an alias for `"add"` in `trailingSlash()` mode
23
+
24
+ ## [0.2.15] - 2026-02-25
25
+
26
+ ### Bug Fixes
27
+
28
+ - **`create-shovel`** - Fixed linting in generated JS projects (missing browser globals)
29
+ - **`create-shovel`** - Fixed linting in generated Crank projects (now uses `eslint-plugin-crank`)
30
+ - **`create-shovel`** - Fixed Crank `Counter` to use `this.refresh()` callback pattern
31
+
32
+ ## [0.2.14] - 2026-02-24
33
+
34
+ ### Features
35
+
36
+ - **`create-shovel`** - All static-site and full-stack templates now use bundled client entry points through Shovel's asset pipeline instead of CDN links or inline scripts
37
+ - **`create-shovel`** - Added type declarations (`env.d.ts`) for htmx and Alpine in TypeScript projects
38
+ - **`create-shovel`** - Generated projects include ESLint configuration
39
+
40
+ ### Bug Fixes
41
+
42
+ - **`@b9g/platform`** - Added `Window.addEventListener` overload for ServiceWorker event types in `globals.d.ts`
43
+
5
44
  ## [0.2.13] - 2026-02-24
6
45
 
7
46
  ### Bug Fixes
package/bin/cli.js CHANGED
@@ -75,7 +75,7 @@ program.command("develop <entrypoint>").description("Start development server wi
75
75
  DEFAULTS.WORKERS
76
76
  ).option("--platform <name>", "Runtime platform (node, cloudflare, bun)").action(async (entrypoint, options) => {
77
77
  checkPlatformReexec(options);
78
- const { developCommand } = await import("../src/_chunks/develop-I74XUWOE.js");
78
+ const { developCommand } = await import("../src/_chunks/develop-BR7WCNBK.js");
79
79
  await developCommand(entrypoint, options, config);
80
80
  });
81
81
  program.command("create [name]").description("Create a new Shovel project").action(async (name) => {
@@ -91,7 +91,7 @@ program.command("build <entrypoint>").description("Build app for production").op
91
91
  "Run ServiceWorker lifecycle after build (install or activate, default: activate)"
92
92
  ).action(async (entrypoint, options) => {
93
93
  checkPlatformReexec(options);
94
- const { buildCommand } = await import("../src/_chunks/build-YOORTV6F.js");
94
+ const { buildCommand } = await import("../src/_chunks/build-EGT4OE4O.js");
95
95
  await buildCommand(entrypoint, options, config);
96
96
  process.exit(0);
97
97
  });
package/bin/create.js CHANGED
@@ -294,6 +294,11 @@ async function createProject(config, projectPath) {
294
294
  devDependencies["@eslint/js"] = "^10.0.0";
295
295
  if (config.typescript) {
296
296
  devDependencies["typescript-eslint"] = "^8.0.0";
297
+ } else {
298
+ devDependencies["globals"] = "^16.0.0";
299
+ }
300
+ if (isCrank) {
301
+ devDependencies["eslint-plugin-crank"] = "^0.2.0";
297
302
  }
298
303
  }
299
304
  const scripts = {
@@ -358,23 +363,34 @@ async function createProject(config, projectPath) {
358
363
  );
359
364
  }
360
365
  if (hasClientBundle) {
366
+ const crankImport = isCrank ? `import crank from "eslint-plugin-crank";
367
+ ` : "";
368
+ const crankConfig = isCrank ? `
369
+ { plugins: { crank }, rules: crank.configs.recommended.rules },` : "";
361
370
  let eslintConfig;
362
371
  if (config.typescript) {
363
372
  eslintConfig = `import js from "@eslint/js";
364
373
  import tseslint from "typescript-eslint";
365
-
374
+ ${crankImport}
366
375
  export default tseslint.config(
367
376
  js.configs.recommended,
368
377
  tseslint.configs.recommended,
369
- { ignores: ["dist/"] },
378
+ { ignores: ["dist/"] },${crankConfig}
370
379
  );
371
380
  `;
372
381
  } else {
382
+ let langOpts = "globals: globals.browser";
383
+ let filesOpt = "";
384
+ if (isCrank && config.useJSX) {
385
+ filesOpt = `files: ["**/*.{js,jsx}"], `;
386
+ langOpts += ", parserOptions: { ecmaFeatures: { jsx: true } }";
387
+ }
373
388
  eslintConfig = `import js from "@eslint/js";
374
-
389
+ import globals from "globals";
390
+ ${crankImport}
375
391
  export default [
376
- js.configs.recommended,
377
- { ignores: ["dist/"] },
392
+ { ${filesOpt}...js.configs.recommended, languageOptions: { ${langOpts} } },
393
+ { ignores: ["dist/"] },${crankConfig}
378
394
  ];
379
395
  `;
380
396
  }
@@ -783,8 +799,7 @@ export function Page({title, children, clientUrl}${t ? ": {title: string, childr
783
799
  export function *Counter(${t ? "this: Context" : ""}) {
784
800
  let count = 0;
785
801
  const handleClick = () => {
786
- count++;
787
- this.refresh();
802
+ this.refresh(() => count++);
788
803
  };
789
804
  for ({} of this) {
790
805
  yield <button onclick={handleClick}>Clicked: {count}</button>;
@@ -866,8 +881,7 @@ export function Page({title, children, clientUrl}${t ? ": {title: string, childr
866
881
  export function *Counter(${t ? "this: Context" : ""}) {
867
882
  let count = 0;
868
883
  const handleClick = () => {
869
- count++;
870
- this.refresh();
884
+ this.refresh(() => count++);
871
885
  };
872
886
  for ({} of this) {
873
887
  yield jsx\`<button onclick=\${handleClick}>Clicked: \${count}</button>\`;
@@ -1261,8 +1275,7 @@ export function Page({title, children, clientUrl}${t ? ": {title: string, childr
1261
1275
  export function *Counter(${t ? "this: Context" : ""}) {
1262
1276
  let count = 0;
1263
1277
  const handleClick = () => {
1264
- count++;
1265
- this.refresh();
1278
+ this.refresh(() => count++);
1266
1279
  };
1267
1280
  for ({} of this) {
1268
1281
  yield <button onclick={handleClick}>Clicked: {count}</button>;
@@ -1363,8 +1376,7 @@ export function Page({title, children, clientUrl}${t ? ": {title: string, childr
1363
1376
  export function *Counter(${t ? "this: Context" : ""}) {
1364
1377
  let count = 0;
1365
1378
  const handleClick = () => {
1366
- count++;
1367
- this.refresh();
1379
+ this.refresh(() => count++);
1368
1380
  };
1369
1381
  for ({} of this) {
1370
1382
  yield jsx\`<button onclick=\${handleClick}>Clicked: \${count}</button>\`;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@b9g/shovel",
3
- "version": "0.2.14",
3
+ "version": "0.2.16",
4
4
  "description": "ServiceWorker-first universal deployment platform. Write ServiceWorker apps once, deploy anywhere (Node/Bun/Cloudflare). Registry-based multi-app orchestration.",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -35,7 +35,7 @@
35
35
  "@b9g/assets": "^0.2.1",
36
36
  "@b9g/crank": "^0.7.7",
37
37
  "@b9g/libuild": "^0.1.24",
38
- "@b9g/router": "^0.2.3",
38
+ "@b9g/router": "^0.2.5",
39
39
  "@eslint/js": "^9.0.0",
40
40
  "@logtape/file": "^2.0.0",
41
41
  "@types/bun": "^1.3.4",
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  ServerBundler,
3
3
  loadPlatformModule
4
- } from "./chunk-DRCLXHTF.js";
4
+ } from "./chunk-TPEOHBYY.js";
5
5
  import {
6
6
  findProjectRoot,
7
7
  findWorkspaceRoot
@@ -44,6 +44,7 @@ function normalizePath(basePath) {
44
44
  }
45
45
  function assetsPlugin(options = {}) {
46
46
  const outDir = options.outDir ?? "dist";
47
+ const minify = options.minify ?? true;
47
48
  const sharedManifest = options.sharedManifest;
48
49
  const manifest = {
49
50
  assets: {},
@@ -114,7 +115,7 @@ function assetsPlugin(options = {}) {
114
115
  target: ["es2022", "chrome90"],
115
116
  platform: "browser",
116
117
  write: false,
117
- minify: true,
118
+ minify,
118
119
  // outdir is required for esbuild to know where to put extracted CSS and chunks
119
120
  outdir: outDir,
120
121
  // Apply polyfills and user-provided build options
@@ -216,7 +217,7 @@ function assetsPlugin(options = {}) {
216
217
  entryPoints: [entryPath],
217
218
  bundle: true,
218
219
  write: false,
219
- minify: true,
220
+ minify,
220
221
  // outdir required for esbuild to generate output paths
221
222
  outdir: outDir,
222
223
  plugins,
@@ -871,6 +872,7 @@ var ServerBundler = class {
871
872
  assetsPlugin({
872
873
  outDir: outputDir,
873
874
  plugins: userPlugins,
875
+ minify,
874
876
  jsx: jsxOptions.jsx,
875
877
  jsxFactory: jsxOptions.jsxFactory,
876
878
  jsxFragment: jsxOptions.jsxFragment,
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  ServerBundler,
3
3
  loadPlatformModule
4
- } from "./chunk-DRCLXHTF.js";
4
+ } from "./chunk-TPEOHBYY.js";
5
5
  import {
6
6
  DEFAULTS
7
7
  } from "./chunk-7GONPLNW.js";