Skip to content

Commit 6178b02

Browse files
GregBrimbledaisyfaithauma
authored andcommitted
Remove .clone warning from Pages Functions docs (#22025)
1 parent 832abd1 commit 6178b02

File tree

5 files changed

+108
-116
lines changed

5 files changed

+108
-116
lines changed

src/content/docs/pages/functions/plugins/hcaptcha.mdx

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ sidebar:
55
order: 1
66
---
77

8-
import { Render } from "~/components"
8+
import { Render } from "~/components";
99

1010
The hCaptcha Pages Plugin validates hCaptcha tokens.
1111

@@ -37,8 +37,6 @@ export const onRequestPost: PagesFunction[] = [
3737
];
3838
```
3939

40-
<Render file="request-dot-clone-warning" product="workers" />
41-
4240
This Plugin only exposes a single route. It will be available wherever it is mounted. In the above example, because it is mounted in `functions/register.ts`, it will validate requests to `/register`. The Plugin is mounted with a single object parameter with the following properties.
4341

4442
[`secret`](https://dashboard.hcaptcha.com/settings) (mandatory) and [`sitekey`](https://dashboard.hcaptcha.com/sites) (optional) can both be found in your hCaptcha dashboard.

src/content/docs/pages/functions/plugins/index.mdx

Lines changed: 104 additions & 104 deletions
Original file line numberDiff line numberDiff line change
@@ -3,95 +3,90 @@ pcx_content_type: concept
33
title: Pages Plugins
44
sidebar:
55
order: 9
6-
76
---
87

9-
import { DirectoryListing, Render } from "~/components"
8+
import { DirectoryListing, Render } from "~/components";
109

1110
Cloudflare maintains a number of official Pages Plugins for you to use in your Pages projects:
1211

1312
<DirectoryListing />
1413

15-
***
14+
---
1615

1716
## Author a Pages Plugin
1817

1918
A Pages Plugin is a Pages Functions distributable which includes built-in routing and functionality. Developers can include a Plugin as a part of their Pages project wherever they chose, and can pass it some configuration options. The full power of Functions is available to Plugins, including middleware, parameterized routes, and static assets.
2019

2120
For example, a Pages Plugin could:
2221

23-
* Intercept HTML pages and inject in a third-party script.
24-
* Proxy a third-party service's API.
25-
* Validate authorization headers.
26-
* Provide a full admin web app experience.
27-
* Store data in KV or Durable Objects.
28-
* Server-side render (SSR) webpages with data from a CMS.
29-
* Report errors and track performance.
22+
- Intercept HTML pages and inject in a third-party script.
23+
- Proxy a third-party service's API.
24+
- Validate authorization headers.
25+
- Provide a full admin web app experience.
26+
- Store data in KV or Durable Objects.
27+
- Server-side render (SSR) webpages with data from a CMS.
28+
- Report errors and track performance.
3029

3130
A Pages Plugin is essentially a library that developers can use to augment their existing Pages project with a deep integration to Functions.
3231

3332
## Use a Pages Plugin
3433

3534
Developers can enhance their projects by mounting a Pages Plugin at a route of their application. Plugins will provide instructions of where they should typically be mounted (for example, an admin interface might be mounted at `functions/admin/[[path]].ts`, and an error logger might be mounted at `functions/_middleware.ts`). Additionally, each Plugin may take some configuration (for example, with an API token).
3635

37-
***
36+
---
3837

3938
## Static form example
4039

4140
In this example, you will build a Pages Plugin and then include it in a project.
4241

4342
The first Plugin should:
4443

45-
* intercept HTML forms.
46-
* store the form submission in [KV](/kv/api/).
47-
* respond to submissions with a developer's custom response.
44+
- intercept HTML forms.
45+
- store the form submission in [KV](/kv/api/).
46+
- respond to submissions with a developer's custom response.
4847

4948
### 1. Create a new Pages Plugin
5049

5150
Create a `package.json` with the following:
5251

5352
```json
5453
{
55-
"name": "@cloudflare/static-form-interceptor",
56-
"main": "dist/index.js",
57-
"types": "index.d.ts",
58-
"files": ["dist", "index.d.ts", "tsconfig.json"],
59-
"scripts": {
60-
"build": "npx wrangler pages functions build --plugin --outdir=dist",
61-
"prepare": "npm run build"
62-
}
54+
"name": "@cloudflare/static-form-interceptor",
55+
"main": "dist/index.js",
56+
"types": "index.d.ts",
57+
"files": ["dist", "index.d.ts", "tsconfig.json"],
58+
"scripts": {
59+
"build": "npx wrangler pages functions build --plugin --outdir=dist",
60+
"prepare": "npm run build"
61+
}
6362
}
6463
```
6564

6665
:::note
6766

68-
6967
The `npx wrangler pages functions build` command supports a number of arguments, including:
7068

71-
* `--plugin` which tells the command to build a Pages Plugin, (rather than Pages Functions as part of a Pages project)
72-
* `--outdir` which allows you to specify where to output the built Plugin
73-
* `--external` which can be used to avoid bundling external modules in the Plugin
74-
* `--watch` argument tells the command to watch for changes to the source files and rebuild the Plugin automatically
69+
- `--plugin` which tells the command to build a Pages Plugin, (rather than Pages Functions as part of a Pages project)
70+
- `--outdir` which allows you to specify where to output the built Plugin
71+
- `--external` which can be used to avoid bundling external modules in the Plugin
72+
- `--watch` argument tells the command to watch for changes to the source files and rebuild the Plugin automatically
7573

7674
For more information about the available arguments, run `npx wrangler pages functions build --help`.
7775

78-
7976
:::
8077

8178
In our example, `dist/index.js` will be the entrypoint to your Plugin. This is a generated file built by Wrangler with the `npm run build` command. Add the `dist/` directory to your `.gitignore`.
8279

8380
Next, create a `functions` directory and start coding your Plugin. The `functions` folder will be mounted at some route by the developer, so consider how you want to structure your files. Generally:
8481

85-
* if you want your Plugin to run on a single route of the developer's choice (for example, `/foo`), create a `functions/index.ts` file.
86-
* if you want your Plugin to be mounted and serve all requests beyond a certain path (for example, `/admin/login` and `/admin/dashboard`), create a `functions/[[path]].ts` file.
87-
* if you want your Plugin to intercept requests but fallback on either other Functions or the project's static assets, create a `functions/_middleware.ts` file.
82+
- if you want your Plugin to run on a single route of the developer's choice (for example, `/foo`), create a `functions/index.ts` file.
83+
- if you want your Plugin to be mounted and serve all requests beyond a certain path (for example, `/admin/login` and `/admin/dashboard`), create a `functions/[[path]].ts` file.
84+
- if you want your Plugin to intercept requests but fallback on either other Functions or the project's static assets, create a `functions/_middleware.ts` file.
8885

8986
:::note[Do not include the mounted path in your Plugin]
9087

91-
9288
Your Plugin should not use the mounted path anywhere in the file structure (for example, `/foo` or `/admin`). Developers should be free to mount your Plugin wherever they choose, but you can make recommendations of how you expect this to be mounted in your `README.md`.
9389

94-
9590
:::
9691

9792
You are free to use as many different files as you need. The structure of a Plugin is exactly the same as Functions in a Pages project today, except that the handlers receive a new property of their parameter object, `pluginArgs`. This property is the initialization parameter that a developer passes when mounting a Plugin. You can use this to receive API tokens, KV/Durable Object namespaces, or anything else that your Plugin needs to work.
@@ -100,44 +95,48 @@ Returning to your static form example, if you want to intercept requests and ove
10095

10196
```typescript
10297
class FormHandler {
103-
element(element) {
104-
const name = element.getAttribute('data-static-form-name')
105-
element.setAttribute('method', 'POST')
106-
element.removeAttribute('action')
107-
element.append(`<input type="hidden" name="static-form-name" value="${name}" />`, { html: true })
108-
}
98+
element(element) {
99+
const name = element.getAttribute("data-static-form-name");
100+
element.setAttribute("method", "POST");
101+
element.removeAttribute("action");
102+
element.append(
103+
`<input type="hidden" name="static-form-name" value="${name}" />`,
104+
{ html: true },
105+
);
106+
}
109107
}
110108

111109
export const onRequestGet = async (context) => {
112-
// We first get the original response from the project
113-
const response = await context.next()
110+
// We first get the original response from the project
111+
const response = await context.next();
114112

115-
// Then, using HTMLRewriter, we transform `form` elements with a `data-static-form-name` attribute, to tell them to POST to the current page
116-
return new HTMLRewriter().on('form[data-static-form-name]', new FormHandler()).transform(response)
117-
}
113+
// Then, using HTMLRewriter, we transform `form` elements with a `data-static-form-name` attribute, to tell them to POST to the current page
114+
return new HTMLRewriter()
115+
.on("form[data-static-form-name]", new FormHandler())
116+
.transform(response);
117+
};
118118

119119
export const onRequestPost = async (context) => {
120-
// Parse the form
121-
const formData = await context.request.formData()
122-
const name = formData.get('static-form-name')
123-
const entries = Object.fromEntries([...formData.entries()].filter(([name]) => name !== 'static-form-name'))
124-
125-
// Get the arguments given to the Plugin by the developer
126-
const { kv, respondWith } = context.pluginArgs
127-
128-
129-
// Store form data in KV under key `form-name:YYYY-MM-DDTHH:MM:SSZ`
130-
const key = `${name}:${new Date().toISOString()}`
131-
context.waitUntil(kv.put(name, JSON.stringify(entries)))
132-
133-
// Respond with whatever the developer wants
134-
const response = await respondWith({ formData })
135-
return response
136-
}
120+
// Parse the form
121+
const formData = await context.request.formData();
122+
const name = formData.get("static-form-name");
123+
const entries = Object.fromEntries(
124+
[...formData.entries()].filter(([name]) => name !== "static-form-name"),
125+
);
126+
127+
// Get the arguments given to the Plugin by the developer
128+
const { kv, respondWith } = context.pluginArgs;
129+
130+
// Store form data in KV under key `form-name:YYYY-MM-DDTHH:MM:SSZ`
131+
const key = `${name}:${new Date().toISOString()}`;
132+
context.waitUntil(kv.put(name, JSON.stringify(entries)));
133+
134+
// Respond with whatever the developer wants
135+
const response = await respondWith({ formData });
136+
return response;
137+
};
137138
```
138139

139-
<Render file="request-dot-clone-warning" product="workers" />
140-
141140
### 2. Type your Pages Plugin
142141

143142
To create a good developer experience, you should consider adding TypeScript typings to your Plugin. This allows developers to use their IDE features for autocompletion, and also ensure that they include all the parameters you are expecting.
@@ -146,8 +145,8 @@ In the `index.d.ts`, export a function which takes your `pluginArgs` and returns
146145

147146
```typescript
148147
export type PluginArgs = {
149-
kv: KVNamespace;
150-
respondWith: (args: { formData: FormData }) => Promise<Response>;
148+
kv: KVNamespace;
149+
respondWith: (args: { formData: FormData }) => Promise<Response>;
151150
};
152151

153152
export default function (args: PluginArgs): PagesFunction;
@@ -163,7 +162,7 @@ You can distribute your Plugin however you choose. Popular options include publi
163162

164163
Make sure you are including the generated `dist/` directory, your typings `index.d.ts`, as well as a `README.md` with instructions on how developers can use your Plugin.
165164

166-
***
165+
---
167166

168167
### 5. Install your Pages Plugin
169168

@@ -187,14 +186,14 @@ A Plugin's default export is a function which takes the same context parameter t
187186
import staticFormInterceptorPlugin from "@cloudflare/static-form-interceptor";
188187

189188
export const onRequest = (context) => {
190-
return staticFormInterceptorPlugin({
191-
kv: context.env.FORM_KV,
192-
respondWith: async ({ formData }) => {
193-
// Could call email/notification service here
194-
const name = formData.get("name");
195-
return new Response(`Thank you for your submission, ${name}!`);
196-
},
197-
})(context);
189+
return staticFormInterceptorPlugin({
190+
kv: context.env.FORM_KV,
191+
respondWith: async ({ formData }) => {
192+
// Could call email/notification service here
193+
const name = formData.get("name");
194+
return new Response(`Thank you for your submission, ${name}!`);
195+
},
196+
})(context);
198197
};
199198
```
200199

@@ -207,20 +206,20 @@ With your Plugin mounted on the `/contact` route, a corresponding HTML file migh
207206
```html
208207
<!DOCTYPE html>
209208
<html>
210-
<body>
211-
<h1>Contact us</h1>
212-
<!-- Include the `data-static-form-name` attribute to name the submission -->
213-
<form data-static-form-name="contact">
214-
<label>
215-
<span>Name</span>
216-
<input type="text" autocomplete="name" name="name" />
217-
</label>
218-
<label>
219-
<span>Message</span>
220-
<textarea name="message"></textarea>
221-
</label>
222-
</form>
223-
</body>
209+
<body>
210+
<h1>Contact us</h1>
211+
<!-- Include the `data-static-form-name` attribute to name the submission -->
212+
<form data-static-form-name="contact">
213+
<label>
214+
<span>Name</span>
215+
<input type="text" autocomplete="name" name="name" />
216+
</label>
217+
<label>
218+
<span>Message</span>
219+
<textarea name="message"></textarea>
220+
</label>
221+
</form>
222+
</body>
224223
</html>
225224
```
226225

@@ -234,7 +233,7 @@ If you experience any problems with any one Plugin, file an issue on that Plugin
234233

235234
If you experience any problems with Plugins in general, we would appreciate your feedback in the #pages-discussions channel in [Discord](https://discord.com/invite/cloudflaredev)! We are excited to see what you build with Plugins and welcome any feedback about the authoring or developer experience. Let us know in the Discord channel if there is anything you need to make Plugins even more powerful.
236235

237-
***
236+
---
238237

239238
## Chain your Plugin
240239

@@ -246,25 +245,26 @@ import cloudflareAccessPlugin from "@cloudflare/pages-plugin-cloudflare-access";
246245
import adminDashboardPlugin from "@cloudflare/a-fictional-admin-plugin";
247246

248247
export const onRequest = [
249-
// Initialize a Sentry Plugin to capture any errors
250-
sentryPlugin({ dsn: "https://sentry.io/welcome/xyz" }),
248+
// Initialize a Sentry Plugin to capture any errors
249+
sentryPlugin({ dsn: "https://sentry.io/welcome/xyz" }),
251250

252-
// Initialize a Cloudflare Access Plugin to ensure only administrators can access this protected route
253-
cloudflareAccessPlugin({
254-
domain: "https://test.cloudflareaccess.com",
255-
aud: "4714c1358e65fe4b408ad6d432a5f878f08194bdb4752441fd56faefa9b2b6f2",
256-
}),
251+
// Initialize a Cloudflare Access Plugin to ensure only administrators can access this protected route
252+
cloudflareAccessPlugin({
253+
domain: "https://test.cloudflareaccess.com",
254+
aud: "4714c1358e65fe4b408ad6d432a5f878f08194bdb4752441fd56faefa9b2b6f2",
255+
}),
257256

258-
// Populate the Sentry plugin with additional information about the current user
259-
(context) => {
260-
const email = context.data.cloudflareAccessJWT.payload?.email || "service user";
257+
// Populate the Sentry plugin with additional information about the current user
258+
(context) => {
259+
const email =
260+
context.data.cloudflareAccessJWT.payload?.email || "service user";
261261

262-
context.data.sentry.setUser({ email });
262+
context.data.sentry.setUser({ email });
263263

264-
return next();
265-
},
264+
return next();
265+
},
266266

267-
// Finally, serve the admin dashboard plugin, knowing that errors will be captured and that every incoming request has been authenticated
268-
adminDashboardPlugin(),
267+
// Finally, serve the admin dashboard plugin, knowing that errors will be captured and that every incoming request has been authenticated
268+
adminDashboardPlugin(),
269269
];
270270
```

src/content/docs/pages/functions/plugins/turnstile.mdx

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ sidebar:
55
order: 1
66
---
77

8-
import { Render } from "~/components"
8+
import { Render } from "~/components";
99

1010
[Turnstile](/turnstile/) is Cloudflare's smart CAPTCHA alternative.
1111

@@ -47,8 +47,6 @@ export const onRequestPost = [
4747
];
4848
```
4949

50-
<Render file="request-dot-clone-warning" product="workers" />
51-
5250
This Plugin only exposes a single route to verify an incoming Turnstile response in a `POST` as the `cf-turnstile-response` parameter. It will be available wherever it is mounted. In the example above, it is mounted in `functions/register.ts`. As a result, it will validate requests to `/register`.
5351

5452
## Properties

src/content/docs/pages/how-to/refactor-a-worker-to-pages-functions.mdx

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ pcx_content_type: how-to
33
title: Refactor a Worker to a Pages Function
44
---
55

6-
import { Render } from "~/components"
6+
import { Render } from "~/components";
77

88
In this guide, you will learn how to refactor a Worker made to intake form submissions to a Pages Function that can be hosted on your Cloudflare Pages application. [Pages Functions](/pages/functions/) is a serverless function that lives within the same project directory as your application and is deployed with Cloudflare Pages. It enables you to run server-side code that adds dynamic functionality without running a dedicated server. You may want to refactor a Worker to a Pages Function for one of these reasons:
99

@@ -103,8 +103,6 @@ const HandleAirtableData = (body, env) => {
103103
};
104104
```
105105

106-
<Render file="request-dot-clone-warning" product="workers" />
107-
108106
### Refactor your Worker
109107

110108
To refactor the above Worker, go to your Pages project directory and create a `/functions` folder. In `/functions`, create a `form.js` file. This file will handle form submissions.

0 commit comments

Comments
 (0)