Skip to content

Commit 9e58af7

Browse files
docs: update for vite (#3308)
Update docs for vite
1 parent 6ddc0fb commit 9e58af7

18 files changed

Lines changed: 369 additions & 315 deletions

File tree

docs/canary/advanced/builder.md

Lines changed: 195 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,195 @@
1+
---
2+
description: |
3+
The Builder class is used to generate optimized assets for production.
4+
---
5+
6+
> [warn]: The `Builder` class was used during the alpha phase of Fresh 2 before
7+
> the Fresh vite plugin was released. You can skip this page if you're using
8+
> vite.
9+
10+
The `Builder` class is used to generate production assets of your app. You'll
11+
typically find it being created inside your project's `dev.ts` file.
12+
13+
```ts dev.ts
14+
import { Builder } from "fresh/dev";
15+
16+
const builder = new Builder({ target: "safari12" });
17+
18+
if (Deno.args.includes("build")) {
19+
// This creates a production build
20+
await builder.build();
21+
} else {
22+
// This starts a development server with live reload
23+
await builder.listen(() => import("./main.ts"));
24+
}
25+
```
26+
27+
## Options
28+
29+
You can customize the builder by passing options.
30+
31+
```ts dev.ts
32+
const builder = new Builder({
33+
// Browser target for generated code. Maps to https://esbuild.github.io/api/#target
34+
target?: string | string[];
35+
// The root directory of the project. All other paths will be resolved
36+
// against this if they're relative. (Default: `Deno.cwd()`)
37+
root?: string;
38+
// The path to your server entry point. (Default: `<root>/main.ts`)
39+
serverEntry?: string;
40+
// Where to write generated files when doing a production build.
41+
// (default: `<root>/_fresh/`)
42+
outDir?: string;
43+
// Path to static file directory. (Default: `<root>/static/`)
44+
staticDir?: string;
45+
// Path to island directory. (Default: `<root>/islands`)
46+
islandDir?: string;
47+
// Path to routes directory. (Default: `<root>/routes`)
48+
routeDir?: string;
49+
// File paths which should be ignored
50+
ignore?: RegExp[];
51+
// Optionally generate production source maps
52+
// See https://esbuild.github.io/api/#source-maps
53+
sourceMap?: {
54+
kind?: boolean | 'linked' | 'inline' | 'external' | 'both';
55+
sourceRoot?: string;
56+
sourcesContent?: boolean;
57+
};
58+
})
59+
```
60+
61+
## Registering islands
62+
63+
The builder is where you'll register files that contain islands. This is the
64+
same API that Fresh uses internally.
65+
66+
```ts dev.ts
67+
const builder = new Builder();
68+
69+
// Path to local island
70+
builder.registerIsland("path/to/my/Island.tsx");
71+
// File urls work too
72+
builder.registerIsland("file:///path/to/my/Island.tsx");
73+
// Also islands from jsr
74+
builder.registerIsland("jsr:@marvinh-test/fresh-island");
75+
```
76+
77+
## Adding build plugins
78+
79+
The `Builder` has a very simple processing mechanism for static files.
80+
81+
```ts dev.ts
82+
builder.onTransformStaticFile({
83+
pluginName: "My cool plugin",
84+
filter: /\.css$/,
85+
}, (args) => {
86+
// Prepend `body { background: red }` to every `.css` file
87+
const code = `body { background: red } ${args.text}`;
88+
89+
return {
90+
content: code,
91+
map: undefined, // Optional: source maps
92+
};
93+
});
94+
```
95+
96+
> [info]: Only static files in `static/` or the value you set `staticDir` to
97+
> will be processed. The builder won't process anything else.
98+
99+
## Testing
100+
101+
Testing applications with the `Builder` class involves creating a build snapshot
102+
and assigning that to each app instance.
103+
104+
```ts my-app.test.ts
105+
// Best to do this once instead of for every test case for
106+
// performance reasons.
107+
const builder = new Builder();
108+
const applySnapshot = await builder.build({ snapshot: "memory" });
109+
110+
function testApp() {
111+
const app = new App()
112+
.get("/", () => new Response("hello"))
113+
.fsRoutes();
114+
115+
// Applies build snapshot to this app instance.
116+
applySnapshot(app);
117+
return app;
118+
}
119+
120+
Deno.test("My Test", async () => {
121+
const handler = testApp().handler();
122+
123+
const response = await handler(new Request("http://localhost"));
124+
const text = await response.text();
125+
126+
if (text !== "hello") {
127+
throw new Error("fail");
128+
}
129+
});
130+
```
131+
132+
## Tailwindcss
133+
134+
[Tailwindcss](https://tailwindcss.com/) is a utility-first CSS framework that
135+
generates CSS out of the class names that are used in JSX. Since we use
136+
Tailwindcss ourselves here at Deno, Fresh ships with an official plugin for
137+
that.
138+
139+
### Usage
140+
141+
1. Set `nodeModulesDir` in `deno.json` to `"auto"` or `"manual"`
142+
143+
```diff deno.json
144+
{
145+
"name": "@example/my-cool-project"
146+
+ "nodeModulesDir": "auto",
147+
"imports": {
148+
...
149+
}
150+
}
151+
```
152+
153+
2. Run `deno install jsr:@fresh/plugin-tailwind`
154+
3. Update `dev.ts`:
155+
156+
```diff dev.ts
157+
import { Builder } from "fresh/dev";
158+
+ import { tailwind } from "@fresh/plugin-tailwind";
159+
160+
const builder = new Builder();
161+
+ tailwind(builder);
162+
```
163+
164+
4. Add `@import "tailwindcss";` at the top of your main stylesheet.
165+
166+
For more information on how to use tailwindcss, check out
167+
[their documentation](https://tailwindcss.com/docs/styling-with-utility-classes).
168+
169+
### Options
170+
171+
You can customize the tailwind plugin via the following options:
172+
173+
```ts dev.ts
174+
tailwind(builder, app, {
175+
// Exclude certain files from processing
176+
exclude: ["/admin/**", "*.temp.css"],
177+
// Force optimization (defaults to production mode)
178+
optimize: true,
179+
// Exclude base styles
180+
base: null,
181+
});
182+
```
183+
184+
### Tailwindcss v3
185+
186+
If can't update to the current version of tailwindcss we have a dedicated
187+
`@fresh/plugin-tailwindcss-v3` plugin that uses tailwindcss v3. That way you can
188+
decided on your own when it's best to update to v4.
189+
190+
```ts dev.ts
191+
import { Builder } from "fresh/dev";
192+
import { tailwind } from "@fresh/plugin-tailwind-v3";
193+
194+
tailwind(builder, {});
195+
```

docs/canary/advanced/forms.md

Lines changed: 13 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,9 @@ This example demonstrates how to handle `application/x-www-form-urlencoded`
2020
`<form>` submissions:
2121

2222
```tsx routes/subscribe.tsx
23-
import { Handlers } from "$fresh/server.ts";
23+
import { define } from "../utils.ts";
2424

25-
export const handler: Handlers = {
25+
export const handlers = define.handlers({
2626
async GET(req, ctx) {
2727
return await ctx.render();
2828
},
@@ -40,9 +40,9 @@ export const handler: Handlers = {
4040
headers,
4141
});
4242
},
43-
};
43+
});
4444

45-
export default function Subscribe() {
45+
export default define.page<typeof handlers>(function Subscribe() {
4646
return (
4747
<>
4848
<form method="post">
@@ -51,7 +51,7 @@ export default function Subscribe() {
5151
</form>
5252
</>
5353
);
54-
}
54+
});
5555
```
5656

5757
When the user submits the form, Deno will retrieve the `email` value using the
@@ -65,40 +65,30 @@ that this time, we have to explicitly declare the form's encoding to be
6565
`multipart/form-data`.
6666

6767
```tsx routes/subscribe.tsx
68-
import { Handlers, type PageProps } from "$fresh/server.ts";
68+
import { define } from "../utils.ts";
6969

70-
interface Props {
71-
message: string | null;
72-
}
73-
74-
export const handler: Handlers<Props> = {
70+
export const handler = define.handlers({
7571
async GET(req, ctx) {
76-
return await ctx.render({
77-
message: null,
78-
});
72+
return { data: { message: null } };
7973
},
8074
async POST(req, ctx) {
8175
const form = await req.formData();
8276
const file = form.get("my-file") as File;
8377

8478
if (!file) {
85-
return ctx.render({
86-
message: `Please try again`,
87-
});
79+
return { data: { message: "Please try again" } };
8880
}
8981

9082
const name = file.name;
9183
const contents = await file.text();
9284

9385
console.log(contents);
9486

95-
return ctx.render({
96-
message: `${name} uploaded!`,
97-
});
87+
return { data: { message: `${name} uploaded!` } };
9888
},
99-
};
89+
});
10090

101-
export default function Upload(props: PageProps<Props>) {
91+
export default define.page<typeof handlers>(function Upload(props) {
10292
const { message } = props.data;
10393
return (
10494
<>
@@ -109,7 +99,7 @@ export default function Upload(props: PageProps<Props>) {
10999
{message ? <p>{message}</p> : null}
110100
</>
111101
);
112-
}
102+
});
113103
```
114104

115105
## A note of caution

docs/canary/advanced/index.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
description: |
3+
This chapter goes over some advanced concepts of Fresh.
4+
---
5+
6+
This section of the documentation describes advanced functionality of Fresh.

docs/canary/advanced/partials.md

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,10 @@ The quickest way to get started is to enable partials for every page in
1818
`routes/_app.tsx` by making the following changes.
1919

2020
```diff routes/_app.tsx
21-
import { PageProps } from "$fresh/server.ts";
22-
+ import { Partial } from "$fresh/runtime.ts";
21+
import { define } from "../utils.ts";
22+
+ import { Partial } from "fresh/runtime";
2323

24-
export default function App({ Component }: PageProps) {
24+
export default define.page(function App({ Component }) {
2525
return (
2626
<html>
2727
<head>
@@ -37,7 +37,7 @@ The quickest way to get started is to enable partials for every page in
3737
</body>
3838
</html>
3939
);
40-
}
40+
});
4141
```
4242

4343
By adding the `f-client-nav` attribute, we enable partials for every element
@@ -81,7 +81,9 @@ documentation (marked green here).
8181
The code for such a page (excluding styling) might look like this:
8282

8383
```tsx routes/docs/[id].tsx
84-
export default defineRoute(async (req, ctx) => {
84+
import { define } from "../../utils.ts";
85+
86+
export default define.page(async (ctx) => {
8587
const content = await loadContent(ctx.params.id);
8688

8789
return (
@@ -102,8 +104,8 @@ An optimal route that only renders the content instead of the outer layout with
102104
the sidebar might look like this respectively.
103105

104106
```tsx routes/partials/docs/[id].tsx
105-
import { defineRoute, RouteConfig } from "$fresh/server.ts";
106-
import { Partial } from "$fresh/runtime.ts";
107+
import { define } from "../utils.ts";
108+
import { Partial } from "fresh/runtime";
107109

108110
// We only want to render the content, so disable
109111
// the `_app.tsx` template as well as any potentially
@@ -113,7 +115,7 @@ export const config: RouteConfig = {
113115
skipInheritedLayouts: true,
114116
};
115117

116-
export default defineRoute(async (req, ctx) => {
118+
export default define.page(async (ctx) => {
117119
const content = await loadContent(ctx.params.id);
118120

119121
// Only render the new content

docs/canary/advanced/vite.md

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
---
2+
description: |
3+
Configure the fresh vite plugin.
4+
---
5+
6+
The Fresh vite plugin can be optionally configured in the following ways:
7+
8+
```ts vite.config.ts
9+
import { defineConfig, type Plugin } from "vite";
10+
import { fresh } from "@fresh/plugin-vite";
11+
12+
export default defineConfig({
13+
plugins: [
14+
fresh({
15+
// Path to main server entry file. Default: main.ts
16+
serverEntry: "./path/to/main.ts",
17+
// Path to main client entry file. Default: client.ts
18+
clientEntry: "./path/to/client.ts",
19+
// Path to islands directory. Default: ./islands
20+
islandsDir: "./islands",
21+
// Path to routes directory. Default: ./routes
22+
routeDir: "./routes",
23+
// Optional regex to ignore folders when crawling the routes and
24+
// island directory.
25+
ignore: [/[\\/]+some-folder[\\/]+/],
26+
// Additional specifiers to treat as island files. This is used
27+
// for declaring islands from third party packages.
28+
islandSpecifiers: ["@example/my-remote-island"],
29+
}),
30+
],
31+
});
32+
```

0 commit comments

Comments
 (0)