Fix NodeJS 22+ path handling, improve SnapshotFS handling, add bundleRules
This commit is contained in:
@@ -136,6 +136,22 @@ compile({
|
||||
export function createBundle (options: NexeOptions): Promise<string>
|
||||
```
|
||||
- default: true
|
||||
- #### `bundleRules: object`
|
||||
- Configuration for the runtime module resolution inside the snapshot.
|
||||
This controls how bare module specifiers (e.g., `require('lodash')`) are resolved from the embedded `node_modules`.
|
||||
- Properties:
|
||||
- `conditions?: string[]` – The set of conditions to use when evaluating the exports field of a package.
|
||||
Default: `['require', 'node', 'default']`.
|
||||
- `basePath?: string` – The virtual filesystem path where `node_modules` is mounted. Default: `'/snapshot/node_modules'`.
|
||||
- Example:
|
||||
```
|
||||
javascript
|
||||
{
|
||||
conditions: ['require', 'node', 'production'],
|
||||
basePath: '/snapshot/packages'
|
||||
}
|
||||
```
|
||||
- default: `{ conditions: ['require', 'node', 'default'], basePath: '/snapshot/node_modules' }`
|
||||
- #### `name: string`
|
||||
- Module friendly name of the application
|
||||
- default: basename of the input file, or `nexe_${Date.now()}`
|
||||
|
||||
Generated
+120
-44
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "nexe",
|
||||
"version": "5.0.0-beta.5",
|
||||
"version": "5.0.0-beta.6",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "nexe",
|
||||
"version": "5.0.0-beta.5",
|
||||
"version": "5.0.0-beta.6",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@calebboyd/semaphore": "^1.3.1",
|
||||
@@ -19,6 +19,7 @@
|
||||
"chalk": "^2.4.2",
|
||||
"globby": "^11.0.2",
|
||||
"meriyah": "^4.3.5",
|
||||
"minimatch": "^10.1.2",
|
||||
"minimist": "^1.2.8",
|
||||
"mkdirp": "^1.0.4",
|
||||
"multistream": "^4.1.0",
|
||||
@@ -167,6 +168,19 @@
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@eslint/eslintrc/node_modules/minimatch": {
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
|
||||
"integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"brace-expansion": "^1.1.7"
|
||||
},
|
||||
"engines": {
|
||||
"node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@eslint/js": {
|
||||
"version": "8.57.1",
|
||||
"resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.1.tgz",
|
||||
@@ -193,6 +207,19 @@
|
||||
"node": ">=10.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@humanwhocodes/config-array/node_modules/minimatch": {
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
|
||||
"integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"brace-expansion": "^1.1.7"
|
||||
},
|
||||
"engines": {
|
||||
"node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@humanwhocodes/module-importer": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz",
|
||||
@@ -215,6 +242,27 @@
|
||||
"dev": true,
|
||||
"license": "BSD-3-Clause"
|
||||
},
|
||||
"node_modules/@isaacs/balanced-match": {
|
||||
"version": "4.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@isaacs/balanced-match/-/balanced-match-4.0.1.tgz",
|
||||
"integrity": "sha512-yzMTt9lEb8Gv7zRioUilSglI0c0smZ9k5D65677DLWLtWJaXIS3CqcGyUFByYKlnUj6TkjLVs54fBl6+TiGQDQ==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": "20 || >=22"
|
||||
}
|
||||
},
|
||||
"node_modules/@isaacs/brace-expansion": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@isaacs/brace-expansion/-/brace-expansion-5.0.1.tgz",
|
||||
"integrity": "sha512-WMz71T1JS624nWj2n2fnYAuPovhv7EUhk69R6i9dsVyzxt5eM3bjwvgk9L+APE1TRscGysAVMANkB0jh0LQZrQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@isaacs/balanced-match": "^4.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": "20 || >=22"
|
||||
}
|
||||
},
|
||||
"node_modules/@isaacs/fs-minipass": {
|
||||
"version": "4.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@isaacs/fs-minipass/-/fs-minipass-4.0.1.tgz",
|
||||
@@ -1990,9 +2038,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/diff": {
|
||||
"version": "5.2.0",
|
||||
"resolved": "https://registry.npmjs.org/diff/-/diff-5.2.0.tgz",
|
||||
"integrity": "sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A==",
|
||||
"version": "5.2.2",
|
||||
"resolved": "https://registry.npmjs.org/diff/-/diff-5.2.2.tgz",
|
||||
"integrity": "sha512-vtcDfH3TOjP8UekytvnHH1o1P4FcUdt4eQ1Y+Abap1tk/OB2MWQvcwS2ClCd1zuIhc3JKOx6p3kod8Vfys3E+A==",
|
||||
"dev": true,
|
||||
"license": "BSD-3-Clause",
|
||||
"engines": {
|
||||
@@ -2061,13 +2109,13 @@
|
||||
}
|
||||
},
|
||||
"node_modules/enhanced-resolve": {
|
||||
"version": "5.18.3",
|
||||
"resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.18.3.tgz",
|
||||
"integrity": "sha512-d4lC8xfavMeBjzGr2vECC3fsGXziXZQyJxD868h2M/mBI3PwAuODxAkLkq5HYuvrPYcUtiLzsTo8U3PgX3Ocww==",
|
||||
"version": "5.19.0",
|
||||
"resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.19.0.tgz",
|
||||
"integrity": "sha512-phv3E1Xl4tQOShqSte26C7Fl84EwUdZsyOuSSk9qtAGyyQs2s3jJzComh+Abf4g187lUUAvH+H26omrqia2aGg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"graceful-fs": "^4.2.4",
|
||||
"tapable": "^2.2.0"
|
||||
"tapable": "^2.3.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10.13.0"
|
||||
@@ -2104,9 +2152,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/es-module-lexer": {
|
||||
"version": "1.7.0",
|
||||
"resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.7.0.tgz",
|
||||
"integrity": "sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==",
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-2.0.0.tgz",
|
||||
"integrity": "sha512-5POEcUuZybH7IdmGsD8wlf0AI55wMecM9rVBTI/qEAy2c1kTOm3DjFYjrBdI2K3BaJjJYfYFeRtM0t9ssnRuxw==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/es-object-atoms": {
|
||||
@@ -2422,6 +2470,19 @@
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/eslint/node_modules/minimatch": {
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
|
||||
"integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"brace-expansion": "^1.1.7"
|
||||
},
|
||||
"engines": {
|
||||
"node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/eslint/node_modules/strip-ansi": {
|
||||
"version": "6.0.1",
|
||||
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
|
||||
@@ -2905,6 +2966,18 @@
|
||||
"integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==",
|
||||
"license": "BSD-2-Clause"
|
||||
},
|
||||
"node_modules/glob/node_modules/minimatch": {
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
|
||||
"integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"brace-expansion": "^1.1.7"
|
||||
},
|
||||
"engines": {
|
||||
"node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/globals": {
|
||||
"version": "13.24.0",
|
||||
"resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz",
|
||||
@@ -3535,9 +3608,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/lodash": {
|
||||
"version": "4.17.21",
|
||||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
|
||||
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
|
||||
"version": "4.17.23",
|
||||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.23.tgz",
|
||||
"integrity": "sha512-LgVTMpQtIopCi79SJeDiP0TfWi5CNEc/L/aRdTh3yIvmZXTnheWpKjSZhnvMl8iXbC1tFg9gdHHDMLoV7CnG+w==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/lodash.defaults": {
|
||||
@@ -3765,15 +3838,18 @@
|
||||
}
|
||||
},
|
||||
"node_modules/minimatch": {
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
|
||||
"integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
|
||||
"license": "ISC",
|
||||
"version": "10.1.2",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.1.2.tgz",
|
||||
"integrity": "sha512-fu656aJ0n2kcXwsnwnv9g24tkU5uSmOlTjd6WyyaKm2Z+h1qmY6bAjrcaIxF/BslFqbZ8UBtbJi7KgQOZD2PTw==",
|
||||
"license": "BlueOak-1.0.0",
|
||||
"dependencies": {
|
||||
"brace-expansion": "^1.1.7"
|
||||
"@isaacs/brace-expansion": "^5.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": "*"
|
||||
"node": "20 || >=22"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/isaacs"
|
||||
}
|
||||
},
|
||||
"node_modules/minimist": {
|
||||
@@ -4912,9 +4988,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/tar": {
|
||||
"version": "7.5.2",
|
||||
"resolved": "https://registry.npmjs.org/tar/-/tar-7.5.2.tgz",
|
||||
"integrity": "sha512-7NyxrTE4Anh8km8iEy7o0QYPs+0JKBTj5ZaqHg6B39erLg0qYXN3BijtShwbsNSvQ+LN75+KV+C4QR/f6Gwnpg==",
|
||||
"version": "7.5.7",
|
||||
"resolved": "https://registry.npmjs.org/tar/-/tar-7.5.7.tgz",
|
||||
"integrity": "sha512-fov56fJiRuThVFXD6o6/Q354S7pnWMJIVlDBYijsTNx6jKSE4pvrDTs6lUnmGvNyfJwFQQwWy3owKz1ucIhveQ==",
|
||||
"license": "BlueOak-1.0.0",
|
||||
"dependencies": {
|
||||
"@isaacs/fs-minipass": "^4.0.0",
|
||||
@@ -4944,9 +5020,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/terser": {
|
||||
"version": "5.44.1",
|
||||
"resolved": "https://registry.npmjs.org/terser/-/terser-5.44.1.tgz",
|
||||
"integrity": "sha512-t/R3R/n0MSwnnazuPpPNVO60LX0SKL45pyl9YlvxIdkH0Of7D5qM2EVe+yASRIlY5pZ73nclYJfNANGWPwFDZw==",
|
||||
"version": "5.46.0",
|
||||
"resolved": "https://registry.npmjs.org/terser/-/terser-5.46.0.tgz",
|
||||
"integrity": "sha512-jTwoImyr/QbOWFFso3YoU3ik0jBBDJ6JTOQiy/J2YxVJdZCc+5u7skhNwiOR3FQIygFqVUPHl7qbbxtjW2K3Qg==",
|
||||
"license": "BSD-2-Clause",
|
||||
"dependencies": {
|
||||
"@jridgewell/source-map": "^0.3.3",
|
||||
@@ -4962,9 +5038,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/terser-webpack-plugin": {
|
||||
"version": "5.3.15",
|
||||
"resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.15.tgz",
|
||||
"integrity": "sha512-PGkOdpRFK+rb1TzVz+msVhw4YMRT9txLF4kRqvJhGhCM324xuR3REBSHALN+l+sAhKUmz0aotnjp5D+P83mLhQ==",
|
||||
"version": "5.3.16",
|
||||
"resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.16.tgz",
|
||||
"integrity": "sha512-h9oBFCWrq78NyWWVcSwZarJkZ01c2AyGrzs1crmHZO3QUg9D61Wu4NPjBy69n7JqylFF5y+CsUZYmYEIZ3mR+Q==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@jridgewell/trace-mapping": "^0.3.25",
|
||||
@@ -5180,9 +5256,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/ts-node/node_modules/diff": {
|
||||
"version": "4.0.2",
|
||||
"resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz",
|
||||
"integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==",
|
||||
"version": "4.0.4",
|
||||
"resolved": "https://registry.npmjs.org/diff/-/diff-4.0.4.tgz",
|
||||
"integrity": "sha512-X07nttJQkwkfKfvTPG/KSnE2OMdcUCao6+eXF3wmnIQRn2aPAHH3VxDbDOdegkd6JbPsXqShpvEOHfAT+nCNwQ==",
|
||||
"dev": true,
|
||||
"license": "BSD-3-Clause",
|
||||
"engines": {
|
||||
@@ -5325,9 +5401,9 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/watchpack": {
|
||||
"version": "2.4.4",
|
||||
"resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.4.tgz",
|
||||
"integrity": "sha512-c5EGNOiyxxV5qmTtAB7rbiXxi1ooX1pQKMLX/MIabJjRA0SJBQOjKF+KSVfHkr9U1cADPon0mRiVe/riyaiDUA==",
|
||||
"version": "2.5.1",
|
||||
"resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.5.1.tgz",
|
||||
"integrity": "sha512-Zn5uXdcFNIA1+1Ei5McRd+iRzfhENPCe7LeABkJtNulSxjma+l7ltNx55BWZkRlwRnpOgHqxnjyaDgJnNXnqzg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"glob-to-regexp": "^0.4.1",
|
||||
@@ -5347,9 +5423,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/webpack": {
|
||||
"version": "5.103.0",
|
||||
"resolved": "https://registry.npmjs.org/webpack/-/webpack-5.103.0.tgz",
|
||||
"integrity": "sha512-HU1JOuV1OavsZ+mfigY0j8d1TgQgbZ6M+J75zDkpEAwYeXjWSqrGJtgnPblJjd/mAyTNQ7ygw0MiKOn6etz8yw==",
|
||||
"version": "5.105.0",
|
||||
"resolved": "https://registry.npmjs.org/webpack/-/webpack-5.105.0.tgz",
|
||||
"integrity": "sha512-gX/dMkRQc7QOMzgTe6KsYFM7DxeIONQSui1s0n/0xht36HvrgbxtM1xBlgx596NbpHuQU8P7QpKwrZYwUX48nw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/eslint-scope": "^3.7.7",
|
||||
@@ -5360,10 +5436,10 @@
|
||||
"@webassemblyjs/wasm-parser": "^1.14.1",
|
||||
"acorn": "^8.15.0",
|
||||
"acorn-import-phases": "^1.0.3",
|
||||
"browserslist": "^4.26.3",
|
||||
"browserslist": "^4.28.1",
|
||||
"chrome-trace-event": "^1.0.2",
|
||||
"enhanced-resolve": "^5.17.3",
|
||||
"es-module-lexer": "^1.2.1",
|
||||
"enhanced-resolve": "^5.19.0",
|
||||
"es-module-lexer": "^2.0.0",
|
||||
"eslint-scope": "5.1.1",
|
||||
"events": "^3.2.0",
|
||||
"glob-to-regexp": "^0.4.1",
|
||||
@@ -5374,8 +5450,8 @@
|
||||
"neo-async": "^2.6.2",
|
||||
"schema-utils": "^4.3.3",
|
||||
"tapable": "^2.3.0",
|
||||
"terser-webpack-plugin": "^5.3.11",
|
||||
"watchpack": "^2.4.4",
|
||||
"terser-webpack-plugin": "^5.3.16",
|
||||
"watchpack": "^2.5.1",
|
||||
"webpack-sources": "^3.3.3"
|
||||
},
|
||||
"bin": {
|
||||
|
||||
+9
-7
@@ -2,11 +2,12 @@
|
||||
"name": "nexe",
|
||||
"description": "Create a single executable out of your Node.js application",
|
||||
"license": "MIT",
|
||||
"version": "5.0.0-beta.5",
|
||||
"version": "5.0.1-beta",
|
||||
"contributors": [
|
||||
"Craig Condon <craig.j.condon@gmail.com> (http://crcn.io)",
|
||||
"Jared Allard <jaredallard@outlook.com>",
|
||||
"Caleb Boyd <caleb.boyd@hotmail.com>"
|
||||
"Caleb Boyd <caleb.boyd@hotmail.com>",
|
||||
"Seth Olivarez <me@oxmc.me> (http://oxmc.me)"
|
||||
],
|
||||
"scripts": {
|
||||
"ci:build": "ts-node tasks/build",
|
||||
@@ -54,6 +55,7 @@
|
||||
"chalk": "^2.4.2",
|
||||
"globby": "^11.0.2",
|
||||
"meriyah": "^4.3.5",
|
||||
"minimatch": "^10.1.2",
|
||||
"minimist": "^1.2.8",
|
||||
"mkdirp": "^1.0.4",
|
||||
"multistream": "^4.1.0",
|
||||
@@ -76,17 +78,17 @@
|
||||
"@types/ora": "^3.2.0",
|
||||
"@types/rimraf": "3.0.2",
|
||||
"@types/semver": "^7.3.13",
|
||||
"@typescript-eslint/eslint-plugin": "^5.59.0",
|
||||
"@typescript-eslint/parser": "^5.59.0",
|
||||
"chai": "^4.3.7",
|
||||
"eslint": "^8.40.0",
|
||||
"eslint-config-prettier": "^8.8.0",
|
||||
"eslint-plugin-prettier": "^4.2.1",
|
||||
"execa": "^5.1.1",
|
||||
"lodash": "^4.17.21",
|
||||
"mocha": "^10.2.0",
|
||||
"prettier": "^2.8.7",
|
||||
"ts-node": "^10.9.1",
|
||||
"@typescript-eslint/eslint-plugin": "^5.59.0",
|
||||
"@typescript-eslint/parser": "^5.59.0",
|
||||
"eslint": "^8.40.0",
|
||||
"eslint-config-prettier": "^8.8.0",
|
||||
"eslint-plugin-prettier": "^4.2.1",
|
||||
"typescript": "^5.0.3",
|
||||
"webpack-cli": "^5.0.1"
|
||||
}
|
||||
|
||||
+263
-47
@@ -3,7 +3,7 @@ import { patchFs, PosixFS, NodeFS } from "@yarnpkg/fslib";
|
||||
import { SnapshotZipFS } from "./SnapshotZipFS";
|
||||
import * as assert from "assert";
|
||||
import * as constants from "constants";
|
||||
import { dirname } from "path";
|
||||
import { dirname, relative, sep } from "path";
|
||||
|
||||
export interface NexeHeader {
|
||||
blobPath: string;
|
||||
@@ -16,7 +16,7 @@ export interface NexeHeader {
|
||||
}
|
||||
|
||||
let originalFsMethods: any = null;
|
||||
let lazyRestoreFs = () => { };
|
||||
let lazyRestoreFs = () => {};
|
||||
const patches = (process as any).nexe.patches || {};
|
||||
const originalPatches = { ...patches };
|
||||
delete (process as any).nexe;
|
||||
@@ -47,15 +47,19 @@ function shimFs(binary: NexeHeader, fs: typeof import("fs") = require("fs")) {
|
||||
libzip: getLibzipSync(),
|
||||
zipFs,
|
||||
baseFs: nodeFs,
|
||||
root: dirname(process.argv[0]),
|
||||
root: dirname(process.argv[0]), // executable directory = original project root
|
||||
});
|
||||
const posixSnapshotZipFs = new PosixFS(snapshotZipFS);
|
||||
patchFs(fs, posixSnapshotZipFs);
|
||||
patchFs(fs, posixSnapshotZipFs); // patches global fs
|
||||
|
||||
// Capture the project root for path mapping
|
||||
const projectRoot = dirname(process.argv[0]);
|
||||
const drive = projectRoot.slice(0, 2); // e.g., "C:"
|
||||
|
||||
// Enable logging with DEBUG=nexe:require
|
||||
let log = (_: string) => true;
|
||||
if ((process.env.DEBUG || "").toLowerCase().includes("nexe:require")) {
|
||||
process.stderr.write(
|
||||
// @ts-ignore
|
||||
`[nexe] - FILES ${JSON.stringify(
|
||||
// @ts-ignore - accessing private property for debugging
|
||||
Array.from(zipFs.entries.keys()),
|
||||
@@ -64,7 +68,6 @@ function shimFs(binary: NexeHeader, fs: typeof import("fs") = require("fs")) {
|
||||
)}\n`
|
||||
);
|
||||
process.stderr.write(
|
||||
// @ts-ignore
|
||||
`[nexe] - DIRECTORIES ${JSON.stringify(
|
||||
// @ts-ignore - accessing private property for debugging
|
||||
Array.from(zipFs.listings.keys()),
|
||||
@@ -72,60 +75,273 @@ function shimFs(binary: NexeHeader, fs: typeof import("fs") = require("fs")) {
|
||||
4
|
||||
)}\n`
|
||||
);
|
||||
log = (text: string) => {
|
||||
return process.stderr.write(`[nexe] - ${text}\n`);
|
||||
};
|
||||
log = (text: string) => process.stderr.write(`[nexe] - ${text}\n`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a Windows path to the snapshot POSIX path.
|
||||
* Handles:
|
||||
* - Paths under the original project root (e.g., C:\Users\oxmc\Desktop\src\entry.js → /snapshot/src/entry.js)
|
||||
* - Paths that have been converted to C:\snapshot\... (from _findPath returning /snapshot/...)
|
||||
* - Already POSIX /snapshot/... paths (return as-is)
|
||||
*/
|
||||
function toSnapshotPath(filePath: string): string {
|
||||
// Already a POSIX snapshot path
|
||||
if (filePath.startsWith("/snapshot/")) {
|
||||
return filePath;
|
||||
}
|
||||
// Handle Windows-style snapshot path: e.g., C:\snapshot\src\entry.js
|
||||
if (filePath.startsWith(drive + "\\snapshot\\")) {
|
||||
return "/snapshot/" + filePath.slice(drive.length + 9).replace(/\\/g, "/");
|
||||
}
|
||||
// Path under original project root
|
||||
if (filePath.startsWith(projectRoot)) {
|
||||
const rel = relative(projectRoot, filePath);
|
||||
return "/snapshot/" + rel.replace(/\\/g, "/");
|
||||
}
|
||||
// Not mappable – return unchanged (will likely fail)
|
||||
return filePath;
|
||||
}
|
||||
|
||||
// --- Internal Module Patches (unconditionally assigned) ---
|
||||
|
||||
function internalModuleReadFile(this: any, original: any, ...args: any[]) {
|
||||
log(`internalModuleReadFile ${args[0]}`);
|
||||
// Strip Windows extended-length path prefix if present
|
||||
let filePath = typeof args[0] === "string" ? args[0] : "";
|
||||
if (filePath.startsWith("\\\\?\\")) {
|
||||
filePath = filePath.slice(4);
|
||||
}
|
||||
const mappedPath = toSnapshotPath(filePath);
|
||||
log(`internalModuleReadFile ${filePath} -> ${mappedPath}`);
|
||||
try {
|
||||
return posixSnapshotZipFs.readFileSync(args[0], "utf-8");
|
||||
// Use the patched fs (which already sees the zip)
|
||||
return fs.readFileSync(mappedPath, "utf-8");
|
||||
} catch (e) {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
if (patches.internalModuleReadFile) {
|
||||
patches.internalModuleReadFile = internalModuleReadFile;
|
||||
}
|
||||
let returningArray: boolean;
|
||||
patches.internalModuleReadJSON = function (
|
||||
this: any,
|
||||
original: any,
|
||||
...args: any[]
|
||||
) {
|
||||
if (returningArray == null)
|
||||
returningArray = Array.isArray(original.call(this, ""));
|
||||
const res = internalModuleReadFile.call(this, original, ...args);
|
||||
return returningArray && !Array.isArray(res)
|
||||
? res === ""
|
||||
? []
|
||||
: [res, /"(main|name|type|exports|imports)"/.test(res)]
|
||||
: res;
|
||||
|
||||
patches.internalModuleReadFile = internalModuleReadFile;
|
||||
|
||||
// internalModuleReadJSON should return a string (or undefined) in Node 22
|
||||
patches.internalModuleReadJSON = function (this: any, original: any, ...args: any[]) {
|
||||
const content = internalModuleReadFile.call(this, original, ...args);
|
||||
return content === "" ? undefined : content;
|
||||
};
|
||||
patches.internalModuleStat = function (
|
||||
this: any,
|
||||
original: any,
|
||||
...args: any[]
|
||||
) {
|
||||
let statPath = args[0];
|
||||
//in node 22, the path arg moved to arg[1]
|
||||
if (typeof args[0] !== "string") statPath = args[1];
|
||||
let result = 0;
|
||||
try {
|
||||
const stat = posixSnapshotZipFs.statSync(statPath);
|
||||
if (stat.isDirectory()) result = 1;
|
||||
else result = 0;
|
||||
} catch (e) {
|
||||
result = -constants.ENOENT;
|
||||
|
||||
// Handle Node 22+ signature: first arg is context (non-string), second is path
|
||||
function internalModuleStat(this: any, original: any, ...args: any[]) {
|
||||
const target = args[0];
|
||||
let statPath: string;
|
||||
|
||||
// Node 22+: args[0] is context (often a buffer), args[1] is the path string
|
||||
if (typeof target === "number") {
|
||||
// file descriptor case – unchanged
|
||||
try {
|
||||
originalFsMethods.fstatSync(target);
|
||||
return 0;
|
||||
} catch (e) {
|
||||
return -constants.ENOENT;
|
||||
}
|
||||
}
|
||||
log(`internalModuleStat ${result} ${statPath}`);
|
||||
return result;
|
||||
};
|
||||
|
||||
if (typeof target === "string") {
|
||||
// Node <22 or when a string is passed directly
|
||||
statPath = target;
|
||||
} else {
|
||||
// Node 22+: path is the second argument
|
||||
statPath = args[1];
|
||||
}
|
||||
|
||||
if (typeof statPath !== "string") {
|
||||
// Unexpected: fallback to original
|
||||
return original.call(this, ...args);
|
||||
}
|
||||
|
||||
// Strip Windows extended-length prefix
|
||||
if (statPath.startsWith("\\\\?\\")) {
|
||||
statPath = statPath.slice(4);
|
||||
}
|
||||
|
||||
const mappedPath = toSnapshotPath(statPath);
|
||||
log(`internalModuleStat ${statPath} -> ${mappedPath}`);
|
||||
|
||||
try {
|
||||
const stat = fs.statSync(mappedPath);
|
||||
return stat.isDirectory() ? 1 : 0;
|
||||
} catch (e) {
|
||||
return -constants.ENOENT;
|
||||
}
|
||||
}
|
||||
|
||||
patches.internalModuleStat = internalModuleStat;
|
||||
|
||||
// --- Patch Module._findPath with a correct exports resolver ---
|
||||
|
||||
// Helper to check if a path exists and is a file
|
||||
function isFile(p: string): boolean {
|
||||
try {
|
||||
const stat = fs.statSync(p);
|
||||
return stat.isFile();
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Recursive exports resolver following Node's conditional exports
|
||||
function resolvePackageExports(exports: any, conditions: string[]): string | null {
|
||||
if (typeof exports === "string") {
|
||||
return exports;
|
||||
}
|
||||
if (!exports || typeof exports !== "object") {
|
||||
return null;
|
||||
}
|
||||
// Handle "." subpath first (for bare module, we always start with ".")
|
||||
const subExports = exports["."] ?? exports;
|
||||
return resolveExportsObject(subExports, conditions);
|
||||
}
|
||||
|
||||
function resolveExportsObject(obj: any, conditions: string[]): string | null {
|
||||
if (typeof obj === "string") {
|
||||
return obj;
|
||||
}
|
||||
if (!obj || typeof obj !== "object") {
|
||||
return null;
|
||||
}
|
||||
// Iterate over keys in order; if a key matches a condition, take that branch
|
||||
for (const key of Object.keys(obj)) {
|
||||
if (conditions.includes(key)) {
|
||||
const value = obj[key];
|
||||
if (typeof value === "string") {
|
||||
return value;
|
||||
}
|
||||
if (value && typeof value === "object") {
|
||||
const nested = resolveExportsObject(value, conditions);
|
||||
if (nested) return nested;
|
||||
}
|
||||
}
|
||||
}
|
||||
// If no matching condition, try "default" if not already tried
|
||||
if (!conditions.includes("default") && obj.default) {
|
||||
const def = obj.default;
|
||||
if (typeof def === "string") return def;
|
||||
if (def && typeof def === "object") {
|
||||
return resolveExportsObject(def, conditions);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
let _origFindPath: ((...args: any[]) => any) | null = null;
|
||||
try {
|
||||
const Module = require("module");
|
||||
const nodePath = require("path");
|
||||
const capturedOrigFindPath = (Module as any)._findPath;
|
||||
if (typeof capturedOrigFindPath === "function") {
|
||||
_origFindPath = capturedOrigFindPath;
|
||||
(Module as any)._findPath = function nexeFindPath(this: any, ...args: any[]) {
|
||||
// Try original first
|
||||
let result: any;
|
||||
try {
|
||||
result = capturedOrigFindPath.apply(this, args);
|
||||
} catch (_) {
|
||||
result = false;
|
||||
}
|
||||
if (result) return result;
|
||||
|
||||
const request: string = args[0];
|
||||
// Only handle bare module specifiers
|
||||
if (!request || request[0] === "." || nodePath.isAbsolute(request)) {
|
||||
return result;
|
||||
}
|
||||
|
||||
// Use snapshot node_modules as the base for all bare modules
|
||||
const basePath = "/snapshot/node_modules";
|
||||
const pkgJsonPath = nodePath.posix.join(basePath, request, "package.json");
|
||||
log(`_findPath trying snapshot package.json: ${pkgJsonPath}`);
|
||||
let pkg: any;
|
||||
try {
|
||||
pkg = JSON.parse(fs.readFileSync(pkgJsonPath, "utf8") as string);
|
||||
} catch (e) {
|
||||
return result; // not found in snapshot
|
||||
}
|
||||
|
||||
// 1. Try exports field with appropriate conditions (CJS, Node)
|
||||
if (pkg.exports) {
|
||||
const conditions = ["require", "node", "default"];
|
||||
const exportTarget = resolvePackageExports(pkg.exports, conditions);
|
||||
if (exportTarget) {
|
||||
const candidate = nodePath.posix.join(basePath, request, exportTarget);
|
||||
log(`_findPath trying exports target: ${candidate}`);
|
||||
if (isFile(candidate)) return candidate;
|
||||
// Try with extensions if the export target doesn't have one
|
||||
for (const ext of [".js", ".json", ".node"]) {
|
||||
const withExt = candidate + ext;
|
||||
if (isFile(withExt)) return withExt;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 2. Fallback to main field
|
||||
let main = "index.js";
|
||||
if (typeof pkg.main === "string") {
|
||||
main = pkg.main;
|
||||
}
|
||||
|
||||
// Normalize main path
|
||||
if (main.startsWith("./")) main = main.slice(2);
|
||||
if (!main || main === ".") main = "index.js";
|
||||
if (main.endsWith("/")) main += "index.js";
|
||||
|
||||
const mainPath = nodePath.posix.join(basePath, request, main);
|
||||
log(`_findPath trying main: ${mainPath}`);
|
||||
|
||||
// Detailed check for main
|
||||
try {
|
||||
const st = fs.statSync(mainPath);
|
||||
if (st.isFile()) return mainPath;
|
||||
if (st.isDirectory()) {
|
||||
const idxPath = nodePath.posix.join(mainPath, "index.js");
|
||||
if (isFile(idxPath)) return idxPath;
|
||||
}
|
||||
} catch (e) {
|
||||
// mainPath may not exist; proceed to extension checks
|
||||
}
|
||||
|
||||
// 3. Try with extensions
|
||||
for (const ext of [".js", ".json", ".node"]) {
|
||||
const withExt = mainPath + ext;
|
||||
if (isFile(withExt)) return withExt;
|
||||
}
|
||||
|
||||
// 4. Common patterns: if main is missing, look for index.js in the package root
|
||||
const fallbackIndex = nodePath.posix.join(basePath, request, "index.js");
|
||||
if (isFile(fallbackIndex)) return fallbackIndex;
|
||||
|
||||
// 5. If package uses a dist subdirectory (like axios), try dist/index.js or dist/<name>.js
|
||||
const distIndex = nodePath.posix.join(basePath, request, "dist", "index.js");
|
||||
if (isFile(distIndex)) return distIndex;
|
||||
const distMain = nodePath.posix.join(basePath, request, "dist", request + ".js");
|
||||
if (isFile(distMain)) return distMain;
|
||||
|
||||
return result;
|
||||
};
|
||||
}
|
||||
} catch (_) {
|
||||
// Patching _findPath failed, ignore
|
||||
}
|
||||
|
||||
lazyRestoreFs = () => {
|
||||
Object.assign(fs, originalFsMethods);
|
||||
Object.assign(patches, originalPatches);
|
||||
lazyRestoreFs = () => { };
|
||||
if (_origFindPath !== null) {
|
||||
try {
|
||||
const Module = require("module");
|
||||
(Module as any)._findPath = _origFindPath;
|
||||
} catch (_) {}
|
||||
_origFindPath = null;
|
||||
}
|
||||
lazyRestoreFs = () => {};
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -16,6 +16,15 @@ export interface NexePatch {
|
||||
(compiler: NexeCompiler, next: () => Promise<void>): Promise<void>;
|
||||
}
|
||||
|
||||
export interface ModuleBundleRule {
|
||||
include?: string[];
|
||||
exclude?: string[];
|
||||
}
|
||||
|
||||
export interface BundleRules {
|
||||
[moduleName: string]: ModuleBundleRule;
|
||||
}
|
||||
|
||||
export interface NexeOptions {
|
||||
build: boolean;
|
||||
input: string;
|
||||
@@ -36,6 +45,7 @@ export interface NexeOptions {
|
||||
rc: { [key: string]: string };
|
||||
enableNodeCli: boolean;
|
||||
bundle: boolean | string;
|
||||
bundleRules?: BundleRules;
|
||||
patches: (string | NexePatch)[];
|
||||
plugins: (string | NexePatch)[];
|
||||
native: any;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
const fs = require("fs"),
|
||||
fd = fs.openSync(process.execPath, "r"),
|
||||
stat = fs.statSync(fd),
|
||||
stat = fs.fstatSync(fd),
|
||||
tailSize = Math.min(stat.size, 16000),
|
||||
tailWindow = Buffer.alloc(tailSize),
|
||||
match = "<nexe" + "~~sentinel>",
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
import { NexeCompiler } from '../compiler'
|
||||
|
||||
export default async function fsStat(compiler: NexeCompiler, next: () => Promise<void>) {
|
||||
await compiler.replaceInFileAsync(
|
||||
'lib/fs.js',
|
||||
'function statSync(path, options = { bigint: false, throwIfNoEntry: true }) {',
|
||||
`function statSync(path, options = { bigint: false, throwIfNoEntry: true }) {
|
||||
// If Node passes a file descriptor, we must fstat the REAL fs
|
||||
if (typeof path === 'number') {
|
||||
try {
|
||||
return fstatSync(path, options);
|
||||
} catch (e) {
|
||||
if (options.throwIfNoEntry) {
|
||||
throw e;
|
||||
}
|
||||
return options.bigint ? BigInt(-1) : -1;
|
||||
}
|
||||
}
|
||||
`
|
||||
)
|
||||
|
||||
return next()
|
||||
}
|
||||
@@ -6,7 +6,10 @@ import flags from "./flags";
|
||||
import ico from "./ico";
|
||||
import rc from "./node-rc";
|
||||
import snapshot from "./snapshot";
|
||||
import fsStat from "./fs-stat-debug";
|
||||
|
||||
// Patches are applied in order, so if a patch depends on another patch, it should be listed after the patch it depends on.
|
||||
// For example, if a patch modifies the output of gyp, it should be listed after gyp in this array.
|
||||
const patches = [gyp, bootNexe, buildFixes, cli, flags, ico, rc, snapshot];
|
||||
|
||||
export default patches;
|
||||
|
||||
+213
-14
@@ -1,8 +1,122 @@
|
||||
import { NexeCompiler, NexeError } from "../compiler";
|
||||
import { resolve, relative } from "path";
|
||||
import { resolve, relative, sep, join } from "path";
|
||||
import resolveFiles, { resolveSync } from "resolve-dependencies";
|
||||
import { dequote, STDIN_FLAG, semverGt } from "../util";
|
||||
import { Readable } from "stream";
|
||||
import { minimatch } from "minimatch";
|
||||
import { readdirSync, statSync } from "fs";
|
||||
|
||||
type ModuleRule = {
|
||||
include?: string[];
|
||||
exclude?: string[];
|
||||
};
|
||||
|
||||
function getModuleName(file: string): string | null {
|
||||
const parts = file.split(/[\\/]/);
|
||||
const idx = parts.lastIndexOf("node_modules");
|
||||
if (idx === -1) return null;
|
||||
|
||||
const name = parts[idx + 1];
|
||||
if (!name) return null;
|
||||
|
||||
return name.startsWith("@")
|
||||
? parts.slice(idx + 1, idx + 3).join("/")
|
||||
: name;
|
||||
}
|
||||
|
||||
function getModuleBasePath(file: string, moduleName: string): string | null {
|
||||
const parts = file.split(/[\\/]/);
|
||||
const idx = parts.lastIndexOf("node_modules");
|
||||
if (idx === -1) return null;
|
||||
|
||||
const baseParts = parts.slice(0, idx + 1);
|
||||
if (moduleName.startsWith("@")) {
|
||||
baseParts.push(...moduleName.split("/"));
|
||||
} else {
|
||||
baseParts.push(moduleName);
|
||||
}
|
||||
|
||||
return baseParts.join(sep);
|
||||
}
|
||||
|
||||
function getModuleRelativePath(file: string, moduleName: string): string {
|
||||
const normalizedFile = file.replace(/\\/g, '/');
|
||||
const normalizedModuleName = moduleName.replace(/\\/g, '/');
|
||||
|
||||
const marker = `node_modules/${normalizedModuleName}/`;
|
||||
const idx = normalizedFile.indexOf(marker);
|
||||
|
||||
if (idx === -1) {
|
||||
return "";
|
||||
}
|
||||
|
||||
return normalizedFile.slice(idx + marker.length);
|
||||
}
|
||||
|
||||
function getAllFilesInModule(basePath: string): string[] {
|
||||
const files: string[] = [];
|
||||
|
||||
function walk(dir: string) {
|
||||
try {
|
||||
const entries = readdirSync(dir);
|
||||
|
||||
for (const entry of entries) {
|
||||
const fullPath = join(dir, entry);
|
||||
try {
|
||||
const stat = statSync(fullPath);
|
||||
|
||||
if (stat.isDirectory()) {
|
||||
walk(fullPath);
|
||||
} else if (stat.isFile()) {
|
||||
files.push(fullPath);
|
||||
}
|
||||
} catch (err) {
|
||||
// Skip files we can't read
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
// Skip directories we can't read
|
||||
}
|
||||
}
|
||||
|
||||
walk(basePath);
|
||||
return files;
|
||||
}
|
||||
|
||||
function shouldIncludeFile(
|
||||
file: string,
|
||||
moduleName: string,
|
||||
rule: ModuleRule
|
||||
): boolean {
|
||||
const rel = getModuleRelativePath(file, moduleName);
|
||||
|
||||
if (!rel) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Always include package.json
|
||||
if (rel === "package.json") {
|
||||
return true;
|
||||
}
|
||||
|
||||
// If there's an include list, file MUST match it
|
||||
if (rule.include && rule.include.length > 0) {
|
||||
const matchesInclude = rule.include.some((g) => minimatch(rel, g));
|
||||
if (!matchesInclude) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Check exclude patterns
|
||||
if (rule.exclude && rule.exclude.length > 0) {
|
||||
const matchesExclude = rule.exclude.some((g) => minimatch(rel, g));
|
||||
if (matchesExclude) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function getStdIn(stdin: Readable): Promise<string> {
|
||||
let out = "";
|
||||
@@ -25,7 +139,11 @@ function getStdIn(stdin: Readable): Promise<string> {
|
||||
}
|
||||
|
||||
export default async function bundle(compiler: NexeCompiler, next: any) {
|
||||
const { bundle: doBundle, cwd, input: inputPath } = compiler.options;
|
||||
const { bundle: doBundle, cwd, input: inputPath, bundleRules } = compiler.options;
|
||||
|
||||
const rules: Record<string, ModuleRule> =
|
||||
bundleRules && Object.keys(bundleRules).length ? bundleRules : {};
|
||||
|
||||
let input = inputPath;
|
||||
compiler.entrypoint = "./" + relative(cwd, input);
|
||||
|
||||
@@ -66,13 +184,11 @@ export default async function bundle(compiler: NexeCompiler, next: any) {
|
||||
|
||||
const step = compiler.log.step("Resolving dependencies...");
|
||||
|
||||
const { files, warnings } = await resolveFiles(
|
||||
input,
|
||||
...Object.keys(compiler.bundle.list).filter(
|
||||
(x) => x.endsWith(".js") || x.endsWith(".mjs")
|
||||
),
|
||||
{ cwd, expand: "variable", loadContent: false }
|
||||
);
|
||||
const { files, warnings } = await resolveFiles(input, {
|
||||
cwd,
|
||||
expand: "variable",
|
||||
loadContent: false,
|
||||
});
|
||||
|
||||
if (
|
||||
warnings.filter(
|
||||
@@ -82,14 +198,97 @@ export default async function bundle(compiler: NexeCompiler, next: any) {
|
||||
throw new NexeError("Parsing Error:\n" + warnings.join("\n"));
|
||||
}
|
||||
|
||||
//TODO: warnings.forEach((x) => console.log(x))
|
||||
// If no bundle rules, use original behavior
|
||||
if (Object.keys(rules).length === 0) {
|
||||
const pkgJsonsToAdd = new Set<string>();
|
||||
|
||||
await Promise.all(
|
||||
Object.entries(files).map(([key]) => {
|
||||
step.log(`Including dependency: ${key}`);
|
||||
// Collect the package.json for each bundled module so Node can
|
||||
// resolve the correct entry point (main/exports) at runtime.
|
||||
const moduleName = getModuleName(key);
|
||||
if (moduleName) {
|
||||
const basePath = getModuleBasePath(key, moduleName);
|
||||
if (basePath) {
|
||||
pkgJsonsToAdd.add(join(basePath, "package.json"));
|
||||
}
|
||||
}
|
||||
return compiler.addResource(key);
|
||||
})
|
||||
);
|
||||
|
||||
await Promise.all(
|
||||
Array.from(pkgJsonsToAdd).map((pkgJson) => {
|
||||
try {
|
||||
statSync(pkgJson);
|
||||
step.log(`Including package.json: ${pkgJson}`);
|
||||
return compiler.addResource(pkgJson);
|
||||
} catch (e) {
|
||||
// package.json doesn't exist on disk, skip
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
return next();
|
||||
}
|
||||
|
||||
// Track modules with explicit bundle rules
|
||||
const modulesWithRules = new Map<string, string>();
|
||||
|
||||
for (const file of Object.keys(files)) {
|
||||
const moduleName = getModuleName(file);
|
||||
if (moduleName && rules[moduleName] && !modulesWithRules.has(moduleName)) {
|
||||
const basePath = getModuleBasePath(file, moduleName);
|
||||
if (basePath) {
|
||||
modulesWithRules.set(moduleName, basePath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Collect files to include
|
||||
const filesToInclude = new Set<string>();
|
||||
|
||||
// Add all files that AREN'T from modules with rules (preserve original behavior)
|
||||
for (const file of Object.keys(files)) {
|
||||
const moduleName = getModuleName(file);
|
||||
|
||||
// If this file is from a module with rules, skip it here
|
||||
if (moduleName && modulesWithRules.has(moduleName)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// All other files get included as normal
|
||||
filesToInclude.add(file);
|
||||
}
|
||||
|
||||
// For modules WITH rules: scan and filter
|
||||
for (const [moduleName, basePath] of modulesWithRules) {
|
||||
const rule = rules[moduleName];
|
||||
|
||||
step.log(`Scanning ${moduleName} with bundle rules...`);
|
||||
|
||||
const moduleFiles = getAllFilesInModule(basePath);
|
||||
|
||||
for (const file of moduleFiles) {
|
||||
const rel = getModuleRelativePath(file, moduleName);
|
||||
|
||||
if (shouldIncludeFile(file, moduleName, rule)) {
|
||||
filesToInclude.add(file);
|
||||
step.log(`Including ${rel} from ${moduleName}`);
|
||||
} else {
|
||||
step.log(`Excluding ${rel} from ${moduleName}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Add all files
|
||||
await Promise.all(
|
||||
Object.entries(files).map(([key]) => {
|
||||
step.log(`Including dependency: ${key}`);
|
||||
return compiler.addResource(key);
|
||||
Array.from(filesToInclude).map((file) => {
|
||||
step.log(`Including dependency: ${file}`);
|
||||
return compiler.addResource(file);
|
||||
})
|
||||
);
|
||||
|
||||
return next();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user