nexfpack 0.1.0 → 0.1.1
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/index.d.cts +1 -0
- package/index.d.mts +17 -0
- package/{index.mts → index.mjs} +176 -207
- package/package.json +11 -1
- package/index.cts +0 -3
- package/tsconfig.json +0 -19
package/index.d.cts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/index.d.mts
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
interface NexfpackOptions {
|
|
2
|
+
name?: string;
|
|
3
|
+
root?: string;
|
|
4
|
+
relativeRoot?: boolean;
|
|
5
|
+
entry?: string;
|
|
6
|
+
output?: string;
|
|
7
|
+
tempdir?: string;
|
|
8
|
+
autoDeleteTempFiles?: boolean;
|
|
9
|
+
ignorefile?: string;
|
|
10
|
+
ignore?: string[];
|
|
11
|
+
enabledSign?: boolean;
|
|
12
|
+
autoRun?: boolean;
|
|
13
|
+
configFile?: string;
|
|
14
|
+
}
|
|
15
|
+
declare function nexfpack(options: NexfpackOptions): Promise<void>;
|
|
16
|
+
export default nexfpack;
|
|
17
|
+
export { NexfpackOptions, nexfpack };
|
package/{index.mts → index.mjs}
RENAMED
|
@@ -1,99 +1,74 @@
|
|
|
1
|
-
import copyfiles from 'copyfiles'
|
|
2
|
-
import fs from 'fs'
|
|
3
|
-
import path from 'path'
|
|
4
|
-
import os from 'os'
|
|
5
|
-
import child_process from 'child_process'
|
|
6
|
-
import { pipeline } from 'stream/promises'
|
|
7
|
-
import { packTar } from 'modern-tar/fs'
|
|
8
|
-
// @ts-ignore
|
|
9
|
-
import { inject } from 'postject';
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
root
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
enabledSign: options.enabledSign ?? false,
|
|
73
|
-
autoRun: options.autoRun ?? false,
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
function listAllFiles(dir: string): string[] {
|
|
78
|
-
const result: string[] = [];
|
|
79
|
-
const entries = fs.readdirSync(dir);
|
|
80
|
-
|
|
81
|
-
for (const entry of entries) {
|
|
82
|
-
const fullPath = path.join(dir, entry);
|
|
83
|
-
const stat = fs.statSync(fullPath);
|
|
84
|
-
if (stat.isDirectory()) {
|
|
85
|
-
result.push(...listAllFiles(fullPath));
|
|
86
|
-
} else {
|
|
87
|
-
result.push(fullPath);
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
return result;
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
async function nexfpack(options: NexfpackOptions) {
|
|
94
|
-
try {
|
|
95
|
-
console.log(
|
|
96
|
-
`
|
|
1
|
+
import copyfiles from 'copyfiles';
|
|
2
|
+
import fs from 'fs';
|
|
3
|
+
import path from 'path';
|
|
4
|
+
import os from 'os';
|
|
5
|
+
import child_process from 'child_process';
|
|
6
|
+
import { pipeline } from 'stream/promises';
|
|
7
|
+
import { packTar } from 'modern-tar/fs';
|
|
8
|
+
// @ts-ignore
|
|
9
|
+
import { inject } from 'postject';
|
|
10
|
+
async function fillOptions(options) {
|
|
11
|
+
let cwd;
|
|
12
|
+
if (options.root && !options.relativeRoot) {
|
|
13
|
+
cwd = options.root;
|
|
14
|
+
}
|
|
15
|
+
else if (options.configFile) {
|
|
16
|
+
cwd = path.dirname(options.configFile);
|
|
17
|
+
}
|
|
18
|
+
else {
|
|
19
|
+
cwd = process.cwd();
|
|
20
|
+
}
|
|
21
|
+
if (options.root && options.relativeRoot) {
|
|
22
|
+
cwd = path.resolve(cwd, options.root);
|
|
23
|
+
}
|
|
24
|
+
function getIgnores() {
|
|
25
|
+
if (options.ignorefile) {
|
|
26
|
+
return fs.readFileSync(path.resolve(cwd, options.ignorefile), 'utf8').split('\n').map(line => {
|
|
27
|
+
return line.split('#')[0].trim();
|
|
28
|
+
}).filter(line => line !== '');
|
|
29
|
+
}
|
|
30
|
+
else if (options.ignore) {
|
|
31
|
+
return options.ignore;
|
|
32
|
+
}
|
|
33
|
+
else if (fs.existsSync(path.resolve(cwd, '.nexfpackignore'))) {
|
|
34
|
+
return fs.readFileSync(path.resolve(cwd, '.nexfpackignore'), 'utf8').split('\n').map(line => {
|
|
35
|
+
return line.split('#')[0].trim();
|
|
36
|
+
}).filter(line => line !== '');
|
|
37
|
+
}
|
|
38
|
+
else {
|
|
39
|
+
return [];
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
return {
|
|
43
|
+
name: options.name ?? 'nexfpack-app',
|
|
44
|
+
root: cwd,
|
|
45
|
+
entry: path.resolve(cwd, options.entry ?? 'index.js'),
|
|
46
|
+
output: path.resolve(cwd, options.output ?? 'dist'),
|
|
47
|
+
tempdir: path.resolve(cwd, options.tempdir ?? '.nexfpack-temp'),
|
|
48
|
+
autoDeleteTempFiles: options.autoDeleteTempFiles ?? true,
|
|
49
|
+
ignore: getIgnores(),
|
|
50
|
+
enabledSign: options.enabledSign ?? false,
|
|
51
|
+
autoRun: options.autoRun ?? false,
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
function listAllFiles(dir) {
|
|
55
|
+
const result = [];
|
|
56
|
+
const entries = fs.readdirSync(dir);
|
|
57
|
+
for (const entry of entries) {
|
|
58
|
+
const fullPath = path.join(dir, entry);
|
|
59
|
+
const stat = fs.statSync(fullPath);
|
|
60
|
+
if (stat.isDirectory()) {
|
|
61
|
+
result.push(...listAllFiles(fullPath));
|
|
62
|
+
}
|
|
63
|
+
else {
|
|
64
|
+
result.push(fullPath);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
return result;
|
|
68
|
+
}
|
|
69
|
+
async function nexfpack(options) {
|
|
70
|
+
try {
|
|
71
|
+
console.log(`
|
|
97
72
|
__ _ __ _
|
|
98
73
|
/ \\ / /\\_____\\ \\ / /
|
|
99
74
|
/ /\\ \\ / / / ____/\\ \\/ /
|
|
@@ -110,77 +85,71 @@ async function nexfpack(options: NexfpackOptions) {
|
|
|
110
85
|
| | / ____ \\ | |___ | |\\ \\
|
|
111
86
|
|_| /_/ \\_\\ |_____| |_| \\_\\
|
|
112
87
|
|
|
113
|
-
`)
|
|
114
|
-
console.log('▶️ Start packing...');
|
|
115
|
-
console.log('🧪 Tips: Nexfpack is very experimental. It may have some errors.')
|
|
116
|
-
let config
|
|
117
|
-
if (options.configFile) {
|
|
118
|
-
config = JSON.parse(fs.readFileSync(options.configFile, 'utf8'))
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
if (!fs.existsSync(filledConfig.tempdir)) {
|
|
125
|
-
fs.mkdirSync(filledConfig.tempdir, { recursive: true });
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
fs.
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
console.log('📄 Copying files...');
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
}
|
|
164
|
-
const
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
};
|
|
179
|
-
for (const file of allNodeModulesFiles) {
|
|
180
|
-
const relativePath = path.relative(path.join(filledConfig.tempdir, 'node_modules'), file);
|
|
181
|
-
seaConfigContent.assets[`node_modules/${relativePath}`] = file;
|
|
182
|
-
}
|
|
183
|
-
fs.writeFileSync(path.join(filledConfig.tempdir, 'sea-config.json'), JSON.stringify(seaConfigContent));
|
|
88
|
+
`);
|
|
89
|
+
console.log('▶️ Start packing...');
|
|
90
|
+
console.log('🧪 Tips: Nexfpack is very experimental. It may have some errors.');
|
|
91
|
+
let config;
|
|
92
|
+
if (options.configFile) {
|
|
93
|
+
config = JSON.parse(fs.readFileSync(options.configFile, 'utf8'));
|
|
94
|
+
}
|
|
95
|
+
else {
|
|
96
|
+
config = options;
|
|
97
|
+
}
|
|
98
|
+
const filledConfig = await fillOptions(config);
|
|
99
|
+
if (!fs.existsSync(filledConfig.tempdir)) {
|
|
100
|
+
fs.mkdirSync(filledConfig.tempdir, { recursive: true });
|
|
101
|
+
}
|
|
102
|
+
else {
|
|
103
|
+
fs.rmSync(filledConfig.tempdir, { recursive: true, force: true });
|
|
104
|
+
fs.mkdirSync(filledConfig.tempdir, { recursive: true });
|
|
105
|
+
}
|
|
106
|
+
console.log('📄 Copying files...');
|
|
107
|
+
if (!fs.existsSync(path.join(filledConfig.tempdir, 'source-copy'))) {
|
|
108
|
+
fs.mkdirSync(path.join(filledConfig.tempdir, 'source-copy'), { recursive: true });
|
|
109
|
+
}
|
|
110
|
+
await new Promise((resolve, reject) => {
|
|
111
|
+
copyfiles([filledConfig.root, path.join(filledConfig.tempdir, 'source-copy')], { up: 1, exclude: filledConfig.ignore }, (err) => {
|
|
112
|
+
if (err) {
|
|
113
|
+
console.error('❌ Failed to copy files:', err);
|
|
114
|
+
reject(err);
|
|
115
|
+
}
|
|
116
|
+
else {
|
|
117
|
+
resolve();
|
|
118
|
+
}
|
|
119
|
+
});
|
|
120
|
+
});
|
|
121
|
+
console.log('📜 Packing source...');
|
|
122
|
+
const tarStream = packTar(path.join(filledConfig.tempdir, 'source-copy'));
|
|
123
|
+
const writeStream = fs.createWriteStream(path.join(filledConfig.tempdir, 'source.tar'));
|
|
124
|
+
await pipeline(tarStream, writeStream);
|
|
125
|
+
console.log('📦 Packing executable...');
|
|
126
|
+
fs.writeFileSync(path.join(filledConfig.tempdir, 'package.json'), JSON.stringify({
|
|
127
|
+
name: filledConfig.name,
|
|
128
|
+
version: '1.0.0',
|
|
129
|
+
type: 'commonjs',
|
|
130
|
+
main: 'launcher.cjs',
|
|
131
|
+
dependencies: {
|
|
132
|
+
"modern-tar": "^0.7.6"
|
|
133
|
+
}
|
|
134
|
+
}, null, 2));
|
|
135
|
+
const installSpawnResult = child_process.spawnSync('npm install --omit=dev', { stdio: 'inherit', cwd: filledConfig.tempdir, shell: true });
|
|
136
|
+
if (installSpawnResult.status !== 0) {
|
|
137
|
+
throw new Error('❌ Failed to install dependencies');
|
|
138
|
+
}
|
|
139
|
+
const allNodeModulesFiles = listAllFiles(path.join(filledConfig.tempdir, 'node_modules'));
|
|
140
|
+
const seaConfigContent = {
|
|
141
|
+
"main": "./launcher.cjs",
|
|
142
|
+
"output": "./sea-prep.blob",
|
|
143
|
+
"disableExperimentalSEAWarning": true,
|
|
144
|
+
"assets": {
|
|
145
|
+
"source.tar": "./source.tar",
|
|
146
|
+
}
|
|
147
|
+
};
|
|
148
|
+
for (const file of allNodeModulesFiles) {
|
|
149
|
+
const relativePath = path.relative(path.join(filledConfig.tempdir, 'node_modules'), file);
|
|
150
|
+
seaConfigContent.assets[`node_modules/${relativePath}`] = file;
|
|
151
|
+
}
|
|
152
|
+
fs.writeFileSync(path.join(filledConfig.tempdir, 'sea-config.json'), JSON.stringify(seaConfigContent));
|
|
184
153
|
const launcherContent = `
|
|
185
154
|
(async () => {
|
|
186
155
|
const fs = require('fs');
|
|
@@ -236,43 +205,43 @@ async function nexfpack(options: NexfpackOptions) {
|
|
|
236
205
|
}
|
|
237
206
|
fs.rmSync(tempDir, { recursive: true, force: true });
|
|
238
207
|
})();
|
|
239
|
-
`;
|
|
240
|
-
fs.writeFileSync(path.join(filledConfig.tempdir, 'launcher.cjs'), launcherContent);
|
|
241
|
-
const blobSpawnResult = child_process.spawnSync('node --experimental-sea-config sea-config.json', { stdio: 'inherit', cwd: filledConfig.tempdir, shell: true });
|
|
242
|
-
if (blobSpawnResult.status !== 0) {
|
|
243
|
-
throw new Error('❌ Failed to generate blob');
|
|
244
|
-
}
|
|
245
|
-
const NODE_SEA_FUSE = 'NODE_SEA_FUSE_fce680ab2cc467b6e072b8b5df1996b2';
|
|
246
|
-
const blobData = fs.readFileSync(path.join(filledConfig.tempdir, 'sea-prep.blob'));
|
|
247
|
-
const injectOptions
|
|
248
|
-
sentinelFuse: NODE_SEA_FUSE,
|
|
249
|
-
};
|
|
250
|
-
if (os.platform() === 'darwin') {
|
|
251
|
-
injectOptions.machoSegmentName = 'NODE_SEA';
|
|
252
|
-
}
|
|
253
|
-
const ext = os.platform() === 'win32' ? '.exe' : '';
|
|
254
|
-
const exePath = path.join(filledConfig.output, filledConfig.name + ext);
|
|
255
|
-
if (!fs.existsSync(filledConfig.output)) {
|
|
256
|
-
fs.mkdirSync(filledConfig.output, { recursive: true });
|
|
257
|
-
}
|
|
258
|
-
fs.copyFileSync(process.execPath, exePath);
|
|
259
|
-
await inject(exePath, 'NODE_SEA_BLOB', blobData, injectOptions);
|
|
260
|
-
if (filledConfig.enabledSign) {
|
|
261
|
-
console.log("⚠️ Sorry, we can't sign your executable file. Please sign it by yourself.");
|
|
262
|
-
}
|
|
263
|
-
if (filledConfig.autoDeleteTempFiles) {
|
|
264
|
-
console.log('♻️ Deleting temp files...');
|
|
265
|
-
fs.rmSync(filledConfig.tempdir, { recursive: true, force: true });
|
|
266
|
-
}
|
|
267
|
-
console.log('✅ Done!');
|
|
268
|
-
if (filledConfig.autoRun) {
|
|
269
|
-
console.log('🚀 Auto-run executable...');
|
|
270
|
-
child_process.spawnSync(exePath, { stdio: 'inherit', cwd: filledConfig.output, shell: true });
|
|
271
|
-
}
|
|
272
|
-
}
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
export default nexfpack
|
|
278
|
-
export {
|
|
208
|
+
`;
|
|
209
|
+
fs.writeFileSync(path.join(filledConfig.tempdir, 'launcher.cjs'), launcherContent);
|
|
210
|
+
const blobSpawnResult = child_process.spawnSync('node --experimental-sea-config sea-config.json', { stdio: 'inherit', cwd: filledConfig.tempdir, shell: true });
|
|
211
|
+
if (blobSpawnResult.status !== 0) {
|
|
212
|
+
throw new Error('❌ Failed to generate blob');
|
|
213
|
+
}
|
|
214
|
+
const NODE_SEA_FUSE = 'NODE_SEA_FUSE_fce680ab2cc467b6e072b8b5df1996b2';
|
|
215
|
+
const blobData = fs.readFileSync(path.join(filledConfig.tempdir, 'sea-prep.blob'));
|
|
216
|
+
const injectOptions = {
|
|
217
|
+
sentinelFuse: NODE_SEA_FUSE,
|
|
218
|
+
};
|
|
219
|
+
if (os.platform() === 'darwin') {
|
|
220
|
+
injectOptions.machoSegmentName = 'NODE_SEA';
|
|
221
|
+
}
|
|
222
|
+
const ext = os.platform() === 'win32' ? '.exe' : '';
|
|
223
|
+
const exePath = path.join(filledConfig.output, filledConfig.name + ext);
|
|
224
|
+
if (!fs.existsSync(filledConfig.output)) {
|
|
225
|
+
fs.mkdirSync(filledConfig.output, { recursive: true });
|
|
226
|
+
}
|
|
227
|
+
fs.copyFileSync(process.execPath, exePath);
|
|
228
|
+
await inject(exePath, 'NODE_SEA_BLOB', blobData, injectOptions);
|
|
229
|
+
if (filledConfig.enabledSign) {
|
|
230
|
+
console.log("⚠️ Sorry, we can't sign your executable file. Please sign it by yourself.");
|
|
231
|
+
}
|
|
232
|
+
if (filledConfig.autoDeleteTempFiles) {
|
|
233
|
+
console.log('♻️ Deleting temp files...');
|
|
234
|
+
fs.rmSync(filledConfig.tempdir, { recursive: true, force: true });
|
|
235
|
+
}
|
|
236
|
+
console.log('✅ Done!');
|
|
237
|
+
if (filledConfig.autoRun) {
|
|
238
|
+
console.log('🚀 Auto-run executable...');
|
|
239
|
+
child_process.spawnSync(exePath, { stdio: 'inherit', cwd: filledConfig.output, shell: true });
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
catch (err) {
|
|
243
|
+
console.error('❌ Nexfpack Failed:', err);
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
export default nexfpack;
|
|
247
|
+
export { nexfpack };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nexfpack",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1",
|
|
4
4
|
"description": "A tool for building single executable files from Node.js scripts or modules.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": "https://github.com/nexfteam/Nexfpack",
|
|
@@ -21,6 +21,16 @@
|
|
|
21
21
|
"bin": {
|
|
22
22
|
"nexfpack": "cli.mjs"
|
|
23
23
|
},
|
|
24
|
+
"files": [
|
|
25
|
+
"index.cjs",
|
|
26
|
+
"index.mjs",
|
|
27
|
+
"cli.mjs",
|
|
28
|
+
"README.md",
|
|
29
|
+
"README-CN.md",
|
|
30
|
+
"LICENSE",
|
|
31
|
+
"index.d.mts",
|
|
32
|
+
"index.d.cts"
|
|
33
|
+
],
|
|
24
34
|
"scripts": {
|
|
25
35
|
"compile": "tsc"
|
|
26
36
|
},
|
package/index.cts
DELETED
package/tsconfig.json
DELETED
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"compilerOptions": {
|
|
3
|
-
"target": "ES2022",
|
|
4
|
-
"module": "NodeNext",
|
|
5
|
-
"moduleResolution": "NodeNext",
|
|
6
|
-
"types": ["node"],
|
|
7
|
-
"lib": ["ES2022", "ESNext"],
|
|
8
|
-
"outDir": "./",
|
|
9
|
-
"rootDir": "./",
|
|
10
|
-
"strict": true,
|
|
11
|
-
"esModuleInterop": true,
|
|
12
|
-
"skipLibCheck": true,
|
|
13
|
-
"declaration": true,
|
|
14
|
-
"declarationMap": false,
|
|
15
|
-
"sourceMap": false
|
|
16
|
-
},
|
|
17
|
-
"include": ["**/*.mts", "**/*.cts", "**/*.ts"],
|
|
18
|
-
"exclude": ["node_modules", "test", "**/*.d.ts", "**/*.d.mts", "**/*.d.cts", "**/test.*"]
|
|
19
|
-
}
|