Skip to content

Commit

Permalink
Get optimized builds to work with multi main apps
Browse files Browse the repository at this point in the history
Closes #823
  • Loading branch information
Manuel Mujica committed Sep 14, 2017
1 parent 5f26720 commit a20f947
Show file tree
Hide file tree
Showing 10 changed files with 268 additions and 79 deletions.
126 changes: 91 additions & 35 deletions lib/graph/slim_graph.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
var first = require("lodash/first");
var negate = require("lodash/negate");
var concat = require("lodash/concat");
var partial = require("lodash/partial");
Expand All @@ -11,23 +12,27 @@ var makeSlimConfigNode = require("../node/make_slim_config_node");
module.exports = function(options) {
var slimmedBundles = [];

var jsBundles = options.bundles
.filter(isJavaScriptBundle)
.map(function(bundle) {
bundle.nodes = bundle.nodes.filter(function(node) {
return (
!isConfigNode(options.configMain, node) && !isExcludedFromBuild(node)
);
});
return bundle;
});
if (isMultiMain(options.mains) && options.splitLoader) {
throw new Error(
[
`Cannot create slim buid; "splitLoader" is not supported in multi main apps`,
`Please, set "splitLoader" to false and try again`
].join("\n")
);
}

var otherBundles = options.bundles
.filter(negate(isJavaScriptBundle))
.map(function(bundle) {
bundle.nodes = bundle.nodes.filter(negate(isExcludedFromBuild));
return bundle;
// filter out nodes flagged to be removed from the build and config nodes
options.bundles.forEach(function(bundle) {
bundle.nodes = bundle.nodes.filter(function(node) {
return (
!isConfigNode(options.configMain, node) &&
!isExcludedFromBuild(node)
);
});
});

var jsBundles = options.bundles.filter(isJavaScriptBundle);
var nonJsBundles = options.bundles.filter(negate(isJavaScriptBundle));

var slimConfigNode = makeSlimConfigNode({
target: options.target,
Expand All @@ -47,45 +52,96 @@ module.exports = function(options) {
nodes: [],
splitLoader: true,
progressive: true,
sharedBundles: [],
target: options.target,
slimConfig: options.slimConfig,
plugins: !!otherBundles.length,
mainModuleId: options.mainModuleId
plugins: !!nonJsBundles.length,
mainModuleId: getMainModuleId(options.graph, options.mains[0])
})
])
);

slimmedBundles = concat(
loaderBundle,
jsBundles.map(partial(toSlimBundle, options.target)),
otherBundles
nonJsBundles
);
} else {
var mainBundle = jsBundles.shift();

// the main bundle includes the loader code
mainBundle.nodes = [
slimConfigNode,
makeSlimShimNode({
target: options.target,
nodes: mainBundle.nodes,
plugins: !!otherBundles.length,
slimConfig: options.slimConfig,
progressive: !!jsBundles.length,
mainModuleId: options.mainModuleId
})
];
var getMainName = function(bundle) {
return first(bundle.bundles);
};

var isEntryPointBundle = function(bundle) {
return (
bundle.bundles.length === 1 &&
includes(options.mains, getMainName(bundle))
);
};

var entryPointBundles = jsBundles.filter(isEntryPointBundle);
var secondaryBundles = jsBundles.filter(negate(isEntryPointBundle));

// each entry point bundle includes the loader code
entryPointBundles.forEach(function(bundle) {
var mainName = getMainName(bundle);

var sharedBundles = getSharedBundlesOf(
jsBundles.filter(function(b) {
return b.name !== bundle.name;
}),
mainName
);

bundle.nodes = [
slimConfigNode,
makeSlimShimNode({
nodes: bundle.nodes,
target: options.target,
sharedBundles: sharedBundles,
plugins: !!nonJsBundles.length,
slimConfig: options.slimConfig,
progressive: !!secondaryBundles.length,
mainModuleId: getMainModuleId(options.graph, mainName)
})
];

});

slimmedBundles = concat(
mainBundle,
jsBundles.map(partial(toSlimBundle, options.target)),
otherBundles
entryPointBundles,
secondaryBundles.map(partial(toSlimBundle, options.target)),
nonJsBundles
);
}

return slimmedBundles;
};

/**
* Whether there are multiple mains to be built
* @param {Array} mains
* @return {boolean}
*/
function isMultiMain(mains) {
return mains.length > 1;
}

/**
* Return the main module slim id
* @param {Object} graph
* @param {string} mainName
* @return {number} The slim id
*/
function getMainModuleId(graph, mainName) {
return graph[mainName].load.uniqueId;
}

function getSharedBundlesOf(bundles, mainName) {
return bundles.filter(function(b) {
return includes(b.bundles, mainName);
});
}

function toSlimBundle(target, bundle) {
var cloned = cloneDeep(bundle);
cloned.nodes = [makeSlimBundleNode(target, cloned)];
Expand Down
1 change: 1 addition & 0 deletions lib/node/make_slim_shim_node.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ module.exports = function(options) {
plugins: options.plugins,
splitLoader: options.splitLoader,
progressive: options.progressive,
sharedBundles: options.sharedBundles,
extensions: options.slimConfig.extensions.length,
resolve: options.slimConfig.identifiersToResolve.length
});
Expand Down
94 changes: 65 additions & 29 deletions lib/node/slim/make_shim_template.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
var first = require("lodash/first");
var template = require("lodash/template");

var slimPluginsPartial = `
Expand All @@ -19,36 +20,31 @@ var importSlimExtensionsPartial = `
});
`;

var renderMainImportPartial = function(options) {
return `
${options.target === "node" ? "module.exports = " : ""} ${
options.splitLoader ?
"stealRequire.dynamic(<%= mainModuleId %>);" :
"stealRequire(<%= mainModuleId %>);"};
`;
var importSharedBundlesPartial = function(bundles) {
// get a list of the first node ids inside the shared bundles
// stealRequire.dynamic expects node ids and not bundle ids
var ids = bundles.map(function(bundle) {
return first(bundle.nodes).load.uniqueId;
});

return `${JSON.stringify(ids)}.map(stealRequire.dynamic)`;
};

var resolveHook = {
loaderExtension: function(options) {
return `
// hook into resolve to load stuff before the graph is executed
stealRequire.resolve = function(id) {
return Promise.resolve(id);
};
${options.extensions ? importSlimExtensionsPartial : ""}
Promise.all(
(steal.identifiersToResolve || []).map(function(id) {
return stealRequire.resolve(id, steal).then(function(resolved) {
resolvedIdentifiers[id] = resolved;
});
})
).then(function() {
${renderMainImportPartial(options)}
baseResolve: `
// hook into resolve to load stuff before the graph is executed
stealRequire.resolve = function(id) {
return Promise.resolve(id);
};
`,

resolveIds: `
(steal.identifiersToResolve || []).map(function(id) {
return stealRequire.resolve(id, steal).then(function(resolved) {
resolvedIdentifiers[id] = resolved;
});
`;
},
})
`,

stealRequireExtension: `
if (moduleId === "@empty") {
Expand All @@ -61,6 +57,44 @@ var resolveHook = {
`
};

var renderMainImportPartial = function(options) {
var result;
var sharedBundles = options.sharedBundles || [];
var prefix = options.target === "node" ? "module.exports = " : "";

var importMainPartial = options.splitLoader ?
prefix + "stealRequire.dynamic(<%= mainModuleId %>);" :
prefix + "stealRequire(<%= mainModuleId %>);";

if (options.resolve && sharedBundles.length) {
result = `
var beforeMain = [];
beforeMain.concat(${resolveHook.resolveIds});
beforeMain.concat(${importSharedBundlesPartial(sharedBundles)});
Promise.all(beforeMain).then(function() {
${importMainPartial}
});
`;
} else if (options.resolve) {
result = `
Promise.all(${resolveHook.resolveIds}).then(function() {
${importMainPartial}
});
`;
} else if (sharedBundles.length) {
result = `
Promise.all(${importSharedBundlesPartial(sharedBundles)})
.then(function() {
${importMainPartial}
});
`;
} else {
result = importMainPartial;
}

return result;
};

module.exports = function(options) {
return template(`
(function(modules) {
Expand Down Expand Up @@ -98,9 +132,11 @@ module.exports = function(options) {
${renderProgressivePartial(options)}
${options.resolve ?
resolveHook.loaderExtension(options) :
renderMainImportPartial(options)}
${options.resolve ? resolveHook.baseResolve : ""};
${options.extensions ? importSlimExtensionsPartial : ""}
${renderMainImportPartial(options)}
})([
<%= args %>
]);
Expand Down
12 changes: 2 additions & 10 deletions lib/stream/slim.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ module.exports = function(options) {
try {
next(null, doSlimGrap(data, opts));
} catch (err) {
console.log(err);
next(err);
}
});
Expand All @@ -25,11 +26,11 @@ module.exports = function(options) {
function doSlimGrap(data, options) {
data.bundles = slimGraph({
graph: data.graph,
mains: data.mains,
bundles: data.bundles,
target: options.target,
baseUrl: data.loader.baseURL,
slimConfig: data.loader.slimConfig,
mainModuleId: getMainModuleId(data),
splitLoader: data.options.splitLoader,
bundlesPath: data.configuration.bundlesPath,
configMain: data.loader.configMain || "package.json!npm",
Expand All @@ -39,15 +40,6 @@ function doSlimGrap(data, options) {
return data;
}

/**
* Return the main module slim id
* @param {Object} data - The slim stream data object
* @return {number} The slim id
*/
function getMainModuleId(data) {
var mainName = data.mains[0];
return data.graph[mainName].load.uniqueId;
}

/**
* An array of module names/ids to be progressively loaded
Expand Down
10 changes: 10 additions & 0 deletions test/multi-main/slim_app_a.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<script src="./dist/bundles/app_a.js"></script>
</body>
</html>
10 changes: 10 additions & 0 deletions test/multi-main/slim_app_b.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<script src="./dist/bundles/app_b.js"></script>
</body>
</html>
10 changes: 10 additions & 0 deletions test/multi-main/slim_app_c.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<script src="./dist/bundles/app_c.js"></script>
</body>
</html>
10 changes: 10 additions & 0 deletions test/multi-main/slim_app_d.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<script src="./dist/bundles/app_d.js"></script>
</body>
</html>
2 changes: 1 addition & 1 deletion test/slim_build_conditionals_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ var testHelpers = require("./helpers");
var fileExists = require("./file_exists");
var optimize = require("../lib/build/slim");

describe("build app using steal-conditional", function() {
describe("using steal-conditional and slim builds", function() {
this.timeout(30000);

var find = testHelpers.find;
Expand Down

0 comments on commit a20f947

Please sign in to comment.