diff --git a/lib/build/slim.js b/lib/build/slim.js index 9dc7ba0f..5b7e2b28 100644 --- a/lib/build/slim.js +++ b/lib/build/slim.js @@ -17,10 +17,10 @@ var addModuleIds = require("../stream/add_module_ids"); var addBundleIds = require("../stream/add_bundle_ids"); var filterGraph = require("../stream/filter_slim_graph"); var addPluginNames = require("../stream/add_plugin_names"); +var addAtStealShim = require("../stream/add_steal_shim"); var addAtLoaderShim = require("../stream/add_loader_shim"); var cloneBuildData = require("../stream/clone_build_data"); var loadNodeBuilder = require("../stream/load_node_builder"); -var checkSlimSupport = require("../stream/check_slim_support"); var convertSlimConfig = require("../stream/convert_slim_config"); var adjustBundlesPath = require("../stream/adjust_bundles_path"); var write = require("../bundle/write_bundles").createWriteStream; @@ -60,7 +60,7 @@ module.exports = function(cfg, opts) { graph(config, options), buildType("optimize"), filterGraph(), - checkSlimSupport(), + addAtStealShim(), addAtLoaderShim(), addModuleIds(), convertSlimConfig(), diff --git a/lib/slim/checks/steal.js b/lib/slim/checks/steal.js deleted file mode 100644 index a0294acf..00000000 --- a/lib/slim/checks/steal.js +++ /dev/null @@ -1,36 +0,0 @@ -var keys = require("lodash/keys"); -var isPluginExcludedFromBuild = require("../../node/is_plugin_excluded"); - -/** - * Checks whether the @steal node is in the graph - * @param {string} configMain - The configMain module name - * @throws if @steal is found in the graph - */ -module.exports = function(configMain, graph) { - keys(graph).forEach(function(name) { - var node = graph[name]; - - // the configMain node does depend on @steal/@loader but it won't be - // included in the slim build, we can skip it. Same for plugins that - // will be only be used during the build process. - if (name === configMain || isPluginExcludedFromBuild(node)) { - return; - } - - isAtSteal(name); - node.dependencies.forEach(isAtSteal); - }); -}; - -/** - * Checks whether the module name is @steal - * @param {string} name - The module name to be checked - * @throws if the name is @steal - */ -function isAtSteal(name) { - if (name === "@steal") { - throw new Error( - `Cannot create slim build. "@steal" module is not supported` - ); - } -} diff --git a/lib/stream/add_steal_shim.js b/lib/stream/add_steal_shim.js new file mode 100644 index 00000000..c7b18883 --- /dev/null +++ b/lib/stream/add_steal_shim.js @@ -0,0 +1,103 @@ +var colors = require("colors"); +var through = require("through2"); +var keys = require("lodash/keys"); +var omit = require("lodash/omit"); +var defaultTo = require("lodash/defaultTo"); +var isPluginExcludedFromBuild = require("../node/is_plugin_excluded"); + +module.exports = function() { + return through.obj(function(data, enc, next) { + try { + next(null, addAtLoaderShim(data)); + } catch (err) { + next(err); + } + }); +}; + +/** + * Adds a node to the graph with an "@steal" shim + * @param {Object} data - The slim stream data object + * @return {Object} The mutated stream object + */ +function addAtLoaderShim(data) { + var graph = omit(data.graph, data.loader.configMain); + + if (includesAtSteal(graph)) { + console.log( + colors.yellow( + `Warning: the @steal module is not fully supported in optimized builds` + ) + ); + data.graph["@steal"] = makeShimNode(data.loader.main); + } + + return data; +} + +/** + * Looks for "@steal" in the dependency graph + * @param {Object} graph - The dependency graph + * @return {boolean} true if found, false otherwise + */ +function includesAtSteal(graph) { + var found = false; + + var isAtSteal = function(name) { + return name === "@steal"; + }; + + keys(graph).forEach(function(name) { + var node = graph[name]; + + if (isPluginExcludedFromBuild(node)) { + return; + } + + if (isAtSteal(name)) { + return (found = true); + } + + defaultTo(node.dependencies, []).forEach(function(depName) { + if (isAtSteal(depName)) { + return (found = true); + } + }); + }); + + return found; +} + +/** + * Returns an @steal shim graph node + * @param {string} main - The main module name + * @return {Object} The faux "@steal" graph node + */ +function makeShimNode(main) { + return { + bundles: [main], + dependencies: ["@loader"], + deps: ["@loader"], + load: { + address: "", + metadata: { + format: "amd", + deps: ["@loader"], + dependencies: ["@loader"] + }, + name: "@steal", + source: ` + define("@steal", ["@loader"], function(atLoader) { + var steal = {}; + + steal.loader = atLoader; + steal.done = function() { + return Promise.resolve(); + }; + + return steal; + }); + ` + } + }; +} diff --git a/test/slim/at_steal/index.html b/test/slim/at_steal/index.html new file mode 100644 index 00000000..e92fe852 --- /dev/null +++ b/test/slim/at_steal/index.html @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/test/slim/at_steal/main.js b/test/slim/at_steal/main.js new file mode 100644 index 00000000..f052df0d --- /dev/null +++ b/test/slim/at_steal/main.js @@ -0,0 +1,5 @@ +var steal = require("@steal"); + +steal.done().then(function() { + window.atSteal = steal; +}); diff --git a/test/slim/at_steal/stealconfig.js b/test/slim/at_steal/stealconfig.js new file mode 100644 index 00000000..cdda8858 --- /dev/null +++ b/test/slim/at_steal/stealconfig.js @@ -0,0 +1,8 @@ +steal.config({ + main: "main", + envs: { + "window-production": { + serviceBaseURL: "/api/production" + } + } +}); diff --git a/test/slim_build_test.js b/test/slim_build_test.js index b4490c83..d9bb505b 100644 --- a/test/slim_build_test.js +++ b/test/slim_build_test.js @@ -378,7 +378,6 @@ describe("slim builds", function() { }); }); - it("rejects build promise if unknown target passed in", function(done) { var base = path.join(__dirname, "slim", "basics"); var config = { config: path.join(base, "stealconfig.js") }; @@ -643,4 +642,37 @@ describe("slim builds", function() { }); }); }); + + it("has partial support for @steal usage", function() { + var base = path.join(__dirname, "slim", "at_steal"); + var config = { config: path.join(base, "stealconfig.js") }; + + return rmdir(path.join(base, "dist")) + .then(function() { + return optimize(config, { minify: false, quiet: true }); + }) + .then(function() { + return open(path.join("test", "slim", "at_steal", "index.html")); + }) + .then(function(args) { + return Promise.all([args.close, find(args.browser, "atSteal")]); + }) + .then(function(data) { + var close = data[0]; + var atSteal = data[1]; + + assert.ok( + typeof steal.done === "function", + "should include a .done function" + ); + + assert.equal( + atSteal.loader.serviceBaseURL, + "/api/production", + "should include @loader properties" + ); + + close(); + }); + }); }); diff --git a/test/slim_support_checks_test.js b/test/slim_support_checks_test.js deleted file mode 100644 index 6dabc416..00000000 --- a/test/slim_support_checks_test.js +++ /dev/null @@ -1,27 +0,0 @@ -var assert = require("assert"); - -describe("slim support checks", function() { - describe("checkSteal", function() { - var checkSteal = require("../lib/slim/checks/steal"); - - it("throws if @steal is in the graph", function() { - assert.throws( - function() { - checkSteal("stealconfig.js", { - main: { - dependencies: ["@steal"] - }, - "stealconfig.js": {} - }); - }, - function(err) { - return /"@steal" module is not supported/.test(err.message); - } - ); - }); - - it("does not throw if @steal missing from graph", function() { - assert.equal(checkSteal({}), undefined); - }); - }); -}); diff --git a/test/test.js b/test/test.js index 5ca1038a..75293ca7 100644 --- a/test/test.js +++ b/test/test.js @@ -14,7 +14,6 @@ require("./cli/make_outputs_test"); require("./cli/cmd_live_test"); require("./get_es_module_imports_test"); require("./cli/make_build_options_test"); -require("./slim_support_checks_test"); require("./slim_build_conditionals_test"); // Integration tests