@hono/cli 0.1.1 → 0.1.3

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.
Files changed (3) hide show
  1. package/README.md +5 -0
  2. package/dist/cli.js +51 -77
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -255,6 +255,8 @@ hono optimize [entry] [options]
255
255
  **Options:**
256
256
 
257
257
  - `-o, --outfile <outfile>` - Output file
258
+ - `-m, --minify` - minify output file
259
+ - `-t, --target [target]` - environment target
258
260
 
259
261
  **Examples:**
260
262
 
@@ -267,6 +269,9 @@ hono optimize -o dist/app.js src/app.ts
267
269
 
268
270
  # Export bundled file with minification
269
271
  hono optimize -m
272
+
273
+ # Specify environment target
274
+ hono optimize -t es2024
270
275
  ```
271
276
 
272
277
  ## Tips
package/dist/cli.js CHANGED
@@ -70,61 +70,30 @@ import { dirname, join, resolve } from "path";
70
70
 
71
71
  // src/utils/build.ts
72
72
  import * as esbuild from "esbuild";
73
- async function* buildAndImportApp(filePath, options = {}) {
74
- let resolveApp;
75
- let appPromise;
76
- const preparePromise = () => {
77
- appPromise = new Promise((resolve4) => {
78
- resolveApp = resolve4;
73
+ import { extname } from "path";
74
+ import { pathToFileURL } from "url";
75
+ async function buildAndImportApp(filePath, options = {}) {
76
+ const ext = extname(filePath);
77
+ if ([".ts", ".tsx", ".jsx"].includes(ext)) {
78
+ const result = await esbuild.build({
79
+ entryPoints: [filePath],
80
+ bundle: true,
81
+ write: false,
82
+ format: "esm",
83
+ target: "node20",
84
+ jsx: "automatic",
85
+ jsxImportSource: "hono/jsx",
86
+ platform: "node",
87
+ external: options.external || []
79
88
  });
80
- };
81
- preparePromise();
82
- const context2 = await esbuild.context({
83
- entryPoints: [filePath],
84
- bundle: true,
85
- write: false,
86
- format: "esm",
87
- target: "node20",
88
- jsx: "automatic",
89
- jsxImportSource: "hono/jsx",
90
- platform: "node",
91
- external: options.external || [],
92
- plugins: [
93
- {
94
- name: "watch",
95
- setup(build2) {
96
- build2.onEnd(async (result) => {
97
- try {
98
- const code = result.outputFiles?.[0]?.text || "";
99
- const dataUrl = `data:text/javascript;base64,${Buffer.from(code).toString("base64")}`;
100
- const module = await import(dataUrl);
101
- const app = module.default;
102
- if (!app) {
103
- throw new Error("Failed to build app");
104
- }
105
- if (!app || typeof app.request !== "function") {
106
- throw new Error("No valid Hono app exported from the file");
107
- }
108
- try {
109
- resolveApp(app);
110
- } catch {
111
- }
112
- } catch (error) {
113
- console.error("Error building app", error);
114
- }
115
- });
116
- }
117
- }
118
- ]
119
- });
120
- await context2.watch();
121
- if (!options.watch) {
122
- await context2.dispose();
89
+ const code = result.outputFiles[0].text;
90
+ const dataUrl = `data:text/javascript;base64,${Buffer.from(code).toString("base64")}`;
91
+ const module = await import(dataUrl);
92
+ return module.default;
93
+ } else {
94
+ const module = await import(pathToFileURL(filePath).href);
95
+ return module.default;
123
96
  }
124
- do {
125
- yield await appPromise;
126
- preparePromise();
127
- } while (options.watch);
128
97
  }
129
98
 
130
99
  // src/commands/optimize/index.ts
@@ -139,10 +108,9 @@ function optimizeCommand(program2) {
139
108
  throw new Error(`Entry file ${entry} does not exist`);
140
109
  }
141
110
  const appFilePath = realpathSync(appPath);
142
- const buildIterator = buildAndImportApp(appFilePath, {
111
+ const app = await buildAndImportApp(appFilePath, {
143
112
  external: ["@hono/node-server"]
144
113
  });
145
- const app = (await buildIterator.next()).value;
146
114
  let routerName;
147
115
  let importStatement;
148
116
  let assignRouterStatement;
@@ -193,13 +161,13 @@ function optimizeCommand(program2) {
193
161
  plugins: [
194
162
  {
195
163
  name: "hono-optimize",
196
- setup(build2) {
164
+ setup(build3) {
197
165
  const honoPseudoImportPath = "hono-optimized-pseudo-import-path";
198
- build2.onResolve({ filter: /^hono$/ }, async (args) => {
166
+ build3.onResolve({ filter: /^hono$/ }, async (args) => {
199
167
  if (!args.importer) {
200
168
  return void 0;
201
169
  }
202
- const resolved = await build2.resolve(args.path, {
170
+ const resolved = await build3.resolve(args.path, {
203
171
  kind: "import-statement",
204
172
  resolveDir: args.resolveDir
205
173
  });
@@ -207,7 +175,7 @@ function optimizeCommand(program2) {
207
175
  path: join(dirname(resolved.path), honoPseudoImportPath)
208
176
  };
209
177
  });
210
- build2.onLoad({ filter: new RegExp(`/${honoPseudoImportPath}$`) }, async () => {
178
+ build3.onLoad({ filter: new RegExp(`/${honoPseudoImportPath}$`) }, async () => {
211
179
  return {
212
180
  contents: `
213
181
  import { HonoBase } from 'hono/hono-base'
@@ -235,7 +203,7 @@ import { existsSync as existsSync2, realpathSync as realpathSync2 } from "fs";
235
203
  import { resolve as resolve2 } from "path";
236
204
  var DEFAULT_ENTRY_CANDIDATES2 = ["src/index.ts", "src/index.tsx", "src/index.js", "src/index.jsx"];
237
205
  function requestCommand(program2) {
238
- program2.command("request").description("Send request to Hono app using app.request()").argument("[file]", "Path to the Hono app file").option("-P, --path <path>", "Request path", "/").option("-X, --method <method>", "HTTP method", "GET").option("-d, --data <data>", "Request body data").option("-w, --watch", "Watch for changes and re-run the request", false).option(
206
+ program2.command("request").description("Send request to Hono app using app.request()").argument("[file]", "Path to the Hono app file").option("-P, --path <path>", "Request path", "/").option("-X, --method <method>", "HTTP method", "GET").option("-d, --data <data>", "Request body data").option(
239
207
  "-H, --header <header>",
240
208
  "Custom headers",
241
209
  (value, previous) => {
@@ -244,15 +212,11 @@ function requestCommand(program2) {
244
212
  []
245
213
  ).action(async (file, options) => {
246
214
  const path = options.path || "/";
247
- const watch = options.watch;
248
- const buildIterator = getBuildIterator(file, watch);
249
- for await (const app of buildIterator) {
250
- const result = await executeRequest(app, path, options);
251
- console.log(JSON.stringify(result, null, 2));
252
- }
215
+ const result = await executeRequest(file, path, options);
216
+ console.log(JSON.stringify(result, null, 2));
253
217
  });
254
218
  }
255
- function getBuildIterator(appPath, watch) {
219
+ async function executeRequest(appPath, requestPath, options) {
256
220
  let entry;
257
221
  let resolvedAppPath;
258
222
  if (appPath) {
@@ -266,12 +230,12 @@ function getBuildIterator(appPath, watch) {
266
230
  throw new Error(`Entry file ${entry} does not exist`);
267
231
  }
268
232
  const appFilePath = realpathSync2(resolvedAppPath);
269
- return buildAndImportApp(appFilePath, {
270
- external: ["@hono/node-server"],
271
- watch
233
+ const app = await buildAndImportApp(appFilePath, {
234
+ external: ["@hono/node-server"]
272
235
  });
273
- }
274
- async function executeRequest(app, requestPath, options) {
236
+ if (!app || typeof app.request !== "function") {
237
+ throw new Error("No valid Hono app exported from the file");
238
+ }
275
239
  const url = new URL(requestPath, "http://localhost");
276
240
  const requestInit = {
277
241
  method: options.method || "GET"
@@ -307,7 +271,11 @@ async function executeRequest(app, requestPath, options) {
307
271
  function searchCommand(program2) {
308
272
  program2.command("search").argument("<query>", "Search query for Hono documentation").option("-l, --limit <number>", "Number of results to show (default: 5)", (value) => {
309
273
  const parsed = parseInt(value, 10);
310
- if (isNaN(parsed) || parsed < 1 || parsed > 20) {
274
+ if (isNaN(parsed) || parsed < 1) {
275
+ throw new Error(`Limit must be a number between 1 and 20. Received: ${value}
276
+ `);
277
+ }
278
+ if (parsed > 20) {
311
279
  console.warn("Limit must be a number between 1 and 20\n");
312
280
  return 5;
313
281
  }
@@ -502,7 +470,14 @@ var builtinMap = {
502
470
  }
503
471
  });
504
472
  function serveCommand(program2) {
505
- program2.command("serve").description("Start server").argument("[entry]", "entry file").option("-p, --port <port>", "port number").option("--show-routes", "show registered routes").option(
473
+ program2.command("serve").description("Start server").argument("[entry]", "entry file").option("-p, --port <port>", "port number", (value) => {
474
+ const parsed = parseInt(value, 10);
475
+ if (!/^\d+$/.test(value) || parsed < 0 || parsed > 65535) {
476
+ throw new Error(`Port must be a number between 0 and 65535. Received: ${value}
477
+ `);
478
+ }
479
+ return parsed;
480
+ }).option("--show-routes", "show registered routes").option(
506
481
  "--use <middleware>",
507
482
  "use middleware",
508
483
  (value, previous) => {
@@ -520,10 +495,9 @@ function serveCommand(program2) {
520
495
  app = new Hono();
521
496
  } else {
522
497
  const appFilePath = realpathSync3(appPath);
523
- const buildIterator = buildAndImportApp(appFilePath, {
498
+ app = await buildAndImportApp(appFilePath, {
524
499
  external: ["@hono/node-server"]
525
500
  });
526
- app = (await buildIterator.next()).value;
527
501
  }
528
502
  }
529
503
  const allFunctions = {};
@@ -556,7 +530,7 @@ function serveCommand(program2) {
556
530
  serve(
557
531
  {
558
532
  fetch: baseApp.fetch,
559
- port: options.port ? Number.parseInt(options.port) : 7070
533
+ port: options.port ?? 7070
560
534
  },
561
535
  (info) => {
562
536
  console.log(`Listening on http://localhost:${info.port}`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hono/cli",
3
- "version": "0.1.1",
3
+ "version": "0.1.3",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "hono": "dist/cli.js"