seabox 0.1.0-beta.2 → 0.1.0-beta.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +353 -110
- package/bin/seabox-rebuild.mjs +95 -0
- package/bin/seabox.mjs +135 -0
- package/lib/{blob.js → blob.mjs} +12 -18
- package/lib/bootstrap.cjs +753 -0
- package/lib/build-cache.mjs +199 -0
- package/lib/build.mjs +75 -0
- package/lib/config.mjs +234 -0
- package/lib/{crypto-assets.js → crypto-assets.mjs} +12 -47
- package/lib/entry-bundler.mjs +64 -0
- package/lib/{fetch-node.js → fetch-node.mjs} +10 -16
- package/lib/index.mjs +26 -0
- package/lib/inject.mjs +111 -0
- package/lib/{manifest.js → manifest.mjs} +5 -11
- package/lib/multi-target-builder.mjs +620 -0
- package/lib/native-scanner.mjs +210 -0
- package/lib/{obfuscate.js → obfuscate.mjs} +9 -31
- package/lib/require-shim.mjs +111 -0
- package/lib/rolldown-bundler.mjs +415 -0
- package/lib/{unsign.js → unsign.cjs} +7 -32
- package/package.json +10 -5
- package/bin/seabox-rebuild.js +0 -395
- package/bin/seabox.js +0 -81
- package/lib/bindings.js +0 -31
- package/lib/bootstrap.js +0 -697
- package/lib/build.js +0 -283
- package/lib/bytenode-hack.js +0 -56
- package/lib/config.js +0 -118
- package/lib/index.js +0 -27
- package/lib/inject.js +0 -81
- package/lib/scanner.js +0 -153
package/README.md
CHANGED
|
@@ -1,22 +1,23 @@
|
|
|
1
1
|
# seabox
|
|
2
2
|
|
|
3
|
-
A reusable tool for building Node.js Single Executable Applications (SEA) with native-module support.
|
|
3
|
+
A reusable tool for building Node.js Single Executable Applications (SEA) with native-module support and binary extraction.
|
|
4
4
|
|
|
5
5
|
## Features
|
|
6
6
|
|
|
7
7
|
- Bundle Node.js applications into standalone executables
|
|
8
|
-
- Automatic
|
|
9
|
-
-
|
|
8
|
+
- **Automatic asset detection** from `path.join(__dirname, ...)` patterns
|
|
9
|
+
- **Automatic native module detection** (.node files) with pattern transforms
|
|
10
|
+
- Platform-specific library extraction (DLLs, shared libraries)
|
|
11
|
+
- Asset encryption with obfuscated keys
|
|
10
12
|
- Multi-platform targeting (Windows, Linux, macOS)
|
|
11
13
|
- V8 snapshot support for faster startup
|
|
12
14
|
- Integrity checking for extracted binaries
|
|
13
15
|
- Automatic code signature removal before injection
|
|
14
|
-
- Simple configuration via package.json
|
|
15
16
|
|
|
16
17
|
## Use case
|
|
17
|
-
This tooling was created as an alternative to pkg, which is unfortunatly deprecated, and where forks were running foul of virus checkers. By using node's SEA, the executables are directly from nodejs's distribution source, and built using node's native Single Executable Application solution. Unfortunatly this does mean native modules embedded within the exe cannot run directly and must be extracted to a location on the disk on first run - This tooling automates that process for you, while providing arbitrary asset embedding. Embedded assets are _not_ extracted and access to them is handled by intercepting require and fs.
|
|
18
|
+
This tooling was created as an alternative to pkg, which is unfortunatly deprecated, and where forks were running foul of virus checkers. By using node's SEA, the executables are directly downloaded from nodejs's distribution source, and built using node's native Single Executable Application solution. Unfortunatly this does mean native modules embedded within the exe cannot run directly and must be extracted to a location on the disk on first run - This tooling automates that process for you, while providing arbitrary asset embedding. Embedded assets are _not_ extracted and access to them is handled by intercepting require and fs.
|
|
18
19
|
|
|
19
|
-
Note: **V8 snapshot includes and embedds the original source**, this is currently a limitation of Node's SEA tooling as far as I can tell; thus the snapshot is only useful for faster startup.
|
|
20
|
+
Note: **V8 snapshot includes and embedds the original source**, this is currently a limitation of Node's SEA tooling as far as I can tell; thus the snapshot is only useful for faster startup. Its possible to get around this by using bytenode's vm.script hack (embed the bytenode code as an asset and run another vm snapshot with the faux script input) and I'll look into supporting it in the future.
|
|
20
21
|
|
|
21
22
|
## Installation
|
|
22
23
|
|
|
@@ -26,64 +27,81 @@ npm install --save-dev seabox
|
|
|
26
27
|
|
|
27
28
|
## Configuration
|
|
28
29
|
|
|
29
|
-
|
|
30
|
+
Create a `seabox.config.json` file in your project root:
|
|
30
31
|
|
|
31
32
|
```json
|
|
32
33
|
{
|
|
33
|
-
"
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
"./
|
|
37
|
-
"
|
|
38
|
-
"
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
"
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
"node24.11.0-win32-x64"
|
|
48
|
-
],
|
|
49
|
-
"output": "myapp.exe",
|
|
50
|
-
"outputPath": "dist",
|
|
51
|
-
"disableExperimentalSEAWarning": true,
|
|
52
|
-
"useSnapshot": true,
|
|
53
|
-
"useCodeCache": false
|
|
54
|
-
}
|
|
34
|
+
"entry": "./src/index.js",
|
|
35
|
+
"outputs": [
|
|
36
|
+
{
|
|
37
|
+
"path": "./dist/win",
|
|
38
|
+
"target": "node24.11.0-win32-x64",
|
|
39
|
+
"output": "myapp.exe"
|
|
40
|
+
}
|
|
41
|
+
],
|
|
42
|
+
"bundler": {
|
|
43
|
+
"external": []
|
|
44
|
+
},
|
|
45
|
+
"encryptAssets": false,
|
|
46
|
+
"useSnapshot": true,
|
|
47
|
+
"verbose": false
|
|
55
48
|
}
|
|
56
49
|
```
|
|
57
50
|
|
|
58
51
|
## Configuration Options
|
|
59
52
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
53
|
+
| Option | Type | Required | Description |
|
|
54
|
+
|--------|------|----------|-------------|
|
|
55
|
+
| `entry` | `string` | Yes | Path to your application's entry point |
|
|
56
|
+
| `outputs` | `array` | Yes | Array of build targets |
|
|
57
|
+
| `outputs[].path` | `string` | Yes | Output directory for this target |
|
|
58
|
+
| `outputs[].target` | `string` | Yes | Build target (format: `nodeX.Y.Z-platform-arch`) |
|
|
59
|
+
| `outputs[].output` | `string` | Yes | Output filename |
|
|
60
|
+
| `outputs[].libraries` | `array` | No | Glob patterns for shared libraries (DLLs/SOs) requiring filesystem extraction (defaults: `**/*.dll` for Windows, `**/*.so*` for Linux, `**/*.dylib` for macOS) |
|
|
61
|
+
| `outputs[].rcedit` | `object` | No | Windows executable metadata (icon, version info) |
|
|
62
|
+
| `assets` | `array` | No | Glob patterns for assets to embed (merged with auto-detected assets) |
|
|
63
|
+
| `bundler` | `object` | No | Bundler options |
|
|
64
|
+
| `bundler.external` | `array` | No | Modules to exclude from bundling |
|
|
65
|
+
| `bundler.plugins` | `array` | No | Additional Rollup plugins |
|
|
66
|
+
| `bundler.minify` | `boolean` | No | Minify bundled code |
|
|
67
|
+
| `bundler.sourcemap` | `boolean` | No | Generate source maps |
|
|
68
|
+
| `encryptAssets` | `boolean` | No | Enable asset encryption (default: false) |
|
|
69
|
+
| `encryptExclude` | `array` | No | Glob patterns to exclude from encryption |
|
|
70
|
+
| `useSnapshot` | `boolean` | No | Enable V8 startup snapshots (default: true) |
|
|
71
|
+
| `useCodeCache` | `boolean` | No | Enable V8 code cache (default: false) |
|
|
72
|
+
| `cacheLocation` | `string` | No | Path for code cache storage |
|
|
73
|
+
| `verbose` | `boolean` | No | Enable verbose logging (default: false) |
|
|
73
74
|
|
|
74
75
|
## Usage
|
|
75
76
|
|
|
76
|
-
|
|
77
|
+
### CLI Commands
|
|
78
|
+
|
|
79
|
+
```bash
|
|
80
|
+
# Build executable(s)
|
|
81
|
+
npx seabox build
|
|
82
|
+
|
|
83
|
+
# Build with verbose output
|
|
84
|
+
npx seabox build --verbose
|
|
85
|
+
|
|
86
|
+
# Specify custom config file
|
|
87
|
+
npx seabox build --config custom-config.json
|
|
77
88
|
|
|
78
|
-
|
|
89
|
+
# Initialize a new config file
|
|
90
|
+
npx seabox init
|
|
91
|
+
|
|
92
|
+
# Show help
|
|
93
|
+
npx seabox help
|
|
94
|
+
```
|
|
79
95
|
|
|
80
|
-
|
|
96
|
+
### npm Scripts (Recommended)
|
|
97
|
+
|
|
98
|
+
Add to your `package.json`:
|
|
81
99
|
|
|
82
100
|
```json
|
|
83
101
|
{
|
|
84
102
|
"scripts": {
|
|
85
|
-
"build
|
|
86
|
-
"build:
|
|
103
|
+
"build": "seabox build",
|
|
104
|
+
"build:verbose": "seabox build --verbose"
|
|
87
105
|
}
|
|
88
106
|
}
|
|
89
107
|
```
|
|
@@ -91,27 +109,13 @@ Add a build script to your `package.json`:
|
|
|
91
109
|
Then run:
|
|
92
110
|
|
|
93
111
|
```bash
|
|
94
|
-
npm run build
|
|
95
|
-
```
|
|
96
|
-
|
|
97
|
-
### CLI
|
|
98
|
-
|
|
99
|
-
```bash
|
|
100
|
-
# Build using package.json configuration
|
|
101
|
-
npx seabox
|
|
102
|
-
|
|
103
|
-
# Build using a standalone config file (alternative to package.json)
|
|
104
|
-
npx seabox --config sea-config.json
|
|
105
|
-
|
|
106
|
-
# Verbose output
|
|
107
|
-
npx seabox --verbose
|
|
108
|
-
|
|
112
|
+
npm run build
|
|
109
113
|
```
|
|
110
114
|
|
|
111
115
|
### Programmatic API
|
|
112
116
|
|
|
113
117
|
```javascript
|
|
114
|
-
|
|
118
|
+
import { build } from 'seabox';
|
|
115
119
|
|
|
116
120
|
await build({
|
|
117
121
|
projectRoot: process.cwd(),
|
|
@@ -121,72 +125,99 @@ await build({
|
|
|
121
125
|
|
|
122
126
|
## How It Works
|
|
123
127
|
|
|
124
|
-
|
|
125
|
-
2. **Manifest Generation**: Creates a runtime manifest with metadata for binary extraction
|
|
126
|
-
3. **Bootstrap Injection**: Prepends bootstrap code to handle native module extraction
|
|
127
|
-
4. **Blob Creation**: Uses Node.js SEA tooling to create the application blob
|
|
128
|
-
5. **Binary Fetching**: Downloads the target Node.js binary and removes its signature
|
|
129
|
-
6. **Injection**: Uses postject to inject the blob into the Node binary
|
|
130
|
-
7. **Output**: Produces a standalone executable ready for signing and distribution
|
|
128
|
+
seabox automates the entire SEA build process:
|
|
131
129
|
|
|
132
|
-
|
|
130
|
+
1. **Bundling** - Automatically bundles your app with Rollup, detecting:
|
|
131
|
+
- Native module patterns (`bindings`, `node-gyp-build`, direct `.node` requires)
|
|
132
|
+
- Asset references via `path.join(__dirname, 'relative/path')`
|
|
133
133
|
|
|
134
|
-
|
|
135
|
-
-
|
|
136
|
-
-
|
|
137
|
-
-
|
|
134
|
+
2. **Asset Collection** - Gathers assets from three sources:
|
|
135
|
+
- **Auto-detected**: Files referenced via `path.join(__dirname, ...)` patterns
|
|
136
|
+
- **Config globs**: Patterns specified in `assets` array
|
|
137
|
+
- **Libraries**: Platform-specific shared libraries (DLLs/SOs)
|
|
138
138
|
|
|
139
|
-
|
|
139
|
+
3. **Native Module Rebuilding** - Rebuilds native modules for target platform
|
|
140
140
|
|
|
141
|
-
|
|
141
|
+
4. **Bootstrap Injection** - Adds runtime code for asset loading and native module extraction
|
|
142
142
|
|
|
143
|
-
|
|
143
|
+
5. **SEA Blob Creation** - Packages everything using Node.js SEA tooling
|
|
144
144
|
|
|
145
|
-
|
|
146
|
-
{
|
|
147
|
-
"sea": {
|
|
148
|
-
"cacheLocation": "%LOCALAPPDATA%\\myapp-cache"
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
```
|
|
145
|
+
6. **Binary Preparation** - Downloads target Node.js binary and removes code signature
|
|
152
146
|
|
|
153
|
-
|
|
154
|
-
- **Windows**: `%LOCALAPPDATA%`, `%APPDATA%`, `%TEMP%`, etc.
|
|
155
|
-
- **Unix/Linux/macOS**: `$HOME`, `$TMPDIR`, `${XDG_CACHE_HOME}`, etc.
|
|
147
|
+
7. **Injection** - Uses `postject` to inject the blob into the Node.js binary
|
|
156
148
|
|
|
157
|
-
**
|
|
149
|
+
8. **Output** - Produces standalone executable(s) ready for distribution
|
|
158
150
|
|
|
159
|
-
|
|
160
|
-
# Windows
|
|
161
|
-
set SEACACHE=C:\custom\cache\path
|
|
162
|
-
myapp.exe
|
|
151
|
+
### Automatic Asset Detection
|
|
163
152
|
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
153
|
+
**Like pkg**, seabox automatically detects and embeds assets referenced in your code:
|
|
154
|
+
|
|
155
|
+
```javascript
|
|
156
|
+
import path from 'path';
|
|
157
|
+
import { fileURLToPath } from 'url';
|
|
158
|
+
|
|
159
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
160
|
+
|
|
161
|
+
// This asset will be automatically detected and embedded
|
|
162
|
+
const configPath = path.join(__dirname, '../config/app.json');
|
|
163
|
+
const config = JSON.parse(fs.readFileSync(configPath, 'utf8'));
|
|
167
164
|
```
|
|
168
165
|
|
|
169
|
-
|
|
166
|
+
**Detection works with:**
|
|
167
|
+
- `path.join(__dirname, 'relative/path')`
|
|
168
|
+
- `path.resolve(__dirname, 'relative/path')`
|
|
169
|
+
- Multiple path segments: `path.join(__dirname, '..', 'assets', 'file.txt')`
|
|
170
170
|
|
|
171
|
-
|
|
171
|
+
**Asset sources (merged and deduplicated):**
|
|
172
|
+
1. **Auto-detected** from code analysis during bundling
|
|
173
|
+
2. **Config globs** from `assets: ["./data/**/*", "./public/**/*"]`
|
|
174
|
+
3. **Platform libraries** from `outputs[].libraries` (e.g., DLLs for Windows)
|
|
172
175
|
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
+
### Native Module Support
|
|
177
|
+
|
|
178
|
+
seabox automatically handles native modules without any configuration:
|
|
179
|
+
|
|
180
|
+
**Supported patterns:**
|
|
181
|
+
- `require('bindings')('module')` - Standard bindings package
|
|
182
|
+
- `require('./build/Release/addon.node')` - Direct requires
|
|
183
|
+
- `require('node-gyp-build')(__dirname)` - Prebuild binaries
|
|
184
|
+
- `require('node-pre-gyp')` patterns - Pre-compiled binaries
|
|
176
185
|
|
|
177
|
-
|
|
178
|
-
|
|
186
|
+
**At runtime:**
|
|
187
|
+
- Native modules are extracted to a cache directory on first run
|
|
188
|
+
- Modules are integrity-checked with SHA-256 hashes
|
|
189
|
+
- Custom `require()` shim loads modules from cache
|
|
190
|
+
- Works transparently with packages like `better-sqlite3`, `sharp`, `canvas`, etc.
|
|
179
191
|
|
|
180
|
-
|
|
181
|
-
|
|
192
|
+
|
|
193
|
+
### Platform-Specific Libraries
|
|
194
|
+
|
|
195
|
+
Libraries that require filesystem access (like DLLs that are loaded via `dlopen`) can be specified with glob patterns:
|
|
196
|
+
|
|
197
|
+
```json
|
|
198
|
+
{
|
|
199
|
+
"outputs": [
|
|
200
|
+
{
|
|
201
|
+
"target": "node24.11.0-win32-x64",
|
|
202
|
+
"libraries": ["**/*.dll"] // Auto-extracted at runtime
|
|
203
|
+
}
|
|
204
|
+
]
|
|
205
|
+
}
|
|
182
206
|
```
|
|
183
207
|
|
|
184
|
-
|
|
185
|
-
-
|
|
186
|
-
-
|
|
187
|
-
-
|
|
208
|
+
**Defaults by platform:**
|
|
209
|
+
- **Windows**: `**/*.dll`
|
|
210
|
+
- **Linux**: `**/*.so`, `**/*.so.*`
|
|
211
|
+
- **macOS**: `**/*.dylib`
|
|
212
|
+
|
|
213
|
+
These files are extracted on first run (like `.node` files) since they need to be loaded from the filesystem.
|
|
214
|
+
|
|
215
|
+
### Code Signature Removal
|
|
188
216
|
|
|
189
|
-
|
|
217
|
+
Required before SEA injection. Platform-specific tools needed:
|
|
218
|
+
- **Windows**: `signtool.exe` (from Windows SDK)
|
|
219
|
+
- **macOS**: `codesign` (included with Xcode)
|
|
220
|
+
- **Linux**: Not required
|
|
190
221
|
|
|
191
222
|
## Asset Encryption
|
|
192
223
|
|
|
@@ -229,3 +260,215 @@ seabox supports optional AES-256-GCM encryption of embedded assets to protect yo
|
|
|
229
260
|
|
|
230
261
|
MIT
|
|
231
262
|
Copyright Meirion Hughes 2025
|
|
263
|
+
## Examples
|
|
264
|
+
|
|
265
|
+
### Basic Application
|
|
266
|
+
|
|
267
|
+
```javascript
|
|
268
|
+
// src/index.js
|
|
269
|
+
console.log('Hello from SEA!');
|
|
270
|
+
console.log('Platform:', process.platform);
|
|
271
|
+
console.log('Architecture:', process.arch);
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
```json
|
|
275
|
+
// seabox.config.json
|
|
276
|
+
{
|
|
277
|
+
"entry": "./src/index.js",
|
|
278
|
+
"outputs": [
|
|
279
|
+
{
|
|
280
|
+
"path": "./dist",
|
|
281
|
+
"target": "node24.11.0-win32-x64",
|
|
282
|
+
"output": "hello.exe"
|
|
283
|
+
}
|
|
284
|
+
]
|
|
285
|
+
}
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
### With Assets (Auto-Detection)
|
|
289
|
+
|
|
290
|
+
```javascript
|
|
291
|
+
// src/index.js
|
|
292
|
+
import fs from 'fs';
|
|
293
|
+
import path from 'path';
|
|
294
|
+
import { fileURLToPath } from 'url';
|
|
295
|
+
|
|
296
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
297
|
+
|
|
298
|
+
// Assets referenced via path.join(__dirname, ...) are auto-detected
|
|
299
|
+
const configPath = path.join(__dirname, '../config/settings.json');
|
|
300
|
+
const config = JSON.parse(fs.readFileSync(configPath, 'utf8'));
|
|
301
|
+
|
|
302
|
+
console.log('Config loaded:', config);
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
No configuration needed - the asset is automatically detected and embedded!
|
|
306
|
+
|
|
307
|
+
### With Config Assets
|
|
308
|
+
|
|
309
|
+
```json
|
|
310
|
+
{
|
|
311
|
+
"entry": "./src/index.js",
|
|
312
|
+
"outputs": [
|
|
313
|
+
{
|
|
314
|
+
"path": "./dist",
|
|
315
|
+
"target": "node24.11.0-win32-x64",
|
|
316
|
+
"output": "myapp.exe"
|
|
317
|
+
}
|
|
318
|
+
],
|
|
319
|
+
"assets": [
|
|
320
|
+
"./public/**/*",
|
|
321
|
+
"./data/**/*.json",
|
|
322
|
+
"!**/*.md"
|
|
323
|
+
]
|
|
324
|
+
}
|
|
325
|
+
```
|
|
326
|
+
|
|
327
|
+
All files matching the glob patterns will be embedded. Auto-detected assets are merged automatically.
|
|
328
|
+
|
|
329
|
+
### With Native Modules
|
|
330
|
+
|
|
331
|
+
```javascript
|
|
332
|
+
// src/index.js
|
|
333
|
+
import Database from 'better-sqlite3';
|
|
334
|
+
|
|
335
|
+
const db = new Database(':memory:');
|
|
336
|
+
db.exec('CREATE TABLE users (name TEXT)');
|
|
337
|
+
db.prepare('INSERT INTO users VALUES (?)').run('Alice');
|
|
338
|
+
|
|
339
|
+
const users = db.prepare('SELECT * FROM users').all();
|
|
340
|
+
console.log('Users:', users);
|
|
341
|
+
|
|
342
|
+
db.close();
|
|
343
|
+
```
|
|
344
|
+
|
|
345
|
+
No special configuration needed - seabox automatically detects and handles the native module!
|
|
346
|
+
|
|
347
|
+
### Multi-Platform Build
|
|
348
|
+
|
|
349
|
+
```json
|
|
350
|
+
{
|
|
351
|
+
"entry": "./src/index.js",
|
|
352
|
+
"outputs": [
|
|
353
|
+
{
|
|
354
|
+
"path": "./dist/win",
|
|
355
|
+
"target": "node24.11.0-win32-x64",
|
|
356
|
+
"output": "myapp.exe"
|
|
357
|
+
},
|
|
358
|
+
{
|
|
359
|
+
"path": "./dist/linux",
|
|
360
|
+
"target": "node24.11.0-linux-x64",
|
|
361
|
+
"output": "myapp"
|
|
362
|
+
},
|
|
363
|
+
{
|
|
364
|
+
"path": "./dist/macos",
|
|
365
|
+
"target": "node24.11.0-darwin-arm64",
|
|
366
|
+
"output": "myapp"
|
|
367
|
+
}
|
|
368
|
+
],
|
|
369
|
+
"bundler": {
|
|
370
|
+
"external": []
|
|
371
|
+
},
|
|
372
|
+
"useSnapshot": true
|
|
373
|
+
}
|
|
374
|
+
```
|
|
375
|
+
|
|
376
|
+
Run `seabox build` and get executables for all three platforms!
|
|
377
|
+
|
|
378
|
+
## Advanced Features
|
|
379
|
+
|
|
380
|
+
### Asset Encryption
|
|
381
|
+
|
|
382
|
+
Protect your source code with AES-256-GCM encryption:
|
|
383
|
+
|
|
384
|
+
```json
|
|
385
|
+
{
|
|
386
|
+
"entry": "./src/index.js",
|
|
387
|
+
"outputs": [
|
|
388
|
+
{
|
|
389
|
+
"path": "./dist",
|
|
390
|
+
"target": "node24.11.0-win32-x64",
|
|
391
|
+
"output": "myapp.exe"
|
|
392
|
+
}
|
|
393
|
+
],
|
|
394
|
+
"encryptAssets": true,
|
|
395
|
+
"encryptExclude": ["*.txt"]
|
|
396
|
+
}
|
|
397
|
+
```
|
|
398
|
+
|
|
399
|
+
### External Dependencies
|
|
400
|
+
|
|
401
|
+
Exclude packages from bundling:
|
|
402
|
+
|
|
403
|
+
```json
|
|
404
|
+
{
|
|
405
|
+
"entry": "./src/index.js",
|
|
406
|
+
"outputs": [
|
|
407
|
+
{
|
|
408
|
+
"path": "./dist",
|
|
409
|
+
"target": "node24.11.0-win32-x64",
|
|
410
|
+
"output": "myapp.exe"
|
|
411
|
+
}
|
|
412
|
+
],
|
|
413
|
+
"bundler": {
|
|
414
|
+
"external": ["fsevents", "some-optional-dep"]
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
```json
|
|
418
|
+
{
|
|
419
|
+
"bundler": {
|
|
420
|
+
"external": ["fsevents", "some-optional-dep"]
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
```
|
|
424
|
+
|
|
425
|
+
Useful for:
|
|
426
|
+
- Platform-specific optional dependencies
|
|
427
|
+
- Packages that don't bundle well
|
|
428
|
+
- Reducing bundle size
|
|
429
|
+
|
|
430
|
+
## Platform Support
|
|
431
|
+
|
|
432
|
+
### Supported Targets
|
|
433
|
+
|
|
434
|
+
| Platform | Architectures | Example |
|
|
435
|
+
|----------|--------------|---------|
|
|
436
|
+
| Windows | x64, arm64 | `node24.11.0-win32-x64` |
|
|
437
|
+
| Linux | x64, arm64 | `node24.11.0-linux-x64` |
|
|
438
|
+
| macOS | x64, arm64 | `node24.11.0-darwin-arm64` |
|
|
439
|
+
|
|
440
|
+
### Node.js Versions
|
|
441
|
+
|
|
442
|
+
Works with Node.js 18.0.0 and above that support SEA.
|
|
443
|
+
|
|
444
|
+
## Troubleshooting
|
|
445
|
+
|
|
446
|
+
### Native modules not loading
|
|
447
|
+
|
|
448
|
+
If you see errors about missing `.node` files:
|
|
449
|
+
1. Check that the module was detected during build (look for "Native modules detected" in output)
|
|
450
|
+
2. Run with `--verbose` to see detailed bundling info
|
|
451
|
+
3. Ensure the module uses standard patterns (`bindings`, `node-gyp-build`, etc.)
|
|
452
|
+
|
|
453
|
+
### Build fails with signature removal error
|
|
454
|
+
|
|
455
|
+
Install the required tools:
|
|
456
|
+
- **Windows**: Install Windows SDK for `signtool.exe`
|
|
457
|
+
- **macOS**: Install Xcode Command Line Tools for `codesign`
|
|
458
|
+
|
|
459
|
+
### Cross-compilation issues
|
|
460
|
+
|
|
461
|
+
When building for a different platform than your current OS:
|
|
462
|
+
- Native module detection works cross-platform
|
|
463
|
+
- The bundled JavaScript is platform-agnostic
|
|
464
|
+
- Each target is built independently with the correct Node.js binary
|
|
465
|
+
|
|
466
|
+
## Contributing
|
|
467
|
+
|
|
468
|
+
Contributions welcome! Please open an issue or PR on [GitHub](https://github.com/MeirionHughes/seabox).
|
|
469
|
+
|
|
470
|
+
## License
|
|
471
|
+
|
|
472
|
+
MIT
|
|
473
|
+
|
|
474
|
+
Copyright © 2025 Meirion Hughes
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* seabox-rebuild.mjs
|
|
4
|
+
* Rebuild native modules for target platform/architecture
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { execSync } from 'child_process';
|
|
8
|
+
import fs from 'fs';
|
|
9
|
+
import path from 'path';
|
|
10
|
+
import { fileURLToPath } from 'url';
|
|
11
|
+
|
|
12
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
13
|
+
const __dirname = path.dirname(__filename);
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Rebuild a native module for a specific target
|
|
17
|
+
* @param {string} modulePath - Path to the native module
|
|
18
|
+
* @param {string} platform - Target platform (win32, linux, darwin)
|
|
19
|
+
* @param {string} arch - Target architecture (x64, arm64)
|
|
20
|
+
* @param {boolean} verbose - Enable verbose logging
|
|
21
|
+
*/
|
|
22
|
+
function rebuildNativeModule(modulePath, platform, arch, verbose = false) {
|
|
23
|
+
if (verbose) {
|
|
24
|
+
console.log(`Rebuilding native module: ${modulePath}`);
|
|
25
|
+
console.log(`Target: ${platform}-${arch}`);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const packageJsonPath = path.join(modulePath, 'package.json');
|
|
29
|
+
if (!fs.existsSync(packageJsonPath)) {
|
|
30
|
+
throw new Error(`No package.json found in ${modulePath}`);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const pkg = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
|
|
34
|
+
const moduleName = pkg.name;
|
|
35
|
+
|
|
36
|
+
// Check if module has native bindings
|
|
37
|
+
const hasBindingGyp = fs.existsSync(path.join(modulePath, 'binding.gyp'));
|
|
38
|
+
if (!hasBindingGyp && !pkg.gypfile) {
|
|
39
|
+
if (verbose) {
|
|
40
|
+
console.log(`Module ${moduleName} does not appear to have native bindings, skipping`);
|
|
41
|
+
}
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
try {
|
|
46
|
+
// Use node-gyp to rebuild for the target platform
|
|
47
|
+
const cmd = `npx node-gyp rebuild --target_platform=${platform} --target_arch=${arch}`;
|
|
48
|
+
|
|
49
|
+
if (verbose) {
|
|
50
|
+
console.log(`Running: ${cmd}`);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
execSync(cmd, {
|
|
54
|
+
cwd: modulePath,
|
|
55
|
+
stdio: verbose ? 'inherit' : 'pipe',
|
|
56
|
+
env: {
|
|
57
|
+
...process.env,
|
|
58
|
+
npm_config_target_platform: platform,
|
|
59
|
+
npm_config_target_arch: arch
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
if (verbose) {
|
|
64
|
+
console.log(`✓ Successfully rebuilt ${moduleName}`);
|
|
65
|
+
}
|
|
66
|
+
} catch (error) {
|
|
67
|
+
if (verbose) {
|
|
68
|
+
console.error(`Failed to rebuild ${moduleName}:`, error.message);
|
|
69
|
+
}
|
|
70
|
+
throw error;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// CLI entry point
|
|
75
|
+
if (import.meta.url === `file://${process.argv[1]}`) {
|
|
76
|
+
const args = process.argv.slice(2);
|
|
77
|
+
|
|
78
|
+
if (args.length < 3) {
|
|
79
|
+
console.error('Usage: seabox-rebuild <module-path> <platform> <arch> [--verbose]');
|
|
80
|
+
process.exit(1);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
const [modulePath, platform, arch] = args;
|
|
84
|
+
const verbose = args.includes('--verbose') || args.includes('-v');
|
|
85
|
+
|
|
86
|
+
try {
|
|
87
|
+
rebuildNativeModule(modulePath, platform, arch, verbose);
|
|
88
|
+
process.exit(0);
|
|
89
|
+
} catch (error) {
|
|
90
|
+
console.error('Rebuild failed:', error.message);
|
|
91
|
+
process.exit(1);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export { rebuildNativeModule };
|