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 513c81efb..f5f933f64 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 66d875ec5..c80a38393 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 d232c284d..c17810527 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 838911a3a..000000000 --- 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 f331a9463..86e2b4911 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 000000000..7f2ce5045 --- /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 a3fac7c18..81b97fd4d 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 4273f52b1..58081f111 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 76977f651..f1464a442 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 f7affea1c..435ad3d8c 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 0aeed3bdc..5cba6422f 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 4a6472896..000000000 --- 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 a7f23ac79..0f13e2cdf 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 000000000..c39cf94e7 --- /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 000000000..55b558594 --- /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 000000000..a74f262d6 --- /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 000000000..7ebeddcae --- /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 000000000..a36492c00 --- /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 bec1e19cb..4fcff89b9 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 274e19243..c6644a631 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 000000000..2f8e41d8c --- /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 000000000..18d07c95a --- /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 a66365764..281569571 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 07f2384bf..50f78f58e 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 a5b817fb8..222223acc 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 075871c76..000000000 --- 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 e2d07e617..32cfb1566 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 21f24df45..478d74349 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 e5b3a285d..506c56368 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 5b7460484..477a153d1 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 000000000..2f8e41d8c --- /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 000000000..07b26a514 --- /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', + }, + ], + }), + ], +}; +