diff --git a/.changeset/afraid-oranges-happen.md b/.changeset/afraid-oranges-happen.md
new file mode 100644
index 0000000000000..7544f665d5473
--- /dev/null
+++ b/.changeset/afraid-oranges-happen.md
@@ -0,0 +1,7 @@
+---
+"wrangler": patch
+---
+
+fix: `site.entry-point` should not be a hard deprecation
+
+To make migration of v1 projects easier, Sites projects should still work, including the `entry-point` field (which currently errors out). This enables `site.entry-point` as a valid entry point, with a deprecation warning.
diff --git a/examples/legacy-site-app/public/404.html b/examples/legacy-site-app/public/404.html
new file mode 100644
index 0000000000000..5642852452d0b
--- /dev/null
+++ b/examples/legacy-site-app/public/404.html
@@ -0,0 +1,40 @@
+
+
+
+
+
+
+
+
+
+
+
404 Not Found
+
Oh dang! We couldn't find that page.
+
+
+
+
diff --git a/examples/legacy-site-app/public/favicon.ico b/examples/legacy-site-app/public/favicon.ico
new file mode 100644
index 0000000000000..cc6c23bd37bb4
Binary files /dev/null and b/examples/legacy-site-app/public/favicon.ico differ
diff --git a/examples/legacy-site-app/public/img/200-wrangler-ferris.gif b/examples/legacy-site-app/public/img/200-wrangler-ferris.gif
new file mode 100644
index 0000000000000..8853751fac7b3
Binary files /dev/null and b/examples/legacy-site-app/public/img/200-wrangler-ferris.gif differ
diff --git a/examples/legacy-site-app/public/img/404-wrangler-ferris.gif b/examples/legacy-site-app/public/img/404-wrangler-ferris.gif
new file mode 100644
index 0000000000000..0ac1479fcf6f4
Binary files /dev/null and b/examples/legacy-site-app/public/img/404-wrangler-ferris.gif differ
diff --git a/examples/legacy-site-app/public/index.html b/examples/legacy-site-app/public/index.html
new file mode 100644
index 0000000000000..d07cf620748f2
--- /dev/null
+++ b/examples/legacy-site-app/public/index.html
@@ -0,0 +1,40 @@
+
+
+
+
+
+
+
+
+
+
+
200 Success
+
Hello World! Welcome to your Workers Site.
+
+
+
+
diff --git a/examples/legacy-site-app/workers-site/.gitignore b/examples/legacy-site-app/workers-site/.gitignore
new file mode 100644
index 0000000000000..7915249fd6155
--- /dev/null
+++ b/examples/legacy-site-app/workers-site/.gitignore
@@ -0,0 +1,3 @@
+node_modules
+dist
+worker
diff --git a/examples/legacy-site-app/workers-site/index.js b/examples/legacy-site-app/workers-site/index.js
new file mode 100644
index 0000000000000..806f91a5a189a
--- /dev/null
+++ b/examples/legacy-site-app/workers-site/index.js
@@ -0,0 +1,81 @@
+import { getAssetFromKV, mapRequestToAsset } from '@cloudflare/kv-asset-handler'
+
+/**
+ * The DEBUG flag will do two things that help during development:
+ * 1. we will skip caching on the edge, which makes it easier to
+ * debug.
+ * 2. we will return an error message on exception in your Response rather
+ * than the default 404.html page.
+ */
+const DEBUG = false
+
+addEventListener('fetch', event => {
+ event.respondWith(handleEvent(event))
+})
+
+async function handleEvent(event) {
+ let options = {}
+
+ /**
+ * You can add custom logic to how we fetch your assets
+ * by configuring the function `mapRequestToAsset`
+ */
+ // options.mapRequestToAsset = handlePrefix(/^\/docs/)
+
+ try {
+ if (DEBUG) {
+ // customize caching
+ options.cacheControl = {
+ bypassCache: true,
+ }
+ }
+
+ const page = await getAssetFromKV(event, options)
+
+ // allow headers to be altered
+ const response = new Response(page.body, page)
+
+ response.headers.set('X-XSS-Protection', '1; mode=block')
+ response.headers.set('X-Content-Type-Options', 'nosniff')
+ response.headers.set('X-Frame-Options', 'DENY')
+ response.headers.set('Referrer-Policy', 'unsafe-url')
+ response.headers.set('Feature-Policy', 'none')
+
+ return response
+
+ } catch (e) {
+ // if an error is thrown try to serve the asset at 404.html
+ if (!DEBUG) {
+ try {
+ let notFoundResponse = await getAssetFromKV(event, {
+ mapRequestToAsset: req => new Request(`${new URL(req.url).origin}/404.html`, req),
+ })
+
+ return new Response(notFoundResponse.body, { ...notFoundResponse, status: 404 })
+ } catch (e) {}
+ }
+
+ return new Response(e.message || e.toString(), { status: 500 })
+ }
+}
+
+/**
+ * Here's one example of how to modify a request to
+ * remove a specific prefix, in this case `/docs` from
+ * the url. This can be useful if you are deploying to a
+ * route on a zone, or if you only want your static content
+ * to exist at a specific path.
+ */
+function handlePrefix(prefix) {
+ return request => {
+ // compute the default (e.g. / -> index.html)
+ let defaultAssetKey = mapRequestToAsset(request)
+ let url = new URL(defaultAssetKey.url)
+
+ // strip the prefix from the path for lookup
+ url.pathname = url.pathname.replace(prefix, '/')
+
+ // inherit all other props from the default request
+ return new Request(url.toString(), defaultAssetKey)
+ }
+}
diff --git a/examples/legacy-site-app/workers-site/package-lock.json b/examples/legacy-site-app/workers-site/package-lock.json
new file mode 100644
index 0000000000000..8c7b88b240391
--- /dev/null
+++ b/examples/legacy-site-app/workers-site/package-lock.json
@@ -0,0 +1,20 @@
+{
+ "version": "1.0.0",
+ "lockfileVersion": 1,
+ "requires": true,
+ "dependencies": {
+ "@cloudflare/kv-asset-handler": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/@cloudflare/kv-asset-handler/-/kv-asset-handler-0.1.2.tgz",
+ "integrity": "sha512-otES1gV5mEhNh82p/sJERPMMrC7UOLV2JyfKf4e3EX1TmMkZ3N8IDGAqRNsoRU8UYTO7wc83I7pH1p4ozAdgMQ==",
+ "requires": {
+ "mime": "^2.5.2"
+ }
+ },
+ "mime": {
+ "version": "2.5.2",
+ "resolved": "https://registry.npmjs.org/mime/-/mime-2.5.2.tgz",
+ "integrity": "sha512-tqkh47FzKeCPD2PUiPB6pkbMzsCasjxAfC62/Wap5qrUWcb+sFasXUC5I3gYM5iBM8v/Qpn4UK0x+j0iHyFPDg=="
+ }
+ }
+}
diff --git a/examples/legacy-site-app/workers-site/package.json b/examples/legacy-site-app/workers-site/package.json
new file mode 100644
index 0000000000000..2b4250e7ab3ae
--- /dev/null
+++ b/examples/legacy-site-app/workers-site/package.json
@@ -0,0 +1,10 @@
+{
+ "private": true,
+ "version": "1.0.0",
+ "description": "A template for kick starting a Cloudflare Workers project",
+ "main": "index.js",
+ "license": "MIT",
+ "dependencies": {
+ "@cloudflare/kv-asset-handler": "~0.1.2"
+ }
+}
diff --git a/examples/legacy-site-app/wrangler.toml b/examples/legacy-site-app/wrangler.toml
new file mode 100644
index 0000000000000..420a605a0256d
--- /dev/null
+++ b/examples/legacy-site-app/wrangler.toml
@@ -0,0 +1,6 @@
+account_id = ""
+name = "legacy-site-app"
+type = "webpack"
+workers_dev = true
+site = { bucket = "./public" }
+compatibility_date = "2022-04-24"
diff --git a/packages/wrangler/src/__tests__/configuration.test.ts b/packages/wrangler/src/__tests__/configuration.test.ts
index 428a41250f99e..f22cbc561d095 100644
--- a/packages/wrangler/src/__tests__/configuration.test.ts
+++ b/packages/wrangler/src/__tests__/configuration.test.ts
@@ -7,6 +7,8 @@ import type {
RawEnvironment,
} from "../config";
+const isWindows = process.platform === "win32";
+
describe("normalizeAndValidateConfig()", () => {
it("should use defaults for empty configuration", () => {
const { config, diagnostics } = normalizeAndValidateConfig({}, undefined, {
@@ -230,8 +232,9 @@ describe("normalizeAndValidateConfig()", () => {
const expectedConfig: RawConfig = {
site: {
bucket: "BUCKET",
- include: ["INCLUDE_1", "INCLUDE_2"],
+ "entry-point": "my-site",
exclude: ["EXCLUDE_1", "EXCLUDE_2"],
+ include: ["INCLUDE_1", "INCLUDE_2"],
},
};
@@ -243,13 +246,33 @@ describe("normalizeAndValidateConfig()", () => {
expect(config).toEqual(expect.objectContaining(expectedConfig));
expect(diagnostics.hasErrors()).toBe(false);
- expect(diagnostics.hasWarnings()).toBe(false);
+ expect(diagnostics.hasWarnings()).toBe(true);
+ if (!isWindows) {
+ expect(diagnostics.renderWarnings()).toMatchInlineSnapshot(`
+ "Processing wrangler configuration:
+ - DEPRECATION: \\"site.entry-point\\":
+ Delete the \`site.entry-point\` field, then add the top level \`main\` field to your configuration file:
+ \`\`\`
+ main = \\"my-site/index.js\\"
+ \`\`\`"
+ `);
+ } else {
+ expect(diagnostics.renderWarnings()).toMatchInlineSnapshot(`
+ "Processing wrangler configuration:
+ - DEPRECATION: \\"site.entry-point\\":
+ Delete the \`site.entry-point\` field, then add the top level \`main\` field to your configuration file:
+ \`\`\`
+ main = \\"my-site\\index.js\\"
+ \`\`\`"
+ `);
+ }
});
it("should error if `site` config is missing `bucket`", () => {
const expectedConfig: RawConfig = {
// @ts-expect-error we're intentionally passing an invalid configuration here
site: {
+ "entry-point": "workers-site",
include: ["INCLUDE_1", "INCLUDE_2"],
exclude: ["EXCLUDE_1", "EXCLUDE_2"],
},
@@ -262,18 +285,38 @@ describe("normalizeAndValidateConfig()", () => {
);
expect(config).toEqual(expect.objectContaining(expectedConfig));
+ expect(diagnostics.hasWarnings()).toBe(true);
expect(diagnostics.hasErrors()).toBe(true);
+ if (!isWindows) {
+ expect(diagnostics.renderWarnings()).toMatchInlineSnapshot(`
+ "Processing wrangler configuration:
+ - DEPRECATION: \\"site.entry-point\\":
+ Delete the \`site.entry-point\` field, then add the top level \`main\` field to your configuration file:
+ \`\`\`
+ main = \\"workers-site/index.js\\"
+ \`\`\`"
+ `);
+ } else {
+ expect(diagnostics.renderWarnings()).toMatchInlineSnapshot(`
+ "Processing wrangler configuration:
+ - DEPRECATION: \\"site.entry-point\\":
+ Delete the \`site.entry-point\` field, then add the top level \`main\` field to your configuration file:
+ \`\`\`
+ main = \\"workers-site\\index.js\\"
+ \`\`\`"
+ `);
+ }
expect(diagnostics.renderErrors()).toMatchInlineSnapshot(`
"Processing wrangler configuration:
- \\"site.bucket\\" is a required field."
`);
- expect(diagnostics.hasWarnings()).toBe(false);
});
it("should error on invalid `site` values", () => {
const expectedConfig = {
site: {
bucket: "BUCKET",
+ "entry-point": 111,
include: [222, 333],
exclude: [444, 555],
},
@@ -286,17 +329,37 @@ describe("normalizeAndValidateConfig()", () => {
);
expect(config).toEqual(expect.objectContaining(expectedConfig));
- expect(diagnostics.hasWarnings()).toBe(false);
+ expect(diagnostics.hasWarnings()).toBe(true);
expect(diagnostics.renderErrors()).toMatchInlineSnapshot(`
"Processing wrangler configuration:
- Expected \\"sites.include.[0]\\" to be of type string but got 222.
- Expected \\"sites.include.[1]\\" to be of type string but got 333.
- Expected \\"sites.exclude.[0]\\" to be of type string but got 444.
- - Expected \\"sites.exclude.[1]\\" to be of type string but got 555."
+ - Expected \\"sites.exclude.[1]\\" to be of type string but got 555.
+ - Expected \\"site.entry-point\\" to be of type string but got 111."
+ `);
+ if (!isWindows) {
+ expect(diagnostics.renderWarnings()).toMatchInlineSnapshot(`
+ "Processing wrangler configuration:
+ - DEPRECATION: \\"site.entry-point\\":
+ Delete the \`site.entry-point\` field, then add the top level \`main\` field to your configuration file:
+ \`\`\`
+ main = \\"111/index.js\\"
+ \`\`\`"
+ `);
+ } else {
+ expect(diagnostics.renderWarnings()).toMatchInlineSnapshot(`
+ "Processing wrangler configuration:
+ - DEPRECATION: \\"site.entry-point\\":
+ Delete the \`site.entry-point\` field, then add the top level \`main\` field to your configuration file:
+ \`\`\`
+ main = \\"111\\index.js\\"
+ \`\`\`"
`);
+ }
});
- it("should error with a deprecation warning if entry-point is defined", async () => {
+ it("should log a deprecation warning if entry-point is defined", async () => {
const { config, diagnostics } = normalizeAndValidateConfig(
{
site: {
@@ -311,22 +374,32 @@ describe("normalizeAndValidateConfig()", () => {
expect(config.site).toMatchInlineSnapshot(`
Object {
"bucket": "some/path",
+ "entry-point": "some/other/script.js",
"exclude": Array [],
"include": Array [],
}
`);
expect(diagnostics.hasWarnings()).toBe(true);
- expect(diagnostics.hasErrors()).toBe(true);
- expect(diagnostics.renderWarnings()).toMatchInlineSnapshot(`
+ expect(diagnostics.hasErrors()).toBe(false);
+ if (!isWindows) {
+ expect(diagnostics.renderWarnings()).toMatchInlineSnapshot(`
"Processing wrangler configuration:
- - Unexpected fields found in site field: \\"entry-point\\""
+ - DEPRECATION: \\"site.entry-point\\":
+ Delete the \`site.entry-point\` field, then add the top level \`main\` field to your configuration file:
+ \`\`\`
+ main = \\"some/other/script.js\\"
+ \`\`\`"
`);
- expect(diagnostics.renderErrors()).toMatchInlineSnapshot(`
+ } else {
+ expect(diagnostics.renderWarnings()).toMatchInlineSnapshot(`
"Processing wrangler configuration:
- - NO LONGER SUPPORTED: \\"site.entry-point\\":
- The \`site.entry-point\` config field is no longer used.
- The entry-point should be specified via the command line or the \`main\` config field."
+ - DEPRECATION: \\"site.entry-point\\":
+ Delete the \`site.entry-point\` field, then add the top level \`main\` field to your configuration file:
+ \`\`\`
+ main = \\"some\\other\\script.js\\"
+ \`\`\`"
`);
+ }
});
});
diff --git a/packages/wrangler/src/__tests__/publish.test.ts b/packages/wrangler/src/__tests__/publish.test.ts
index da3ee66fd350b..282dec0aa1f94 100644
--- a/packages/wrangler/src/__tests__/publish.test.ts
+++ b/packages/wrangler/src/__tests__/publish.test.ts
@@ -758,10 +758,19 @@ export default{
"
`);
- expect(std.warn).toMatchInlineSnapshot(`""`);
+ expect(std.warn).toMatchInlineSnapshot(`
+ "[33m▲ [43;33m[[43;30mWARNING[43;33m][0m [1mProcessing wrangler.toml configuration:
+ - Because you've defined a [site] configuration, we've defaulting to \\"workers-site\\" for the deprecated \`site.entry-point\`field.
+ Add the top level \`main\` field to your configuration file:
+ \`\`\`
+ main = \\"workers-site/index.js\\"
+ \`\`\`[0m
+
+ "
+ `);
});
- it("should error if there is a `site.entry-point` configuration", async () => {
+ it("should warn if there is a `site.entry-point` configuration", async () => {
const assets = [
{ filePath: "assets/file-1.txt", content: "Content of file-1" },
{ filePath: "assets/file-2.txt", content: "Content of file-2" },
@@ -784,35 +793,102 @@ export default{
mockListKVNamespacesRequest(kvNamespace);
mockKeyListRequest(kvNamespace.id, []);
mockUploadAssetsToKVRequest(kvNamespace.id, assets);
+ await runWrangler("publish ./index.js");
- await expect(runWrangler("publish ./index.js")).rejects
- .toThrowErrorMatchingInlineSnapshot(`
- "Processing wrangler.toml configuration:
- - NO LONGER SUPPORTED: \\"site.entry-point\\":
- The \`site.entry-point\` config field is no longer used.
- The entry-point should be specified via the command line or the \`main\` config field."
- `);
+ expect(std).toMatchInlineSnapshot(`
+ Object {
+ "debug": "",
+ "err": "",
+ "out": "Reading assets/file-1.txt...
+ Uploading as assets/file-1.2ca234f380.txt...
+ Reading assets/file-2.txt...
+ Uploading as assets/file-2.5938485188.txt...
+ ↗️ Done syncing assets
+ Uploaded test-name (TIMINGS)
+ Published test-name (TIMINGS)
+ test-name.test-sub-domain.workers.dev",
+ "warn": "[33m▲ [43;33m[[43;30mWARNING[43;33m][0m [1mProcessing wrangler.toml configuration:
+ - DEPRECATION: \\"site.entry-point\\":
+ Delete the \`site.entry-point\` field, then add the top level \`main\` field to your configuration file:
+ \`\`\`
+ main = \\"index.js\\"
+ \`\`\`[0m
- expect(std.out).toMatchInlineSnapshot(`
- "
- [32mIf you think this is a bug then please create an issue at https://github.com/cloudflare/wrangler2/issues/new.[0m"
+ ",
+ }
`);
- expect(std.err).toMatchInlineSnapshot(`
- "[31mX [41;31m[[41;97mERROR[41;31m][0m [1mProcessing wrangler.toml configuration:
- - NO LONGER SUPPORTED: \\"site.entry-point\\":
- The \`site.entry-point\` config field is no longer used.
- The entry-point should be specified via the command line or the \`main\` config field.[0m
+ });
- "
- `);
- expect(std.warn).toMatchInlineSnapshot(`
- "[33m▲ [43;33m[[43;30mWARNING[43;33m][0m [1mProcessing wrangler.toml configuration:
- - Unexpected fields found in site field: \\"entry-point\\"[0m
+ it("should resolve site.entry-point relative to wrangler.toml", async () => {
+ const assets = [
+ { filePath: "assets/file-1.txt", content: "Content of file-1" },
+ { filePath: "assets/file-2.txt", content: "Content of file-2" },
+ ];
+ const kvNamespace = {
+ title: "__test-name-workers_sites_assets",
+ id: "__test-name-workers_sites_assets-id",
+ };
+ fs.mkdirSync("my-site");
+ process.chdir("my-site");
+ writeWranglerToml({
+ site: {
+ bucket: "assets",
+ "entry-point": "my-entry",
+ },
+ });
+ fs.mkdirSync("my-entry");
+ fs.writeFileSync("my-entry/index.js", "export default {}");
+ writeAssets(assets);
+ process.chdir("..");
+ mockUploadWorkerRequest();
+ mockSubDomainRequest();
+ mockListKVNamespacesRequest(kvNamespace);
+ mockKeyListRequest(kvNamespace.id, []);
+ mockUploadAssetsToKVRequest(kvNamespace.id, assets);
+ await runWrangler("publish --config ./my-site/wrangler.toml");
- "
+ expect(std).toMatchInlineSnapshot(`
+ Object {
+ "debug": "",
+ "err": "",
+ "out": "Reading assets/file-1.txt...
+ Uploading as assets/file-1.2ca234f380.txt...
+ Reading assets/file-2.txt...
+ Uploading as assets/file-2.5938485188.txt...
+ ↗️ Done syncing assets
+ Uploaded test-name (TIMINGS)
+ Published test-name (TIMINGS)
+ test-name.test-sub-domain.workers.dev",
+ "warn": "[33m▲ [43;33m[[43;30mWARNING[43;33m][0m [1mProcessing my-site/wrangler.toml configuration:
+ - DEPRECATION: \\"site.entry-point\\":
+ Delete the \`site.entry-point\` field, then add the top level \`main\` field to your configuration file:
+ \`\`\`
+ main = \\"my-entry/index.js\\"
+ \`\`\`[0m
+
+ ",
+ }
`);
});
+ it("should error if both main and site.entry-point are specified", async () => {
+ writeWranglerToml({
+ main: "some-entry",
+ site: {
+ bucket: "some-bucket",
+ "entry-point": "./index.js",
+ },
+ });
+
+ await expect(runWrangler("publish")).rejects
+ .toThrowErrorMatchingInlineSnapshot(`
+ "Processing wrangler.toml configuration:
+ - Don't define both the \`main\` and \`site.entry-point\` fields in your configuration.
+ They serve the same purpose: to point to the entry-point of your worker.
+ Delete the \`site.entry-point\` field from your config."
+ `);
+ });
+
it("should error if there is no entry-point specified", async () => {
writeWranglerToml();
writeWorkerSource();
diff --git a/packages/wrangler/src/config/validation.ts b/packages/wrangler/src/config/validation.ts
index 0a11bc4c51939..297f26b149d86 100644
--- a/packages/wrangler/src/config/validation.ts
+++ b/packages/wrangler/src/config/validation.ts
@@ -85,16 +85,6 @@ export function normalizeAndValidateConfig(
true
);
- deprecated(
- diagnostics,
- rawConfig,
- `site.entry-point`,
- `The \`site.entry-point\` config field is no longer used.\nThe entry-point should be specified via the command line or the \`main\` config field.`,
- false,
- "NO LONGER SUPPORTED",
- "error"
- );
-
validateOptionalProperty(
diagnostics,
"",
@@ -204,7 +194,12 @@ export function normalizeAndValidateConfig(
diagnostics,
rawConfig.migrations ?? []
),
- site: normalizeAndValidateSite(diagnostics, rawConfig.site),
+ site: normalizeAndValidateSite(
+ diagnostics,
+ configPath,
+ rawConfig,
+ activeEnv.main
+ ),
wasm_modules: normalizeAndValidateModulePaths(
diagnostics,
configPath,
@@ -454,15 +449,86 @@ function normalizeAndValidateMigrations(
*/
function normalizeAndValidateSite(
diagnostics: Diagnostics,
- rawSite: Config["site"]
+ configPath: string | undefined,
+ rawConfig: RawConfig,
+ mainEntryPoint: string | undefined
): Config["site"] {
- if (rawSite !== undefined) {
- const { bucket, include = [], exclude = [], ...rest } = rawSite;
- validateAdditionalProperties(diagnostics, "site", Object.keys(rest), []);
+ if (rawConfig?.site !== undefined) {
+ const { bucket, include = [], exclude = [], ...rest } = rawConfig.site;
+
+ validateAdditionalProperties(diagnostics, "site", Object.keys(rest), [
+ "entry-point",
+ ]);
validateRequiredProperty(diagnostics, "site", "bucket", bucket, "string");
validateTypedArray(diagnostics, "sites.include", include, "string");
validateTypedArray(diagnostics, "sites.exclude", exclude, "string");
- return { bucket, include, exclude };
+ validateOptionalProperty(
+ diagnostics,
+ "site",
+ "entry-point",
+ rawConfig.site["entry-point"],
+ "string"
+ );
+
+ deprecated(
+ diagnostics,
+ rawConfig,
+ `site.entry-point`,
+ `Delete the \`site.entry-point\` field, then add the top level \`main\` field to your configuration file:\n` +
+ `\`\`\`\n` +
+ `main = "${path.join(
+ String(rawConfig.site["entry-point"]) || "workers-site",
+ path.extname(String(rawConfig.site["entry-point"]) || "workers-site")
+ ? ""
+ : "index.js"
+ )}"\n` +
+ `\`\`\``,
+ false,
+ undefined,
+ "warning"
+ );
+
+ let siteEntryPoint = rawConfig.site["entry-point"];
+
+ if (!mainEntryPoint && !rawConfig.site["entry-point"]) {
+ // this means that we're defaulting to "workers-site"
+ // so let's add the deprecation warning
+ diagnostics.warnings.push(
+ `Because you've defined a [site] configuration, we've defaulting to "workers-site" for the deprecated \`site.entry-point\`field.\n` +
+ `Add the top level \`main\` field to your configuration file:\n` +
+ `\`\`\`\n` +
+ `main = "workers-site/index.js"\n` +
+ `\`\`\``
+ );
+ siteEntryPoint = "workers-site";
+ }
+
+ if (mainEntryPoint && rawConfig.site["entry-point"]) {
+ diagnostics.errors.push(
+ `Don't define both the \`main\` and \`site.entry-point\` fields in your configuration.\n` +
+ `They serve the same purpose: to point to the entry-point of your worker.\n` +
+ `Delete the \`site.entry-point\` field from your config.`
+ );
+ siteEntryPoint = rawConfig.site["entry-point"];
+ }
+
+ if (configPath && siteEntryPoint) {
+ // rewrite the path to be relative to the config file
+ siteEntryPoint = path.relative(
+ process.cwd(),
+ path.join(
+ path.dirname(configPath),
+ rawConfig.site["entry-point"] || "workers-site"
+ )
+ );
+ }
+
+ return {
+ bucket,
+ "entry-point": siteEntryPoint,
+ include,
+ exclude,
+ };
}
return undefined;
}
diff --git a/packages/wrangler/src/entry.ts b/packages/wrangler/src/entry.ts
index 05c524a797baf..332bbc1628921 100644
--- a/packages/wrangler/src/entry.ts
+++ b/packages/wrangler/src/entry.ts
@@ -1,5 +1,5 @@
import assert from "node:assert";
-import { existsSync } from "node:fs";
+import { existsSync, lstatSync } from "node:fs";
import path from "node:path";
import * as esbuild from "esbuild";
import { execaCommand } from "execa";
@@ -25,13 +25,20 @@ export async function getEntry(
): Promise {
let file: string;
let directory = process.cwd();
+ let isSiteEntryPoint = false;
if (args.script) {
// If the script name comes from the command line it is relative to the current working directory.
file = path.resolve(args.script);
} else if (config.main === undefined) {
- throw new Error(
- `Missing entry-point: The entry-point should be specified via the command line (e.g. \`wrangler ${command} path/to/script\`) or the \`main\` config field.`
- );
+ if (config.site?.["entry-point"]) {
+ isSiteEntryPoint = true;
+ directory = path.resolve(path.dirname(config.configPath ?? "."));
+ file = path.resolve(config.site?.["entry-point"]);
+ } else {
+ throw new Error(
+ `Missing entry-point: The entry-point should be specified via the command line (e.g. \`wrangler ${command} path/to/script\`) or the \`main\` config field.`
+ );
+ }
} else {
directory = path.resolve(path.dirname(config.configPath ?? "."));
file = path.resolve(directory, config.main);
@@ -39,6 +46,13 @@ export async function getEntry(
await runCustomBuild(file, config.build);
+ if (isSiteEntryPoint) {
+ // site.entry-point could be a directory
+ if (existsSync(file) && lstatSync(file).isDirectory()) {
+ file = path.resolve(file, "index.js");
+ }
+ }
+
if (fileExists(file) === false) {
throw new Error(
`Could not resolve "${path.relative(process.cwd(), file)}".`