quickbundle 3.0.0-next-9f62eb1 → 3.0.0-next-c70f8cb

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.
Files changed (3) hide show
  1. package/README.md +1 -0
  2. package/dist/index.js +34 -118
  3. package/package.json +1 -6
package/README.md CHANGED
@@ -105,6 +105,7 @@ yarn add quickbundle
105
105
  > [!warning]
106
106
  > The `compile` command relies on the [Node.js SEA (Single Executable Applications feature)](https://nodejs.org/api/single-executable-applications.html). This feature comes with some limitations which Quickbundle attempts to address:
107
107
  >
108
+ > - The minimum compatible Node.js version is v25.5.0 (to support `--build-sea` flag).
108
109
  > - The source code must not rely on [external dependencies](https://github.com/nodejs/single-executable/discussions/70) 🛑. To partially address this, Quickbundle bundles all dependencies (whatever their types, as long as they're used) and inline dynamic imports by default ✅.
109
110
  > - The bundled code must use the CommonJS module system 🛑. To address this, Quickbundle always outputs CJS modules in compile mode ✅.
110
111
 
package/dist/index.js CHANGED
@@ -6,16 +6,11 @@ import url from "@rollup/plugin-url";
6
6
  import { createRequire } from "node:module";
7
7
  import { dts } from "rolldown-plugin-dts";
8
8
  import externals from "rollup-plugin-node-externals";
9
- import decompress from "decompress";
10
- import { createWriteStream } from "node:fs";
11
- import { copyFile, mkdir, readFile, rename, rm, writeFile } from "node:fs/promises";
12
- import { Readable } from "node:stream";
13
- import { finished } from "node:stream/promises";
14
- import os from "node:os";
9
+ import { readFile, rename, rm } from "node:fs/promises";
15
10
 
16
11
  //#region package.json
17
12
  var name = "quickbundle";
18
- var version = "3.0.0-next-9f62eb1";
13
+ var version = "3.0.0-next-c70f8cb";
19
14
 
20
15
  //#endregion
21
16
  //#region src/bundler/build.ts
@@ -44,16 +39,6 @@ const build = async (input) => {
44
39
  //#endregion
45
40
  //#region src/helpers.ts
46
41
  /**
47
- * Resolve a relative path from the Quickbundle node modules directory.
48
- * @param paths - Relative paths.
49
- * @returns The resolved absolute path.
50
- * @example
51
- * resolveFromInternalDirectory("dist", "node");
52
- */
53
- const resolveFromInternalDirectory = (...paths) => {
54
- return resolve(import.meta.dirname, "../", ...paths);
55
- };
56
- /**
57
42
  * Resolve a relative path from the current working project directory.
58
43
  * @param paths - Relative paths.
59
44
  * @returns The resolved absolute path.
@@ -68,12 +53,8 @@ const createRegExpMatcher = (regex) => {
68
53
  return regex.exec(value)?.groups;
69
54
  };
70
55
  };
71
- const createDirectory = async (path) => {
72
- await mkdir(path, { recursive: true });
73
- };
74
- const copyFile$1 = async (fromPath, toPath) => {
75
- await createDirectory(dirname(toPath));
76
- await copyFile(fromPath, toPath);
56
+ const readFile$1 = async (filePath) => {
57
+ return readFile(filePath);
77
58
  };
78
59
  const removePath = async (path) => {
79
60
  await rm(path, {
@@ -81,28 +62,6 @@ const removePath = async (path) => {
81
62
  recursive: true
82
63
  });
83
64
  };
84
- const readFile$1 = async (filePath) => {
85
- return readFile(filePath);
86
- };
87
- const writeFile$1 = async (filePath, content) => {
88
- await createDirectory(dirname(filePath));
89
- await writeFile(filePath, content, "utf8");
90
- };
91
- const download = async (url, filePath) => {
92
- await createDirectory(dirname(filePath));
93
- const { body, ok, status, statusText } = await fetch(url);
94
- if (!ok) throw new Error(`An error ocurred while downloading \`${url}\`. Received \`${status}\` status code with the following message \`${statusText}\`.`);
95
- if (!body) throw new Error(`Empty body received while downloading \`${url}\`.`);
96
- await finished(Readable.fromWeb(body).pipe(createWriteStream(filePath)));
97
- };
98
- const unzip = async (input, output) => {
99
- const { targetedArchivePath } = input;
100
- const { directoryPath } = output;
101
- await decompress(input.path, directoryPath, { filter(file) {
102
- return file.path === targetedArchivePath;
103
- } });
104
- await rename(join(directoryPath, targetedArchivePath), join(directoryPath, output.filename));
105
- };
106
65
  const createCommand = (program, input) => {
107
66
  return program.command(input).option({
108
67
  defaultValue: false,
@@ -327,9 +286,6 @@ const formatSize = (bytes) => {
327
286
 
328
287
  //#endregion
329
288
  //#region src/commands/compile.ts
330
- const TEMPORARY_PATH = resolveFromInternalDirectory("dist", "tmp");
331
- const TEMPORARY_DOWNLOAD_PATH = join(TEMPORARY_PATH, "zip");
332
- const TEMPORARY_RUNTIME_PATH = join(TEMPORARY_PATH, "runtime");
333
289
  const createCompileCommand = (program) => {
334
290
  return program.command({
335
291
  description: "Compiles the source code into a self-contained executable",
@@ -352,45 +308,42 @@ const createCompileCommand = (program) => {
352
308
  },
353
309
  key: "config",
354
310
  label: "Create configuration"
355
- }).task({
356
- async handler({ targetInput }) {
357
- if (targetInput === "local") {
358
- await copyFile$1(process.execPath, TEMPORARY_RUNTIME_PATH);
359
- return getOsType(os.type());
360
- }
361
- const matchedRuntimeParts = matchRuntimeParts(targetInput);
362
- if (!matchedRuntimeParts) throw new Error("Invalid `runtime` flag input. The accepted targets are the one listed in https://nodejs.org/download/release/ with the following format `node-vx.y.z-(darwin|linux|win)-(arm64|x64|x86)`.");
363
- const osType = getOsType(matchedRuntimeParts.os);
364
- const extension = osType === "windows" ? "zip" : "tar.gz";
365
- await download(`https://nodejs.org/download/release/${matchedRuntimeParts.version}/${targetInput}.${extension}`, TEMPORARY_DOWNLOAD_PATH);
366
- await unzip({
367
- path: TEMPORARY_DOWNLOAD_PATH,
368
- targetedArchivePath: osType === "windows" ? join(targetInput, "node.exe") : join(targetInput, "bin", "node")
369
- }, {
370
- directoryPath: dirname(TEMPORARY_RUNTIME_PATH),
371
- filename: basename(TEMPORARY_RUNTIME_PATH)
372
- });
373
- return osType;
374
- },
375
- key: "osType",
376
- label({ targetInput }) {
377
- return `Get \`${targetInput}\` runtime`;
378
- }
379
311
  }).task({
380
312
  async handler({ config }) {
381
313
  await build(config);
382
314
  },
383
315
  label: "Build"
384
316
  }).task({
385
- async handler({ config, osType }) {
386
- await Promise.all(config.metadata.map(async ({ bin, require }) => {
317
+ async handler({ config, targetInput }) {
318
+ for (const { bin, require } of config.metadata) {
387
319
  if (!require || !bin) return;
388
- return compile({
389
- bin,
390
- input: require,
391
- osType
392
- });
393
- }));
320
+ let os = process.platform === "win32" ? "win" : process.platform;
321
+ let architecture = process.arch;
322
+ let version = void 0;
323
+ if (targetInput !== "local") {
324
+ const nodeProperties = getNodeProperties(targetInput);
325
+ if (!nodeProperties) throw new Error("Invalid `runtime` flag input. The accepted targets are the one listed in https://nodejs.org/download/release/ with the following format `node-vx.y.z-(darwin|linux|win)-(arm64|x64|x86)`.");
326
+ architecture = nodeProperties.architecture;
327
+ os = nodeProperties.os;
328
+ version = nodeProperties.version;
329
+ }
330
+ const distributionPath = dirname(require);
331
+ const target = `${os}-${architecture}`;
332
+ const targetPath = join(distributionPath, target);
333
+ const packAppFlags = Object.entries({
334
+ "entry": require,
335
+ "output-dir": distributionPath,
336
+ "output-name": bin,
337
+ "runtime": version ? `node@${version}` : void 0,
338
+ target
339
+ }).map(([flagName, flagValue]) => {
340
+ if (!flagValue) return void 0;
341
+ return `--${flagName} ${flagValue}`;
342
+ }).filter(Boolean).join(" ");
343
+ await helpers.exec(`npx --yes pnpm pack-app ${packAppFlags}`);
344
+ await rename(join(targetPath, bin), join(distributionPath, bin));
345
+ await Promise.all([require, targetPath].map(async (path) => removePath(path)));
346
+ }
394
347
  },
395
348
  label({ config }) {
396
349
  return `Compile ${config.metadata.map(({ bin }) => {
@@ -400,44 +353,7 @@ const createCompileCommand = (program) => {
400
353
  }
401
354
  });
402
355
  };
403
- const getOsType = (input) => {
404
- switch (input) {
405
- case "Darwin":
406
- case "darwin": return "macos";
407
- case "Linux":
408
- case "linux": return "linux";
409
- case "win":
410
- case "Windows_NT": return "windows";
411
- default: throw new Error(`Unsupported operating system \`${input}\``);
412
- }
413
- };
414
- const matchRuntimeParts = createRegExpMatcher(/^node-(?<version>v\d+\.\d+\.\d+)-(?<os>darwin|linux|win)-(?<architecture>arm64|x64|x86)$/);
415
- const compile = async ({ bin, input, osType }) => {
416
- const inputFileName = basename(input);
417
- const inputDirectory = dirname(input);
418
- const resolveFromInputDirectory = (...paths) => {
419
- return resolve(inputDirectory, ...paths);
420
- };
421
- const blobFileName = resolveFromInputDirectory(`${inputFileName}.blob`);
422
- const executableFileName = resolveFromInputDirectory(`${bin}${osType === "windows" ? ".exe" : ""}`);
423
- const seaConfigFileName = resolveFromInputDirectory(`${inputFileName}.sea-config.json`);
424
- await writeFile$1(seaConfigFileName, JSON.stringify({
425
- disableExperimentalSEAWarning: true,
426
- main: input,
427
- output: blobFileName,
428
- useCodeCache: false,
429
- useSnapshot: false
430
- }));
431
- await Promise.all([helpers.exec(`node --experimental-sea-config ${seaConfigFileName}`), copyFile$1(TEMPORARY_RUNTIME_PATH, executableFileName)]);
432
- if (osType === "macos") await helpers.exec(`codesign --remove-signature ${executableFileName}`);
433
- await helpers.exec(`npx postject ${executableFileName} NODE_SEA_BLOB ${blobFileName} --sentinel-fuse NODE_SEA_FUSE_fce680ab2cc467b6e072b8b5df1996b2 ${osType === "macos" ? "--macho-segment-name NODE_SEA" : ""}`);
434
- if (osType === "macos") await helpers.exec(`codesign --sign - ${executableFileName}`);
435
- await Promise.all([
436
- blobFileName,
437
- seaConfigFileName,
438
- TEMPORARY_PATH
439
- ].map(async (path) => removePath(path)));
440
- };
356
+ const getNodeProperties = createRegExpMatcher(/^node-(?<version>v\d+\.\d+\.\d+)-(?<os>darwin|linux|win)-(?<architecture>arm64|x64|x86)$/);
441
357
 
442
358
  //#endregion
443
359
  //#region src/bundler/watch.ts
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "quickbundle",
3
- "version": "3.0.0-next-9f62eb1",
3
+ "version": "3.0.0-next-c70f8cb",
4
4
  "description": "The zero-configuration transpiler and bundler for the web",
5
5
  "keywords": [
6
6
  "library",
@@ -41,17 +41,12 @@
41
41
  ],
42
42
  "dependencies": {
43
43
  "@rollup/plugin-url": "^8.0.2",
44
- "decompress": "^4.2.1",
45
44
  "gzip-size": "^7.0.0",
46
45
  "rolldown": "^1.2.0",
47
46
  "rolldown-plugin-dts": "^0.27.14",
48
47
  "rollup-plugin-node-externals": "^9.0.1",
49
48
  "termost": "^1.9.1"
50
49
  },
51
- "devDependencies": {
52
- "@types/decompress": "4.2.7",
53
- "@types/node": "24.13.3"
54
- },
55
50
  "peerDependencies": {
56
51
  "typescript": "^4.7.0 || ^5.0.0 || ^6.0.0 || ^7.0.0"
57
52
  },