From 78b2f16843537da2519255ee4ebb82fada38e827 Mon Sep 17 00:00:00 2001 From: Karthik Ganeshram Date: Fri, 17 Oct 2025 19:48:55 +0530 Subject: [PATCH 1/2] 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 6bb8f845..763e721c 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 -o dist/{{ project-name | kebab_case }}.wasm", + "build": "node build.mjs && mkdirp dist && j2w -i build/bundle.js -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 45f26a7b..a707ca45 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 -o dist/{{ project-name | kebab_case }}.wasm", + "build": "node build.mjs && mkdirp dist && j2w -i build/bundle.js -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 e5061f36..53a193ea 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", + "build": "node build.mjs && mkdirp dist && j2w -d -i build/bundle.js -o dist/test-app.wasm", "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 8819202d6f1c72a4e088dcb4016ff0fdb6c588ac Mon Sep 17 00:00:00 2001 From: Karthik Ganeshram Date: Mon, 20 Oct 2025 21:02:46 +0530 Subject: [PATCH 2/2] 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 53a193ea..e5061f36 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", + "build": "node build.mjs && mkdirp dist && j2w -i build/bundle.js -o dist/test-app.wasm", "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) {