isolate-package 1.13.2 → 1.14.0-0

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
@@ -210,30 +210,6 @@ Because the configuration loader depends on this setting, its output is not
210
210
  affected by this setting. If you want to debug the configuration set
211
211
  `DEBUG_ISOLATE_CONFIG=true` before you run `isolate`
212
212
 
213
- ### forceNpm
214
-
215
- Type: `boolean`, default: `false`
216
-
217
- By default the isolate process will generate output based on the package manager
218
- that you are using for your monorepo. But your deployment target might not be
219
- compatible with that package manager, or it might not be the best choice given
220
- the available tooling.
221
-
222
- Also, it should not really matter what package manager is used in de deployment
223
- as long as the versions match your original lockfile.
224
-
225
- By setting this option to `true` you are forcing the isolate output to use NPM.
226
- A package-lock file will be generated based on the contents of node_modules and
227
- therefore should match the versions in your original lockfile.
228
-
229
- This way you can enjoy using PNPM or Yarn for your monorepo, while your
230
- deployment uses NPM with modules locked to the same versions.
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
-
237
213
  ### buildDirName
238
214
 
239
215
  Type: `string | undefined`, default: `undefined`
@@ -341,13 +317,8 @@ When you use the `targetPackagePath` option, this setting will be ignored.
341
317
  ## Lockfiles
342
318
 
343
319
  The isolate process tries to generate an isolated / pruned lockfile for the
344
- package manager that you use in your monorepo. If the package manager is not
345
- supported (modern Yarn versions), it can still generate a matching NPM lockfile
346
- based on the installed versions in node_modules.
347
-
348
- In case your package manager is not supported by your deployment target you can
349
- also choose NPM to be used by setting the `makeNpmLockfile` to `true` in your
350
- configuration.
320
+ package manager that you use in your monorepo. The strategy is different for
321
+ each package manager, with NPM currently being the least attractive.
351
322
 
352
323
  ### NPM
353
324
 
@@ -366,13 +337,8 @@ after Arborist has finished doing its thing.
366
337
 
367
338
  ### PNPM
368
339
 
369
- The PNPM lockfile format is very readable (YAML) but getting it adapted to the
370
- isolate output was a bit of a trip.
371
-
372
- It turns out, at least up to v10, that the isolated output has to be formatted
373
- as a workspace itself, otherwise dependencies of internally linked packages are
374
- not installed by PNPM. Therefore, the output looks a bit different from other
375
- package managers:
340
+ For PNPM, the isolated output will be formatted as a workspace itself, otherwise
341
+ dependencies of internally linked packages are not installed by PNPM.
376
342
 
377
343
  - Links are preserved
378
344
  - Versions specifiers like "workspace:\*" are preserved
package/dist/index.mjs CHANGED
@@ -5,9 +5,9 @@ import path19 from "node:path";
5
5
  import { unique } from "remeda";
6
6
 
7
7
  // src/lib/config.ts
8
- import fs6 from "fs-extra";
9
- import assert from "node:assert";
10
- import path3 from "node:path";
8
+ import fs8 from "fs-extra";
9
+ import assert2 from "node:assert";
10
+ import path6 from "node:path";
11
11
  import { isEmpty } from "remeda";
12
12
 
13
13
  // src/lib/logger.ts
@@ -137,16 +137,109 @@ async function readTypedJson(filePath) {
137
137
 
138
138
  // src/lib/utils/pack.ts
139
139
  import { exec } from "node:child_process";
140
- import fs3 from "node:fs";
140
+ import fs5 from "node:fs";
141
+ import path5 from "node:path";
142
+
143
+ // src/lib/package-manager/index.ts
144
+ import path4 from "node:path";
145
+
146
+ // src/lib/package-manager/helpers/infer-from-files.ts
147
+ import fs3 from "fs-extra";
148
+ import { execSync } from "node:child_process";
141
149
  import path2 from "node:path";
142
- async function pack(srcDir, dstDir, usePnpmPack) {
150
+
151
+ // src/lib/package-manager/names.ts
152
+ var supportedPackageManagerNames = ["pnpm", "yarn", "npm"];
153
+ function getLockfileFileName(name) {
154
+ switch (name) {
155
+ case "pnpm":
156
+ return "pnpm-lock.yaml";
157
+ case "yarn":
158
+ return "yarn.lock";
159
+ case "npm":
160
+ return "package-lock.json";
161
+ }
162
+ }
163
+
164
+ // src/lib/package-manager/helpers/infer-from-files.ts
165
+ function inferFromFiles(workspaceRoot) {
166
+ for (const name of supportedPackageManagerNames) {
167
+ const lockfileName = getLockfileFileName(name);
168
+ if (fs3.existsSync(path2.join(workspaceRoot, lockfileName))) {
169
+ return { name, version: getVersion(name) };
170
+ }
171
+ }
172
+ if (fs3.existsSync(path2.join(workspaceRoot, "npm-shrinkwrap.json"))) {
173
+ return { name: "npm", version: getVersion("npm") };
174
+ }
175
+ throw new Error(`Failed to detect package manager`);
176
+ }
177
+ function getVersion(packageManagerName) {
178
+ const buffer = execSync(`${packageManagerName} --version`);
179
+ return buffer.toString().trim();
180
+ }
181
+
182
+ // src/lib/package-manager/helpers/infer-from-manifest.ts
183
+ import fs4 from "fs-extra";
184
+ import assert from "node:assert";
185
+ import path3 from "node:path";
186
+ function inferFromManifest(workspaceRoot) {
187
+ const log = useLogger();
188
+ const rootManifest = readTypedJsonSync(
189
+ path3.join(workspaceRoot, "package.json")
190
+ );
191
+ if (!rootManifest.packageManager) {
192
+ log.debug("No packageManager field found in root manifest");
193
+ return;
194
+ }
195
+ const [name, version = "*"] = rootManifest.packageManager.split("@");
196
+ assert(
197
+ supportedPackageManagerNames.includes(name),
198
+ `Package manager "${name}" is not currently supported`
199
+ );
200
+ const lockfileName = getLockfileFileName(name);
201
+ assert(
202
+ fs4.existsSync(path3.join(workspaceRoot, lockfileName)),
203
+ `Manifest declares ${name} to be the packageManager, but failed to find ${lockfileName} in workspace root`
204
+ );
205
+ return { name, version };
206
+ }
207
+
208
+ // src/lib/package-manager/index.ts
209
+ var packageManager;
210
+ function usePackageManager() {
211
+ if (!packageManager) {
212
+ throw Error(
213
+ "No package manager detected. Make sure to call detectPackageManager() before usePackageManager()"
214
+ );
215
+ }
216
+ return packageManager;
217
+ }
218
+ function detectPackageManager(workspaceRootDir) {
219
+ if (isRushWorkspace(workspaceRootDir)) {
220
+ packageManager = inferFromFiles(
221
+ path4.join(workspaceRootDir, "common/config/rush")
222
+ );
223
+ } else {
224
+ packageManager = inferFromManifest(workspaceRootDir) ?? inferFromFiles(workspaceRootDir);
225
+ }
226
+ return packageManager;
227
+ }
228
+ function shouldUsePnpmPack() {
229
+ const { name, version } = usePackageManager();
230
+ const majorVersion = parseInt(version.split(".")[0], 10);
231
+ return name === "pnpm" && majorVersion >= 8;
232
+ }
233
+
234
+ // src/lib/utils/pack.ts
235
+ async function pack(srcDir, dstDir) {
236
+ const log = useLogger();
143
237
  const execOptions = {
144
238
  maxBuffer: 10 * 1024 * 1024
145
239
  };
146
- const log = useLogger();
147
240
  const previousCwd = process.cwd();
148
241
  process.chdir(srcDir);
149
- const stdout = usePnpmPack ? await new Promise((resolve, reject) => {
242
+ const stdout = shouldUsePnpmPack() ? await new Promise((resolve, reject) => {
150
243
  exec(
151
244
  `pnpm pack --pack-destination "${dstDir}"`,
152
245
  execOptions,
@@ -170,9 +263,9 @@ async function pack(srcDir, dstDir, usePnpmPack) {
170
263
  }
171
264
  );
172
265
  });
173
- const fileName = path2.basename(stdout.trim());
174
- const filePath = path2.join(dstDir, fileName);
175
- if (!fs3.existsSync(filePath)) {
266
+ const fileName = path5.basename(stdout.trim());
267
+ const filePath = path5.join(dstDir, fileName);
268
+ if (!fs5.existsSync(filePath)) {
176
269
  log.error(
177
270
  `The response from pack could not be resolved to an existing file: ${filePath}`
178
271
  );
@@ -184,21 +277,21 @@ async function pack(srcDir, dstDir, usePnpmPack) {
184
277
  }
185
278
 
186
279
  // src/lib/utils/unpack.ts
187
- import fs4 from "fs-extra";
280
+ import fs6 from "fs-extra";
188
281
  import tar from "tar-fs";
189
282
  import { createGunzip } from "zlib";
190
283
  async function unpack(filePath, unpackDir) {
191
284
  await new Promise((resolve, reject) => {
192
- fs4.createReadStream(filePath).pipe(createGunzip()).pipe(tar.extract(unpackDir)).on("finish", () => resolve()).on("error", (err) => reject(err));
285
+ fs6.createReadStream(filePath).pipe(createGunzip()).pipe(tar.extract(unpackDir)).on("finish", () => resolve()).on("error", (err) => reject(err));
193
286
  });
194
287
  }
195
288
 
196
289
  // src/lib/utils/yaml.ts
197
- import fs5 from "fs-extra";
290
+ import fs7 from "fs-extra";
198
291
  import yaml from "yaml";
199
292
  function readTypedYamlSync(filePath) {
200
293
  try {
201
- const rawContent = fs5.readFileSync(filePath, "utf-8");
294
+ const rawContent = fs7.readFileSync(filePath, "utf-8");
202
295
  const data = yaml.parse(rawContent);
203
296
  return data;
204
297
  } catch (err) {
@@ -208,7 +301,7 @@ function readTypedYamlSync(filePath) {
208
301
  }
209
302
  }
210
303
  function writeTypedYamlSync(filePath, content) {
211
- fs5.writeFileSync(filePath, yaml.stringify(content), "utf-8");
304
+ fs7.writeFileSync(filePath, yaml.stringify(content), "utf-8");
212
305
  }
213
306
 
214
307
  // src/lib/config.ts
@@ -249,12 +342,12 @@ function resolveConfig() {
249
342
  }
250
343
  setLogLevel(process.env.DEBUG_ISOLATE_CONFIG ? "debug" : "info");
251
344
  const log = useLogger();
252
- const configFilePath = path3.join(process.cwd(), CONFIG_FILE_NAME);
345
+ const configFilePath = path6.join(process.cwd(), CONFIG_FILE_NAME);
253
346
  if (_user_defined_config) {
254
347
  log.debug(`Using user defined config:`, inspectValue(_user_defined_config));
255
348
  } else {
256
349
  log.debug(`Attempting to load config from ${configFilePath}`);
257
- _user_defined_config = fs6.existsSync(configFilePath) ? readTypedJsonSync(configFilePath) : {};
350
+ _user_defined_config = fs8.existsSync(configFilePath) ? readTypedJsonSync(configFilePath) : {};
258
351
  }
259
352
  const foreignKeys = Object.keys(_user_defined_config).filter(
260
353
  (key) => !validConfigKeys.includes(key)
@@ -272,92 +365,6 @@ function resolveConfig() {
272
365
  return config;
273
366
  }
274
367
 
275
- // src/lib/package-manager/index.ts
276
- import path6 from "node:path";
277
-
278
- // src/lib/package-manager/helpers/infer-from-files.ts
279
- import fs7 from "fs-extra";
280
- import { execSync } from "node:child_process";
281
- import path4 from "node:path";
282
-
283
- // src/lib/package-manager/names.ts
284
- var supportedPackageManagerNames = ["pnpm", "yarn", "npm"];
285
- function getLockfileFileName(name) {
286
- switch (name) {
287
- case "pnpm":
288
- return "pnpm-lock.yaml";
289
- case "yarn":
290
- return "yarn.lock";
291
- case "npm":
292
- return "package-lock.json";
293
- }
294
- }
295
-
296
- // src/lib/package-manager/helpers/infer-from-files.ts
297
- function inferFromFiles(workspaceRoot) {
298
- for (const name of supportedPackageManagerNames) {
299
- const lockfileName = getLockfileFileName(name);
300
- if (fs7.existsSync(path4.join(workspaceRoot, lockfileName))) {
301
- return { name, version: getVersion(name) };
302
- }
303
- }
304
- if (fs7.existsSync(path4.join(workspaceRoot, "npm-shrinkwrap.json"))) {
305
- return { name: "npm", version: getVersion("npm") };
306
- }
307
- throw new Error(`Failed to detect package manager`);
308
- }
309
- function getVersion(packageManagerName) {
310
- const buffer = execSync(`${packageManagerName} --version`);
311
- return buffer.toString().trim();
312
- }
313
-
314
- // src/lib/package-manager/helpers/infer-from-manifest.ts
315
- import fs8 from "fs-extra";
316
- import assert2 from "node:assert";
317
- import path5 from "node:path";
318
- function inferFromManifest(workspaceRoot) {
319
- const log = useLogger();
320
- const rootManifest = readTypedJsonSync(
321
- path5.join(workspaceRoot, "package.json")
322
- );
323
- if (!rootManifest.packageManager) {
324
- log.debug("No packageManager field found in root manifest");
325
- return;
326
- }
327
- const [name, version = "*"] = rootManifest.packageManager.split("@");
328
- assert2(
329
- supportedPackageManagerNames.includes(name),
330
- `Package manager "${name}" is not currently supported`
331
- );
332
- const lockfileName = getLockfileFileName(name);
333
- assert2(
334
- fs8.existsSync(path5.join(workspaceRoot, lockfileName)),
335
- `Manifest declares ${name} to be the packageManager, but failed to find ${lockfileName} in workspace root`
336
- );
337
- return { name, version };
338
- }
339
-
340
- // src/lib/package-manager/index.ts
341
- var packageManager;
342
- function usePackageManager() {
343
- if (!packageManager) {
344
- throw Error(
345
- "No package manager detected. Make sure to call detectPackageManager() before usePackageManager()"
346
- );
347
- }
348
- return packageManager;
349
- }
350
- function detectPackageManager(workspaceRootDir) {
351
- if (isRushWorkspace(workspaceRootDir)) {
352
- packageManager = inferFromFiles(
353
- path6.join(workspaceRootDir, "common/config/rush")
354
- );
355
- } else {
356
- packageManager = inferFromManifest(workspaceRootDir) ?? inferFromFiles(workspaceRootDir);
357
- }
358
- return packageManager;
359
- }
360
-
361
368
  // src/lib/lockfile/helpers/generate-npm-lockfile.ts
362
369
  import Arborist from "@npmcli/arborist";
363
370
  import fs9 from "fs-extra";
@@ -562,15 +569,6 @@ async function processLockfile({
562
569
  targetPackageManifest
563
570
  }) {
564
571
  const log = useLogger();
565
- const { forceNpm } = useConfig();
566
- if (forceNpm) {
567
- log.info("Forcing to use NPM for isolate output");
568
- await generateNpmLockfile({
569
- workspaceRootDir,
570
- isolateDir
571
- });
572
- return true;
573
- }
574
572
  const { name, version } = usePackageManager();
575
573
  let usedFallbackToNpm = false;
576
574
  switch (name) {
@@ -687,12 +685,11 @@ function adaptManifestInternalDeps({
687
685
  // src/lib/manifest/helpers/adapt-internal-package-manifests.ts
688
686
  async function adaptInternalPackageManifests(internalPackageNames, packagesRegistry, isolateDir) {
689
687
  const packageManager2 = usePackageManager();
690
- const { forceNpm } = useConfig();
691
688
  await Promise.all(
692
689
  internalPackageNames.map(async (packageName) => {
693
690
  const { manifest, rootRelativeDir } = packagesRegistry[packageName];
694
691
  const strippedManifest = omit(manifest, ["scripts", "devDependencies"]);
695
- const outputManifest = packageManager2.name === "pnpm" && !forceNpm ? (
692
+ const outputManifest = packageManager2.name === "pnpm" ? (
696
693
  /**
697
694
  * For PNPM the output itself is a workspace so we can preserve the specifiers
698
695
  * with "workspace:*" in the output manifest.
@@ -742,9 +739,9 @@ async function adaptTargetPackageManifest({
742
739
  workspaceRootDir
743
740
  }) {
744
741
  const packageManager2 = usePackageManager();
745
- const { includeDevDependencies, forceNpm, pickFromScripts, omitFromScripts } = useConfig();
742
+ const { includeDevDependencies, pickFromScripts, omitFromScripts } = useConfig();
746
743
  const inputManifest = includeDevDependencies ? manifest : omit2(manifest, ["devDependencies"]);
747
- const adaptedManifest = packageManager2.name === "pnpm" && !forceNpm ? (
744
+ const adaptedManifest = packageManager2.name === "pnpm" ? (
748
745
  /**
749
746
  * For PNPM the output itself is a workspace so we can preserve the specifiers
750
747
  * with "workspace:*" in the output manifest, but we do want to adopt the
@@ -816,25 +813,15 @@ async function packDependencies({
816
813
  }) {
817
814
  const log = useLogger();
818
815
  const packedFileByName = {};
819
- const { name, version } = usePackageManager();
820
- const versionMajor = parseInt(version.split(".")[0], 10);
821
- const usePnpmPack = name === "pnpm" && versionMajor >= 8;
822
- if (usePnpmPack) {
823
- log.debug("Using PNPM pack instead of NPM pack");
824
- }
825
816
  for (const dependency of internalPackageNames) {
826
817
  const def = packagesRegistry[dependency];
827
818
  assert4(dependency, `Failed to find package definition for ${dependency}`);
828
- const { name: name2 } = def.manifest;
829
- if (packedFileByName[name2]) {
830
- log.debug(`Skipping ${name2} because it has already been packed`);
819
+ const { name } = def.manifest;
820
+ if (packedFileByName[name]) {
821
+ log.debug(`Skipping ${name} because it has already been packed`);
831
822
  continue;
832
823
  }
833
- packedFileByName[name2] = await pack(
834
- def.absoluteDir,
835
- packDestinationDir,
836
- usePnpmPack
837
- );
824
+ packedFileByName[name] = await pack(def.absoluteDir, packDestinationDir);
838
825
  }
839
826
  return packedFileByName;
840
827
  }
@@ -1061,6 +1048,9 @@ async function isolate(options = {}) {
1061
1048
  packageManager2.name,
1062
1049
  packageManager2.version
1063
1050
  );
1051
+ if (shouldUsePnpmPack()) {
1052
+ log.debug("Use PNPM pack instead of NPM pack");
1053
+ }
1064
1054
  const packagesRegistry = await createPackagesRegistry(
1065
1055
  workspaceRootDir,
1066
1056
  config.workspacePackages
@@ -1114,7 +1104,7 @@ async function isolate(options = {}) {
1114
1104
  manifest.packageManager = `npm@${npmVersion}`;
1115
1105
  await writeManifest(isolateDir, manifest);
1116
1106
  }
1117
- if (packageManager2.name === "pnpm" && !config.forceNpm) {
1107
+ if (packageManager2.name === "pnpm") {
1118
1108
  if (isRushWorkspace(workspaceRootDir)) {
1119
1109
  const packagesFolderNames = unique(
1120
1110
  internalPackageNames.map(