@maka/meteor-sdk 0.2.8 → 0.2.10
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 +11 -5
- package/isopackets/combined/isopacket-buildinfo.json +1 -1
- package/isopackets/combined/npm/node_modules/meteor/babel-compiler/node_modules/.npm-shrinkwrap.json +3 -3
- package/isopackets/combined/npm/node_modules/meteor/babel-compiler/node_modules/.package-lock.json +4 -4
- package/isopackets/combined/npm/node_modules/meteor/babel-compiler/node_modules/baseline-browser-mapping/dist/index.cjs +1 -1
- package/isopackets/combined/npm/node_modules/meteor/babel-compiler/node_modules/baseline-browser-mapping/dist/index.js +1 -1
- package/isopackets/combined/npm/node_modules/meteor/babel-compiler/node_modules/baseline-browser-mapping/package.json +1 -1
- package/isopackets/combined/npm/node_modules/meteor/boilerplate-generator/node_modules/.package-lock.json +1 -1
- package/isopackets/combined/npm/node_modules/meteor/constraint-solver/node_modules/.package-lock.json +1 -1
- package/isopackets/combined/npm/node_modules/meteor/ddp-client/node_modules/.package-lock.json +1 -1
- package/isopackets/combined/npm/node_modules/meteor/ecmascript/node_modules/.package-lock.json +1 -1
- package/isopackets/combined/npm/node_modules/meteor/ecmascript-runtime/node_modules/.package-lock.json +1 -1
- package/isopackets/combined/npm/node_modules/meteor/ecmascript-runtime-client/node_modules/.package-lock.json +1 -1
- package/isopackets/combined/npm/node_modules/meteor/ecmascript-runtime-server/node_modules/.package-lock.json +1 -1
- package/isopackets/combined/npm/node_modules/meteor/fetch/node_modules/.package-lock.json +1 -1
- package/isopackets/combined/npm/node_modules/meteor/inter-process-messaging/node_modules/.package-lock.json +1 -1
- package/isopackets/combined/npm/node_modules/meteor/logging/node_modules/.package-lock.json +1 -1
- package/isopackets/combined/npm/node_modules/meteor/logic-solver/node_modules/.package-lock.json +1 -1
- package/isopackets/combined/npm/node_modules/meteor/meteor/node_modules/.package-lock.json +1 -1
- package/isopackets/combined/npm/node_modules/meteor/modules/node_modules/.package-lock.json +1 -1
- package/isopackets/combined/npm/node_modules/meteor/modules-runtime/node_modules/.package-lock.json +1 -1
- package/isopackets/combined/npm/node_modules/meteor/npm-mongo/node_modules/.package-lock.json +1 -1
- package/isopackets/combined/npm/node_modules/meteor/package-version-parser/node_modules/.package-lock.json +1 -1
- package/isopackets/combined/npm/node_modules/meteor/promise/node_modules/.package-lock.json +1 -1
- package/isopackets/combined/npm/node_modules/meteor/react-fast-refresh/node_modules/.package-lock.json +1 -1
- package/isopackets/combined/npm/node_modules/meteor/socket-stream-client/node_modules/.package-lock.json +1 -1
- package/package.json +1 -1
- package/src/project.js +40 -0
- package/tools/fs/optimistic.ts +106 -1
- package/tools/fs/safe-watcher.ts +40 -0
- package/tools/fs/watch.ts +39 -0
- package/tools/isobuild/meteor-npm.js +171 -39
- package/isopackets/combined/npm/node_modules/meteor/fetch/node_modules/node-fetch/.meteor-portable-2.json +0 -1
|
@@ -23,6 +23,7 @@ import {
|
|
|
23
23
|
import { wrap as wrapOptimistic } from "optimism";
|
|
24
24
|
import {
|
|
25
25
|
dirtyNodeModulesDirectory,
|
|
26
|
+
dirtyReplacedDirectory,
|
|
26
27
|
optimisticLStat,
|
|
27
28
|
optimisticStatOrNull,
|
|
28
29
|
optimisticReadJsonOrNull,
|
|
@@ -791,6 +792,7 @@ async function restoreNodeModulesFromNpmDepsCache(packageName, packageNpmDir) {
|
|
|
791
792
|
await files.cp_r(cachedNodeModules, tmpDir, { preserveSymlinks: true });
|
|
792
793
|
await files.renameDirAlmostAtomically(tmpDir, nodeModulesDir);
|
|
793
794
|
dirtyNodeModulesDirectory(nodeModulesDir);
|
|
795
|
+
dirtyReplacedDirectory(nodeModulesDir);
|
|
794
796
|
return true;
|
|
795
797
|
} catch (e) {
|
|
796
798
|
try {
|
|
@@ -893,6 +895,71 @@ function pruneNpmDepsCache(packageCacheDir, keepDir) {
|
|
|
893
895
|
} catch (e) {}
|
|
894
896
|
}
|
|
895
897
|
|
|
898
|
+
// Install a package's npm deps purely from its shipped
|
|
899
|
+
// npm-shrinkwrap.json -- no evaluated Npm.depends needed, which is what
|
|
900
|
+
// makes prewarm-time (pre-package.js) installs possible. Mirrors
|
|
901
|
+
// updateExistingNpmDirectory's preserved-shrinkwrap branch exactly:
|
|
902
|
+
// mapped shrinkwrap + minimal package.json into a temp dir, `npm
|
|
903
|
+
// install`, then completeNpmDirectory (which also seeds the cache).
|
|
904
|
+
// The top-level dependency map is derived from the shrinkwrap itself
|
|
905
|
+
// (exact versions; resolved URLs for non-registry deps) -- a superset
|
|
906
|
+
// of the real Npm.depends, which npm accepts since every entry is
|
|
907
|
+
// pinned to what the lock installs. If the shipped shrinkwrap turns
|
|
908
|
+
// out stale relative to the package's actual Npm.depends, the build's
|
|
909
|
+
// own subtree verification catches it and reinstalls normally.
|
|
910
|
+
// Callers must hold the npm package lock for packageNpmDir.
|
|
911
|
+
async function preinstallNpmDepsFromShrinkwrap(packageName, packageNpmDir) {
|
|
912
|
+
const shrinkwrappedDependenciesTree =
|
|
913
|
+
getShrinkwrappedDependenciesTree(packageNpmDir);
|
|
914
|
+
const npmDependencies = treeToDependencies(
|
|
915
|
+
minimizeDependencyTree(shrinkwrappedDependenciesTree));
|
|
916
|
+
if (_.isEmpty(npmDependencies)) {
|
|
917
|
+
return false;
|
|
918
|
+
}
|
|
919
|
+
const cacheKey = npmDepsCacheKey(packageNpmDir);
|
|
920
|
+
|
|
921
|
+
const newPackageNpmDir =
|
|
922
|
+
convertColonsInPath(packageNpmDir) + '-prewarm-' + utils.randomToken();
|
|
923
|
+
tmpDirs.push(newPackageNpmDir);
|
|
924
|
+
try {
|
|
925
|
+
makeNewPackageNpmDir(newPackageNpmDir);
|
|
926
|
+
|
|
927
|
+
const mappedDependencies = Object.entries(
|
|
928
|
+
shrinkwrappedDependenciesTree.dependencies
|
|
929
|
+
).reduce((acc, [name, info]) => {
|
|
930
|
+
return { ...acc, [`node_modules/${name}`]: info };
|
|
931
|
+
}, {});
|
|
932
|
+
|
|
933
|
+
files.writeFile(
|
|
934
|
+
files.pathJoin(newPackageNpmDir, 'npm-shrinkwrap.json'),
|
|
935
|
+
JSON.stringify({
|
|
936
|
+
...shrinkwrappedDependenciesTree,
|
|
937
|
+
dependencies: mappedDependencies,
|
|
938
|
+
}, null, 2)
|
|
939
|
+
);
|
|
940
|
+
files.writeFile(
|
|
941
|
+
files.pathJoin(newPackageNpmDir, 'package.json'),
|
|
942
|
+
JSON.stringify({ dependencies: npmDependencies }, null, 2)
|
|
943
|
+
);
|
|
944
|
+
|
|
945
|
+
logUpdateDependencies(packageName, npmDependencies);
|
|
946
|
+
await installFromShrinkwrap(newPackageNpmDir);
|
|
947
|
+
|
|
948
|
+
files.unlink(files.pathJoin(newPackageNpmDir, 'npm-shrinkwrap.json'));
|
|
949
|
+
files.unlink(files.pathJoin(newPackageNpmDir, 'package.json'));
|
|
950
|
+
|
|
951
|
+
await completeNpmDirectory(
|
|
952
|
+
packageName, newPackageNpmDir, packageNpmDir, npmDependencies,
|
|
953
|
+
cacheKey);
|
|
954
|
+
return true;
|
|
955
|
+
} finally {
|
|
956
|
+
if (files.exists(newPackageNpmDir)) {
|
|
957
|
+
await files.rm_recursive_deferred(newPackageNpmDir);
|
|
958
|
+
}
|
|
959
|
+
tmpDirs = _.without(tmpDirs, newPackageNpmDir);
|
|
960
|
+
}
|
|
961
|
+
}
|
|
962
|
+
|
|
896
963
|
// Restore every restorable package under packagesDir from the cache, in
|
|
897
964
|
// parallel, before the (serial) per-package build pipeline reaches
|
|
898
965
|
// them. Purely filesystem-driven: a candidate is any package dir with a
|
|
@@ -900,69 +967,129 @@ function pruneNpmDepsCache(packageCacheDir, keepDir) {
|
|
|
900
967
|
// package.js evaluation is needed. Safe to run concurrently with a
|
|
901
968
|
// build -- each restore holds the same cross-process lock
|
|
902
969
|
// updateDependencies() takes, and re-checks its precondition under it.
|
|
903
|
-
//
|
|
970
|
+
//
|
|
971
|
+
// Options:
|
|
972
|
+
// - onlyPackages: array of package names to consider (REQUIRED for
|
|
973
|
+
// installOnMiss -- without a scope, cold-cache installs would cover
|
|
974
|
+
// every bundled package instead of just the app's).
|
|
975
|
+
// - installOnMiss: after the restore phase, npm-install the remaining
|
|
976
|
+
// misses from their shipped shrinkwraps, in parallel.
|
|
977
|
+
// - concurrency (restore pool, default 8), installConcurrency (npm
|
|
978
|
+
// pool, default 3 -- kept small because concurrent npm processes
|
|
979
|
+
// contend on npm's shared content cache).
|
|
980
|
+
//
|
|
981
|
+
// Returns {restored, installed}.
|
|
904
982
|
meteorNpm.prewarmNpmDepsCache = async function (packagesDir, options) {
|
|
905
983
|
options = options || {};
|
|
984
|
+
const none = { restored: 0, installed: 0 };
|
|
906
985
|
if (npmDepsCacheDisabled()) {
|
|
907
|
-
return
|
|
986
|
+
return none;
|
|
908
987
|
}
|
|
909
988
|
packagesDir = files.convertToStandardPath(packagesDir);
|
|
910
989
|
|
|
990
|
+
const only = options.onlyPackages &&
|
|
991
|
+
new Set(options.onlyPackages);
|
|
911
992
|
const candidates = [];
|
|
993
|
+
// A dir is a candidate when it has a shipped shrinkwrap but no
|
|
994
|
+
// installed tree. `name` keys the cache entry, so it must match what
|
|
995
|
+
// the normal install path passes as packageName: the package name for
|
|
996
|
+
// .npm/package, the plugin name for .npm/plugin/<pluginName>.
|
|
997
|
+
function considerCandidate(name, packageNpmDir) {
|
|
998
|
+
if (! files.exists(
|
|
999
|
+
files.pathJoin(packageNpmDir, "npm-shrinkwrap.json"))) {
|
|
1000
|
+
return;
|
|
1001
|
+
}
|
|
1002
|
+
if (files.exists(files.pathJoin(
|
|
1003
|
+
packageNpmDir, "node_modules", ".package-lock.json"))) {
|
|
1004
|
+
return;
|
|
1005
|
+
}
|
|
1006
|
+
candidates.push({ name, packageNpmDir });
|
|
1007
|
+
}
|
|
912
1008
|
try {
|
|
913
1009
|
files.readdir(packagesDir).forEach(name => {
|
|
914
|
-
|
|
915
|
-
files.pathJoin(packagesDir, name, ".npm", "package");
|
|
916
|
-
if (! files.exists(
|
|
917
|
-
files.pathJoin(packageNpmDir, "npm-shrinkwrap.json"))) {
|
|
1010
|
+
if (only && ! only.has(name)) {
|
|
918
1011
|
return;
|
|
919
1012
|
}
|
|
920
|
-
|
|
921
|
-
|
|
1013
|
+
considerCandidate(
|
|
1014
|
+
name, files.pathJoin(packagesDir, name, ".npm", "package"));
|
|
1015
|
+
// Build plugins keep their own npm trees at .npm/plugin/<plugin
|
|
1016
|
+
// name> -- these install during the runner's FIRST build, i.e.
|
|
1017
|
+
// inside the file-watch window, where the resulting .npm churn
|
|
1018
|
+
// can restart the build (post-update "flapping"). Prewarming them
|
|
1019
|
+
// here moves that work before the watcher arms.
|
|
1020
|
+
const pluginRoot = files.pathJoin(packagesDir, name, ".npm", "plugin");
|
|
1021
|
+
let pluginNames;
|
|
1022
|
+
try {
|
|
1023
|
+
pluginNames = files.readdir(pluginRoot);
|
|
1024
|
+
} catch (e) {
|
|
922
1025
|
return;
|
|
923
1026
|
}
|
|
924
|
-
|
|
1027
|
+
pluginNames.forEach(pluginName => {
|
|
1028
|
+
if (pluginName.startsWith(".") ||
|
|
1029
|
+
pluginName.endsWith(".lock") ||
|
|
1030
|
+
pluginName.includes("-new-") ||
|
|
1031
|
+
pluginName.includes("-prewarm-")) {
|
|
1032
|
+
return;
|
|
1033
|
+
}
|
|
1034
|
+
considerCandidate(
|
|
1035
|
+
pluginName, files.pathJoin(pluginRoot, pluginName));
|
|
1036
|
+
});
|
|
925
1037
|
});
|
|
926
1038
|
} catch (e) {
|
|
927
|
-
return
|
|
1039
|
+
return none;
|
|
928
1040
|
}
|
|
929
1041
|
if (! candidates.length) {
|
|
930
|
-
return
|
|
1042
|
+
return none;
|
|
931
1043
|
}
|
|
932
1044
|
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
1045
|
+
function installedAlready(candidate) {
|
|
1046
|
+
return files.exists(files.pathJoin(
|
|
1047
|
+
candidate.packageNpmDir, "node_modules", ".package-lock.json"));
|
|
1048
|
+
}
|
|
1049
|
+
|
|
1050
|
+
async function runPool(queue, size, fn) {
|
|
1051
|
+
let nextIndex = 0;
|
|
1052
|
+
let completed = 0;
|
|
1053
|
+
async function worker() {
|
|
1054
|
+
while (nextIndex < queue.length) {
|
|
1055
|
+
const candidate = queue[nextIndex++];
|
|
1056
|
+
try {
|
|
1057
|
+
// Re-check under the lock: a concurrent build (or the other
|
|
1058
|
+
// prewarm phase) may have handled this package already.
|
|
1059
|
+
const ok = await withNpmPackageLock(
|
|
1060
|
+
candidate.packageNpmDir,
|
|
1061
|
+
async () => ! installedAlready(candidate) && fn(candidate)
|
|
1062
|
+
);
|
|
1063
|
+
if (ok) {
|
|
1064
|
+
completed++;
|
|
1065
|
+
}
|
|
1066
|
+
} catch (e) {
|
|
1067
|
+
// Best-effort; the build's own updateDependencies() will
|
|
1068
|
+
// handle this package the normal way.
|
|
1069
|
+
if (options.debugThrow) {
|
|
1070
|
+
console.error("prewarm error for " + candidate.name + ":",
|
|
1071
|
+
(e && e.stack) || e);
|
|
951
1072
|
}
|
|
952
|
-
);
|
|
953
|
-
if (ok) {
|
|
954
|
-
restored++;
|
|
955
1073
|
}
|
|
956
|
-
} catch (e) {
|
|
957
|
-
// Best-effort; the build's own updateDependencies() will handle
|
|
958
|
-
// this package the normal way.
|
|
959
1074
|
}
|
|
960
1075
|
}
|
|
1076
|
+
await Promise.all(
|
|
1077
|
+
_.times(Math.min(size, queue.length || 1), worker));
|
|
1078
|
+
return completed;
|
|
1079
|
+
}
|
|
1080
|
+
|
|
1081
|
+
const restored = await runPool(
|
|
1082
|
+
candidates, options.concurrency || 8,
|
|
1083
|
+
c => restoreNodeModulesFromNpmDepsCache(c.name, c.packageNpmDir));
|
|
1084
|
+
|
|
1085
|
+
let installed = 0;
|
|
1086
|
+
if (options.installOnMiss && only) {
|
|
1087
|
+
const misses = candidates.filter(c => ! installedAlready(c));
|
|
1088
|
+
installed = await runPool(
|
|
1089
|
+
misses, options.installConcurrency || 3,
|
|
1090
|
+
c => preinstallNpmDepsFromShrinkwrap(c.name, c.packageNpmDir));
|
|
961
1091
|
}
|
|
962
|
-
|
|
963
|
-
options.concurrency || 8, candidates.length);
|
|
964
|
-
await Promise.all(_.times(concurrency, worker));
|
|
965
|
-
return restored;
|
|
1092
|
+
return { restored, installed };
|
|
966
1093
|
};
|
|
967
1094
|
|
|
968
1095
|
var updateExistingNpmDirectory = async function (packageName, newPackageNpmDir,
|
|
@@ -1293,6 +1420,11 @@ async function completeNpmDirectory(
|
|
|
1293
1420
|
await files.renameDirAlmostAtomically(newPackageNpmDir, packageNpmDir);
|
|
1294
1421
|
|
|
1295
1422
|
dirtyNodeModulesDirectory(files.pathJoin(packageNpmDir, "node_modules"));
|
|
1423
|
+
// The whole .npm dir was just atomically replaced; any optimistic
|
|
1424
|
+
// result cached during the swap window (e.g. a null hash for
|
|
1425
|
+
// npm-shrinkwrap.json) must be forgotten deterministically -- watcher
|
|
1426
|
+
// events can't be relied on for this (see dirtyReplacedDirectory).
|
|
1427
|
+
dirtyReplacedDirectory(packageNpmDir);
|
|
1296
1428
|
|
|
1297
1429
|
if (! _.isEmpty(npmDependencies)) {
|
|
1298
1430
|
scheduleNpmDepsCachePopulate(
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
true
|