mirror of
https://github.com/zhigang1992/react-native.git
synced 2026-05-22 03:27:35 +08:00
Summary: The `BundlesLayout` will be used as a persistent index. As such, it would be easier to avoid having dependencies to `Module`, `Package`, `Asset`, etc. We're not using that information for now and if we happen to need to use it we could always fetch it using the `ModuleCache`.
118 lines
3.3 KiB
JavaScript
118 lines
3.3 KiB
JavaScript
/**
|
|
* Copyright (c) 2015-present, Facebook, Inc.
|
|
* All rights reserved.
|
|
*
|
|
* This source code is licensed under the BSD-style license found in the
|
|
* LICENSE file in the root directory of this source tree. An additional grant
|
|
* of patent rights can be found in the PATENTS file in the same directory.
|
|
*/
|
|
'use strict';
|
|
|
|
const _ = require('underscore');
|
|
const declareOpts = require('../lib/declareOpts');
|
|
|
|
const validateOpts = declareOpts({
|
|
dependencyResolver: {
|
|
type: 'object',
|
|
required: true,
|
|
},
|
|
});
|
|
|
|
const BUNDLE_PREFIX = 'bundle';
|
|
|
|
/**
|
|
* Class that takes care of separating the graph of dependencies into
|
|
* separate bundles
|
|
*/
|
|
class BundlesLayout {
|
|
constructor(options) {
|
|
const opts = validateOpts(options);
|
|
this._resolver = opts.dependencyResolver;
|
|
|
|
this._moduleToBundle = Object.create(null);
|
|
}
|
|
|
|
generateLayout(entryPaths, isDev) {
|
|
var currentBundleID = 0;
|
|
const rootBundle = {
|
|
id: BUNDLE_PREFIX + '.' + currentBundleID++,
|
|
modules: [],
|
|
children: [],
|
|
};
|
|
var pending = [{paths: entryPaths, bundle: rootBundle}];
|
|
|
|
return promiseWhile(
|
|
() => pending.length > 0,
|
|
() => rootBundle,
|
|
() => {
|
|
const {paths, bundle} = pending.shift();
|
|
|
|
// pending sync dependencies we still need to explore for the current
|
|
// pending dependency
|
|
const pendingSyncDeps = paths;
|
|
|
|
// accum variable for sync dependencies of the current pending
|
|
// dependency we're processing
|
|
const syncDependencies = Object.create(null);
|
|
|
|
return promiseWhile(
|
|
() => pendingSyncDeps.length > 0,
|
|
() => {
|
|
const dependencies = Object.keys(syncDependencies);
|
|
if (dependencies.length > 0) {
|
|
bundle.modules = dependencies;
|
|
}
|
|
},
|
|
index => {
|
|
const pendingSyncDep = pendingSyncDeps.shift();
|
|
return this._resolver
|
|
.getDependencies(pendingSyncDep, {dev: isDev})
|
|
.then(deps => {
|
|
deps.dependencies.forEach(dep => {
|
|
if (dep.path !== pendingSyncDep && !dep.isPolyfill()) {
|
|
pendingSyncDeps.push(dep.path);
|
|
}
|
|
syncDependencies[dep.path] = true;
|
|
this._moduleToBundle[dep.path] = bundle.id;
|
|
});
|
|
deps.asyncDependencies.forEach(asyncDeps => {
|
|
const childBundle = {
|
|
id: bundle.id + '.' + currentBundleID++,
|
|
modules: [],
|
|
children: [],
|
|
};
|
|
|
|
bundle.children.push(childBundle);
|
|
pending.push({paths: asyncDeps, bundle: childBundle});
|
|
});
|
|
});
|
|
},
|
|
);
|
|
},
|
|
);
|
|
}
|
|
|
|
getBundleIDForModule(path) {
|
|
return this._moduleToBundle[path];
|
|
}
|
|
}
|
|
|
|
// Runs the body Promise meanwhile the condition callback is satisfied.
|
|
// Once it's not satisfied anymore, it returns what the results callback
|
|
// indicates
|
|
function promiseWhile(condition, result, body) {
|
|
return _promiseWhile(condition, result, body, 0);
|
|
}
|
|
|
|
function _promiseWhile(condition, result, body, index) {
|
|
if (!condition()) {
|
|
return Promise.resolve(result());
|
|
}
|
|
|
|
return body(index).then(() =>
|
|
_promiseWhile(condition, result, body, index + 1)
|
|
);
|
|
}
|
|
|
|
module.exports = BundlesLayout;
|