Skip to content

Commit

Permalink
fix(wrangler): Support switching between static and dynamic Workers
Browse files Browse the repository at this point in the history
This commit fixes the current behaviour of watch mode for Workers with assets, and adds support for switching between static and dynamic Workers within a single `wrangler dev` session.
  • Loading branch information
CarmenPopoviciu committed Sep 19, 2024
1 parent 2ddbb65 commit 77dcf22
Show file tree
Hide file tree
Showing 3 changed files with 241 additions and 11 deletions.
7 changes: 7 additions & 0 deletions .changeset/bright-guests-destroy.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
"wrangler": patch
---

fix: Support switching between static and dynamic Workers

This commit fixes the current behaviour of watch mode for Workers with assets, and adds support for switching between static and dynamic Workers within a single `wrangler dev` session.
201 changes: 201 additions & 0 deletions packages/wrangler/e2e/dev.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1087,6 +1087,110 @@ describe("watch mode", () => {
"<h1>Read more about Workers + Assets</h1>"
);
});

it(`supports switching from assets-only to Workers with assets during the current dev session`, async () => {
const helper = new WranglerE2ETestHelper();
await helper.seed({
"wrangler.toml": dedent`
name = "${workerName}"
compatibility_date = "2023-01-01"
[experimental_assets]
directory = "./public"
`,
"public/index.html": dedent`
<h1>Hello Workers + Assets</h1>`,
});
const worker = helper.runLongLived(cmd);
const { url } = await worker.waitForReady();

// verify response from Asset Worker
let { response } = await fetchWithETag(`${url}/index.html`, {});
expect(await response.text()).toBe("<h1>Hello Workers + Assets</h1>");

// verify no response from route that will be handled by the
// User Worker in the future
({ response } = await fetchWithETag(`${url}/hey`, {}));
expect(await response.status).toBe(404);

await helper.seed({
"wrangler.toml": dedent`
name = "${workerName}"
main = "src/index.ts"
compatibility_date = "2023-01-01"
[experimental_assets]
directory = "./public"
`,
"src/index.ts": dedent`
export default {
fetch(request) {
return new Response("Hello from user Worker!")
}
}`,
});

await worker.waitForReload();

({ response } = await fetchWithETag(`${url}/index.html`, {}));
expect(await response.text()).toBe("<h1>Hello Workers + Assets</h1>");

({ response } = await fetchWithETag(`${url}/hey`, {}));
expect(await response.text()).toBe("Hello from user Worker!");
});

it(`supports switching from Workers with assets to assets-only during the current dev session`, async () => {
const helper = new WranglerE2ETestHelper();
await helper.seed({
"wrangler.toml": dedent`
name = "${workerName}"
main = "src/index.ts"
compatibility_date = "2023-01-01"
[experimental_assets]
directory = "./public"
`,
"public/index.html": dedent`
<h1>Hello Workers + Assets</h1>`,
"src/index.ts": dedent`
export default {
fetch(request) {
return new Response("Hello from user Worker!")
}
}`,
});

const worker = helper.runLongLived(cmd);
const { url } = await worker.waitForReady();

// verify response from Asset Worker
let { response } = await fetchWithETag(`${url}/index.html`, {});
expect(await response.text()).toBe("<h1>Hello Workers + Assets</h1>");

// verify response from User Worker
({ response } = await fetchWithETag(`${url}/hey`, {}));
expect(await response.text()).toBe("Hello from user Worker!");

await helper.seed({
"wrangler.toml": dedent`
name = "${workerName}"
compatibility_date = "2023-01-01"
[experimental_assets]
directory = "./public"
`,
});

await worker.waitForReload();

// verify we still get the correct response from Asset Worker
({ response } = await fetchWithETag(`${url}/index.html`, {}));
expect(await response.text()).toBe("<h1>Hello Workers + Assets</h1>");

// verify we no longer get a response from the User Worker
({ response } = await fetchWithETag(`${url}/hey`, {}));
expect(await response.status).toBe(404);
});
}
);

Expand Down Expand Up @@ -1176,5 +1280,102 @@ describe("watch mode", () => {
));
expect(response.status).toBe(404);
});

it(`supports switching from assets-only to Workers with assets during the current dev session`, async () => {
const helper = new WranglerE2ETestHelper();
await helper.seed({
"wrangler.toml": dedent`
name = "${workerName}"
compatibility_date = "2023-01-01"
`,
"dist/index.html": dedent`
<h1>Hello Workers + Assets</h1>`,
"src/index.ts": dedent`
export default {
fetch(request) {
return new Response("Hello from user Worker!")
}
}`,
});
const worker = helper.runLongLived(cmd);
const { url } = await worker.waitForReady();

// verify response from Asset Worker
let { response } = await fetchWithETag(`${url}/index.html`, {});
expect(await response.text()).toBe("<h1>Hello Workers + Assets</h1>");
expect(await response.status).toBe(200);

// verify no response from route that will be handled by the
// User Worker in the future
({ response } = await fetchWithETag(`${url}/hey`, {}));
expect(await response.status).toBe(404);

await helper.seed({
"wrangler.toml": dedent`
name = "${workerName}"
main = "src/index.ts"
compatibility_date = "2023-01-01"
`,
});

await worker.waitForReload();

({ response } = await fetchWithETag(`${url}/index.html`, {}));
expect(await response.text()).toBe("<h1>Hello Workers + Assets</h1>");
expect(await response.status).toBe(200);

({ response } = await fetchWithETag(`${url}/hey`, {}));
expect(await response.text()).toBe("Hello from user Worker!");
expect(await response.status).toBe(200);
});

it(`supports switching from Workers with assets to assets-only Workers during the current dev session`, async () => {
const helper = new WranglerE2ETestHelper();
await helper.seed({
"wrangler.toml": dedent`
name = "${workerName}"
main = "src/index.ts"
compatibility_date = "2023-01-01"
`,
"dist/index.html": dedent`
<h1>Hello Workers + Assets</h1>`,
"src/index.ts": dedent`
export default {
fetch(request) {
return new Response("Hello from user Worker!")
}
}`,
});
const worker = helper.runLongLived(cmd);
const { url } = await worker.waitForReady();

// verify response from Asset Worker
let { response } = await fetchWithETag(`${url}/index.html`, {});
expect(await response.text()).toBe("<h1>Hello Workers + Assets</h1>");
expect(await response.status).toBe(200);

// verify nresponse from User Worker
({ response } = await fetchWithETag(`${url}/hey`, {}));
expect(await response.text()).toBe("Hello from user Worker!");
expect(await response.status).toBe(200);

await helper.seed({
"wrangler.toml": dedent`
name = "${workerName}"
compatibility_date = "2023-01-01"
`,
});

await worker.waitForReload();

({ response } = await fetchWithETag(`${url}/index.html`, {}));
// verify response from Asset
expect(await response.text()).toBe("<h1>Hello Workers + Assets</h1>");
expect(await response.status).toBe(200);

// verify no response from User Worker
({ response } = await fetchWithETag(`${url}/hey`, {}));
expect(await response.status).toBe(404);
});
});
});
44 changes: 33 additions & 11 deletions packages/wrangler/src/dev.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -836,11 +836,39 @@ export async function startDev(args: StartDevOptions) {

logger.log(`${path.basename(config.configPath)} changed...`);

/*
* If this is a Worker with assets, we want to enable switching
* from assets only Worker to Worker with assets and vice versa
* during local development. For that, we need to watch for changes
* in the `wrangler.toml` file, specifically the `main` configuration
* key, and re-asses the entry point every time.
*/
if (experimentalAssetsOptions?.directory) {
entry = await getEntry(
{
legacyAssets: args.legacyAssets,
script: args.script,
moduleRoot: args.moduleRoot,
experimentalAssets: args.experimentalAssets,
},
config,
"dev"
);

// this gets passed into the Dev React element, so ensure we don't
// block scope this var
experimentalAssetsOptions = processExperimentalAssetsArg(
args,
config
);
}

/*
* Handle experimental assets watching on config file changes
*
* 1. if experimental assets was specified via CLI args, config file
* changes shouldn't affect anything
* 1. if experimental assets was specified via CLI args, only config file
* changes related to `main` will matter. In this case, re-running
* `processExperimentalAssetsArg` is enough (see above)
* 2. if experimental_assets was not specififed via the configuration
* file, but it is now, we should start watching the assets
* directory
Expand All @@ -851,13 +879,6 @@ export async function startDev(args: StartDevOptions) {
if (experimentalAssetsOptions && !args.experimentalAssets) {
await assetsWatcher?.close();

// this gets passed into the Dev React element, so ensure we don't
// block scope this var
experimentalAssetsOptions = processExperimentalAssetsArg(
args,
config
);

if (experimentalAssetsOptions) {
assetsWatcher = watch(experimentalAssetsOptions.directory, {
persistent: true,
Expand All @@ -878,8 +899,9 @@ export async function startDev(args: StartDevOptions) {
});
}

const devServerSettings = await validateDevServerSettings(args, config);
let { entry } = devServerSettings;
const {
entry,
upstreamProtocol,
host,
routes,
Expand All @@ -891,7 +913,7 @@ export async function startDev(args: StartDevOptions) {
localPersistencePath,
processEntrypoint,
additionalModules,
} = await validateDevServerSettings(args, config);
} = devServerSettings;

const nodejsCompatMode = getNodeCompatMode(
args.compatibilityFlags ?? config.compatibility_flags ?? [],
Expand Down

0 comments on commit 77dcf22

Please sign in to comment.