mirror of
https://github.com/meteor/meteor.git
synced 2026-05-02 03:01:46 -04:00
155 lines
4.4 KiB
JavaScript
155 lines
4.4 KiB
JavaScript
// This file needs to work in old web browsers and old node versions
|
|
// It should not use js features newer than EcmaScript 5.
|
|
//
|
|
// Handles loading linked code for packages and apps
|
|
// Ensures packages and eager requires run in the correct order
|
|
// when there is code that uses top level await
|
|
|
|
var pending = Object.create(null);
|
|
var hasOwn = Object.prototype.hasOwnProperty;
|
|
|
|
function queue(name, deps, runImage) {
|
|
pending[name] = [];
|
|
|
|
var pendingDepsCount = 0;
|
|
|
|
function onDepLoaded() {
|
|
pendingDepsCount -= 1;
|
|
|
|
if (pendingDepsCount === 0) {
|
|
load(name, runImage);
|
|
}
|
|
}
|
|
|
|
deps.forEach(function (dep) {
|
|
if (hasOwn.call(pending, dep)) {
|
|
pendingDepsCount += 1;
|
|
pending[dep].push(onDepLoaded);
|
|
} else {
|
|
// load must always be called for a package's dependencies first.
|
|
// If the package is not pending, then it must have already loaded
|
|
// or is a weak dependency, and the dependency is not being used.
|
|
}
|
|
});
|
|
|
|
if (pendingDepsCount === 0) {
|
|
load(name, runImage);
|
|
}
|
|
}
|
|
|
|
function load(name, runImage) {
|
|
var config = runImage();
|
|
|
|
runEagerModules(config, function (mainModuleExports) {
|
|
// Get the exports after the eager code has been run
|
|
var exports = config.export ? config.export() : {};
|
|
if (config.mainModulePath) {
|
|
Package._define(name, mainModuleExports, exports);
|
|
} else {
|
|
Package._define(name, exports);
|
|
}
|
|
|
|
var pendingCallbacks = pending[name];
|
|
delete pending[name];
|
|
pendingCallbacks.forEach(function (callback) {
|
|
callback();
|
|
});
|
|
});
|
|
}
|
|
|
|
function runEagerModules(config, callback) {
|
|
if (!config.eagerModulePaths) {
|
|
return callback();
|
|
}
|
|
|
|
var index = -1;
|
|
var mainExports = {};
|
|
var mainModuleAsync = false;
|
|
|
|
function evaluateNextModule() {
|
|
index += 1;
|
|
if (index === config.eagerModulePaths.length) {
|
|
if (mainModuleAsync) {
|
|
// Now that the package has loaded, mark the main module as sync
|
|
// This allows other packages and the app to `require` the package
|
|
// and for it to work the same, regardless of if it uses TLA or not
|
|
// XXX: this is a temporary hack until we find a better way to do this
|
|
const reify = config.require('/node_modules/meteor/modules/node_modules/@meteorjs/reify/lib/runtime');
|
|
reify._requireAsSync(config.mainModulePath);
|
|
}
|
|
|
|
return callback(mainExports);
|
|
}
|
|
|
|
var path = config.eagerModulePaths[index];
|
|
var exports = config.require(path);
|
|
// TODO[fibers]: retest the function checkAsyncModule. It looks like it's returning the wrong values
|
|
// returning false when exports is a promise
|
|
if (exports && exports.then) {
|
|
if (path === config.mainModulePath) {
|
|
mainModuleAsync = true;
|
|
}
|
|
|
|
// Is an async module
|
|
exports.then(function (exports) {
|
|
if (path === config.mainModulePath) {
|
|
mainExports = exports;
|
|
}
|
|
evaluateNextModule();
|
|
});
|
|
} else {
|
|
if (path === config.mainModulePath) {
|
|
mainExports = exports;
|
|
}
|
|
evaluateNextModule();
|
|
}
|
|
}
|
|
|
|
evaluateNextModule();
|
|
}
|
|
|
|
function checkAsyncModule (exports) {
|
|
// Uses descriptor to avoid running any getters
|
|
var isPromise = exports && hasOwn.call(exports, 'then') &&
|
|
typeof Object.getOwnPropertyDescriptor(exports, 'then').value === 'function';
|
|
|
|
if (!isPromise) {
|
|
return false;
|
|
}
|
|
|
|
return hasOwn.call(exports, '__reifyAsyncModule') &&
|
|
Object.getOwnPropertyDescriptor(exports, '__reifyAsyncModule');
|
|
}
|
|
|
|
// For this to be accurate, all linked files must be queued before calling this
|
|
// If all are loaded, returns null. Otherwise, returns a promise
|
|
function waitUntilAllLoaded() {
|
|
var pendingNames = Object.keys(pending);
|
|
|
|
if (pendingNames.length === 0) {
|
|
// All packages are loaded
|
|
// If there were no async packages, then there might not be a promise
|
|
// polyfill loaded either, so we don't create a promise to return
|
|
return null;
|
|
}
|
|
|
|
return new Promise(function (resolve) {
|
|
var pendingCount = pendingNames.length;
|
|
pendingNames.forEach(function (name) {
|
|
pending[name].push(function () {
|
|
pendingCount -= 1;
|
|
if (pendingCount === 0) {
|
|
resolve();
|
|
}
|
|
});
|
|
});
|
|
})
|
|
}
|
|
|
|
// Since the package.js doesn't export load or waitUntilReady
|
|
// these will never be globals in packages or apps that depend on core-runtime
|
|
Package['core-runtime'] = {
|
|
queue: queue,
|
|
waitUntilAllLoaded: waitUntilAllLoaded
|
|
};
|