From 6f6e4ea452e78d3060d53054ffc745ce435c8f7f Mon Sep 17 00:00:00 2001 From: Karthik Ganeshram Date: Fri, 17 Oct 2025 19:48:55 +0530 Subject: [PATCH 1/3] update http templates to use esbuild Signed-off-by: Karthik Ganeshram --- templates/http-js/content/build.mjs | 43 ++++++++++++++++++++ templates/http-js/content/package.json | 5 +-- templates/http-js/content/webpack.config.js | 32 --------------- templates/http-ts/content/build.mjs | 43 ++++++++++++++++++++ templates/http-ts/content/package.json | 5 +-- templates/http-ts/content/webpack.config.js | 44 --------------------- test/test-app/package.json | 2 +- test/test-app/spin.toml | 2 +- test/test-app/src/test.ts | 4 +- 9 files changed, 95 insertions(+), 85 deletions(-) create mode 100644 templates/http-js/content/build.mjs delete mode 100644 templates/http-js/content/webpack.config.js create mode 100644 templates/http-ts/content/build.mjs delete mode 100644 templates/http-ts/content/webpack.config.js diff --git a/templates/http-js/content/build.mjs b/templates/http-js/content/build.mjs new file mode 100644 index 00000000..5106a9b8 --- /dev/null +++ b/templates/http-js/content/build.mjs @@ -0,0 +1,43 @@ +// build.mjs +import { build } from 'esbuild'; +import path from 'path'; +import { SpinEsbuildPlugin } from "@spinframework/build-tools/plugins/esbuild/index.js"; +import fs from 'fs'; + +const spinPlugin = await SpinEsbuildPlugin(); + +// plugin to handle vendor files in node_modules that may not be bundled. +// Instead of generating a real source map for these files, it appends a minimal +// inline source map pointing to an empty source. This avoids errors and ensures +// source maps exist even for unbundled vendor code. +let SourceMapPlugin = { + name: 'excludeVendorFromSourceMap', + setup(build) { + build.onLoad({ filter: /node_modules/ }, args => { + return { + contents: fs.readFileSync(args.path, 'utf8') + + '\n//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIiJdLCJtYXBwaW5ncyI6IkEifQ==', + loader: 'default', + } + }) + }, +} + +await build({ + entryPoints: ['./src/index.ts'], + outfile: './build/bundle.js', + bundle: true, + format: 'esm', + platform: 'node', + sourcemap: true, + minify: false, + plugins: [spinPlugin, SourceMapPlugin], + logLevel: 'error', + loader: { + '.ts': 'ts', + '.tsx': 'tsx', + }, + resolveExtensions: ['.ts', '.tsx', '.js'], + // This prevents sourcemaps from traversing into node_modules + sourceRoot: path.resolve(process.cwd(), 'src'), +}); diff --git a/templates/http-js/content/package.json b/templates/http-js/content/package.json index 85e0ae43..2124499c 100644 --- a/templates/http-js/content/package.json +++ b/templates/http-js/content/package.json @@ -4,7 +4,7 @@ "description": "{{project-description}}", "main": "index.js", "scripts": { - "build": "npx webpack && mkdirp dist && j2w -i build/bundle.js --initLocation http://{{project-name | kebab_case}}.localhost -o dist/{{ project-name | kebab_case }}.wasm", + "build": "node build.mjs && mkdirp dist && j2w -i build/bundle.js --initLocation http://{{project-name | kebab_case}}.localhost -o dist/{{ project-name | kebab_case }}.wasm", "test": "echo \"Error: no test specified\" && exit 1" }, "keywords": [], @@ -12,8 +12,7 @@ "license": "ISC", "devDependencies": { "mkdirp": "^3.0.1", - "webpack": "^5.74.0", - "webpack-cli": "^4.10.0" + "esbuild": "^0.25.8" }, "dependencies": { {%- case http-router -%} diff --git a/templates/http-js/content/webpack.config.js b/templates/http-js/content/webpack.config.js deleted file mode 100644 index af3a4ad0..00000000 --- a/templates/http-js/content/webpack.config.js +++ /dev/null @@ -1,32 +0,0 @@ -import path from 'path'; -import SpinSdkPlugin from "@spinframework/build-tools/plugins/webpack/index.js"; - -const config = async () => { - let SpinPlugin = await SpinSdkPlugin.init() - return { - mode: 'production', - stats: 'errors-only', - entry: './src/index.js', - experiments: { - outputModule: true, - }, - resolve: { - extensions: ['.js'], - }, - output: { - path: path.resolve(process.cwd(), './build'), - filename: 'bundle.js', - module: true, - library: { - type: "module", - } - }, - plugins: [ - SpinPlugin - ], - optimization: { - minimize: false - }, - }; -} -export default config \ No newline at end of file diff --git a/templates/http-ts/content/build.mjs b/templates/http-ts/content/build.mjs new file mode 100644 index 00000000..5106a9b8 --- /dev/null +++ b/templates/http-ts/content/build.mjs @@ -0,0 +1,43 @@ +// build.mjs +import { build } from 'esbuild'; +import path from 'path'; +import { SpinEsbuildPlugin } from "@spinframework/build-tools/plugins/esbuild/index.js"; +import fs from 'fs'; + +const spinPlugin = await SpinEsbuildPlugin(); + +// plugin to handle vendor files in node_modules that may not be bundled. +// Instead of generating a real source map for these files, it appends a minimal +// inline source map pointing to an empty source. This avoids errors and ensures +// source maps exist even for unbundled vendor code. +let SourceMapPlugin = { + name: 'excludeVendorFromSourceMap', + setup(build) { + build.onLoad({ filter: /node_modules/ }, args => { + return { + contents: fs.readFileSync(args.path, 'utf8') + + '\n//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIiJdLCJtYXBwaW5ncyI6IkEifQ==', + loader: 'default', + } + }) + }, +} + +await build({ + entryPoints: ['./src/index.ts'], + outfile: './build/bundle.js', + bundle: true, + format: 'esm', + platform: 'node', + sourcemap: true, + minify: false, + plugins: [spinPlugin, SourceMapPlugin], + logLevel: 'error', + loader: { + '.ts': 'ts', + '.tsx': 'tsx', + }, + resolveExtensions: ['.ts', '.tsx', '.js'], + // This prevents sourcemaps from traversing into node_modules + sourceRoot: path.resolve(process.cwd(), 'src'), +}); diff --git a/templates/http-ts/content/package.json b/templates/http-ts/content/package.json index bea24cd7..ff7f2a96 100644 --- a/templates/http-ts/content/package.json +++ b/templates/http-ts/content/package.json @@ -4,7 +4,7 @@ "description": "{{project-description}}", "main": "index.js", "scripts": { - "build": "npx webpack && mkdirp dist && j2w -i build/bundle.js --initLocation http://{{project-name | kebab_case}}.localhost -o dist/{{ project-name | kebab_case }}.wasm", + "build": "node build.mjs && mkdirp dist && j2w -i build/bundle.js --initLocation http://{{project-name | kebab_case}}.localhost -o dist/{{ project-name | kebab_case }}.wasm", "test": "echo \"Error: no test specified\" && exit 1" }, "keywords": [], @@ -14,8 +14,7 @@ "mkdirp": "^3.0.1", "ts-loader": "^9.4.1", "typescript": "^4.8.4", - "webpack": "^5.74.0", - "webpack-cli": "^4.10.0" + "esbuild": "^0.25.8" }, "dependencies": { {%- case http-router -%} diff --git a/templates/http-ts/content/webpack.config.js b/templates/http-ts/content/webpack.config.js deleted file mode 100644 index e374837b..00000000 --- a/templates/http-ts/content/webpack.config.js +++ /dev/null @@ -1,44 +0,0 @@ -import path from 'path'; -import SpinSdkPlugin from "@spinframework/build-tools/plugins/webpack/index.js"; - -const config = async () => { - let SpinPlugin = await SpinSdkPlugin.init() - return { - mode: 'production', - stats: 'errors-only', - entry: './src/index.ts', - experiments: { - outputModule: true, - }, - module: { - rules: [ - { - test: /\.tsx?$/, - use: 'ts-loader', - exclude: /node_modules/, - }, - ], - }, - resolve: { - extensions: ['.tsx', '.ts', '.js'], - }, - output: { - path: path.resolve(process.cwd(), './build'), - filename: 'bundle.js', - module: true, - library: { - type: "module", - } - }, - plugins: [ - SpinPlugin - ], - optimization: { - minimize: false - }, - performance: { - hints: false, - } - }; -} -export default config \ No newline at end of file diff --git a/test/test-app/package.json b/test/test-app/package.json index 96725dde..5eabeb39 100644 --- a/test/test-app/package.json +++ b/test/test-app/package.json @@ -7,7 +7,7 @@ "keywords": [], "license": "Apache-2.0", "scripts": { - "build": "node build.mjs && mkdirp dist && j2w -i build/bundle.js -o dist/test-app.wasm --initLocation http://foo.bar", + "build": "node build.mjs && mkdirp dist && j2w -d -i build/bundle.js -o dist/test-app.wasm --initLocation http://foo.bar", "test": "echo \"Error: no test specified\" && exit 1" }, "devDependencies": { diff --git a/test/test-app/spin.toml b/test/test-app/spin.toml index a58317ab..b8077aa3 100644 --- a/test/test-app/spin.toml +++ b/test/test-app/spin.toml @@ -13,7 +13,7 @@ component = "test-app" [component.test-app] source = "dist/test-app.wasm" exclude_files = ["**/node_modules"] -allowed_outbound_hosts = ["http://localhost:3000"] +allowed_outbound_hosts = ["http://localhost:3000", "tcp://127.0.0.1:*"] key_value_stores = ["default"] [component.test-app.build] command = ["npm install", "npm run build"] diff --git a/test/test-app/src/test.ts b/test/test-app/src/test.ts index 8ecd4654..438ca1ca 100644 --- a/test/test-app/src/test.ts +++ b/test/test-app/src/test.ts @@ -5,7 +5,9 @@ const decoder = new TextDecoder() const streamingChunks = ["chunk1", "chunk2", "chunk3", "chunk4", "chunk5"] function health(req: Request) { - return new Response("Healthy", { status: 200 }) + let a = 5; + console.log(a) + return new Response("Healthy" + a, { status: 200 }) } function stream(req: Request) { From f21210fb8ebc5017030147f007b3036b5c9021f4 Mon Sep 17 00:00:00 2001 From: Karthik Ganeshram Date: Mon, 20 Oct 2025 21:02:46 +0530 Subject: [PATCH 2/3] add debug config to templates Signed-off-by: Karthik Ganeshram --- .gitignore | 1 + templates/http-js/content/.vscode/launch.json | 14 ++++++++++++++ templates/http-js/content/.vscode/settings.json | 12 ++++++++++++ templates/http-js/content/build.mjs | 1 - templates/http-ts/content/.vscode/launch.json | 14 ++++++++++++++ templates/http-ts/content/.vscode/settings.json | 12 ++++++++++++ templates/http-ts/content/build.mjs | 1 - test/test-app/.vscode/launch.json | 14 ++++++++++++++ test/test-app/.vscode/settings.json | 12 ++++++++++++ test/test-app/package.json | 2 +- test/test-app/spin.toml | 2 +- test/test-app/src/test.ts | 4 +--- 12 files changed, 82 insertions(+), 7 deletions(-) create mode 100644 templates/http-js/content/.vscode/launch.json create mode 100644 templates/http-js/content/.vscode/settings.json create mode 100644 templates/http-ts/content/.vscode/launch.json create mode 100644 templates/http-ts/content/.vscode/settings.json create mode 100644 test/test-app/.vscode/launch.json create mode 100644 test/test-app/.vscode/settings.json diff --git a/.gitignore b/.gitignore index 3eaf29de..3fdc7455 100644 --- a/.gitignore +++ b/.gitignore @@ -8,3 +8,4 @@ dist.js dist/ build/ docs/ +!templates/**/.vscode/ diff --git a/templates/http-js/content/.vscode/launch.json b/templates/http-js/content/.vscode/launch.json new file mode 100644 index 00000000..248c2420 --- /dev/null +++ b/templates/http-js/content/.vscode/launch.json @@ -0,0 +1,14 @@ +{ + "version": "0.2.0", + "configurations": [ + { + "type": "starlingmonkey", + "request": "launch", + "name": "Debug StarlingMonkey component", + "component": "${workspaceFolder}/dist/{{ project-name | kebab_case }}.wasm", + "program": "${workspaceFolder}/src/index.js", + "stopOnEntry": false, + "trace": true + } + ] +} \ No newline at end of file diff --git a/templates/http-js/content/.vscode/settings.json b/templates/http-js/content/.vscode/settings.json new file mode 100644 index 00000000..9acee7bc --- /dev/null +++ b/templates/http-js/content/.vscode/settings.json @@ -0,0 +1,12 @@ +{ + "starlingmonkey": { + "componentRuntime": { + "executable": "spin", + "options": [ + "up", + "-f", + "${workspaceFolder}", + ], + } + } +} \ No newline at end of file diff --git a/templates/http-js/content/build.mjs b/templates/http-js/content/build.mjs index 5106a9b8..894f5441 100644 --- a/templates/http-js/content/build.mjs +++ b/templates/http-js/content/build.mjs @@ -38,6 +38,5 @@ await build({ '.tsx': 'tsx', }, resolveExtensions: ['.ts', '.tsx', '.js'], - // This prevents sourcemaps from traversing into node_modules sourceRoot: path.resolve(process.cwd(), 'src'), }); diff --git a/templates/http-ts/content/.vscode/launch.json b/templates/http-ts/content/.vscode/launch.json new file mode 100644 index 00000000..68e48483 --- /dev/null +++ b/templates/http-ts/content/.vscode/launch.json @@ -0,0 +1,14 @@ +{ + "version": "0.2.0", + "configurations": [ + { + "type": "starlingmonkey", + "request": "launch", + "name": "Debug StarlingMonkey component", + "component": "${workspaceFolder}/dist/{{ project-name | kebab_case }}.wasm", + "program": "${workspaceFolder}/src/index.ts", + "stopOnEntry": false, + "trace": true + } + ] +} \ No newline at end of file diff --git a/templates/http-ts/content/.vscode/settings.json b/templates/http-ts/content/.vscode/settings.json new file mode 100644 index 00000000..9acee7bc --- /dev/null +++ b/templates/http-ts/content/.vscode/settings.json @@ -0,0 +1,12 @@ +{ + "starlingmonkey": { + "componentRuntime": { + "executable": "spin", + "options": [ + "up", + "-f", + "${workspaceFolder}", + ], + } + } +} \ No newline at end of file diff --git a/templates/http-ts/content/build.mjs b/templates/http-ts/content/build.mjs index 5106a9b8..894f5441 100644 --- a/templates/http-ts/content/build.mjs +++ b/templates/http-ts/content/build.mjs @@ -38,6 +38,5 @@ await build({ '.tsx': 'tsx', }, resolveExtensions: ['.ts', '.tsx', '.js'], - // This prevents sourcemaps from traversing into node_modules sourceRoot: path.resolve(process.cwd(), 'src'), }); diff --git a/test/test-app/.vscode/launch.json b/test/test-app/.vscode/launch.json new file mode 100644 index 00000000..471175fd --- /dev/null +++ b/test/test-app/.vscode/launch.json @@ -0,0 +1,14 @@ +{ + "version": "0.2.0", + "configurations": [ + { + "type": "starlingmonkey", + "request": "launch", + "name": "Debug StarlingMonkey component", + "component": "${workspaceFolder}/dist/test-app.wasm", + "program": "${workspaceFolder}/src/index.ts", + "stopOnEntry": false, + "trace": true + } + ] +} \ No newline at end of file diff --git a/test/test-app/.vscode/settings.json b/test/test-app/.vscode/settings.json new file mode 100644 index 00000000..9acee7bc --- /dev/null +++ b/test/test-app/.vscode/settings.json @@ -0,0 +1,12 @@ +{ + "starlingmonkey": { + "componentRuntime": { + "executable": "spin", + "options": [ + "up", + "-f", + "${workspaceFolder}", + ], + } + } +} \ No newline at end of file diff --git a/test/test-app/package.json b/test/test-app/package.json index 5eabeb39..96725dde 100644 --- a/test/test-app/package.json +++ b/test/test-app/package.json @@ -7,7 +7,7 @@ "keywords": [], "license": "Apache-2.0", "scripts": { - "build": "node build.mjs && mkdirp dist && j2w -d -i build/bundle.js -o dist/test-app.wasm --initLocation http://foo.bar", + "build": "node build.mjs && mkdirp dist && j2w -i build/bundle.js -o dist/test-app.wasm --initLocation http://foo.bar", "test": "echo \"Error: no test specified\" && exit 1" }, "devDependencies": { diff --git a/test/test-app/spin.toml b/test/test-app/spin.toml index b8077aa3..a58317ab 100644 --- a/test/test-app/spin.toml +++ b/test/test-app/spin.toml @@ -13,7 +13,7 @@ component = "test-app" [component.test-app] source = "dist/test-app.wasm" exclude_files = ["**/node_modules"] -allowed_outbound_hosts = ["http://localhost:3000", "tcp://127.0.0.1:*"] +allowed_outbound_hosts = ["http://localhost:3000"] key_value_stores = ["default"] [component.test-app.build] command = ["npm install", "npm run build"] diff --git a/test/test-app/src/test.ts b/test/test-app/src/test.ts index 438ca1ca..8ecd4654 100644 --- a/test/test-app/src/test.ts +++ b/test/test-app/src/test.ts @@ -5,9 +5,7 @@ const decoder = new TextDecoder() const streamingChunks = ["chunk1", "chunk2", "chunk3", "chunk4", "chunk5"] function health(req: Request) { - let a = 5; - console.log(a) - return new Response("Healthy" + a, { status: 200 }) + return new Response("Healthy", { status: 200 }) } function stream(req: Request) { From 1de996e0d517d1f6910822a22ffae4c478edf125 Mon Sep 17 00:00:00 2001 From: Karthik Ganeshram Date: Thu, 11 Dec 2025 13:18:57 +0100 Subject: [PATCH 3/3] make the setup to use debugger easier Add a readme note on how to use the debugger. Also adds a commented out outbound host for debugger connection and a npm script to build debug. Signed-off-by: Karthik Ganeshram --- templates/http-js/content/README.md | 9 ++++++++- templates/http-js/content/build.mjs | 2 +- templates/http-js/content/package.json | 1 + templates/http-js/content/spin.toml | 3 +++ templates/http-ts/content/README.md | 9 ++++++++- templates/http-ts/content/package.json | 1 + templates/http-ts/content/spin.toml | 3 +++ 7 files changed, 25 insertions(+), 3 deletions(-) diff --git a/templates/http-js/content/README.md b/templates/http-js/content/README.md index ae9164ee..7a92e09d 100644 --- a/templates/http-js/content/README.md +++ b/templates/http-js/content/README.md @@ -29,4 +29,11 @@ To use additional Spin interfaces, install the corresponding packages: | PostgreSQL | `@spinframework/spin-postgres` | | Redis | `@spinframework/spin-redis` | | SQLite | `@spinframework/spin-sqlite` | -| Variables | `@spinframework/spin-variables` | \ No newline at end of file +| Variables | `@spinframework/spin-variables` | + +## Using the StarlingMonkey Debugger for VS Code + +1. First install the [StarlingMonkey Debugger](https://marketplace.visualstudio.com/items?itemName=BytecodeAlliance.starlingmonkey-debugger) extension. +2. Build the component using the debug command `npm run build:debug`. +3. Uncomment `tcp://127.0.0.1:*` in the `allowed_outbound_hosts` field in the `spin.toml`. +4. Start the debugger in VS Code which should start Spin and attach the debugger. The debugger needs to be restarted for each http call. \ No newline at end of file diff --git a/templates/http-js/content/build.mjs b/templates/http-js/content/build.mjs index 894f5441..e2f1f4fd 100644 --- a/templates/http-js/content/build.mjs +++ b/templates/http-js/content/build.mjs @@ -24,7 +24,7 @@ let SourceMapPlugin = { } await build({ - entryPoints: ['./src/index.ts'], + entryPoints: ['./src/index.js'], outfile: './build/bundle.js', bundle: true, format: 'esm', diff --git a/templates/http-js/content/package.json b/templates/http-js/content/package.json index 2124499c..09bb3f21 100644 --- a/templates/http-js/content/package.json +++ b/templates/http-js/content/package.json @@ -5,6 +5,7 @@ "main": "index.js", "scripts": { "build": "node build.mjs && mkdirp dist && j2w -i build/bundle.js --initLocation http://{{project-name | kebab_case}}.localhost -o dist/{{ project-name | kebab_case }}.wasm", + "build:debug": "node build.mjs && mkdirp dist && j2w -d -i build/bundle.js --initLocation http://{{project-name | kebab_case}}.localhost -o dist/{{ project-name | kebab_case }}.wasm", "test": "echo \"Error: no test specified\" && exit 1" }, "keywords": [], diff --git a/templates/http-js/content/spin.toml b/templates/http-js/content/spin.toml index 038370f3..77434276 100644 --- a/templates/http-js/content/spin.toml +++ b/templates/http-js/content/spin.toml @@ -13,6 +13,9 @@ component = "{{project-name | kebab_case}}" [component.{{project-name | kebab_case}}] source = "dist/{{project-name | kebab_case}}.wasm" exclude_files = ["**/node_modules"] +allowed_outbound_hosts = [ + # "tcp://127.0.0.1:*", # Uncomment this line to while using the StarlingMonkey Debugger +] [component.{{project-name | kebab_case}}.build] command = ["npm install", "npm run build"] watch = ["src/**/*.js"] \ No newline at end of file diff --git a/templates/http-ts/content/README.md b/templates/http-ts/content/README.md index 95740c23..eaf09673 100644 --- a/templates/http-ts/content/README.md +++ b/templates/http-ts/content/README.md @@ -29,4 +29,11 @@ To use additional Spin interfaces, install the corresponding packages: | PostgreSQL | `@spinframework/spin-postgres` | | Redis | `@spinframework/spin-redis` | | SQLite | `@spinframework/spin-sqlite` | -| Variables | `@spinframework/spin-variables` | \ No newline at end of file +| Variables | `@spinframework/spin-variables` | + +## Using the StarlingMonkey Debugger for VS Code + +1. First install the [StarlingMonkey Debugger](https://marketplace.visualstudio.com/items?itemName=BytecodeAlliance.starlingmonkey-debugger) extension. +2. Build the component using the debug command `npm run build:debug`. +3. Uncomment `tcp://127.0.0.1:*` in the `allowed_outbound_hosts` field in the `spin.toml`. +4. Start the debugger in VS Code which should start Spin and attach the debugger. The debugger needs to be restarted for each http call. \ No newline at end of file diff --git a/templates/http-ts/content/package.json b/templates/http-ts/content/package.json index ff7f2a96..cd14703f 100644 --- a/templates/http-ts/content/package.json +++ b/templates/http-ts/content/package.json @@ -5,6 +5,7 @@ "main": "index.js", "scripts": { "build": "node build.mjs && mkdirp dist && j2w -i build/bundle.js --initLocation http://{{project-name | kebab_case}}.localhost -o dist/{{ project-name | kebab_case }}.wasm", + "build:debug": "node build.mjs && mkdirp dist && j2w -d -i build/bundle.js --initLocation http://{{project-name | kebab_case}}.localhost -o dist/{{ project-name | kebab_case }}.wasm", "test": "echo \"Error: no test specified\" && exit 1" }, "keywords": [], diff --git a/templates/http-ts/content/spin.toml b/templates/http-ts/content/spin.toml index 82c26af2..98027d9a 100644 --- a/templates/http-ts/content/spin.toml +++ b/templates/http-ts/content/spin.toml @@ -13,6 +13,9 @@ component = "{{project-name | kebab_case}}" [component.{{project-name | kebab_case}}] source = "dist/{{project-name | kebab_case}}.wasm" exclude_files = ["**/node_modules"] +allowed_outbound_hosts = [ + # "tcp://127.0.0.1:*", # Uncomment this line to while using the StarlingMonkey Debugger +] [component.{{project-name | kebab_case}}.build] command = ["npm install", "npm run build"] watch = ["src/**/*.ts"] \ No newline at end of file