Skip to content

Commit aa35367

Browse files
authored
Merge pull request #5 from d2verb/feat/simpler-serve
simplify serve()
2 parents 42bbb59 + 50b3e68 commit aa35367

7 files changed

Lines changed: 94 additions & 77 deletions

File tree

README.md

Lines changed: 11 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ deno run -A page.tsx
2525
```tsx
2626
/** @jsxImportSource https://esm.sh/preact@10 */
2727
import { useEffect, useState } from "https://esm.sh/preact@10/hooks";
28+
import { serve } from "https://esm.sh/jsr/@d2verb/pera";
2829

2930
type Props = { initial?: number };
3031

@@ -65,21 +66,17 @@ export function App({ initial = 0 }: Props) {
6566
);
6667
}
6768

68-
if (import.meta.main) {
69-
const { serve } = await import("jsr:@d2verb/pera");
70-
71-
await serve({
72-
port: 8080,
73-
title: "Counter Sample",
74-
moduleUrl: import.meta.url,
75-
props: { initial: 4 },
76-
api: {
77-
"/students/:name": {
78-
GET: (_, ctx) => new Response(`Hello, ${ctx.params.name}!`),
79-
},
69+
await serve({
70+
port: 8080,
71+
title: "Counter Sample",
72+
moduleUrl: import.meta.url,
73+
props: { initial: 4 },
74+
api: {
75+
"/students/:name": {
76+
GET: (_, ctx) => new Response(`Hello, ${ctx.params.name}!`),
8077
},
81-
});
82-
}
78+
},
79+
});
8380
```
8481

8582
Open your browser at http://localhost:8080 and see your Preact app running.

deno.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@d2verb/pera",
3-
"version": "0.0.6",
3+
"version": "0.0.7",
44
"license": "MIT",
55
"exports": {
66
".": "./src/mod.ts",

examples/counter.tsx

Lines changed: 11 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
/** @jsxImportSource https://esm.sh/preact@10 */
22
import { useEffect, useState } from "https://esm.sh/preact@10/hooks";
3+
import { serve } from "https://esm.sh/jsr/@d2verb/pera";
34

45
type Props = { initial?: number };
56

@@ -40,18 +41,14 @@ export function App({ initial = 0 }: Props) {
4041
);
4142
}
4243

43-
if (import.meta.main) {
44-
const { serve } = await import("jsr:@d2verb/pera");
45-
46-
await serve({
47-
port: 8080,
48-
title: "Counter Sample",
49-
moduleUrl: import.meta.url,
50-
props: { initial: 4 },
51-
api: {
52-
"/students/:name": {
53-
GET: (_, ctx) => new Response(`Hello, ${ctx.params.name}!`),
54-
},
44+
await serve({
45+
port: 8080,
46+
title: "Counter Sample",
47+
moduleUrl: import.meta.url,
48+
props: { initial: 4 },
49+
api: {
50+
"/students/:name": {
51+
GET: (_, ctx) => new Response(`Hello, ${ctx.params.name}!`),
5552
},
56-
});
57-
}
53+
},
54+
});

src/cli.ts

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ if (args.length === 0 || args[0] !== "new" || args.length > 2) {
4040
const path = args.length === 2 ? args[1] : "app.tsx";
4141
const content = `/** @jsxImportSource https://esm.sh/preact@10 */
4242
import { useState } from "https://esm.sh/preact@10/hooks";
43+
import { serve } from "https://esm.sh/jsr/@d2verb/pera";
4344
4445
export function App() {
4546
const [counter, setCounter] = useState(0);
@@ -53,15 +54,12 @@ export function App() {
5354
);
5455
}
5556
56-
if (import.meta.main) {
57-
const { serve } = await import("jsr:@d2verb/pera");
58-
59-
await serve({
60-
port: 8080,
61-
title: "Counter",
62-
moduleUrl: import.meta.url,
63-
});
64-
}`;
57+
await serve({
58+
port: 8080,
59+
title: "Counter",
60+
moduleUrl: import.meta.url,
61+
});
62+
`;
6563

6664
if (await fileExists(path)) {
6765
console.error(`File ${path} already exists`);

src/mod.ts

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,48 @@
66
* @module
77
*/
88

9-
export * from "./server.ts";
9+
import type { PeraOptions } from "./types.ts";
10+
11+
/**
12+
* Serve the Pera app. serve() implicitly treats a component named App as
13+
* the root component. Therefore, you must define a component named App.
14+
*
15+
* @example Basic Example
16+
* ```ts
17+
* await serve({
18+
* port: 8080,
19+
* moduleUrl: import.meta.url, // This is required
20+
* });
21+
* ```
22+
*
23+
* @example With API
24+
* ```ts
25+
* await serve({
26+
* port: 8080,
27+
* moduleUrl: import.meta.url,
28+
* api: {
29+
* // The actual path is `/_pera/api/students/:name`
30+
* "/students/:name": {
31+
* GET: (_, ctx) => new Response(`Hello, ${ctx.params.name}!`),
32+
* },
33+
* },
34+
* });
35+
* ```
36+
*
37+
* @param opts The options for the Pera app.
38+
*/
39+
export async function serve(opts: PeraOptions): Promise<void> {
40+
if (typeof Deno === "undefined") return;
41+
42+
const { serveImpl } = await import("./server.ts");
43+
return serveImpl(opts);
44+
}
45+
1046
export type {
1147
ApiContext,
1248
ApiFn,
1349
ApiMap,
1450
ApiMethod,
1551
ApiMethodMap,
1652
} from "./api.ts";
53+
export type { PeraOptions };

src/server.ts

Lines changed: 4 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,48 +1,14 @@
1-
import { type ApiMap, type ApiMethod, findEndpoint } from "./api.ts";
1+
import { type ApiMethod, findEndpoint } from "./api.ts";
22
import { escapeHtml, filePathFromModuleUrl } from "./utils.ts";
3+
import type { PeraOptions } from "./types.ts";
34
import { transpile } from "@deno/emit";
45

56
/**
6-
* The options for the Pera app.
7-
*/
8-
export type PeraOptions = {
9-
/** The port to listen on. (Default: 8080) */
10-
port?: number;
11-
/** The title of the app. This value will be used as the title of the HTML document. (Default: "Pera App") */
12-
title?: string;
13-
/** The props to pass to the App component. (Default: {}) */
14-
// deno-lint-ignore no-explicit-any
15-
props?: Record<string, any>;
16-
/** The URL of the module to import the App component from. */
17-
moduleUrl: string;
18-
/** The ID of the root element to render the App component into. (Default: "root") */
19-
rootId?: string;
20-
/** Whether to enable hot module replacement. (Default: true) */
21-
hmr?: boolean;
22-
/** The API endpoints to expose to the client. (Default: {}) */
23-
api?: ApiMap;
24-
};
25-
26-
/**
27-
* Serve the Pera app. serve() implicitly treats a component named App as
28-
* the root component. Therefore, you must define a component named App.
29-
*
30-
* @example Basic Example
31-
* ```ts
32-
* // Make sure to import the serve function in the main module.
33-
* if (import.meta.main) {
34-
* const { serve } = await import("jsr:@d2verb/pera");
35-
*
36-
* await serve({
37-
* port: 8080,
38-
* moduleUrl: import.meta.url,
39-
* });
40-
* }
41-
* ```
7+
* The implementation of the serve() function.
428
*
439
* @param opts The options for the Pera app.
4410
*/
45-
export function serve(opts: PeraOptions) {
11+
export function serveImpl(opts: PeraOptions) {
4612
const port = opts.port ?? 8080;
4713
const title = opts.title ?? "Pera App";
4814
const rootId = opts.rootId ?? "root";

src/types.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import type { ApiMap } from "./api.ts";
2+
3+
/**
4+
* The options for the Pera app.
5+
*/
6+
export type PeraOptions = {
7+
/** The port to listen on. (Default: 8080) */
8+
port?: number;
9+
/** The title of the app. This value will be used as the title of the HTML document. (Default: "Pera App") */
10+
title?: string;
11+
/** The props to pass to the App component. (Default: {}) */
12+
// deno-lint-ignore no-explicit-any
13+
props?: Record<string, any>;
14+
/** The URL of the module to import the App component from. */
15+
moduleUrl: string;
16+
/** The ID of the root element to render the App component into. (Default: "root") */
17+
rootId?: string;
18+
/** Whether to enable hot module replacement. (Default: true) */
19+
hmr?: boolean;
20+
/** The API endpoints to expose to the client. (Default: {}) */
21+
api?: ApiMap;
22+
};

0 commit comments

Comments
 (0)