diff --git a/.changeset/cuddly-ears-collect.md b/.changeset/cuddly-ears-collect.md
new file mode 100644
index 000000000000..a06229efd3fc
--- /dev/null
+++ b/.changeset/cuddly-ears-collect.md
@@ -0,0 +1,5 @@
+---
+"wrangler": patch
+---
+
+chore: rename `--script-path` to `--outfile` for `wrangler pages functions build` command.
diff --git a/.changeset/spicy-knives-rush.md b/.changeset/spicy-knives-rush.md
new file mode 100644
index 000000000000..6c3f58950e98
--- /dev/null
+++ b/.changeset/spicy-knives-rush.md
@@ -0,0 +1,5 @@
+---
+"wrangler": patch
+---
+
+feature: Adds a `--plugin` option to `wrangler pages functions build` which compiles a Pages Plugin. More information about Pages Plugins can be found [here](https://developers.cloudflare.com/pages/platform/functions/plugins/). This wrangler build is required for both the development of, and inclusion of, plugins.
diff --git a/CODEOWNERS b/CODEOWNERS
index 38f0606a9e02..f8a62fd3a0d4 100644
--- a/CODEOWNERS
+++ b/CODEOWNERS
@@ -1,2 +1,3 @@
# Global owners
* @threepointone @petebacondarwin
+/packages/wrangler/pages/ @GregBrimble
diff --git a/examples/pages-functions-app/CHANGELOG.md b/examples/pages-functions-app/CHANGELOG.md
deleted file mode 100644
index 79ccb4daf6df..000000000000
--- a/examples/pages-functions-app/CHANGELOG.md
+++ /dev/null
@@ -1,7 +0,0 @@
-# example-pages-functions-app
-
-## null
-
-### Patch Changes
-
-- [#617](https://github.com/cloudflare/wrangler2/pull/617) [`8c98c00`](https://github.com/cloudflare/wrangler2/commit/8c98c008a8f80ab92bff6425312a170d7e582533) Thanks [@GregBrimble](https://github.com/GregBrimble)! - Added a Pages Functions example project for tests
diff --git a/examples/pages-functions-app/functions/mounted-plugin/_middleware.ts b/examples/pages-functions-app/functions/mounted-plugin/_middleware.ts
new file mode 100644
index 000000000000..46eaed7b9679
--- /dev/null
+++ b/examples/pages-functions-app/functions/mounted-plugin/_middleware.ts
@@ -0,0 +1,3 @@
+import examplePlugin from "../../../pages-plugin-example";
+
+export const onRequest = examplePlugin({ footerText: "Set from a Plugin!" });
diff --git a/examples/pages-functions-app/public/index.html b/examples/pages-functions-app/public/index.html
index 9f735a6307ae..a289365236c7 100644
--- a/examples/pages-functions-app/public/index.html
+++ b/examples/pages-functions-app/public/index.html
@@ -1 +1,6 @@
-
Hello, world!
+
+
+
+ Hello, world!
+
+
diff --git a/examples/pages-functions-app/public/some-asset.html b/examples/pages-functions-app/public/some-asset.html
index 08d2e2408532..281c968f4329 100644
--- a/examples/pages-functions-app/public/some-asset.html
+++ b/examples/pages-functions-app/public/some-asset.html
@@ -1 +1,6 @@
-An asset
+
+
+
+ An asset
+
+
diff --git a/examples/pages-functions-app/tests/index.test.ts b/examples/pages-functions-app/tests/index.test.ts
index 31b286b0cb36..87e6e1af2831 100644
--- a/examples/pages-functions-app/tests/index.test.ts
+++ b/examples/pages-functions-app/tests/index.test.ts
@@ -93,4 +93,20 @@ describe("Pages Functions", () => {
const text = await response.text();
expect(text).toContain("An asset
");
});
+
+ it("can mount a plugin", async () => {
+ // Middleware
+ let response = await waitUntilReady(
+ "http://localhost:8789/mounted-plugin/some-page"
+ );
+ let text = await response.text();
+ expect(text).toContain("");
+
+ // Fixed page
+ response = await waitUntilReady(
+ "http://localhost:8789/mounted-plugin/fixed"
+ );
+ text = await response.text();
+ expect(text).toContain("I'm a fixed response");
+ });
});
diff --git a/examples/pages-plugin-example/.gitignore b/examples/pages-plugin-example/.gitignore
new file mode 100644
index 000000000000..f72018060151
--- /dev/null
+++ b/examples/pages-plugin-example/.gitignore
@@ -0,0 +1 @@
+/index.js
\ No newline at end of file
diff --git a/examples/pages-plugin-example/functions/_middleware.ts b/examples/pages-plugin-example/functions/_middleware.ts
new file mode 100644
index 000000000000..7158a0516b69
--- /dev/null
+++ b/examples/pages-plugin-example/functions/_middleware.ts
@@ -0,0 +1,20 @@
+class BodyHandler {
+ footerText: string;
+
+ constructor({ footerText }) {
+ this.footerText = footerText;
+ }
+
+ element(element) {
+ // Don't actually set HTML like this!
+ element.append(``, { html: true });
+ }
+}
+
+export const onRequest = async ({ next, pluginArgs }) => {
+ const response = await next();
+
+ return new HTMLRewriter()
+ .on("body", new BodyHandler({ footerText: pluginArgs.footerText }))
+ .transform(response);
+};
diff --git a/examples/pages-plugin-example/functions/fixed.ts b/examples/pages-plugin-example/functions/fixed.ts
new file mode 100644
index 000000000000..b55d9e8a122b
--- /dev/null
+++ b/examples/pages-plugin-example/functions/fixed.ts
@@ -0,0 +1,3 @@
+export const onRequest = () => {
+ return new Response("I'm a fixed response");
+};
diff --git a/examples/pages-plugin-example/package.json b/examples/pages-plugin-example/package.json
new file mode 100644
index 000000000000..6a3c6503ccda
--- /dev/null
+++ b/examples/pages-plugin-example/package.json
@@ -0,0 +1,13 @@
+{
+ "name": "pages-plugin-example",
+ "main": "index.js",
+ "types": "index.d.ts",
+ "files": [
+ "index.js",
+ "index.d.ts",
+ "tsconfig.json"
+ ],
+ "scripts": {
+ "build": "npx wrangler pages functions build --plugin --outfile=index.js"
+ }
+}
diff --git a/package.json b/package.json
index c7b733922c77..a8ee20a72262 100644
--- a/package.json
+++ b/package.json
@@ -37,7 +37,7 @@
"check:type": "npm run check:type --workspaces --if-present",
"check:lint": "eslint \"packages/**/*.[tj]s?(x)\" --cache --cache-strategy content --max-warnings=0",
"check:format": "prettier packages/** .changeset --check --ignore-unknown",
- "build": "npm run build --workspace=wrangler --workspace=jest-environment-wrangler",
+ "build": "npm run build --workspace=wrangler --workspace=jest-environment-wrangler && npm run build --workspace=pages-plugin-example",
"test": "npm run test --workspaces --if-present",
"prettify": "prettier packages/** --write --ignore-unknown"
},
diff --git a/packages/wrangler/pages/functions/buildPlugin.ts b/packages/wrangler/pages/functions/buildPlugin.ts
new file mode 100644
index 000000000000..fca2b03ed1e7
--- /dev/null
+++ b/packages/wrangler/pages/functions/buildPlugin.ts
@@ -0,0 +1,55 @@
+import { resolve } from "node:path";
+import { build } from "esbuild";
+
+type Options = {
+ routesModule: string;
+ outfile: string;
+ minify?: boolean;
+ sourcemap?: boolean;
+ watch?: boolean;
+ onEnd?: () => void;
+};
+
+export function buildPlugin({
+ routesModule,
+ outfile = "bundle.js",
+ minify = false,
+ sourcemap = false,
+ watch = false,
+ onEnd = () => {},
+}: Options) {
+ return build({
+ entryPoints: [resolve(__dirname, "../pages/functions/template-plugin.ts")],
+ inject: [routesModule],
+ bundle: true,
+ format: "esm",
+ target: "esnext",
+ outfile,
+ minify,
+ sourcemap,
+ watch,
+ allowOverwrite: true,
+ plugins: [
+ {
+ name: "wrangler notifier and monitor",
+ setup(pluginBuild) {
+ pluginBuild.onEnd((result) => {
+ if (result.errors.length > 0) {
+ console.error(
+ `${result.errors.length} error(s) and ${result.warnings.length} warning(s) when compiling Worker.`
+ );
+ } else if (result.warnings.length > 0) {
+ console.warn(
+ `${result.warnings.length} warning(s) when compiling Worker.`
+ );
+ onEnd();
+ } else {
+ console.log("Compiled Worker successfully.");
+ onEnd();
+ }
+ });
+ },
+ },
+ ],
+ });
+}
diff --git a/packages/wrangler/pages/functions/filepath-routing.test.ts b/packages/wrangler/pages/functions/filepath-routing.test.ts
index 45e502f71617..95d75ac3a36c 100644
--- a/packages/wrangler/pages/functions/filepath-routing.test.ts
+++ b/packages/wrangler/pages/functions/filepath-routing.test.ts
@@ -143,6 +143,7 @@ describe("filepath-routing", () => {
"module": Array [
"authors/[authorId]/todos/[todoId].ts:onRequestPost",
],
+ "mountPath": "/base/authors/:authorId/todos",
"routePath": "/base/authors/:authorId/todos/:todoId",
},
Object {
@@ -150,6 +151,7 @@ describe("filepath-routing", () => {
"module": Array [
"cats/[[breed]]/blah.ts:onRequestPost",
],
+ "mountPath": "/base/cats/:breed*",
"routePath": "/base/cats/:breed*/blah",
},
Object {
@@ -157,6 +159,7 @@ describe("filepath-routing", () => {
"module": Array [
"cats/[[breed]]/[[name]].ts:onRequestPost",
],
+ "mountPath": "/base/cats/:breed*",
"routePath": "/base/cats/:breed*/:name*",
},
Object {
@@ -164,6 +167,7 @@ describe("filepath-routing", () => {
"module": Array [
"todos/[id].ts:onRequestDelete",
],
+ "mountPath": "/base/todos",
"routePath": "/base/todos/:id",
},
Object {
@@ -171,6 +175,7 @@ describe("filepath-routing", () => {
"module": Array [
"todos/[id].ts:onRequestPost",
],
+ "mountPath": "/base/todos",
"routePath": "/base/todos/:id",
},
Object {
@@ -178,6 +183,7 @@ describe("filepath-routing", () => {
"module": Array [
"books/[[title]].ts:onRequestPost",
],
+ "mountPath": "/base/books",
"routePath": "/base/books/:title*",
},
Object {
@@ -185,6 +191,7 @@ describe("filepath-routing", () => {
"module": Array [
"bar.ts:onRequestDelete",
],
+ "mountPath": "/base/",
"routePath": "/base/bar",
},
Object {
@@ -192,6 +199,7 @@ describe("filepath-routing", () => {
"module": Array [
"bar.ts:onRequestPut",
],
+ "mountPath": "/base/",
"routePath": "/base/bar",
},
Object {
@@ -199,6 +207,7 @@ describe("filepath-routing", () => {
"module": Array [
"foo.ts:onRequestGet",
],
+ "mountPath": "/base/",
"routePath": "/base/foo",
},
Object {
@@ -206,6 +215,7 @@ describe("filepath-routing", () => {
"module": Array [
"foo.ts:onRequestPost",
],
+ "mountPath": "/base/",
"routePath": "/base/foo",
},
],
@@ -218,6 +228,7 @@ describe("filepath-routing", () => {
function routeConfig(routePath: string, method?: string): RouteConfig {
return {
routePath: toUrlPath(routePath),
+ mountPath: toUrlPath("/"),
method: method as HTTPMethod,
};
}
diff --git a/packages/wrangler/pages/functions/filepath-routing.ts b/packages/wrangler/pages/functions/filepath-routing.ts
index 4b33bb1a83b0..1f1a07350fae 100644
--- a/packages/wrangler/pages/functions/filepath-routing.ts
+++ b/packages/wrangler/pages/functions/filepath-routing.ts
@@ -53,6 +53,7 @@ export async function generateConfigFromFileTree({
let routePath = path
.relative(baseDir, filepath)
.slice(0, -ext.length);
+ let mountPath = path.dirname(routePath);
if (isIndexFile || isMiddlewareFile) {
routePath = path.dirname(routePath);
@@ -61,17 +62,24 @@ export async function generateConfigFromFileTree({
if (routePath === ".") {
routePath = "";
}
+ if (mountPath === ".") {
+ mountPath = "";
+ }
routePath = `${baseURL}/${routePath}`;
+ mountPath = `${baseURL}/${mountPath}`;
routePath = routePath.replace(/\[\[([^\]]+)\]\]/g, ":$1*"); // transform [[id]] => :id*
routePath = routePath.replaceAll(/\[([^\]]+)\]/g, ":$1"); // transform [id] => :id
+ mountPath = mountPath.replace(/\[\[([^\]]+)\]\]/g, ":$1*"); // transform [[id]] => :id*
+ mountPath = mountPath.replaceAll(/\[([^\]]+)\]/g, ":$1"); // transform [id] => :id
// These are used as module specifiers so UrlPaths are okay to use even on Windows
const modulePath = toUrlPath(path.relative(baseDir, filepath));
const routeEntry: RouteConfig = {
routePath: toUrlPath(routePath),
+ mountPath: toUrlPath(mountPath),
method: method.toUpperCase() as HTTPMethod,
[isMiddlewareFile ? "middleware" : "module"]: [
`${modulePath}:${exportName}`,
diff --git a/packages/wrangler/pages/functions/routes.ts b/packages/wrangler/pages/functions/routes.ts
index de2607ee325f..c214223dfc22 100755
--- a/packages/wrangler/pages/functions/routes.ts
+++ b/packages/wrangler/pages/functions/routes.ts
@@ -21,6 +21,7 @@ export function isHTTPMethod(
export type RoutesCollection = Array<{
routePath: UrlPath;
+ mountPath: UrlPath;
method?: HTTPMethod;
modules: string[];
middlewares: string[];
@@ -33,6 +34,7 @@ export type Config = {
export type RouteConfig = {
routePath: UrlPath;
+ mountPath: UrlPath;
method?: HTTPMethod;
middleware?: string | string[];
module?: string | string[];
@@ -113,9 +115,11 @@ export function parseConfig(config: Config, baseDir: string) {
});
}
- for (const { routePath, method, ...props } of config.routes ?? []) {
+ for (const { routePath, mountPath, method, ...props } of config.routes ??
+ []) {
routes.push({
routePath,
+ mountPath,
method,
middlewares: parseModuleIdentifiers(props.middleware),
modules: parseModuleIdentifiers(props.module),
@@ -141,6 +145,7 @@ export const routes = [
.map(
(route) => ` {
routePath: "${route.routePath}",
+ mountPath: "${route.mountPath}",
method: "${route.method}",
middlewares: [${route.middlewares.join(", ")}],
modules: [${route.modules.join(", ")}],
diff --git a/packages/wrangler/pages/functions/template-plugin.ts b/packages/wrangler/pages/functions/template-plugin.ts
new file mode 100644
index 000000000000..8f62cd62075a
--- /dev/null
+++ b/packages/wrangler/pages/functions/template-plugin.ts
@@ -0,0 +1,146 @@
+import { match } from "path-to-regexp";
+import type { HTTPMethod } from "./routes";
+
+/* TODO: Grab these from @cloudflare/workers-types instead */
+type Params = Record
;
+
+type EventContext = {
+ request: Request;
+ functionPath: string;
+ waitUntil: (promise: Promise) => void;
+ next: (input?: Request | string, init?: RequestInit) => Promise;
+ env: Env & { ASSETS: { fetch: typeof fetch } };
+ params: Params;
+ data: Data;
+};
+
+type EventPluginContext = {
+ request: Request;
+ functionPath: string;
+ waitUntil: (promise: Promise) => void;
+ next: (input?: Request | string, init?: RequestInit) => Promise;
+ env: Env & { ASSETS: { fetch: typeof fetch } };
+ params: Params;
+ data: Data;
+ pluginArgs: PluginArgs;
+};
+
+declare type PagesFunction<
+ Env = unknown,
+ P extends string = string,
+ Data extends Record = Record
+> = (context: EventContext) => Response | Promise;
+
+declare type PagesPluginFunction<
+ Env = unknown,
+ P extends string = string,
+ Data extends Record = Record,
+ PluginArgs = unknown
+> = (
+ context: EventPluginContext
+) => Response | Promise;
+/* end @cloudflare/workers-types */
+
+type RouteHandler = {
+ routePath: string;
+ mountPath: string;
+ method?: HTTPMethod;
+ modules: PagesFunction[];
+ middlewares: PagesFunction[];
+};
+
+// inject `routes` via ESBuild
+declare const routes: RouteHandler[];
+
+function* executeRequest(request: Request, relativePathname: string) {
+ // First, iterate through the routes (backwards) and execute "middlewares" on partial route matches
+ for (const route of [...routes].reverse()) {
+ if (route.method && route.method !== request.method) {
+ continue;
+ }
+
+ const routeMatcher = match(route.routePath, { end: false });
+ const mountMatcher = match(route.mountPath, { end: false });
+ const matchResult = routeMatcher(relativePathname);
+ const mountMatchResult = mountMatcher(relativePathname);
+ if (matchResult && mountMatchResult) {
+ for (const handler of route.middlewares.flat()) {
+ yield {
+ handler,
+ params: matchResult.params as Params,
+ path: mountMatchResult.path,
+ };
+ }
+ }
+ }
+
+ // Then look for the first exact route match and execute its "modules"
+ for (const route of routes) {
+ if (route.method && route.method !== request.method) {
+ continue;
+ }
+
+ const routeMatcher = match(route.routePath, { end: true });
+ const mountMatcher = match(route.mountPath, { end: false });
+ const matchResult = routeMatcher(relativePathname);
+ const mountMatchResult = mountMatcher(relativePathname);
+ if (matchResult && mountMatchResult && route.modules.length) {
+ for (const handler of route.modules.flat()) {
+ yield {
+ handler,
+ params: matchResult.params as Params,
+ path: matchResult.path,
+ };
+ }
+ break;
+ }
+ }
+}
+
+export default function (pluginArgs) {
+ const onRequest: PagesPluginFunction = async (workerContext) => {
+ let { request } = workerContext;
+ const { env, next, data } = workerContext;
+
+ const url = new URL(request.url);
+ const relativePathname =
+ url.pathname.split(workerContext.functionPath)[1] || "/";
+
+ const handlerIterator = executeRequest(request, relativePathname);
+ const pluginNext = async (input?: RequestInfo, init?: RequestInit) => {
+ if (input !== undefined) {
+ request = new Request(input, init);
+ }
+
+ const result = handlerIterator.next();
+ // Note we can't use `!result.done` because this doesn't narrow to the correct type
+ if (result.done === false) {
+ const { handler, params, path } = result.value;
+ const context = {
+ request,
+ functionPath: workerContext.functionPath + path,
+ next: pluginNext,
+ params,
+ data,
+ pluginArgs,
+ env,
+ waitUntil: workerContext.waitUntil.bind(workerContext),
+ };
+
+ const response = await handler(context);
+
+ // https://fetch.spec.whatwg.org/#null-body-status
+ return new Response(
+ [101, 204, 205, 304].includes(response.status) ? null : response.body,
+ response
+ );
+ } else {
+ return next();
+ }
+ };
+
+ return pluginNext();
+ };
+
+ return onRequest;
+}
diff --git a/packages/wrangler/pages/functions/template-worker.ts b/packages/wrangler/pages/functions/template-worker.ts
index 41d88d878b05..61e3513ca327 100644
--- a/packages/wrangler/pages/functions/template-worker.ts
+++ b/packages/wrangler/pages/functions/template-worker.ts
@@ -6,6 +6,7 @@ type Params = Record
;
type EventContext = {
request: Request;
+ functionPath: string;
waitUntil: (promise: Promise) => void;
next: (input?: Request | string, init?: RequestInit) => Promise;
env: Env & { ASSETS: { fetch: typeof fetch } };
@@ -22,6 +23,7 @@ declare type PagesFunction<
type RouteHandler = {
routePath: string;
+ mountPath: string;
method?: HTTPMethod;
modules: PagesFunction[];
middlewares: PagesFunction[];
@@ -42,7 +44,7 @@ type WorkerContext = {
waitUntil: (promise: Promise) => void;
};
-function* executeRequest(request: Request, _env: FetchEnv) {
+function* executeRequest(request: Request) {
const requestPath = new URL(request.url).pathname;
// First, iterate through the routes (backwards) and execute "middlewares" on partial route matches
@@ -52,12 +54,15 @@ function* executeRequest(request: Request, _env: FetchEnv) {
}
const routeMatcher = match(route.routePath, { end: false });
+ const mountMatcher = match(route.mountPath, { end: false });
const matchResult = routeMatcher(requestPath);
- if (matchResult) {
+ const mountMatchResult = mountMatcher(requestPath);
+ if (matchResult && mountMatchResult) {
for (const handler of route.middlewares.flat()) {
yield {
handler,
params: matchResult.params as Params,
+ path: mountMatchResult.path,
};
}
}
@@ -70,12 +75,15 @@ function* executeRequest(request: Request, _env: FetchEnv) {
}
const routeMatcher = match(route.routePath, { end: true });
+ const mountMatcher = match(route.mountPath, { end: false });
const matchResult = routeMatcher(requestPath);
- if (matchResult && route.modules.length) {
+ const mountMatchResult = mountMatcher(requestPath);
+ if (matchResult && mountMatchResult && route.modules.length) {
for (const handler of route.modules.flat()) {
yield {
handler,
params: matchResult.params as Params,
+ path: matchResult.path,
};
}
break;
@@ -85,7 +93,7 @@ function* executeRequest(request: Request, _env: FetchEnv) {
export default {
async fetch(request: Request, env: FetchEnv, workerContext: WorkerContext) {
- const handlerIterator = executeRequest(request, env);
+ const handlerIterator = executeRequest(request);
const data = {}; // arbitrary data the user can set between functions
const next = async (input?: RequestInfo, init?: RequestInit) => {
if (input !== undefined) {
@@ -98,10 +106,11 @@ export default {
const result = handlerIterator.next();
// Note we can't use `!result.done` because this doesn't narrow to the correct type
- if (result.done == false) {
- const { handler, params } = result.value;
+ if (result.done === false) {
+ const { handler, params, path } = result.value;
const context = {
request: new Request(request.clone()),
+ functionPath: path,
next,
params,
data,
diff --git a/packages/wrangler/src/pages.tsx b/packages/wrangler/src/pages.tsx
index cfa9da7bd045..352529a496b5 100644
--- a/packages/wrangler/src/pages.tsx
+++ b/packages/wrangler/src/pages.tsx
@@ -11,6 +11,7 @@ import Table from "ink-table";
import { getType } from "mime";
import React from "react";
import { format as timeagoFormat } from "timeago.js";
+import { buildPlugin } from "../pages/functions/buildPlugin";
import { buildWorker } from "../pages/functions/buildWorker";
import { generateConfigFromFileTree } from "../pages/functions/filepath-routing";
import { writeRoutesModule } from "../pages/functions/routes";
@@ -694,7 +695,7 @@ async function generateAssetsFetch(directory: string): Promise {
const RUNNING_BUILDERS: BuildResult[] = [];
async function buildFunctions({
- scriptPath,
+ outfile,
outputConfigPath,
functionsDirectory,
minify = false,
@@ -702,8 +703,9 @@ async function buildFunctions({
fallbackService = "ASSETS",
watch = false,
onEnd,
+ plugin = false,
}: {
- scriptPath: string;
+ outfile: string;
outputConfigPath?: string;
functionsDirectory: string;
minify?: boolean;
@@ -711,6 +713,7 @@ async function buildFunctions({
fallbackService?: string;
watch?: boolean;
onEnd?: () => void;
+ plugin?: boolean;
}) {
RUNNING_BUILDERS.forEach(
(runningBuilder) => runningBuilder.stop && runningBuilder.stop()
@@ -737,17 +740,30 @@ async function buildFunctions({
outfile: routesModule,
});
- RUNNING_BUILDERS.push(
- await buildWorker({
- routesModule,
- outfile: scriptPath,
- minify,
- sourcemap,
- fallbackService,
- watch,
- onEnd,
- })
- );
+ if (plugin) {
+ RUNNING_BUILDERS.push(
+ await buildPlugin({
+ routesModule,
+ outfile,
+ minify,
+ sourcemap,
+ watch,
+ onEnd,
+ })
+ );
+ } else {
+ RUNNING_BUILDERS.push(
+ await buildWorker({
+ routesModule,
+ outfile,
+ minify,
+ sourcemap,
+ fallbackService,
+ watch,
+ onEnd,
+ })
+ );
+ }
}
export const pages: BuilderCallback = (yargs) => {
@@ -856,13 +872,13 @@ export const pages: BuilderCallback = (yargs) => {
);
if (usingFunctions) {
- const scriptPath = join(tmpdir(), "./functionsWorker.js");
+ const outfile = join(tmpdir(), "./functionsWorker.js");
- console.log(`Compiling worker to "${scriptPath}"...`);
+ console.log(`Compiling worker to "${outfile}"...`);
try {
await buildFunctions({
- scriptPath,
+ outfile,
functionsDirectory,
sourcemap: true,
watch: true,
@@ -875,7 +891,7 @@ export const pages: BuilderCallback = (yargs) => {
ignoreInitial: true,
}).on("all", async () => {
await buildFunctions({
- scriptPath,
+ outfile,
functionsDirectory,
sourcemap: true,
watch: true,
@@ -884,7 +900,7 @@ export const pages: BuilderCallback = (yargs) => {
});
miniflareArgs = {
- scriptPath,
+ scriptPath: outfile,
};
} else {
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
@@ -1042,7 +1058,7 @@ export const pages: BuilderCallback = (yargs) => {
description: "The directory of Pages Functions",
})
.options({
- "script-path": {
+ outfile: {
type: "string",
default: "_worker.js",
description: "The location of the output Worker script",
@@ -1074,28 +1090,35 @@ export const pages: BuilderCallback = (yargs) => {
description:
"Watch for changes to the functions and automatically rebuild the Worker script",
},
+ plugin: {
+ type: "boolean",
+ default: false,
+ description: "Build a plugin rather than a Worker script",
+ },
})
.epilogue(pagesBetaWarning),
async ({
directory,
- "script-path": scriptPath,
+ outfile,
"output-config-path": outputConfigPath,
minify,
sourcemap,
fallbackService,
watch,
+ plugin,
}) => {
// Beta message for `wrangler pages ` usage
console.log(pagesBetaWarning);
await buildFunctions({
- scriptPath,
+ outfile,
outputConfigPath,
functionsDirectory: directory,
minify,
sourcemap,
fallbackService,
watch,
+ plugin,
});
}
)
diff --git a/packages/wrangler/tsconfig.json b/packages/wrangler/tsconfig.json
index 85ae70074487..bfcac2ec72b8 100644
--- a/packages/wrangler/tsconfig.json
+++ b/packages/wrangler/tsconfig.json
@@ -10,6 +10,7 @@
"vendor",
"*-dist",
"pages/functions/template-worker.ts",
+ "pages/functions/template-plugin.ts",
"templates"
]
}