From 54310ad0abe08400fb8c61109e2255b5a641a586 Mon Sep 17 00:00:00 2001 From: KernelDeimos <7225168+KernelDeimos@users.noreply.github.com> Date: Fri, 7 Nov 2025 17:01:08 -0500 Subject: [PATCH] chore: remove rollup, always use webpack These two issues have affected us, but go away without rollup: - https://github.com/npm/cli/issues/4828 - https://github.com/rollup/rollup/issues/6168 We can just use webpack instead; it has never caused build/npm issues. This migration was done using AI, by pasting error messages over and over again until everything worked. Since we're not actively working on terminal and phoenix (dependents of rollup) currently it doesn't make sense to focus on doing this migration manually, and any errors not observed in basic use can be remedied later. --- package-lock.json | 509 ++---------------- package.json | 3 +- src/backend-core-0/package.json | 9 +- src/backend-core-0/rollup.config.js | 27 - src/backend-core-0/src/exports.js | 2 +- src/backend-core-0/webpack.config.js | 54 ++ .../modules/selfhosted/DevWatcherService.js | 127 ++--- .../modules/selfhosted/SelfHostedModule.js | 12 +- src/phoenix/assets/index.html | 15 +- src/phoenix/config/dev.js | 2 +- src/phoenix/package.json | 10 +- src/phoenix/rollup.config.js | 55 -- src/phoenix/run.json5 | 4 +- .../browser/node-stubs/child_process.js | 3 + .../platform/browser/node-stubs/node-pty.js | 3 + .../src/platform/browser/node-stubs/path.js | 3 + .../platform/browser/node-stubs/process.js | 3 + .../src/platform/browser/node-stubs/stream.js | 3 + src/phoenix/src/puter-shell/main.js | 28 +- src/phoenix/tools/build_tar.sh | 2 +- .../webpack-resolve-extensions-plugin.js | 84 +++ src/phoenix/webpack.config.js | 96 ++++ src/terminal/assets/index.html | 16 +- src/terminal/config/dev.js | 2 +- src/terminal/package.json | 10 +- src/terminal/rollup.config.js | 64 --- src/terminal/run-http.json5 | 4 +- src/terminal/run-https.json5 | 4 +- src/terminal/run-phoenix-http.json5 | 12 +- src/terminal/run.json5 | 8 +- .../webpack-resolve-extensions-plugin.js | 84 +++ src/terminal/webpack.config.js | 77 +++ 32 files changed, 560 insertions(+), 775 deletions(-) delete mode 100644 src/backend-core-0/rollup.config.js create mode 100644 src/backend-core-0/webpack.config.js delete mode 100644 src/phoenix/rollup.config.js create mode 100644 src/phoenix/src/platform/browser/node-stubs/child_process.js create mode 100644 src/phoenix/src/platform/browser/node-stubs/node-pty.js create mode 100644 src/phoenix/src/platform/browser/node-stubs/path.js create mode 100644 src/phoenix/src/platform/browser/node-stubs/process.js create mode 100644 src/phoenix/src/platform/browser/node-stubs/stream.js create mode 100644 src/phoenix/webpack-resolve-extensions-plugin.js create mode 100644 src/phoenix/webpack.config.js delete mode 100644 src/terminal/rollup.config.js create mode 100644 src/terminal/webpack-resolve-extensions-plugin.js create mode 100644 src/terminal/webpack.config.js diff --git a/package-lock.json b/package-lock.json index 513c81ef..f5f933f6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -28,7 +28,6 @@ "json-colorizer": "^3.0.1", "open": "^10.1.0", "parse-domain": "^8.2.2", - "rollup": "^4.52.4", "simple-git": "^3.25.0", "string-template": "^1.0.0", "uuid": "^9.0.1" @@ -5710,83 +5709,6 @@ "integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==", "license": "BSD-3-Clause" }, - "node_modules/@rollup/plugin-node-resolve": { - "version": "15.3.1", - "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-15.3.1.tgz", - "integrity": "sha512-tgg6b91pAybXHJQMAAwW9VuWBO6Thi+q7BCNARLwSqlmsHz0XYURtGvh/AuwSADXSI4h/2uHbs7s4FzlZDGSGA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@rollup/pluginutils": "^5.0.1", - "@types/resolve": "1.20.2", - "deepmerge": "^4.2.2", - "is-module": "^1.0.0", - "resolve": "^1.22.1" - }, - "engines": { - "node": ">=14.0.0" - }, - "peerDependencies": { - "rollup": "^2.78.0||^3.0.0||^4.0.0" - }, - "peerDependenciesMeta": { - "rollup": { - "optional": true - } - } - }, - "node_modules/@rollup/plugin-replace": { - "version": "5.0.7", - "resolved": "https://registry.npmjs.org/@rollup/plugin-replace/-/plugin-replace-5.0.7.tgz", - "integrity": "sha512-PqxSfuorkHz/SPpyngLyg5GCEkOcee9M1bkxiVDr41Pd61mqP1PLOoDPbpl44SB2mQGKwV/In74gqQmGITOhEQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@rollup/pluginutils": "^5.0.1", - "magic-string": "^0.30.3" - }, - "engines": { - "node": ">=14.0.0" - }, - "peerDependencies": { - "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" - }, - "peerDependenciesMeta": { - "rollup": { - "optional": true - } - } - }, - "node_modules/@rollup/pluginutils": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.3.0.tgz", - "integrity": "sha512-5EdhGZtnu3V88ces7s53hhfK5KSASnJZv8Lulpc04cWO3REESroJXg73DFsOmgbU2BhwV0E20bu2IDZb3VKW4Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/estree": "^1.0.0", - "estree-walker": "^2.0.2", - "picomatch": "^4.0.2" - }, - "engines": { - "node": ">=14.0.0" - }, - "peerDependencies": { - "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" - }, - "peerDependenciesMeta": { - "rollup": { - "optional": true - } - } - }, - "node_modules/@rollup/pluginutils/node_modules/estree-walker": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", - "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", - "dev": true, - "license": "MIT" - }, "node_modules/@rollup/rollup-android-arm-eabi": { "version": "4.52.4", "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.52.4.tgz", @@ -5794,6 +5716,7 @@ "cpu": [ "arm" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -5807,6 +5730,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -5820,6 +5744,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -5833,6 +5758,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -5846,6 +5772,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -5859,6 +5786,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -5872,6 +5800,7 @@ "cpu": [ "arm" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -5885,6 +5814,7 @@ "cpu": [ "arm" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -5898,6 +5828,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -5911,6 +5842,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -5924,6 +5856,7 @@ "cpu": [ "loong64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -5937,6 +5870,7 @@ "cpu": [ "ppc64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -5950,6 +5884,7 @@ "cpu": [ "riscv64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -5963,6 +5898,7 @@ "cpu": [ "riscv64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -5976,6 +5912,7 @@ "cpu": [ "s390x" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -5989,6 +5926,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -6002,6 +5940,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -6015,6 +5954,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -6028,6 +5968,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -6041,6 +5982,7 @@ "cpu": [ "ia32" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -6054,6 +5996,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -6067,6 +6010,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -6950,16 +6894,6 @@ "@types/send": "*" } }, - "node_modules/@types/fs-extra": { - "version": "8.1.5", - "resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-8.1.5.tgz", - "integrity": "sha512-0dzKcwO+S8s2kuF5Z9oUWatQJj5Uq/iqphEtE3GQJVRRYm/tD1LglU2UnXi2A8jLq5umkGouOXOR9y0n613ZwQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/node": "*" - } - }, "node_modules/@types/glob": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.2.0.tgz", @@ -7228,13 +7162,6 @@ "node": ">= 0.12" } }, - "node_modules/@types/resolve": { - "version": "1.20.2", - "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.20.2.tgz", - "integrity": "sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==", - "dev": true, - "license": "MIT" - }, "node_modules/@types/send": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/@types/send/-/send-1.2.0.tgz", @@ -9942,16 +9869,6 @@ "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", "license": "MIT" }, - "node_modules/deepmerge": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", - "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/default-browser": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/default-browser/-/default-browser-5.2.1.tgz", @@ -11506,6 +11423,7 @@ "version": "2.3.3", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, "hasInstallScript": true, "license": "MIT", "optional": true, @@ -12688,13 +12606,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/is-module": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz", - "integrity": "sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==", - "dev": true, - "license": "MIT" - }, "node_modules/is-number": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", @@ -12736,16 +12647,6 @@ "node": ">=0.10.0" } }, - "node_modules/is-reference": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-1.2.1.tgz", - "integrity": "sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/estree": "*" - } - }, "node_modules/is-regexp": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/is-regexp/-/is-regexp-3.1.0.tgz", @@ -16273,8 +16174,8 @@ "version": "4.52.4", "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.52.4.tgz", "integrity": "sha512-CLEVl+MnPAiKh5pl4dEWSyMTpuflgNQiLGhMv8ezD5W/qP8AKvmYpCOKRRNOh7oRKnauBZ4SyeYkMS+1VSyKwQ==", + "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@types/estree": "1.0.8" }, @@ -16311,60 +16212,6 @@ "fsevents": "~2.3.2" } }, - "node_modules/rollup-plugin-copy": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/rollup-plugin-copy/-/rollup-plugin-copy-3.5.0.tgz", - "integrity": "sha512-wI8D5dvYovRMx/YYKtUNt3Yxaw4ORC9xo6Gt9t22kveWz1enG9QrhVlagzwrxSC455xD1dHMKhIJkbsQ7d48BA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/fs-extra": "^8.0.1", - "colorette": "^1.1.0", - "fs-extra": "^8.1.0", - "globby": "10.0.1", - "is-plain-object": "^3.0.0" - }, - "engines": { - "node": ">=8.3" - } - }, - "node_modules/rollup-plugin-copy/node_modules/colorette": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/colorette/-/colorette-1.4.0.tgz", - "integrity": "sha512-Y2oEozpomLn7Q3HFP7dpww7AtMJplbM9lGZP6RDfHqmbeRjiwRg4n6VM6j4KLmRke85uWEI7JqF17f3pqdRA0g==", - "dev": true, - "license": "MIT" - }, - "node_modules/rollup-plugin-copy/node_modules/globby": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/globby/-/globby-10.0.1.tgz", - "integrity": "sha512-sSs4inE1FB2YQiymcmTv6NWENryABjUNPeWhOvmn4SjtKybglsyPZxFB3U1/+L1bYi0rNZDqCLlHyLYDl1Pq5A==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/glob": "^7.1.1", - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.0.3", - "glob": "^7.1.3", - "ignore": "^5.1.1", - "merge2": "^1.2.3", - "slash": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/rollup-plugin-copy/node_modules/is-plain-object": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-3.0.1.tgz", - "integrity": "sha512-Xnpx182SBMrr/aBik8y+GuR4U1L9FqMSojwDQwPMmxyC6bvEqly9UBCxhauBF5vNh2gwWJNX6oDV7O+OM4z34g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/run-applescript": { "version": "7.1.0", "resolved": "https://registry.npmjs.org/run-applescript/-/run-applescript-7.1.0.tgz", @@ -19588,106 +19435,8 @@ "version": "1.0.0", "license": "AGPL-3.0-only", "devDependencies": { - "@rollup/plugin-commonjs": "^24.1.0", - "@rollup/plugin-node-resolve": "^15.0.2", - "@rollup/plugin-replace": "^5.0.2", - "rollup": "^3.21.4", - "rollup-plugin-copy": "^3.4.0" - } - }, - "src/backend-core-0/node_modules/@rollup/plugin-commonjs": { - "version": "24.1.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@rollup/pluginutils": "^5.0.1", - "commondir": "^1.0.1", - "estree-walker": "^2.0.2", - "glob": "^8.0.3", - "is-reference": "1.2.1", - "magic-string": "^0.27.0" - }, - "engines": { - "node": ">=14.0.0" - }, - "peerDependencies": { - "rollup": "^2.68.0||^3.0.0" - }, - "peerDependenciesMeta": { - "rollup": { - "optional": true - } - } - }, - "src/backend-core-0/node_modules/brace-expansion": { - "version": "2.0.2", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "src/backend-core-0/node_modules/estree-walker": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", - "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", - "dev": true, - "license": "MIT" - }, - "src/backend-core-0/node_modules/glob": { - "version": "8.1.0", - "dev": true, - "license": "ISC", - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^5.0.1", - "once": "^1.3.0" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "src/backend-core-0/node_modules/magic-string": { - "version": "0.27.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/sourcemap-codec": "^1.4.13" - }, - "engines": { - "node": ">=12" - } - }, - "src/backend-core-0/node_modules/minimatch": { - "version": "5.1.6", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=10" - } - }, - "src/backend-core-0/node_modules/rollup": { - "version": "3.29.5", - "dev": true, - "license": "MIT", - "peer": true, - "bin": { - "rollup": "dist/bin/rollup" - }, - "engines": { - "node": ">=14.18.0", - "npm": ">=8.0.0" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" + "webpack": "^5.88.2", + "webpack-cli": "^5.1.1" } }, "src/backend/node_modules/@smithy/abort-controller": { @@ -20305,41 +20054,15 @@ "sinon": "^17.0.1" }, "devDependencies": { - "@rollup/plugin-commonjs": "^24.1.0", - "@rollup/plugin-node-resolve": "^15.0.2", - "@rollup/plugin-replace": "^5.0.2", + "copy-webpack-plugin": "^12.0.2", "mocha": "^10.8.2", - "rollup": "^3.29.5", - "rollup-plugin-copy": "^3.4.0" + "webpack": "^5.88.2", + "webpack-cli": "^5.1.1" }, "optionalDependencies": { "node-pty": "^1.0.0" } }, - "src/phoenix/node_modules/@rollup/plugin-commonjs": { - "version": "24.1.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@rollup/pluginutils": "^5.0.1", - "commondir": "^1.0.1", - "estree-walker": "^2.0.2", - "glob": "^8.0.3", - "is-reference": "1.2.1", - "magic-string": "^0.27.0" - }, - "engines": { - "node": ">=14.0.0" - }, - "peerDependencies": { - "rollup": "^2.68.0||^3.0.0" - }, - "peerDependenciesMeta": { - "rollup": { - "optional": true - } - } - }, "src/phoenix/node_modules/@sinonjs/fake-timers": { "version": "11.3.1", "license": "BSD-3-Clause", @@ -20347,77 +20070,6 @@ "@sinonjs/commons": "^3.0.1" } }, - "src/phoenix/node_modules/brace-expansion": { - "version": "2.0.2", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "src/phoenix/node_modules/estree-walker": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", - "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", - "dev": true, - "license": "MIT" - }, - "src/phoenix/node_modules/glob": { - "version": "8.1.0", - "dev": true, - "license": "ISC", - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^5.0.1", - "once": "^1.3.0" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "src/phoenix/node_modules/magic-string": { - "version": "0.27.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/sourcemap-codec": "^1.4.13" - }, - "engines": { - "node": ">=12" - } - }, - "src/phoenix/node_modules/minimatch": { - "version": "5.1.6", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=10" - } - }, - "src/phoenix/node_modules/rollup": { - "version": "3.29.5", - "dev": true, - "license": "MIT", - "peer": true, - "bin": { - "rollup": "dist/bin/rollup" - }, - "engines": { - "node": ">=14.18.0", - "npm": ">=8.0.0" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" - } - }, "src/phoenix/node_modules/sinon": { "version": "17.0.1", "license": "BSD-3-Clause", @@ -20477,108 +20129,11 @@ "@xterm/xterm": "^5.5.0" }, "devDependencies": { - "@rollup/plugin-commonjs": "^24.1.0", - "@rollup/plugin-node-resolve": "^15.0.2", - "@rollup/plugin-replace": "^5.0.2", + "copy-webpack-plugin": "^12.0.2", "http-server": "^14.1.1", "mocha": "^10.8.2", - "rollup": "^3.29.5", - "rollup-plugin-copy": "^3.4.0" - } - }, - "src/terminal/node_modules/@rollup/plugin-commonjs": { - "version": "24.1.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@rollup/pluginutils": "^5.0.1", - "commondir": "^1.0.1", - "estree-walker": "^2.0.2", - "glob": "^8.0.3", - "is-reference": "1.2.1", - "magic-string": "^0.27.0" - }, - "engines": { - "node": ">=14.0.0" - }, - "peerDependencies": { - "rollup": "^2.68.0||^3.0.0" - }, - "peerDependenciesMeta": { - "rollup": { - "optional": true - } - } - }, - "src/terminal/node_modules/brace-expansion": { - "version": "2.0.2", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "src/terminal/node_modules/estree-walker": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", - "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", - "dev": true, - "license": "MIT" - }, - "src/terminal/node_modules/glob": { - "version": "8.1.0", - "dev": true, - "license": "ISC", - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^5.0.1", - "once": "^1.3.0" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "src/terminal/node_modules/magic-string": { - "version": "0.27.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/sourcemap-codec": "^1.4.13" - }, - "engines": { - "node": ">=12" - } - }, - "src/terminal/node_modules/minimatch": { - "version": "5.1.6", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=10" - } - }, - "src/terminal/node_modules/rollup": { - "version": "3.29.5", - "dev": true, - "license": "MIT", - "peer": true, - "bin": { - "rollup": "dist/bin/rollup" - }, - "engines": { - "node": ">=14.18.0", - "npm": ">=8.0.0" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" + "webpack": "^5.88.2", + "webpack-cli": "^5.1.1" } }, "src/useapi": { diff --git a/package.json b/package.json index 66d875ec..c80a3839 100644 --- a/package.json +++ b/package.json @@ -77,7 +77,6 @@ "json-colorizer": "^3.0.1", "open": "^10.1.0", "parse-domain": "^8.2.2", - "rollup": "^4.52.4", "simple-git": "^3.25.0", "string-template": "^1.0.0", "uuid": "^9.0.1" @@ -90,4 +89,4 @@ "engines": { "node": ">=20.19.5" } -} +} \ No newline at end of file diff --git a/src/backend-core-0/package.json b/src/backend-core-0/package.json index d232c284..c1781052 100644 --- a/src/backend-core-0/package.json +++ b/src/backend-core-0/package.json @@ -4,7 +4,7 @@ "description": "The ugly name is intentional. We prefer to refactor incrementally which means we need a way to \"re-core\" the backend, and we may do this more than once simultaneously (hence it's `0` right now).", "type": "module", "scripts": { - "build": "rollup -c", + "build": "webpack", "prepare": "npm run build", "test": "echo \"Error: no test specified\" && exit 1" }, @@ -15,11 +15,8 @@ } }, "devDependencies": { - "rollup": "^3.21.4", - "rollup-plugin-copy": "^3.4.0", - "@rollup/plugin-commonjs": "^24.1.0", - "@rollup/plugin-node-resolve": "^15.0.2", - "@rollup/plugin-replace": "^5.0.2" + "webpack": "^5.88.2", + "webpack-cli": "^5.1.1" }, "keywords": [], "author": "", diff --git a/src/backend-core-0/rollup.config.js b/src/backend-core-0/rollup.config.js deleted file mode 100644 index 838911a3..00000000 --- a/src/backend-core-0/rollup.config.js +++ /dev/null @@ -1,27 +0,0 @@ -import { defineConfig } from 'rollup'; -import { nodeResolve } from '@rollup/plugin-node-resolve'; -import commonjs from '@rollup/plugin-commonjs'; - -export default defineConfig([ - // ESM build - { - input: 'src/exports.js', - output: { - dir: 'dist/esm', - format: 'es', - preserveModules: true - }, - plugins: [nodeResolve()] - }, - // CJS build - { - input: 'src/exports.js', - output: { - dir: 'dist/cjs', - format: 'cjs', - preserveModules: true, - entryFileNames: '[name].cjs', - }, - plugins: [nodeResolve(), commonjs()] - } -]); diff --git a/src/backend-core-0/src/exports.js b/src/backend-core-0/src/exports.js index f331a946..86e2b491 100644 --- a/src/backend-core-0/src/exports.js +++ b/src/backend-core-0/src/exports.js @@ -1 +1 @@ -export * as validation from './pdim/validation'; +export * as validation from './pdim/validation.js'; diff --git a/src/backend-core-0/webpack.config.js b/src/backend-core-0/webpack.config.js new file mode 100644 index 00000000..7f2ce504 --- /dev/null +++ b/src/backend-core-0/webpack.config.js @@ -0,0 +1,54 @@ +import path from 'node:path'; +import { fileURLToPath } from 'node:url'; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); + +// ESM build +const esmConfig = { + mode: 'production', + entry: './src/exports.js', + experiments: { + outputModule: true, + }, + output: { + path: path.resolve(__dirname, 'dist/esm'), + filename: 'exports.js', + module: true, + library: { + type: 'module', + }, + }, + optimization: { + minimize: false, + }, + resolve: { + extensions: ['.js', '.mjs'], + fullySpecified: false, + }, + target: 'node', +}; + +// CJS build +const cjsConfig = { + mode: 'production', + entry: './src/exports.js', + output: { + path: path.resolve(__dirname, 'dist/cjs'), + filename: 'exports.cjs', + library: { + type: 'commonjs2', + }, + }, + optimization: { + minimize: false, + }, + resolve: { + extensions: ['.js', '.mjs'], + fullySpecified: false, + }, + target: 'node', +}; + +export default [esmConfig, cjsConfig]; + diff --git a/src/backend/src/modules/selfhosted/DevWatcherService.js b/src/backend/src/modules/selfhosted/DevWatcherService.js index a3fac7c1..81b97fd4 100644 --- a/src/backend/src/modules/selfhosted/DevWatcherService.js +++ b/src/backend/src/modules/selfhosted/DevWatcherService.js @@ -21,7 +21,6 @@ const BaseService = require("../../services/BaseService"); const path_ = require('node:path'); const fs = require('node:fs'); -const rollupModule = require("rollup"); class ProxyLogger { constructor (log) { @@ -70,9 +69,8 @@ class DevWatcherService extends BaseService { async ['__on_ready.webserver'] () { const svc_process = this.services.get('process'); - let { root, commands, webpack, rollup } = this.args; + let { root, commands, webpack } = this.args; if ( ! webpack ) webpack = []; - if ( ! rollup ) rollup = []; let promises = []; for ( const entry of commands ) { @@ -86,10 +84,6 @@ class DevWatcherService extends BaseService { const p = this.start_a_webpack_watcher_(entry); promises.push(p); } - for ( const entry of rollup ) { - const p = this.start_a_rollup_watcher_(entry); - promises.push(p); - } await Promise.all(promises); // It's difficult to tell when webpack is "done" its first @@ -152,8 +146,37 @@ class DevWatcherService extends BaseService { if ( entry.env ) { oldEnv = process.env; const newEnv = Object.create(process.env); + let global_config = null; + try { + const svc_config = this.services.get('config'); + global_config = svc_config ? svc_config.get('global_config') : null; + } catch (e) { + // Config service not available yet, will use null + } + for ( const k in entry.env ) { - newEnv[k] = entry.env[k]; + const envValue = entry.env[k]; + // If it's a function, call it with the config, otherwise use the value directly + if ( typeof envValue === 'function' ) { + try { + const result = envValue({ global_config: global_config }); + // Only set the env var if we got a non-empty result + // This allows the webpack config to use its fallback values + if ( result ) { + newEnv[k] = result; + } + } catch (e) { + // If config is not available yet, don't set the env var + // This allows the webpack config to use its fallback values from config files + // Only log if it's not a null/undefined access error (which is expected) + if ( !e.message.includes('Cannot read properties of null') && + !e.message.includes('Cannot read properties of undefined') ) { + this.log.warn(`Could not evaluate env function for ${k}: ${e.message}`); + } + } + } else { + newEnv[k] = envValue; + } } process.env = newEnv; // Yep, it totally lets us do this } @@ -185,10 +208,13 @@ class DevWatcherService extends BaseService { hideSuccess = true; } if (err || stats.hasErrors()) { - this.log.error(`error information: ${entry.directory} using Webpack`, { - err, - stats, - }); + // Extract error information without serializing the entire stats object + const errorInfo = { + err: err ? err.message : null, + errors: stats.compilation?.errors?.map(e => e.message) || [], + warnings: stats.compilation?.warnings?.map(w => w.message) || [], + }; + this.log.error(`error information: ${entry.directory} using Webpack`, errorInfo); this.log.error(`❌ failed to update ${entry.directory} using Webpack`); } else { // Normally success messages aren't important, but sometimes it takes @@ -200,83 +226,6 @@ class DevWatcherService extends BaseService { } }); } - - async start_a_rollup_watcher_ (entry) { - const possibleConfigNames = [ - ['rollup.config.js', 'package.json'], - ['rollup.config.cjs', 'commonjs'], - ['rollup.config.mjs', 'module'], - ]; - - const { - configjsPath: rollupConfigPath, - moduleType, - } = await this.get_configjs({ - directory: entry.directory, - configIsFor: 'rollup', // for error message - possibleConfigNames, - }); - - const updateRollupPaths = (config, newBase) => { - const onoutput = o => ({ ...o, file: o.file ? path_.join(newBase, o.file) : o.file }); - return { - ...config, - input: path_.join(newBase, config.input), - output: Array.isArray(config.output) - ? config.output.map(onoutput) - : onoutput(config.output), - }; - }; - - let oldEnv; - - if ( entry.env ) { - oldEnv = process.env; - const newEnv = Object.create(process.env); - for ( const k in entry.env ) { - newEnv[k] = entry.env[k]; - } - process.env = newEnv; // Yep, it totally lets us do this - } - - let rollupConfig = moduleType === 'module' - ? (await import(rollupConfigPath)).default - : require(rollupConfigPath); - - if ( oldEnv ) process.env = oldEnv; - - rollupConfig = updateRollupPaths( - rollupConfig, - path_.join(this.args.root, entry.directory), - ); - // rollupConfig.watch = true; // I mean why can't it just... - - const watcher = rollupModule.watch(rollupConfig); - let errorAfterLastEnd = false; - let firstEvent = true; - watcher.on('event', (event) => { - if ( event.code === 'END' ) { - let hideSuccess = false; - if ( firstEvent ) { - firstEvent = false; - hideSuccess = true; - } - if ( errorAfterLastEnd ) { - errorAfterLastEnd = false; - return; - } - if ( ! hideSuccess ) { - this.log.info(`✅ updated ${entry.directory} using Rollup`); - } - } else if ( event.code === 'ERROR' ) { - this.log.error(`error information: ${entry.directory} using Rollup`, { - event, - }); - this.log.error(`❌ failed to update ${entry.directory} using Rollup`); - errorAfterLastEnd = true; - } - }); - } }; module.exports = DevWatcherService; diff --git a/src/backend/src/modules/selfhosted/SelfHostedModule.js b/src/backend/src/modules/selfhosted/SelfHostedModule.js index 4273f52b..58081f11 100644 --- a/src/backend/src/modules/selfhosted/SelfHostedModule.js +++ b/src/backend/src/modules/selfhosted/SelfHostedModule.js @@ -51,23 +51,21 @@ class SelfHostedModule extends AdvancedBase { { services.registerService('__dev-watcher', DevWatcherService, { root: path_.resolve(__dirname, RELATIVE_PATH), - rollup: [ + webpack: [ { name: 'phoenix', directory: 'src/phoenix', env: { - PUTER_JS_URL: ({ global_config: config }) => config.origin + '/sdk/puter.dev.js', + PUTER_JS_URL: ({ global_config: config }) => config?.origin ? config.origin + '/puter.js/v2' : '', }, }, { name: 'terminal', directory: 'src/terminal', env: { - PUTER_JS_URL: ({ global_config: config }) => config.origin + '/sdk/puter.dev.js', + PUTER_JS_URL: ({ global_config: config }) => config?.origin ? config.origin + '/puter.js/v2' : '', }, }, - ], - webpack: [ { name: 'puter.js', directory: 'src/puter-js', @@ -76,8 +74,8 @@ class SelfHostedModule extends AdvancedBase { config.devtool = 'source-map'; }, env: { - PUTER_ORIGIN: ({ global_config: config }) => config.origin, - PUTER_API_ORIGIN: ({ global_config: config }) => config.api_base_url, + PUTER_ORIGIN: ({ global_config: config }) => config?.origin || '', + PUTER_API_ORIGIN: ({ global_config: config }) => config?.api_base_url || '', }, }, { diff --git a/src/phoenix/assets/index.html b/src/phoenix/assets/index.html index 76977f65..f1464a44 100644 --- a/src/phoenix/assets/index.html +++ b/src/phoenix/assets/index.html @@ -1,5 +1,6 @@ + @@ -10,8 +11,20 @@ - + + \ No newline at end of file diff --git a/src/phoenix/config/dev.js b/src/phoenix/config/dev.js index f7affea1..435ad3d8 100644 --- a/src/phoenix/config/dev.js +++ b/src/phoenix/config/dev.js @@ -19,5 +19,5 @@ globalThis.__CONFIG__ = { "origin": "https://puter.local:8080", "shell.href": "https://puter.local:8081", - "sdk_url": "http://puter.localhost:4100/sdk/puter.js", + "sdk_url": "http://puter.localhost:4100/puter.js/v2", }; diff --git a/src/phoenix/package.json b/src/phoenix/package.json index 0aeed3bd..5cba6422 100644 --- a/src/phoenix/package.json +++ b/src/phoenix/package.json @@ -10,12 +10,10 @@ "license": "AGPL-3.0-only", "type": "module", "devDependencies": { - "@rollup/plugin-commonjs": "^24.1.0", - "@rollup/plugin-node-resolve": "^15.0.2", - "@rollup/plugin-replace": "^5.0.2", + "copy-webpack-plugin": "^12.0.2", "mocha": "^10.8.2", - "rollup": "^3.29.5", - "rollup-plugin-copy": "^3.4.0" + "webpack": "^5.88.2", + "webpack-cli": "^5.1.1" }, "dependencies": { "@pkgjs/parseargs": "^0.11.0", @@ -36,4 +34,4 @@ "packages/strataparse", "packages/contextlink" ] -} +} \ No newline at end of file diff --git a/src/phoenix/rollup.config.js b/src/phoenix/rollup.config.js deleted file mode 100644 index 4a647289..00000000 --- a/src/phoenix/rollup.config.js +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright (C) 2024-present Puter Technologies Inc. - * - * This file is part of Puter. - * - * Puter is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published - * by the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ -import { nodeResolve } from '@rollup/plugin-node-resolve' -import commonjs from '@rollup/plugin-commonjs'; -import copy from 'rollup-plugin-copy'; -import process from 'node:process'; -import path from 'node:path'; - -const configFile = process.env.CONFIG_FILE ?? 'config/dev.js'; -await import(`./${configFile}`); - -export default { - input: "src/main_puter.js", - output: { - file: "dist/bundle.js", - format: "iife", - strict: false, - }, - plugins: [ - nodeResolve({ - rootDir: path.join(process.cwd(), '..'), - }), - commonjs(), - copy({ - targets: [ - { - src: 'assets/index.html', - dest: 'dist', - transform: (contents, name) => { - return contents.toString().replace('__SDK_URL__', - process.env.PUTER_JS_URL ?? globalThis.__CONFIG__.sdk_url); - } - }, - { src: 'assets/shell.html', dest: 'dist' }, - { src: configFile, dest: 'dist', rename: 'config.js' } - ] - }), - ] -} diff --git a/src/phoenix/run.json5 b/src/phoenix/run.json5 index a7f23ac7..0f13e2cd 100644 --- a/src/phoenix/run.json5 +++ b/src/phoenix/run.json5 @@ -7,8 +7,8 @@ command: 'npx http-server -p 8080', }, { - name: 'shell.rollup', - command: 'npx rollup -c rollup.config.js --watch', + name: 'shell.webpack', + command: 'npx webpack --watch', pwd: '.' }, ], diff --git a/src/phoenix/src/platform/browser/node-stubs/child_process.js b/src/phoenix/src/platform/browser/node-stubs/child_process.js new file mode 100644 index 00000000..c39cf94e --- /dev/null +++ b/src/phoenix/src/platform/browser/node-stubs/child_process.js @@ -0,0 +1,3 @@ +// Browser stub for node:child_process - not used in browser builds +export default {}; + diff --git a/src/phoenix/src/platform/browser/node-stubs/node-pty.js b/src/phoenix/src/platform/browser/node-stubs/node-pty.js new file mode 100644 index 00000000..55b55859 --- /dev/null +++ b/src/phoenix/src/platform/browser/node-stubs/node-pty.js @@ -0,0 +1,3 @@ +// Browser stub for node-pty - not used in browser builds +export default {}; + diff --git a/src/phoenix/src/platform/browser/node-stubs/path.js b/src/phoenix/src/platform/browser/node-stubs/path.js new file mode 100644 index 00000000..a74f262d --- /dev/null +++ b/src/phoenix/src/platform/browser/node-stubs/path.js @@ -0,0 +1,3 @@ +// Browser stub for node:path - not used in browser builds +export default {}; + diff --git a/src/phoenix/src/platform/browser/node-stubs/process.js b/src/phoenix/src/platform/browser/node-stubs/process.js new file mode 100644 index 00000000..7ebeddca --- /dev/null +++ b/src/phoenix/src/platform/browser/node-stubs/process.js @@ -0,0 +1,3 @@ +// Browser stub for node:process - not used in browser builds +export default {}; + diff --git a/src/phoenix/src/platform/browser/node-stubs/stream.js b/src/phoenix/src/platform/browser/node-stubs/stream.js new file mode 100644 index 00000000..a36492c0 --- /dev/null +++ b/src/phoenix/src/platform/browser/node-stubs/stream.js @@ -0,0 +1,3 @@ +// Browser stub for node:stream - not used in browser builds +export default {}; + diff --git a/src/phoenix/src/puter-shell/main.js b/src/phoenix/src/puter-shell/main.js index bec1e19c..4fcff89b 100644 --- a/src/phoenix/src/puter-shell/main.js +++ b/src/phoenix/src/puter-shell/main.js @@ -16,28 +16,28 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -import builtins from './coreutils/__exports__.js'; import ReadlineLib from "../ansi-shell/readline/readline.js"; +import builtins from './coreutils/__exports__.js'; // TODO: auto-gen argument parser registry from files +import { libs } from '@heyputer/putility'; +import { BetterReader } from 'dev-pty'; +import { ANSIShell } from "../ansi-shell/ANSIShell.js"; import SimpleArgParser from "../ansi-shell/arg-parsers/simple-parser.js"; import ErrorsDecorator from "../ansi-shell/decorators/errors.js"; -import { ANSIShell } from "../ansi-shell/ANSIShell.js"; -import { libs } from '@heyputer/putility'; -const { Context } = libs.context; -import { SHELL_VERSIONS } from "../meta/versions.js"; -import { PuterShellParser } from "../ansi-shell/parsing/PuterShellParser.js"; -import { BuiltinCommandProvider } from "./providers/BuiltinCommandProvider.js"; -import { CreateChatHistoryPlugin } from './plugins/ChatHistoryPlugin.js'; -import { Pipe } from '../ansi-shell/pipeline/Pipe.js'; -import { Coupler } from '../ansi-shell/pipeline/Coupler.js'; -import { BetterReader } from 'dev-pty'; import { MultiWriter } from '../ansi-shell/ioutil/MultiWriter.js'; +import { PuterShellParser } from "../ansi-shell/parsing/PuterShellParser.js"; +import { Coupler } from '../ansi-shell/pipeline/Coupler.js'; +import { Pipe } from '../ansi-shell/pipeline/Pipe.js'; +import { SHELL_VERSIONS } from "../meta/versions.js"; +import { CreateChatHistoryPlugin } from './plugins/ChatHistoryPlugin.js'; +import { BuiltinCommandProvider } from "./providers/BuiltinCommandProvider.js"; import { CompositeCommandProvider } from './providers/CompositeCommandProvider.js'; -import { ScriptCommandProvider } from './providers/ScriptCommandProvider.js'; -import { PuterAppCommandProvider } from './providers/PuterAppCommandProvider.js'; import { EmuCommandProvider } from './providers/EmuCommandProvider.js'; import { PDECommandProvider } from './providers/PDECommandProvider.js'; +import { PuterAppCommandProvider } from './providers/PuterAppCommandProvider.js'; +import { ScriptCommandProvider } from './providers/ScriptCommandProvider.js'; +const { Context } = libs.context; const argparser_registry = { [SimpleArgParser.name]: SimpleArgParser @@ -78,7 +78,7 @@ export const launchPuterShell = async (ctx) => { } // PathCommandProvider is only compatible with node.js for now - // HACK: The import path is split to fool rollup into not including it. + // HACK: The import path is split to fool webpack into not including it. const { PathCommandProvider } = (ctx.platform.name === 'node') ? await import('./providers/' + 'PathCommandProvider.js') : { PathCommandProvider: null }; diff --git a/src/phoenix/tools/build_tar.sh b/src/phoenix/tools/build_tar.sh index 274e1924..c6644a63 100755 --- a/src/phoenix/tools/build_tar.sh +++ b/src/phoenix/tools/build_tar.sh @@ -4,7 +4,7 @@ if [ $(basename "$(pwd)") != "phoenix" ]; then fi export CONFIG_FILE='config/release.js' -npx rollup -c rollup.config.js +npx webpack if [ -d ./release ]; then rm -rf ./release/* diff --git a/src/phoenix/webpack-resolve-extensions-plugin.js b/src/phoenix/webpack-resolve-extensions-plugin.js new file mode 100644 index 00000000..2f8e41d8 --- /dev/null +++ b/src/phoenix/webpack-resolve-extensions-plugin.js @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2024-present Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ +import fs from 'node:fs'; +import path from 'node:path'; + +class ResolveExtensionsPlugin { + apply(compiler) { + compiler.hooks.normalModuleFactory.tap('ResolveExtensionsPlugin', (nmf) => { + nmf.hooks.beforeResolve.tap('ResolveExtensionsPlugin', (data) => { + if (!data) return; + + // Skip if already has an extension + if (data.request.match(/\.(js|mjs|json|ts|tsx|css|html)$/)) { + return; + } + + const context = data.context || compiler.options.context || process.cwd(); + let requestPath; + + // Handle relative imports (starting with ./ or ../) + if (data.request.startsWith('.')) { + requestPath = path.resolve(context, data.request); + } + // Handle package subpath imports (like @heyputer/putility/src/libs/promise) + // Only add .js if there's a subpath (more than just the package name) + else if (data.request.includes('/') && !data.request.startsWith('/') && !data.request.startsWith('.')) { + const parts = data.request.split('/'); + // If there are more than 2 parts (e.g., @scope/pkg/path/to/file), it's a subpath + // Scoped packages like @heyputer/putility have 2 parts for the name + if (data.request.startsWith('@')) { + // Scoped package: @scope/pkg/path -> needs 3+ parts for subpath + if (parts.length > 2) { + data.request = data.request + '.js'; + return; + } + } else { + // Non-scoped package: pkg/path -> needs 2+ parts for subpath + if (parts.length > 1) { + data.request = data.request + '.js'; + return; + } + } + return; // Top-level package import, don't modify + } else { + return; // Not a relative or package subpath import + } + + // Check if .js file exists (for relative imports) + const jsPath = requestPath + '.js'; + if (fs.existsSync(jsPath)) { + data.request = data.request + '.js'; + return; + } + + // Check if it's a directory with index.js + if (fs.existsSync(requestPath) && fs.statSync(requestPath).isDirectory()) { + const indexPath = path.join(requestPath, 'index.js'); + if (fs.existsSync(indexPath)) { + data.request = data.request + '/index.js'; + } + } + }); + }); + } +} + +export default ResolveExtensionsPlugin; + diff --git a/src/phoenix/webpack.config.js b/src/phoenix/webpack.config.js new file mode 100644 index 00000000..18d07c95 --- /dev/null +++ b/src/phoenix/webpack.config.js @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2024-present Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ +import CopyWebpackPlugin from 'copy-webpack-plugin'; +import fs from 'node:fs'; +import path from 'node:path'; +import process from 'node:process'; +import { fileURLToPath } from 'node:url'; +import webpack from 'webpack'; +import ResolveExtensionsPlugin from './webpack-resolve-extensions-plugin.js'; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); + +const configFile = process.env.CONFIG_FILE ?? 'config/dev.js'; +const configPath = path.resolve(__dirname, configFile); + +// Read and evaluate config file manually to avoid webpack processing it +const configContent = fs.readFileSync(configPath, 'utf-8'); +// Create a safe context to evaluate the config +const configContext = { globalThis: { __CONFIG__: {} } }; +// Evaluate the config file in a controlled way +eval(configContent.replace(/globalThis\.__CONFIG__/g, 'configContext.globalThis.__CONFIG__')); + +// Capture config values at build time +const sdkUrl = process.env.PUTER_JS_URL ?? + (configContext.globalThis.__CONFIG__?.sdk_url ?? ''); + +export default { + mode: 'development', + entry: './src/main_puter.js', + output: { + path: path.resolve(__dirname, 'dist'), + filename: 'bundle.js', + iife: true, + }, + resolve: { + modules: [path.resolve(__dirname, '..'), 'node_modules'], + extensions: ['.js', '.mjs', '.json'], + }, + plugins: [ + new ResolveExtensionsPlugin(), + // Replace Node.js built-ins with empty modules for browser builds + new webpack.NormalModuleReplacementPlugin( + /^node:path$/, + path.resolve(__dirname, 'src/platform/browser/node-stubs/path.js') + ), + new webpack.NormalModuleReplacementPlugin( + /^node:child_process$/, + path.resolve(__dirname, 'src/platform/browser/node-stubs/child_process.js') + ), + new webpack.NormalModuleReplacementPlugin( + /^node:stream$/, + path.resolve(__dirname, 'src/platform/browser/node-stubs/stream.js') + ), + new webpack.NormalModuleReplacementPlugin( + /^node:process$/, + path.resolve(__dirname, 'src/platform/browser/node-stubs/process.js') + ), + new webpack.NormalModuleReplacementPlugin( + /^node-pty$/, + path.resolve(__dirname, 'src/platform/browser/node-stubs/node-pty.js') + ), + new CopyWebpackPlugin({ + patterns: [ + { + from: 'assets/index.html', + to: 'index.html', + transform: (content) => { + return content.toString().replace('__SDK_URL__', sdkUrl); + }, + }, + { + from: configFile, + to: 'config.js', + }, + ], + }), + ], +}; + diff --git a/src/terminal/assets/index.html b/src/terminal/assets/index.html index a6636576..28156957 100644 --- a/src/terminal/assets/index.html +++ b/src/terminal/assets/index.html @@ -1,5 +1,6 @@ + @@ -13,10 +14,23 @@ + - + + \ No newline at end of file diff --git a/src/terminal/config/dev.js b/src/terminal/config/dev.js index 07f2384b..50f78f58 100644 --- a/src/terminal/config/dev.js +++ b/src/terminal/config/dev.js @@ -18,5 +18,5 @@ */ globalThis.__CONFIG__ = { "origin": "http://127.0.0.1:8082", - "sdk_url": "http://puter.localhost:4100/sdk/puter.js", + "sdk_url": "http://puter.localhost:4100/puter.js/v2", }; diff --git a/src/terminal/package.json b/src/terminal/package.json index a5b817fb..222223ac 100644 --- a/src/terminal/package.json +++ b/src/terminal/package.json @@ -10,17 +10,15 @@ "license": "AGPL-3.0-only", "type": "module", "devDependencies": { - "@rollup/plugin-commonjs": "^24.1.0", - "@rollup/plugin-node-resolve": "^15.0.2", - "@rollup/plugin-replace": "^5.0.2", + "copy-webpack-plugin": "^12.0.2", "http-server": "^14.1.1", "mocha": "^10.8.2", - "rollup": "^3.29.5", - "rollup-plugin-copy": "^3.4.0" + "webpack": "^5.88.2", + "webpack-cli": "^5.1.1" }, "dependencies": { "@xterm/addon-fit": "^0.10.0", "@xterm/addon-image": "^0.8.0", "@xterm/xterm": "^5.5.0" } -} +} \ No newline at end of file diff --git a/src/terminal/rollup.config.js b/src/terminal/rollup.config.js deleted file mode 100644 index 075871c7..00000000 --- a/src/terminal/rollup.config.js +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright (C) 2024-present Puter Technologies Inc. - * - * This file is part of Puter. - * - * Puter is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published - * by the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ -import { nodeResolve } from '@rollup/plugin-node-resolve' -import commonjs from '@rollup/plugin-commonjs'; -import copy from 'rollup-plugin-copy'; -import process from 'node:process'; -import path from 'node:path'; - -const configFile = process.env.CONFIG_FILE ?? 'config/dev.js'; -await import(`./${configFile}`); - -export default { - input: "src/main.js", - output: { - file: "dist/bundle.js", - format: "iife" - }, - plugins: [ - nodeResolve({ - rootDir: path.join(process.cwd(), '..'), - }), - commonjs(), - copy({ - targets: [ - { - src: 'assets/index.html', - dest: 'dist', - transform: (contents, name) => { - return contents.toString().replace('__SDK_URL__', - process.env.PUTER_JS_URL ?? globalThis.__CONFIG__.sdk_url); - } - }, - { src: 'assets/shell.html', dest: 'dist' }, - { src: 'assets/normalize.css', dest: 'dist' }, - { src: 'assets/style.css', dest: 'dist' }, - - // We add this manually because there's no way to be sure - // _which_ node_modules directory is the correct one, since - // support for workspaces is under-documented and people may - // be using package managers other than npm. - { src: 'assets/xterm.css', dest: 'dist' }, - // { src: 'node_modules/xterm/css/xterm.css', dest: 'dist' }, - - { src: configFile, dest: 'dist', rename: 'config.js' } - ] - }), - ] -} diff --git a/src/terminal/run-http.json5 b/src/terminal/run-http.json5 index e2d07e61..32cfb156 100644 --- a/src/terminal/run-http.json5 +++ b/src/terminal/run-http.json5 @@ -6,9 +6,9 @@ command: 'npx http-server -p 8082', }, { - name: 'term.rollup', + name: 'term.webpack', pwd: '.', - command: 'npx rollup -c rollup.config.js --watch', + command: 'npx webpack --watch', }, ] } diff --git a/src/terminal/run-https.json5 b/src/terminal/run-https.json5 index 21f24df4..478d7434 100644 --- a/src/terminal/run-https.json5 +++ b/src/terminal/run-https.json5 @@ -6,9 +6,9 @@ command: 'npx http-server -p 8082 -S -C "{cert}" -K "{key}"', }, { - name: 'term.rollup', + name: 'term.webpack', pwd: '.', - command: 'npx rollup -c rollup.config.js --watch', + command: 'npx webpack --watch', }, ] } diff --git a/src/terminal/run-phoenix-http.json5 b/src/terminal/run-phoenix-http.json5 index e5b3a285..506c5636 100644 --- a/src/terminal/run-phoenix-http.json5 +++ b/src/terminal/run-phoenix-http.json5 @@ -2,22 +2,22 @@ init: [ { pwd: '.', - command: 'npx rollup -c rollup.config.js' + command: 'npx webpack' }, { pwd: '../phoenix', - command: 'npx rollup -c rollup.config.js' + command: 'npx webpack' }, ], services: [ { - name: 'term.rollup', + name: 'term.webpack', pwd: '.', - command: 'npx rollup -c rollup.config.js --watch', + command: 'npx webpack --watch', }, { - name: 'shell.rollup', - command: 'npx rollup -c rollup.config.js --watch', + name: 'shell.webpack', + command: 'npx webpack --watch', pwd: '../phoenix' }, { diff --git a/src/terminal/run.json5 b/src/terminal/run.json5 index 5b746048..477a153d 100644 --- a/src/terminal/run.json5 +++ b/src/terminal/run.json5 @@ -11,13 +11,13 @@ command: 'npx http-server -p 8080 -S -C "{cert}" -K "{key}"', }, { - name: 'term.rollup', - command: 'npx rollup -c rollup.config.js --watch', + name: 'term.webpack', + command: 'npx webpack --watch', pwd: '.' }, { - name: 'ansi.rollup', - command: 'npx rollup -c rollup.config.js --watch', + name: 'ansi.webpack', + command: 'npx webpack --watch', pwd: '../phoenix' }, ] diff --git a/src/terminal/webpack-resolve-extensions-plugin.js b/src/terminal/webpack-resolve-extensions-plugin.js new file mode 100644 index 00000000..2f8e41d8 --- /dev/null +++ b/src/terminal/webpack-resolve-extensions-plugin.js @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2024-present Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ +import fs from 'node:fs'; +import path from 'node:path'; + +class ResolveExtensionsPlugin { + apply(compiler) { + compiler.hooks.normalModuleFactory.tap('ResolveExtensionsPlugin', (nmf) => { + nmf.hooks.beforeResolve.tap('ResolveExtensionsPlugin', (data) => { + if (!data) return; + + // Skip if already has an extension + if (data.request.match(/\.(js|mjs|json|ts|tsx|css|html)$/)) { + return; + } + + const context = data.context || compiler.options.context || process.cwd(); + let requestPath; + + // Handle relative imports (starting with ./ or ../) + if (data.request.startsWith('.')) { + requestPath = path.resolve(context, data.request); + } + // Handle package subpath imports (like @heyputer/putility/src/libs/promise) + // Only add .js if there's a subpath (more than just the package name) + else if (data.request.includes('/') && !data.request.startsWith('/') && !data.request.startsWith('.')) { + const parts = data.request.split('/'); + // If there are more than 2 parts (e.g., @scope/pkg/path/to/file), it's a subpath + // Scoped packages like @heyputer/putility have 2 parts for the name + if (data.request.startsWith('@')) { + // Scoped package: @scope/pkg/path -> needs 3+ parts for subpath + if (parts.length > 2) { + data.request = data.request + '.js'; + return; + } + } else { + // Non-scoped package: pkg/path -> needs 2+ parts for subpath + if (parts.length > 1) { + data.request = data.request + '.js'; + return; + } + } + return; // Top-level package import, don't modify + } else { + return; // Not a relative or package subpath import + } + + // Check if .js file exists (for relative imports) + const jsPath = requestPath + '.js'; + if (fs.existsSync(jsPath)) { + data.request = data.request + '.js'; + return; + } + + // Check if it's a directory with index.js + if (fs.existsSync(requestPath) && fs.statSync(requestPath).isDirectory()) { + const indexPath = path.join(requestPath, 'index.js'); + if (fs.existsSync(indexPath)) { + data.request = data.request + '/index.js'; + } + } + }); + }); + } +} + +export default ResolveExtensionsPlugin; + diff --git a/src/terminal/webpack.config.js b/src/terminal/webpack.config.js new file mode 100644 index 00000000..07b26a51 --- /dev/null +++ b/src/terminal/webpack.config.js @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2024-present Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ +import CopyWebpackPlugin from 'copy-webpack-plugin'; +import fs from 'node:fs'; +import path from 'node:path'; +import process from 'node:process'; +import { fileURLToPath } from 'node:url'; +import ResolveExtensionsPlugin from './webpack-resolve-extensions-plugin.js'; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); + +const configFile = process.env.CONFIG_FILE ?? 'config/dev.js'; +const configPath = path.resolve(__dirname, configFile); + +// Read and evaluate config file manually to avoid webpack processing it +const configContent = fs.readFileSync(configPath, 'utf-8'); +// Create a safe context to evaluate the config +const configContext = { globalThis: { __CONFIG__: {} } }; +// Evaluate the config file in a controlled way +eval(configContent.replace(/globalThis\.__CONFIG__/g, 'configContext.globalThis.__CONFIG__')); + +// Capture config values at build time +const sdkUrl = process.env.PUTER_JS_URL ?? + (configContext.globalThis.__CONFIG__?.sdk_url ?? ''); + +export default { + mode: 'development', + entry: './src/main.js', + output: { + path: path.resolve(__dirname, 'dist'), + filename: 'bundle.js', + iife: true, + }, + resolve: { + modules: [path.resolve(__dirname, '..'), 'node_modules'], + extensions: ['.js', '.mjs', '.json'], + }, + plugins: [ + new ResolveExtensionsPlugin(), + new CopyWebpackPlugin({ + patterns: [ + { + from: 'assets/index.html', + to: 'index.html', + transform: (content) => { + return content.toString().replace('__SDK_URL__', sdkUrl); + }, + }, + { from: 'assets/normalize.css', to: 'normalize.css' }, + { from: 'assets/style.css', to: 'style.css' }, + { from: 'assets/xterm.css', to: 'xterm.css' }, + { + from: configFile, + to: 'config.js', + }, + ], + }), + ], +}; +