isolate-package 1.9.4 → 1.10.0-2

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 CHANGED
@@ -60,6 +60,9 @@ integrated, check out [mono-ts](https://github.com/0x80/mono-ts)
60
60
  - Compatible with the Firebase tools CLI, including 1st and 2nd generation
61
61
  Firebase Functions. For more information see
62
62
  [the Firebase instructions](./docs/firebase.md).
63
+ - Available in a
64
+ [forked version of firebase-tools](https://github.com/0x80/firebase-tools-with-isolate)
65
+ to preserve live code updates when running the emulators
63
66
 
64
67
  ## Installation
65
68
 
@@ -72,6 +75,11 @@ package manager should work.
72
75
 
73
76
  ## Usage
74
77
 
78
+ > !! If you plan use this for Firebase deployments, and you want to preserve
79
+ > live code updates when running the local emulators, you will want to use
80
+ > [firebase-tools-with-isolate](https://github.com/0x80/firebase-tools-with-isolate)
81
+ > instead.
82
+
75
83
  This package exposes a binary called `isolate`.
76
84
 
77
85
  Run `npx isolate` from the root of the package you want to isolate. Make sure
@@ -221,6 +229,11 @@ therefore should match the versions in your original lockfile.
221
229
  This way you can enjoy using PNPM or Yarn for your monorepo, while your
222
230
  deployment uses NPM with modules locked to the same versions.
223
231
 
232
+ > !! Warning: Generating an NPM lockfile currently requires moving the
233
+ > node_modules from the root of the monorepo temporarily into the isolate
234
+ > directory. This will not be compatible with setups that run multiple isolation
235
+ > processes in parallel.
236
+
224
237
  ### buildDirName
225
238
 
226
239
  Type: `string | undefined`, default: `undefined`
@@ -338,18 +351,18 @@ configuration.
338
351
 
339
352
  ### NPM
340
353
 
341
- For NPM we use a tool called Arborist which is an integral part of the NPM
354
+ For NPM we use a tool called Arborist, which is an integral part of the NPM
342
355
  codebase. It is executed in the isolate output directory and requires the
343
356
  adapted lockfile and the `node_modules` directory from the root of the
344
357
  repository. As this directory is typically quite large, copying it over as part
345
358
  of the isolate flow is not very desirable.
346
359
 
347
360
  To work around this, we move it to the isolate output and then move it back
348
- after Arborist has finished doing its thing. Luckily it doesn't take long and
349
- hopefully this doesn't create any unwanted side effects for IDEs and other tools
350
- that depend on the content of the directory.
361
+ after Arborist has finished doing its thing.
351
362
 
352
- When errors occur in this process, the folder should still be moved back.
363
+ > !! Warning: This will not be compatible with setups that run multiple
364
+ > isolation processes in parallel. Hopefully a future update to NPM Arborist
365
+ > (the part the generates the lockfile) will solve this.
353
366
 
354
367
  ### PNPM
355
368
 
package/dist/index.d.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  type IsolateConfigResolved = {
2
2
  buildDirName?: string;
3
3
  includeDevDependencies: boolean;
4
+ includePatchedDependencies: boolean;
4
5
  isolateDirName: string;
5
6
  logLevel: "info" | "debug" | "warn" | "error";
6
7
  targetPackagePath?: string;
@@ -35,4 +36,4 @@ type IsolateExports = {
35
36
  isolate: typeof isolate;
36
37
  };
37
38
 
38
- export { IsolateExports, Logger, isolate };
39
+ export { type IsolateExports, type Logger, isolate };
package/dist/index.mjs CHANGED
@@ -7,7 +7,7 @@ import path16 from "node:path";
7
7
  import fs5 from "fs-extra";
8
8
  import assert from "node:assert";
9
9
  import path2 from "node:path";
10
- import { isEmpty } from "ramda";
10
+ import { isEmpty } from "remeda";
11
11
 
12
12
  // src/lib/logger.ts
13
13
  import chalk from "chalk";
@@ -124,10 +124,10 @@ async function readTypedJson(filePath) {
124
124
  }
125
125
 
126
126
  // src/lib/utils/pack.ts
127
- import fs2 from "fs-extra";
128
127
  import { exec } from "node:child_process";
128
+ import fs2 from "node:fs";
129
129
  import path from "node:path";
130
- async function pack(srcDir, dstDir, usePnpmPack = false) {
130
+ async function pack(srcDir, dstDir, usePnpmPack) {
131
131
  const execOptions = {
132
132
  maxBuffer: 10 * 1024 * 1024
133
133
  };
@@ -138,9 +138,9 @@ async function pack(srcDir, dstDir, usePnpmPack = false) {
138
138
  exec(
139
139
  `pnpm pack --pack-destination "${dstDir}"`,
140
140
  execOptions,
141
- (err, stdout2, stderr) => {
141
+ (err, stdout2) => {
142
142
  if (err) {
143
- log.error(stderr);
143
+ log.error(getErrorMessage(err));
144
144
  return reject(err);
145
145
  }
146
146
  resolve(stdout2);
@@ -200,6 +200,7 @@ function readTypedYamlSync(filePath) {
200
200
  var configDefaults = {
201
201
  buildDirName: void 0,
202
202
  includeDevDependencies: false,
203
+ includePatchedDependencies: false,
203
204
  isolateDirName: "isolate",
204
205
  logLevel: "info",
205
206
  targetPackagePath: void 0,
@@ -257,7 +258,7 @@ function resolveConfig() {
257
258
  }
258
259
 
259
260
  // src/lib/lockfile/process-lockfile.ts
260
- import { mapObjIndexed } from "ramda";
261
+ import { mapValues } from "remeda";
261
262
 
262
263
  // src/lib/package-manager/helpers/infer-from-files.ts
263
264
  import fs6 from "fs-extra";
@@ -349,6 +350,7 @@ async function generateNpmLockfile({
349
350
  const origRootNodeModulesPath = path5.join(workspaceRootDir, "node_modules");
350
351
  const tempRootNodeModulesPath = path5.join(isolateDir, "node_modules");
351
352
  let hasMovedNodeModules = false;
353
+ let hasError = false;
352
354
  try {
353
355
  if (!fs8.existsSync(origRootNodeModulesPath)) {
354
356
  throw new Error(
@@ -359,7 +361,7 @@ async function generateNpmLockfile({
359
361
  await fs8.move(origRootNodeModulesPath, tempRootNodeModulesPath);
360
362
  hasMovedNodeModules = true;
361
363
  const arborist = new Arborist({ path: isolateDir });
362
- log.debug(`Build tree`);
364
+ log.debug(`Building tree...`);
363
365
  const { meta } = await arborist.buildIdealTree();
364
366
  meta?.commit();
365
367
  const lockfilePath = path5.join(isolateDir, "package-lock.json");
@@ -368,12 +370,16 @@ async function generateNpmLockfile({
368
370
  } catch (err) {
369
371
  console.error(inspectValue(err));
370
372
  log.error(`Failed to generate lockfile: ${getErrorMessage(err)}`);
373
+ hasError = true;
371
374
  } finally {
372
375
  if (hasMovedNodeModules) {
373
376
  log.debug(`Restoring node_modules to the workspace root`);
374
377
  await fs8.move(tempRootNodeModulesPath, origRootNodeModulesPath);
375
378
  }
376
379
  }
380
+ if (hasError) {
381
+ throw new Error("Failed to generate lockfile");
382
+ }
377
383
  }
378
384
 
379
385
  // src/lib/lockfile/helpers/generate-pnpm-lockfile.ts
@@ -384,7 +390,7 @@ import {
384
390
  } from "@pnpm/lockfile-file";
385
391
  import assert3 from "node:assert";
386
392
  import path6 from "node:path";
387
- import { pick } from "ramda";
393
+ import { pick } from "remeda";
388
394
  async function generatePnpmLockfile({
389
395
  workspaceRootDir,
390
396
  targetPackageDir,
@@ -392,7 +398,7 @@ async function generatePnpmLockfile({
392
398
  internalDepPackageNames,
393
399
  packagesRegistry
394
400
  }) {
395
- const { includeDevDependencies } = useConfig();
401
+ const { includeDevDependencies, includePatchedDependencies } = useConfig();
396
402
  const log = useLogger();
397
403
  log.info("Generating PNPM lockfile...");
398
404
  try {
@@ -421,7 +427,7 @@ async function generatePnpmLockfile({
421
427
  ];
422
428
  log.debug("Relevant importer ids:", relevantImporterIds);
423
429
  lockfile.importers = Object.fromEntries(
424
- Object.entries(pick(relevantImporterIds, lockfile.importers)).map(
430
+ Object.entries(pick(lockfile.importers, relevantImporterIds)).map(
425
431
  ([importerId, importer]) => {
426
432
  if (importerId === targetImporterId) {
427
433
  log.debug("Setting target package importer on root");
@@ -429,6 +435,7 @@ async function generatePnpmLockfile({
429
435
  ".",
430
436
  pnpmMapImporter(importer, {
431
437
  includeDevDependencies,
438
+ includePatchedDependencies,
432
439
  directoryByPackageName
433
440
  })
434
441
  ];
@@ -438,6 +445,7 @@ async function generatePnpmLockfile({
438
445
  importerId,
439
446
  pnpmMapImporter(importer, {
440
447
  includeDevDependencies,
448
+ includePatchedDependencies,
441
449
  directoryByPackageName
442
450
  })
443
451
  ];
@@ -447,7 +455,7 @@ async function generatePnpmLockfile({
447
455
  await writeWantedLockfile(isolateDir, lockfile);
448
456
  log.debug("Created lockfile at", path6.join(isolateDir, "pnpm-lock.yaml"));
449
457
  } catch (err) {
450
- log.error(`Failed to generate lockfile: ${getErrorMessage(err)}`);
458
+ throw new Error(`Failed to generate lockfile: ${getErrorMessage(err)}`);
451
459
  }
452
460
  }
453
461
 
@@ -473,25 +481,38 @@ async function generateYarnLockfile({
473
481
  execSync2(`yarn install --cwd ${isolateDir}`);
474
482
  log.debug("Generated lockfile at", newLockfilePath);
475
483
  } catch (err) {
476
- log.error(`Failed to generate lockfile: ${getErrorMessage(err)}`);
484
+ throw new Error(`Failed to generate lockfile: ${getErrorMessage(err)}`);
477
485
  }
478
486
  }
479
487
 
480
488
  // src/lib/lockfile/process-lockfile.ts
481
- function pnpmMapImporter({ dependencies, devDependencies, ...rest }, {
489
+ function pnpmMapImporter({
490
+ dependencies,
491
+ devDependencies,
492
+ patchedDependencies,
493
+ ...rest
494
+ }, {
482
495
  includeDevDependencies,
496
+ includePatchedDependencies,
483
497
  directoryByPackageName
484
498
  }) {
485
499
  return {
486
500
  dependencies: dependencies ? pnpmMapDependenciesLinks(dependencies, directoryByPackageName) : void 0,
487
501
  devDependencies: includeDevDependencies && devDependencies ? pnpmMapDependenciesLinks(devDependencies, directoryByPackageName) : void 0,
502
+ /**
503
+ * Don't know how to map the patched dependencies yet, so we just include
504
+ * them but I don't think it would work like this. The important thing for
505
+ * now is that they are omitted by default, because that is the most common
506
+ * use case.
507
+ */
508
+ patchedDependencies: includePatchedDependencies ? patchedDependencies : void 0,
488
509
  ...rest
489
510
  };
490
511
  }
491
512
  function pnpmMapDependenciesLinks(def, directoryByPackageName) {
492
- return mapObjIndexed(
493
- (version, name) => version.startsWith("link:") ? `link:./${directoryByPackageName[name]}` : version,
494
- def
513
+ return mapValues(
514
+ def,
515
+ (value, key) => value.startsWith("link:") ? `link:./${directoryByPackageName[key]}` : value
495
516
  );
496
517
  }
497
518
  async function processLockfile({
@@ -562,11 +583,11 @@ async function processLockfile({
562
583
  }
563
584
 
564
585
  // src/lib/manifest/adapt-target-package-manifest.ts
565
- import { omit as omit2, pick as pick2 } from "ramda";
586
+ import { omit as omit2, pick as pick2 } from "remeda";
566
587
 
567
588
  // src/lib/manifest/helpers/adapt-internal-package-manifests.ts
568
589
  import path10 from "node:path";
569
- import { omit } from "ramda";
590
+ import { omit } from "remeda";
570
591
 
571
592
  // src/lib/manifest/io.ts
572
593
  import fs10 from "fs-extra";
@@ -630,7 +651,7 @@ async function adaptInternalPackageManifests(internalPackageNames, packagesRegis
630
651
  await Promise.all(
631
652
  internalPackageNames.map(async (packageName) => {
632
653
  const { manifest, rootRelativeDir } = packagesRegistry[packageName];
633
- const inputManifest = includeDevDependencies ? omit(["peerDependencies"], manifest) : omit(["devDependencies", "peerDependencies"], manifest);
654
+ const inputManifest = includeDevDependencies ? omit(manifest, ["peerDependencies"]) : omit(manifest, ["devDependencies", "peerDependencies"]);
634
655
  const outputManifest = packageManager2.name === "pnpm" && !forceNpm ? (
635
656
  /**
636
657
  * For PNPM the output itself is a workspace so we can preserve the specifiers
@@ -654,7 +675,7 @@ async function adaptInternalPackageManifests(internalPackageNames, packagesRegis
654
675
  async function adaptTargetPackageManifest(manifest, packagesRegistry, isolateDir) {
655
676
  const packageManager2 = usePackageManager();
656
677
  const { includeDevDependencies, forceNpm, pickFromScripts, omitFromScripts } = useConfig();
657
- const inputManifest = includeDevDependencies ? manifest : omit2(["devDependencies"], manifest);
678
+ const inputManifest = includeDevDependencies ? manifest : omit2(manifest, ["devDependencies"]);
658
679
  const adaptedManifest = packageManager2.name === "pnpm" && !forceNpm ? (
659
680
  /**
660
681
  * For PNPM the output itself is a workspace so we can preserve the specifiers
@@ -674,7 +695,7 @@ async function adaptTargetPackageManifest(manifest, packagesRegistry, isolateDir
674
695
  * Scripts are removed by default if not explicitly picked or omitted via
675
696
  * config.
676
697
  */
677
- scripts: pickFromScripts ? pick2(pickFromScripts, manifest.scripts) : omitFromScripts ? omit2(omitFromScripts, manifest.scripts) : void 0
698
+ scripts: pickFromScripts ? pick2(manifest.scripts ?? {}, pickFromScripts) : omitFromScripts ? omit2(manifest.scripts ?? {}, omitFromScripts) : void 0
678
699
  };
679
700
  await writeManifest(isolateDir, outputManifest);
680
701
  }
@@ -891,7 +912,7 @@ async function createPackagesRegistry(workspaceRootDir, workspacePackagesOverrid
891
912
  }
892
913
 
893
914
  // src/lib/registry/list-internal-packages.ts
894
- import { uniq } from "ramda";
915
+ import { uniq } from "remeda";
895
916
  function listInternalPackages(manifest, packagesRegistry, { includeDevDependencies = false } = {}) {
896
917
  const allWorkspacePackageNames = Object.keys(packagesRegistry);
897
918
  const internalPackageNames = (includeDevDependencies ? [