quickbundle 0.0.0-next-71fed0b → 0.0.0-next-180c331

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 (2) hide show
  1. package/dist/index.mjs +129 -58
  2. package/package.json +4 -4
package/dist/index.mjs CHANGED
@@ -1,8 +1,8 @@
1
1
  import { helpers, termost } from 'termost';
2
2
  import { readFile as readFile$1 } from 'node:fs/promises';
3
- import process from 'node:process';
3
+ import process, { chdir } from 'node:process';
4
4
  import { watch as watch$1, rollup } from 'rollup';
5
- import { join } from 'node:path';
5
+ import { join, dirname, basename } from 'node:path';
6
6
  import { createRequire } from 'node:module';
7
7
  import { swc } from 'rollup-plugin-swc3';
8
8
  import externals from 'rollup-plugin-node-externals';
@@ -11,8 +11,13 @@ import url from '@rollup/plugin-url';
11
11
  import { nodeResolve } from '@rollup/plugin-node-resolve';
12
12
  import json from '@rollup/plugin-json';
13
13
  import commonjs from '@rollup/plugin-commonjs';
14
+ import os from 'node:os';
15
+ import { writeFileSync } from 'node:fs';
14
16
  import { gzipSize } from 'gzip-size';
15
17
 
18
+ var name = "quickbundle";
19
+ var version = "0.0.0-next-180c331";
20
+
16
21
  const CWD = process.cwd();
17
22
 
18
23
  const readFile = readFile$1;
@@ -37,10 +42,10 @@ const isRecord = (value)=>{
37
42
  return typeof value === "object" && value !== null && !Array.isArray(value);
38
43
  };
39
44
 
40
- const watch = (configurations)=>{
45
+ const watch = (input)=>{
41
46
  process.env.NODE_ENV ??= "development";
42
- const watcher = watch$1(configurations.map((config)=>({
43
- ...config,
47
+ const watcher = watch$1(input.data.map((configItem)=>({
48
+ ...configItem,
44
49
  onLog
45
50
  })));
46
51
  let startDuration;
@@ -85,39 +90,48 @@ const clearLog = (...input)=>{
85
90
 
86
91
  const require = createRequire(import.meta.url);
87
92
  const PKG = require(join(CWD, "./package.json"));
88
- const createConfigurations = (options = {
93
+ const createConfiguration = (options = {
89
94
  minification: false,
90
95
  sourceMaps: false,
91
96
  standalone: false
92
97
  })=>{
93
- return getBuildableExports(options).flatMap((buildableExport)=>{
94
- return [
95
- buildableExport.source && createMainConfig({
96
- ...buildableExport,
97
- source: buildableExport.source
98
- }, options),
99
- buildableExport.source && buildableExport.types && createTypesConfig({
100
- source: buildableExport.source,
101
- types: buildableExport.types
102
- })
103
- ].filter(Boolean);
104
- });
98
+ const buildableExports = getBuildableExports(options);
99
+ return {
100
+ data: buildableExports.flatMap((buildableExport)=>{
101
+ return [
102
+ buildableExport.source && createMainConfig({
103
+ ...buildableExport,
104
+ source: buildableExport.source
105
+ }, options),
106
+ buildableExport.source && buildableExport.types && createTypesConfig({
107
+ source: buildableExport.source,
108
+ types: buildableExport.types
109
+ }, options)
110
+ ].filter(Boolean);
111
+ }),
112
+ metadata: buildableExports
113
+ };
105
114
  };
115
+ // eslint-disable-next-line sonarjs/cyclomatic-complexity
106
116
  const getBuildableExports = ({ standalone })=>{
107
117
  if (standalone) {
108
118
  /**
109
119
  * Entry-point resolution invariants for standalone target (mostly binaries).
110
- */ if (!PKG.source || !PKG.bin) {
111
- throw new Error("Invalid package entry points contract. Standalone compilation is enabled but required fields `source` and/or `bin` are missing. Make sure to set them.");
120
+ */ if (!PKG.source || !PKG.bin || !PKG.name) {
121
+ throw new Error("Invalid package entry points contract. Standalone compilation is enabled but required fields are missing. Make sure to set `name`, `source`, and `bin` fields.");
112
122
  }
113
123
  const bin = PKG.bin;
124
+ const name = PKG.name;
125
+ const source = PKG.source;
114
126
  return isRecord(bin) ? Object.entries(bin).map((data)=>({
127
+ bin: data[0],
115
128
  require: data[1],
116
- source: data[0]
129
+ source
117
130
  })) : [
118
131
  {
132
+ bin: name,
119
133
  require: bin,
120
- source: PKG.source
134
+ source
121
135
  }
122
136
  ];
123
137
  }
@@ -175,15 +189,15 @@ const getBuildableExports = ({ standalone })=>{
175
189
  }
176
190
  return output;
177
191
  };
178
- const getPlugins = (...customPlugins)=>{
192
+ const getPlugins = (customPlugins, options)=>{
179
193
  return [
180
- externals({
194
+ !options.standalone && externals({
181
195
  builtins: true,
182
196
  deps: true,
183
197
  /**
184
- * As they're not installed consumer side, `devDependencies` are declared as internal dependencies (via the `false` value)
185
- * and bundled into the dist if and only if imported and not listed as `peerDependencies` (otherwise, they're considered external).
186
- */ devDeps: false,
198
+ * As they're not installed consumer side, `devDependencies` are declared as internal dependencies (via the `false` value)
199
+ * and bundled into the dist if and only if imported and not listed as `peerDependencies` (otherwise, they're considered external).
200
+ */ devDeps: false,
187
201
  optDeps: true,
188
202
  peerDeps: true
189
203
  }),
@@ -191,7 +205,7 @@ const getPlugins = (...customPlugins)=>{
191
205
  url(),
192
206
  json(),
193
207
  ...customPlugins
194
- ];
208
+ ].filter(Boolean);
195
209
  };
196
210
  const createMainConfig = (entryPoints, options)=>{
197
211
  const { minification, sourceMaps } = options;
@@ -215,13 +229,16 @@ const createMainConfig = (entryPoints, options)=>{
215
229
  return {
216
230
  input: entryPoints.source,
217
231
  output,
218
- plugins: getPlugins(nodeResolve(), swc({
219
- minify: minification,
220
- sourceMaps
221
- }))
232
+ plugins: getPlugins([
233
+ nodeResolve(),
234
+ swc({
235
+ minify: minification,
236
+ sourceMaps
237
+ })
238
+ ], options)
222
239
  };
223
240
  };
224
- const createTypesConfig = (entryPoints)=>{
241
+ const createTypesConfig = (entryPoints, options)=>{
225
242
  return {
226
243
  input: entryPoints.source,
227
244
  output: [
@@ -229,23 +246,25 @@ const createTypesConfig = (entryPoints)=>{
229
246
  file: entryPoints.types
230
247
  }
231
248
  ],
232
- plugins: getPlugins(nodeResolve({
233
- /**
234
- * The `exports` conditional fields definition order is important in the `package.json file`.
235
- * To be resolved first, `types` field must always come first in the package.json exports definition.
236
- * @see https://devblogs.microsoft.com/typescript/announcing-typescript-4-7/#package-json-exports-imports-and-self-referencing.
237
- */ exportConditions: [
238
- "types"
239
- ]
240
- }), dts({
241
- compilerOptions: {
242
- incremental: false
243
- },
244
- respectExternal: true
245
- }))
249
+ plugins: getPlugins([
250
+ nodeResolve({
251
+ /**
252
+ * The `exports` conditional fields definition order is important in the `package.json file`.
253
+ * To be resolved first, `types` field must always come first in the package.json exports definition.
254
+ * @see https://devblogs.microsoft.com/typescript/announcing-typescript-4-7/#package-json-exports-imports-and-self-referencing.
255
+ */ exportConditions: [
256
+ "types"
257
+ ]
258
+ }),
259
+ dts({
260
+ compilerOptions: {
261
+ incremental: false
262
+ },
263
+ respectExternal: true
264
+ })
265
+ ], options)
246
266
  };
247
267
  };
248
- createConfigurations();
249
268
 
250
269
  const createWatchCommand = (program)=>{
251
270
  return createCommand(program, {
@@ -253,7 +272,7 @@ const createWatchCommand = (program)=>{
253
272
  description: "Watch and rebuild on any code change (development mode)"
254
273
  }).task({
255
274
  handler (context) {
256
- watch(createConfigurations({
275
+ watch(createConfiguration({
257
276
  minification: context.minification,
258
277
  sourceMaps: context.sourceMaps,
259
278
  standalone: false
@@ -262,8 +281,9 @@ const createWatchCommand = (program)=>{
262
281
  });
263
282
  };
264
283
 
265
- const build = async (configurations)=>{
284
+ const build = async (input)=>{
266
285
  process.env.NODE_ENV ??= "production";
286
+ const { data: configurations } = input;
267
287
  const output = [];
268
288
  for (const config of configurations){
269
289
  const initialTime = Date.now();
@@ -277,15 +297,15 @@ const build = async (configurations)=>{
277
297
  ];
278
298
  const promises = [];
279
299
  for (const outputEntry of outputEntries){
280
- const outputFilename = outputEntry.file ?? outputEntry.dir;
281
- if (!outputFilename) {
300
+ const outputFilePath = outputEntry.file ?? outputEntry.dir;
301
+ if (!outputFilePath) {
282
302
  throw new Error("Misconfigured file entry point. Make sure to define an `import`, `require`, or `default` field.");
283
303
  }
284
304
  promises.push(new Promise((resolve, reject)=>{
285
305
  bundle.write(outputEntry).then(()=>{
286
306
  resolve({
287
307
  elapsedTime: Date.now() - initialTime,
288
- filename: outputFilename
308
+ filePath: outputFilePath
289
309
  });
290
310
  }).catch((reason)=>{
291
311
  reject(reason);
@@ -298,6 +318,53 @@ const build = async (configurations)=>{
298
318
  return output;
299
319
  };
300
320
 
321
+ const createCompileCommand = (program)=>{
322
+ return program.command({
323
+ name: "compile",
324
+ description: "Compiles the source code into a self-contained executable"
325
+ }).task({
326
+ async handler () {
327
+ const osType = os.type();
328
+ const isWindowsOS = osType === "Windows_NT";
329
+ const isMacOS = osType === "Darwin";
330
+ const configuration = createConfiguration({
331
+ minification: true,
332
+ sourceMaps: false,
333
+ standalone: true
334
+ });
335
+ await build(configuration);
336
+ for (const { bin, require: filePath } of configuration.metadata){
337
+ if (!filePath || !bin) {
338
+ throw new Error("Invalid configuration output. Missing `filePath` or `bin` field definition.");
339
+ }
340
+ chdir(dirname(filePath));
341
+ const fileName = basename(filePath);
342
+ const blobFileName = `${fileName}.blob`;
343
+ /*
344
+ * TODO: split with several tasks
345
+ */ const executableFileName = `${bin}${isWindowsOS ? ".exe" : ""}`;
346
+ const seaConfigFileName = `${fileName}.sea-config.json`;
347
+ writeFileSync(seaConfigFileName, JSON.stringify({
348
+ disableExperimentalSEAWarning: true,
349
+ main: fileName,
350
+ output: blobFileName,
351
+ useCodeCache: false,
352
+ useSnapshot: false
353
+ }), "utf-8");
354
+ await helpers.exec(`node --experimental-sea-config ${seaConfigFileName}`);
355
+ await helpers.exec(`node -e "require('fs').copyFileSync(process.execPath, '${executableFileName}')"`);
356
+ if (isMacOS) {
357
+ await helpers.exec(`codesign --remove-signature ${executableFileName}`);
358
+ }
359
+ await helpers.exec(`npx postject ${executableFileName} NODE_SEA_BLOB ${blobFileName} --sentinel-fuse NODE_SEA_FUSE_fce680ab2cc467b6e072b8b5df1996b2 ${isMacOS ? "--macho-segment-name NODE_SEA" : ""}`);
360
+ if (isMacOS) {
361
+ await helpers.exec(`codesign --sign - ${executableFileName}`);
362
+ }
363
+ }
364
+ }
365
+ });
366
+ };
367
+
301
368
  const createBuildCommand = (program)=>{
302
369
  return createCommand(program, {
303
370
  name: "build",
@@ -306,7 +373,7 @@ const createBuildCommand = (program)=>{
306
373
  key: "buildOutput",
307
374
  label: "Bundle assets 📦",
308
375
  async handler (context) {
309
- return build(createConfigurations({
376
+ return build(createConfiguration({
310
377
  minification: context.minification,
311
378
  sourceMaps: context.sourceMaps,
312
379
  standalone: false
@@ -330,7 +397,7 @@ const createBuildCommand = (program)=>{
330
397
  ].map((message, index)=>{
331
398
  return index === 0 ? message : ` ${message}`;
332
399
  }).join("\n"), {
333
- label: `${item.filename} (took ${item.elapsedTime}ms)`,
400
+ label: `${item.filePath} (took ${item.elapsedTime}ms)`,
334
401
  type: "information"
335
402
  });
336
403
  });
@@ -342,7 +409,7 @@ const createBuildCommand = (program)=>{
342
409
  };
343
410
  const computeBundleSize = async (buildOutput)=>{
344
411
  const computeFileSize = async (buildItemOutput)=>{
345
- const content = await readFile(buildItemOutput.filename);
412
+ const content = await readFile(buildItemOutput.filePath);
346
413
  const gzSize = await gzipSize(content);
347
414
  return {
348
415
  ...buildItemOutput,
@@ -358,9 +425,13 @@ const formatSize = (bytes)=>{
358
425
  };
359
426
 
360
427
  const createProgram = (...commandBuilders)=>{
361
- const program = termost("The zero-configuration transpiler and bundler for the web");
428
+ const program = termost({
429
+ name,
430
+ description: "The zero-configuration transpiler and bundler for the web",
431
+ version
432
+ });
362
433
  for (const commandBuilder of commandBuilders){
363
434
  commandBuilder(program);
364
435
  }
365
436
  };
366
- createProgram(createBuildCommand, createWatchCommand);
437
+ createProgram(createBuildCommand, createWatchCommand, createCompileCommand);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "quickbundle",
3
- "version": "0.0.0-next-71fed0b",
3
+ "version": "0.0.0-next-180c331",
4
4
  "description": "The zero-configuration transpiler and bundler for the web",
5
5
  "author": {
6
6
  "name": "Ayoub Adib",
@@ -58,13 +58,13 @@
58
58
  "rollup-plugin-dts": "^6.1.1",
59
59
  "rollup-plugin-node-externals": "^7.1.3",
60
60
  "rollup-plugin-swc3": "^0.12.1",
61
- "termost": "^0.18.0"
61
+ "termost": "^1.2.0"
62
62
  },
63
63
  "devDependencies": {
64
64
  "@types/node": "22.9.0"
65
65
  },
66
66
  "scripts": {
67
- "build": "rollup --config ./src/bundler/config.ts --configPlugin rollup-plugin-swc3",
68
- "watch": "rollup --watch --config ./src/bundler/config.ts --configPlugin rollup-plugin-swc3"
67
+ "build": "rollup --config ./bundler.config.ts --configPlugin rollup-plugin-swc3",
68
+ "watch": "rollup --watch --config ./bundler.config.ts --configPlugin rollup-plugin-swc3"
69
69
  }
70
70
  }