├── .gitignore ├── .prettierignore ├── .prettierrc ├── README.md ├── build.mjs ├── jest.config.js ├── package-lock.json ├── package.json ├── src ├── index.test.ts ├── index.ts └── workers.d.ts ├── tsconfig.json └── wrangler.toml /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | # Ignore artifacts 2 | dist -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "arrowParens": "avoid", 3 | "trailingComma": "none" 4 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Cloudflare Workers Typescript esbuild ESM template 2 | 3 | A Cloudflare Workers template for using: 4 | 5 | - TypeScript 6 | - Esbuild 7 | - Durable Objects 8 | - Jest 9 | - Workers ESM syntax 10 | - Wrangler 11 | 12 | Worker code is in `src/`. The Durable Object Counter class is in `src/counter.ts`, and the eyeball script is in index.ts. 13 | 14 | Esbuild is configured to output a bundled ES Module to dist/index.mjs. 15 | 16 | There's an example unit test in `src/index.test.ts`, which will run as part of wrangler build. To run tests on their own use npm test. 17 | 18 | On your first publish, you must use `wrangler publish --new-class Counter` to allow the Counter class to implement Durable Objects. 19 | -------------------------------------------------------------------------------- /build.mjs: -------------------------------------------------------------------------------- 1 | import { build } from "esbuild"; 2 | 3 | build({ 4 | bundle: true, 5 | format: "esm", 6 | mainFields: ["browser", "module", "main"], 7 | platform: "neutral", 8 | target: "es2020", 9 | entryPoints: ["./src/index.ts"], 10 | outfile: "./dist/worker.mjs", 11 | sourcemap: false, 12 | charset: "utf8", 13 | minify: process.env.NODE_ENV === "production" ? true : false 14 | }).catch(err => { 15 | console.error(err.stack); 16 | process.exitCode = 1; 17 | }); 18 | -------------------------------------------------------------------------------- /jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | roots: ["/src"], 3 | testMatch: [ 4 | "**/__tests__/**/*.+(ts|tsx|js)", 5 | "**/?(*.)+(spec|test).+(ts|tsx|js)" 6 | ], 7 | transform: { 8 | "^.+\\.(ts|tsx)$": "esbuild-jest" 9 | } 10 | }; 11 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "name": "cloudflare-workers-typescript-esbuild-esm", 4 | "version": "1.0.0", 5 | "description": "Cloudflare Workers template for using esbuild and TypeScript with the ESM syntax", 6 | "module": "./dist/index.mjs", 7 | "scripts": { 8 | "build": "node build.mjs", 9 | "test": "jest", 10 | "format": "prettier --write '**/*.{ts,mjs,js,html,css,json,md}'", 11 | "dev": "miniflare --watch --debug --port 8787", 12 | "publish": "cross-env NODE_ENV=production wrangler publish" 13 | }, 14 | "license": "MIT", 15 | "devDependencies": { 16 | "@cloudflare/workers-types": "^2.2.2", 17 | "@types/jest": "^27.0.2", 18 | "esbuild": "^0.13.4", 19 | "esbuild-jest": "^0.5.0", 20 | "isomorphic-fetch": "^3.0.0", 21 | "jest": "^27.2.4", 22 | "miniflare": "^1.4.1", 23 | "prettier": "^2.4.1", 24 | "typescript": "^4.4.3" 25 | }, 26 | "engines": { 27 | "node": ">=14" 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/index.test.ts: -------------------------------------------------------------------------------- 1 | import "isomorphic-fetch"; 2 | 3 | test("an example test", () => { 4 | expect(23).toBe(23); 5 | }); 6 | 7 | test("make sure test polyfills for fetch api work", () => { 8 | const url = "https://workers.cloudflare.com/"; 9 | const req = new Request(url); 10 | expect(req.url).toBe(url); 11 | }); 12 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | async fetch(request: Request, env: Env) { 3 | return new Response("Hello, world!"); 4 | } 5 | }; 6 | -------------------------------------------------------------------------------- /src/workers.d.ts: -------------------------------------------------------------------------------- 1 | export {}; 2 | 3 | declare global { 4 | interface Env {} 5 | 6 | interface WebSocket { 7 | accept(): void; 8 | } 9 | 10 | class WebSocketPair { 11 | 0: WebSocket; 12 | 1: WebSocket; 13 | } 14 | 15 | interface ResponseInit { 16 | webSocket?: WebSocket; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "esnext", 4 | "lib": ["esnext", "webworker"], 5 | "strict": true, 6 | "moduleResolution": "node", 7 | "skipLibCheck": true, 8 | "esModuleInterop": true, 9 | "types": ["@cloudflare/workers-types", "jest"] 10 | }, 11 | } 12 | -------------------------------------------------------------------------------- /wrangler.toml: -------------------------------------------------------------------------------- 1 | name = "cloudflare-workers-typescript-esbuild-esm" 2 | type = "javascript" 3 | account_id = "" 4 | workers_dev = true 5 | 6 | [build] 7 | command = "npm run build" 8 | [build.upload] 9 | format = "modules" 10 | main = "./worker.mjs" 11 | 12 | [durable_objects] 13 | bindings = [] 14 | --------------------------------------------------------------------------------