diff --git a/.changeset/silver-ties-sell.md b/.changeset/silver-ties-sell.md new file mode 100644 index 000000000000..acffd0fd66ca --- /dev/null +++ b/.changeset/silver-ties-sell.md @@ -0,0 +1,9 @@ +--- +"wrangler": patch +--- + +feat: `wrangler init` offers to create a starter worker + +We got feedback that `wrangler init` felt incomplete, because the immediate next thing folks need is a starter source file. So this adds another step to `wrangler init` where we offer to create that file for you. + +Fixes https://github.com/cloudflare/wrangler2/issues/355 diff --git a/package.json b/package.json index fe2f79821163..48a123d61c72 100644 --- a/package.json +++ b/package.json @@ -46,9 +46,10 @@ "eslintConfig": { "root": true, "ignorePatterns": [ - "packages/*/vendor", - "packages/*/*-dist", - "packages/wrangler/pages/functions/template-worker.ts" + "packages/wrangler/vendor", + "packages/wrangler/*-dist", + "packages/wrangler/pages/functions/template-worker.ts", + "packages/wrangler/templates" ], "parser": "@typescript-eslint/parser", "parserOptions": { diff --git a/packages/wrangler/package.json b/packages/wrangler/package.json index ca00cc0f164f..4b34ee6ca2b9 100644 --- a/packages/wrangler/package.json +++ b/packages/wrangler/package.json @@ -90,7 +90,7 @@ "pages", "miniflare-config-stubs", "wrangler-dist", - "static-asset-facade.js", + "templates", "vendor", "import_meta_url.js" ], diff --git a/packages/wrangler/src/__tests__/index.test.ts b/packages/wrangler/src/__tests__/index.test.ts index ae22c932d365..51f12839ddc9 100644 --- a/packages/wrangler/src/__tests__/index.test.ts +++ b/packages/wrangler/src/__tests__/index.test.ts @@ -150,7 +150,11 @@ describe("wrangler", () => { result: true, }, { - text: "Would you like to use typescript?", + text: "Would you like to use TypeScript?", + result: false, + }, + { + text: "Would you like to create a Worker at src/index.js?", result: false, } ); @@ -175,7 +179,11 @@ describe("wrangler", () => { result: false, }, { - text: "Would you like to use typescript?", + text: "Would you like to use TypeScript?", + result: false, + }, + { + text: "Would you like to create a Worker at src/index.js?", result: false, } ); @@ -201,7 +209,11 @@ describe("wrangler", () => { result: true, }, { - text: "Would you like to use typescript?", + text: "Would you like to use TypeScript?", + result: false, + }, + { + text: "Would you like to create a Worker at src/index.js?", result: false, } ); @@ -230,7 +242,11 @@ describe("wrangler", () => { result: false, }, { - text: "Would you like to use typescript?", + text: "Would you like to use TypeScript?", + result: false, + }, + { + text: "Would you like to create a Worker at src/index.js?", result: false, } ); @@ -259,6 +275,112 @@ describe("wrangler", () => { `); }); + it("should offer to create a worker in a non-typescript project", async () => { + mockConfirm( + { + text: "Would you like to install wrangler into your package.json?", + result: false, + }, + { + text: "Would you like to use TypeScript?", + result: false, + }, + { + text: "Would you like to create a Worker at src/index.js?", + result: true, + } + ); + + fs.writeFileSync( + "./package.json", + JSON.stringify({ name: "test", version: "1.0.0" }), + "utf-8" + ); + + await runWrangler("init"); + expect(fs.existsSync("./src/index.js")).toBe(true); + expect(fs.existsSync("./src/index.ts")).toBe(false); + }); + + it("should offer to create a worker in a typescript project", async () => { + mockConfirm( + { + text: "Would you like to install wrangler into your package.json?", + result: false, + }, + { + text: "Would you like to use TypeScript?", + result: true, + }, + { + text: "Would you like to create a Worker at src/index.ts?", + result: true, + } + ); + + fs.writeFileSync( + "./package.json", + JSON.stringify({ name: "test", version: "1.0.0" }), + "utf-8" + ); + + await runWrangler("init"); + expect(fs.existsSync("./src/index.js")).toBe(false); + expect(fs.existsSync("./src/index.ts")).toBe(true); + }); + + it("should not offer to create a worker in a non-ts project if a file already exists at the location", async () => { + mockConfirm( + { + text: "Would you like to install wrangler into your package.json?", + result: false, + }, + { + text: "Would you like to use TypeScript?", + result: false, + } + ); + + fs.writeFileSync( + "./package.json", + JSON.stringify({ name: "test", version: "1.0.0" }), + "utf-8" + ); + fs.mkdirSync("./src", { recursive: true }); + const PLACEHOLDER = "/* placeholder text */"; + fs.writeFileSync("./src/index.js", PLACEHOLDER, "utf-8"); + + await runWrangler("init"); + expect(fs.readFileSync("./src/index.js", "utf-8")).toBe(PLACEHOLDER); + expect(fs.existsSync("./src/index.ts")).toBe(false); + }); + + it("should not offer to create a worker in a ts project if a file already exists at the location", async () => { + mockConfirm( + { + text: "Would you like to install wrangler into your package.json?", + result: false, + }, + { + text: "Would you like to use TypeScript?", + result: true, + } + ); + + fs.writeFileSync( + "./package.json", + JSON.stringify({ name: "test", version: "1.0.0" }), + "utf-8" + ); + fs.mkdirSync("./src", { recursive: true }); + const PLACEHOLDER = "/* placeholder text */"; + fs.writeFileSync("./src/index.ts", PLACEHOLDER, "utf-8"); + + await runWrangler("init"); + expect(fs.existsSync("./src/index.js")).toBe(false); + expect(fs.readFileSync("./src/index.ts", "utf-8")).toBe(PLACEHOLDER); + }); + it("should create a tsconfig.json and install `workers-types` if none is found and user confirms", async () => { mockConfirm( { @@ -266,8 +388,12 @@ describe("wrangler", () => { result: true, }, { - text: "Would you like to use typescript?", + text: "Would you like to use TypeScript?", result: true, + }, + { + text: "Would you like to create a Worker at src/index.ts?", + result: false, } ); await runWrangler("init"); @@ -319,6 +445,10 @@ describe("wrangler", () => { { text: "Would you like to install the type definitions for Workers into your package.json?", result: true, + }, + { + text: "Would you like to create a Worker at src/index.ts?", + result: false, } ); fs.writeFileSync( diff --git a/packages/wrangler/src/index.tsx b/packages/wrangler/src/index.tsx index 66e4383f25b0..bb84b49dd4b8 100644 --- a/packages/wrangler/src/index.tsx +++ b/packages/wrangler/src/index.tsx @@ -1,6 +1,6 @@ import * as fs from "node:fs"; -import { readFile, writeFile } from "node:fs/promises"; -import path from "node:path/posix"; +import { readFile, writeFile, mkdir } from "node:fs/promises"; +import path from "node:path"; import { setTimeout } from "node:timers/promises"; import TOML from "@iarna/toml"; import { findUp } from "find-up"; @@ -266,11 +266,13 @@ export async function main(argv: string[]): Promise { } } + let isTypescriptProject = false; let pathToTSConfig = await findUp("tsconfig.json"); if (!pathToTSConfig) { // If there's no tsconfig, offer to create one // and install @cloudflare/workers-types - if (await confirm("Would you like to use typescript?")) { + if (await confirm("Would you like to use TypeScript?")) { + isTypescriptProject = true; await writeFile( path.join(process.cwd(), "tsconfig.json"), JSON.stringify( @@ -303,6 +305,7 @@ export async function main(argv: string[]): Promise { pathToTSConfig = path.join(process.cwd(), "tsconfig.json"); } } else { + isTypescriptProject = true; // If there's a tsconfig, check if @cloudflare/workers-types // is already installed, and offer to install it if not const packageJson = JSON.parse( @@ -326,8 +329,44 @@ export async function main(argv: string[]): Promise { console.log( `✨ Installed @cloudflare/workers-types.\nPlease add "@cloudflare/workers-types" to compilerOptions.types in your tsconfig.json` ); - } else { - return; + } + } + } + + if (isTypescriptProject) { + if (!fs.existsSync(path.join(process.cwd(), "src/index.ts"))) { + const shouldCreateSource = await confirm( + `Would you like to create a Worker at src/index.ts?` + ); + if (shouldCreateSource) { + const targetDir = path.join(process.cwd(), "src"); + await mkdir(targetDir, { recursive: true }); + await writeFile( + path.join(targetDir, "index.ts"), + await readFile( + path.join(__dirname, "../templates/new-worker.ts"), + "utf-8" + ) + ); + console.log(`✨ Created src/index.ts`); + } + } + } else { + if (!fs.existsSync(path.join(process.cwd(), "src/index.js"))) { + const shouldCreateSource = await confirm( + `Would you like to create a Worker at src/index.js?` + ); + if (shouldCreateSource) { + const targetDir = path.join(process.cwd(), "src"); + await mkdir(targetDir, { recursive: true }); + await writeFile( + path.join(targetDir, "index.js"), + await readFile( + path.join(__dirname, "../templates/new-worker.js"), + "utf-8" + ) + ); + console.log(`✨ Created src/index.js`); } } } diff --git a/packages/wrangler/src/publish.ts b/packages/wrangler/src/publish.ts index 05c95ff2ca92..f53983eb70e4 100644 --- a/packages/wrangler/src/publish.ts +++ b/packages/wrangler/src/publish.ts @@ -130,7 +130,7 @@ export default async function publish(props: Props): Promise { stdin: { contents: ( await readFile( - path.join(__dirname, "../static-asset-facade.js"), + path.join(__dirname, "../templates/static-asset-facade.js"), "utf8" ) ).replace("__ENTRY_POINT__", file), diff --git a/packages/wrangler/templates/new-worker.js b/packages/wrangler/templates/new-worker.js new file mode 100644 index 000000000000..df629f86184a --- /dev/null +++ b/packages/wrangler/templates/new-worker.js @@ -0,0 +1,15 @@ +/** + * Welcome to Cloudflare Workers! This is your first worker. + * + * - Run `npx wrangler dev src/index.js` in your terminal to start a development server + * - Open a browser tab at http://localhost:8787/ to see your worker in action + * - Run `npx wrangler publish src/index.js --name my-worker` to deploy your worker + * + * Learn more at https://developers.cloudflare.com/workers/ + */ + +export default { + async fetch(request) { + return new Response("Hello World!"); + }, +}; diff --git a/packages/wrangler/templates/new-worker.ts b/packages/wrangler/templates/new-worker.ts new file mode 100644 index 000000000000..6e2db1b00265 --- /dev/null +++ b/packages/wrangler/templates/new-worker.ts @@ -0,0 +1,15 @@ +/** + * Welcome to Cloudflare Workers! This is your first worker. + * + * - Run `wrangler dev src/index.ts` in your terminal to start a development server + * - Open a browser tab at http://localhost:8787/ to see your worker in action + * - Run `wrangler publish src/index.ts --name my-worker` to deploy your worker + * + * Learn more at https://developers.cloudflare.com/workers/ + */ + +export default { + async fetch(request: Request): Promise { + return new Response("Hello World!"); + }, +}; diff --git a/packages/wrangler/static-asset-facade.js b/packages/wrangler/templates/static-asset-facade.js similarity index 100% rename from packages/wrangler/static-asset-facade.js rename to packages/wrangler/templates/static-asset-facade.js diff --git a/tsconfig.json b/tsconfig.json index a2b918d4f2c6..2b24f2b83e12 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -17,8 +17,9 @@ }, "exclude": [ "node_modules/", - "packages/*/vendor", - "packages/*/*-dist", - "packages/wrangler/pages/functions/template-worker.ts" + "packages/wrangler/vendor", + "packages/wrangler/*-dist", + "packages/wrangler/pages/functions/template-worker.ts", + "packages/wrangler/templates" ] }