forked from meteor/meteor
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathuniload.js
151 lines (136 loc) · 5.38 KB
/
uniload.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
var _ = require('underscore');
var bundler = require('./bundler.js');
var buildmessage = require('./buildmessage.js');
var release = require('./release.js');
var packageLoader = require("./package-loader.js");
var files = require('./files.js');
var catalog = require('./catalog.js');
// These are the only packages that may be directly loaded via this package. Add
// more to the list if you need to uniload more things! (You don't have to
// include the dependencies of the packages you directly load in this list.)
var ROOT_PACKAGES = [
'constraint-solver',
'dev-bundle-fetcher',
'ejson',
'js-analyze',
'ddp',
'logging',
'meteor',
'minifiers',
'minimongo',
'mongo',
'package-version-parser',
'boilerplate-generator',
'webapp-hashing'
];
// Load isopacks into the currently running node.js process. Use
// this to use isopacks (such as the DDP client) from command-line
// tools (such as 'meteor'). The requested packages will be loaded
// together will all of their dependencies, and each time you call
// this function you load another, distinct copy of all of the
// packages (except see note about caching below). The return value is
// an object that maps package name to package exports (that is, it is
// the Isopack object from inside the sandbox created for the newly
// loaded packages).
//
// Caching: There is a simple cache. If you call this function with
// exactly the same release and packages, we will attempt to return
// the memoized return value from the previous load (rather than
// creating a whole new copy of the packages in memory). The caching
// logic is not particularly sophisticated. For example, the cache
// will not be flushed if packages change on disk, even if it should
// be, but using a different release name will flush the cache
// completely.
//
// When run from a checkout, uniload only loads local (from the checkout)
// packages: never packages from troposphere. When run from a release build,
// uniload only loads pre-built isopacks that are distributed alongside the
// tool: never local packages or packages from troposphere (so in this mode, it
// never compiles the source of a real package).
//
// Options:
// - packages: The packages to load, as an array of strings. Each
// string may be either "packagename" or "packagename.slice".
//
// Example usage:
// var DDP = require('./uniload.js').load({
// packages: ['ddp'],
// release: release.current.name
// }).ddp.DDP;
// var reverse = DDP.connect('reverse.meteor.com');
// console.log(reverse.call('reverse', 'hello world'));
var cacheRelease = undefined;
var cache = {}; // map from package names (joined with ',') to return value
var load = function (options) {
options = options || {};
// Check the cache first
var cacheKey = (options.packages || []).join(',');
if (_.has(cache, cacheKey)) {
return cache[cacheKey];
}
var undeclaredPackages = _.difference(options.packages, ROOT_PACKAGES);
if (undeclaredPackages.length) {
throw new Error("attempt to uniload undeclared packages: " +
JSON.stringify(undeclaredPackages));
}
// Set up a minimal server-like environment (omitting the parts that
// are specific to the HTTP server). Kind of a hack. I suspect this
// will get refactored before too long. Note that
// __meteor_bootstrap__.require is no longer provided.
var env = {
__meteor_bootstrap__: { startupHooks: [] },
__meteor_runtime_config__: { meteorRelease: "UNILOAD" }
};
var ret;
var messages = buildmessage.capture({
title: "loading isopack"
}, function () {
// Load the code. The uniloader does not call the constraint solver, unless
// it is running from checkout, in which case it will use the constraint
// solver to build its packages in the catalog.
var loader = new packageLoader.PackageLoader({
versions: null,
catalog: catalog.uniload,
constraintSolverOpts: { ignoreProjectDeps: true }
});
// Build the bundler image.
//
// Passing in dependency versions doesn't really make any sense here. We
// don't know the previous dependencies of this package, and, anyway, if we
// are running from checkout, they are all +local, and if we are running
// from release it is a bunch of isopacks. So, we don't pass in
// dependency versions.
var image = bundler.buildJsImage({
name: "load",
packageLoader: loader,
use: options.packages || [],
catalog: catalog.uniload,
ignoreProjectDeps: true
}).image;
ret = image.load(env);
// Run any user startup hooks.
while (env.__meteor_bootstrap__.startupHooks.length) {
var hook = env.__meteor_bootstrap__.startupHooks.shift();
hook();
}
// Setting this to null tells Meteor.startup to call hooks immediately.
env.__meteor_bootstrap__.startupHooks = null;
});
if (messages.hasMessages()) {
// XXX This error handling is not the best, but this should never
// happen in a built release. In the future, the command line
// tool will be a normal Meteor app and will be built ahead of
// time like any other app and this case will disappear.
process.stderr.write("Errors prevented isopack load:\n");
process.stderr.write(messages.formatMessages());
throw new Error("isopack load failed?");
}
// Save to cache
cache[cacheKey] = ret;
return ret;
};
var uniload = exports;
_.extend(exports, {
load: load,
ROOT_PACKAGES: ROOT_PACKAGES
});