faucet-pipeline-js
Version:
JavaScript module bundling for faucet-pipeline
437 lines (369 loc) • 11.8 kB
JavaScript
/* global describe, it, beforeEach, afterEach */
"use strict";
let { MockAssetManager, makeBundle, FIXTURES_DIR } = require("./util");
let faucetJS = require("../../lib");
let path = require("path");
let assert = require("assert");
let DEFAULT_OPTIONS = {
browsers: {}
};
describe("bundling", _ => {
let { exit } = process;
beforeEach(() => {
process.exit = code => {
throw new Error(`exit ${code}`);
};
});
afterEach(() => {
process.exit = exit;
});
it("should verify configuration", () => {
let config = [{}];
let assetManager = new MockAssetManager(FIXTURES_DIR);
let fn = _ => faucetJS(config, assetManager, DEFAULT_OPTIONS)();
assert.throws(fn, /exit 1/); // aborts with "missing `source` configuration"
config[0].source = "./src/index.js";
assert.throws(fn, /exit 1/); // aborts with "missing `target` configuration"
});
it("should combine ES6 modules into a bundle", () => {
let config = [{
source: "./src/index.js",
target: "./dist/bundle.js"
}];
let assetManager = new MockAssetManager(FIXTURES_DIR);
return faucetJS(config, assetManager, DEFAULT_OPTIONS)().
then(_ => {
assetManager.assertWrites([{
filepath: path.resolve(FIXTURES_DIR, "./dist/bundle.js"),
content: makeBundle(`
var util = "UTIL";
console.log(\`[…] $\{util}\`); // eslint-disable-line no-console
`.trim())
}]);
});
});
it("should optionally transpile ES6 to ES5", () => {
let config = [{
source: "./src/index.js",
target: "./dist/bundle.js",
esnext: true
}];
let assetManager = new MockAssetManager(FIXTURES_DIR);
return faucetJS(config, assetManager, DEFAULT_OPTIONS)().
then(_ => {
assetManager.assertWrites([{
filepath: path.resolve(FIXTURES_DIR, "./dist/bundle.js"),
content: makeBundle(`
var util = "UTIL";
console.log("[\\u2026] ".concat(util)); // eslint-disable-line no-console
`.trim())
}]);
});
});
it("should support skipping transpilation for select packages", () => {
let cwd = process.cwd();
process.chdir(FIXTURES_DIR); // XXX: should not be test-specific!?
let restore = _ => process.chdir(cwd);
let config = [{
source: "./src/alt2.js",
target: "./dist/bundle.js",
esnext: {
exclude: ["my-lib"]
}
}];
let assetManager = new MockAssetManager(FIXTURES_DIR);
return faucetJS(config, assetManager, DEFAULT_OPTIONS)().
then(restore, restore). // XXX: hacky
then(_ => {
assetManager.assertWrites([{
filepath: path.resolve(FIXTURES_DIR, "./dist/bundle.js"),
/* eslint-disable max-len */
content: makeBundle(`
function createCommonjsModule(fn, module) {
return module = { exports: {} }, fn(module, module.exports), module.exports;
}
var dist = createCommonjsModule(function (module) {
/* eslint-disable */
(function(window) {
var MYLIB = "MY-LIB";
{
module.exports = MYLIB;
}
}());
});
console.log("[\\u2026] ".concat(dist)); // eslint-disable-line no-console
`.trim())
/* eslint-enable max-len */
}]);
});
});
it("should support custom file extensions", () => {
let config = [{
source: "./src/index.coffee",
target: "./dist/bundle.js",
extensions: [".coffee"]
}];
let assetManager = new MockAssetManager(FIXTURES_DIR);
return faucetJS(config, assetManager, DEFAULT_OPTIONS)().
then(_ => {
assetManager.assertWrites([{
filepath: path.resolve(FIXTURES_DIR, "./dist/bundle.js"),
content: makeBundle(`
var helper = { foo: "lorem", bar: "ipsum" };
console.log(\`[…] $\{helper}\`); // eslint-disable-line no-console
`.trim())
}]);
});
});
it("should support customizing bundle's API", () => {
let config = [{
source: "./src/lib.js",
target: "./dist/bundle.js",
exports: "MYLIB"
}];
let assetManager = new MockAssetManager(FIXTURES_DIR);
return faucetJS(config, assetManager, DEFAULT_OPTIONS)().
then(_ => {
assetManager.assertWrites([{
filepath: path.resolve(FIXTURES_DIR, "./dist/bundle.js"),
content: "var MYLIB = " + makeBundle(`
var util = "UTIL";
var lib = msg => {
console.log(\`[…] $\{util} $\{msg}\`); // eslint-disable-line no-console
};
return lib;
`.trim())
}]);
});
});
it("should support customizing bundle format", () => {
let config = [{
source: "./src/lib.js",
target: "./dist/bundle.js",
format: "amd"
}];
let assetManager = new MockAssetManager(FIXTURES_DIR);
return faucetJS(config, assetManager, DEFAULT_OPTIONS)().
then(_ => {
assetManager.assertWrites([{
filepath: path.resolve(FIXTURES_DIR, "./dist/bundle.js"),
content: `
define(function () { 'use strict';
var util = "UTIL";
var lib = msg => {
console.log(\`[…] $\{util} $\{msg}\`); // eslint-disable-line no-console
};
return lib;
});
`.trim() + "\n"
}]);
});
});
it("should support importing third-party packages", () => {
let config = [{
source: "./src/alt.js",
target: "./dist/bundle.js"
}];
let assetManager = new MockAssetManager(FIXTURES_DIR);
return faucetJS(config, assetManager, DEFAULT_OPTIONS)().
then(_ => {
assetManager.assertWrites([{
filepath: path.resolve(FIXTURES_DIR, "./dist/bundle.js"),
content: makeBundle(`
var MYLIB = "MY-LIB";
console.log(\`[…] $\{MYLIB}\`); // eslint-disable-line no-console
`.trim())
}]);
});
});
it("should support excluding module/package references", () => {
let config = [{
source: "./src/alt.js",
target: "./dist/bundle.js",
externals: { "my-lib": "MYLIB" }
}];
let assetManager = new MockAssetManager(FIXTURES_DIR);
return faucetJS(config, assetManager, DEFAULT_OPTIONS)().
then(_ => {
assetManager.assertWrites([{
filepath: path.resolve(FIXTURES_DIR, "./dist/bundle.js"),
content: `
(function (MYLIB) {
'use strict';
MYLIB = MYLIB && MYLIB.hasOwnProperty('default') ? MYLIB['default'] : MYLIB;
console.log(\`[…] $\{MYLIB}\`); // eslint-disable-line no-console
}(MYLIB));
`.trim() + "\n"
}]);
});
});
it("should take into account Browserslist while transpiling", () => {
let config = [{
source: "./src/index.js",
target: "./dist/bundle.js",
esnext: true
}];
let assetManager = new MockAssetManager(FIXTURES_DIR);
let browsers = { defaults: ["Chrome 63"] };
return faucetJS(config, assetManager, { browsers })().
then(_ => {
assetManager.assertWrites([{
filepath: path.resolve(FIXTURES_DIR, "./dist/bundle.js"),
content: makeBundle(`
var util = "UTIL";
console.log(\`[…] $\{util}\`); // eslint-disable-line no-console
`.trim())
}]);
});
});
it("should allow suppressing Browserslist auto-config while transpiling", () => {
let config = [{
source: "./src/index.js",
target: "./dist/bundle.js",
esnext: {
browserslist: false
}
}];
let assetManager = new MockAssetManager(FIXTURES_DIR);
let browsers = { defaults: ["Chrome 63"] };
return faucetJS(config, assetManager, { browsers })().
then(_ => {
assetManager.assertWrites([{
filepath: path.resolve(FIXTURES_DIR, "./dist/bundle.js"),
content: makeBundle(`
var util = "UTIL";
console.log("[\\u2026] ".concat(util)); // eslint-disable-line no-console
`.trim())
}]);
});
});
it("should allow specifying an alternative Browserslist group", () => {
let config = [{
source: "./src/index.js",
target: "./dist/bundle.js",
esnext: {
browserslist: "modern"
}
}];
let assetManager = new MockAssetManager(FIXTURES_DIR);
let browsers = {
defaults: ["IE 11"],
modern: ["Chrome 63"]
};
return faucetJS(config, assetManager, { browsers })().
then(_ => {
assetManager.assertWrites([{
filepath: path.resolve(FIXTURES_DIR, "./dist/bundle.js"),
content: makeBundle(`
var util = "UTIL";
console.log(\`[…] $\{util}\`); // eslint-disable-line no-console
`.trim())
}]);
});
});
it("should optionally compact bundle", () => {
let config = [{
source: "./src/multiline.js",
target: "./dist/bundle.js"
}];
let assetManager = new MockAssetManager(FIXTURES_DIR);
let options = { browsers: {}, compact: true };
return faucetJS(config, assetManager, options)().
then(_ => {
assetManager.assertWrites([{
filepath: path.resolve(FIXTURES_DIR, "./dist/bundle.js"),
content: makeBundle(`let txt = \`foo
bar\`;
console.log(\`[…] $\{txt}\`);
`.trim(), { compact: true })
}]);
config[0].esnext = true;
assetManager = new MockAssetManager(FIXTURES_DIR);
return faucetJS(config, assetManager, options)();
}).
then(_ => {
assetManager.assertWrites([{
filepath: path.resolve(FIXTURES_DIR, "./dist/bundle.js"),
content: makeBundle(`
var txt = "foo\\n\\nbar";
console.log("[\\u2026] ".concat(txt));
`.trim(), { compact: true })
}]);
config[0].compact = false; // overrides global option
assetManager = new MockAssetManager(FIXTURES_DIR);
return faucetJS(config, assetManager, options)();
}).
then(_ => {
assetManager.assertWrites([{
filepath: path.resolve(FIXTURES_DIR, "./dist/bundle.js"),
content: makeBundle(`
var txt = "foo\\n\\nbar";
console.log("[\\u2026] ".concat(txt)); // eslint-disable-line no-console
`.trim())
}]);
});
});
it("should balk at non-relative paths for target", () => {
let assetManager = new MockAssetManager(FIXTURES_DIR);
let entryPoint = "src/index.js";
let target = "dist/bundle.js";
let compile = (source, target) => faucetJS([{ source, target }],
assetManager, DEFAULT_OPTIONS)();
let fn = _ => compile(`./${entryPoint}`, target);
assert.throws(fn, /exit 1/); // aborts with "path must be relative"
// non-relative path is acceptable for entry point, but a suitable
// package path does not exist
fn = _ => compile("dummy/src/does_not_exist.js", `./${target}`);
assert.throws(fn, /exit 1/); // aborts with "could not resolve"
return compile(`./${entryPoint}`, `./${target}`);
});
it("should support Node resolution algorithm for entry point", () => {
let entryPoint = "dummy/src/index.js";
let target = "./dist/bundle.js";
let assetManager = new MockAssetManager(FIXTURES_DIR);
let compile = (source, target) => faucetJS([{ source, target }],
assetManager, DEFAULT_OPTIONS)();
return compile(entryPoint, target).
then(_ => {
assetManager.assertWrites([{
filepath: path.resolve(FIXTURES_DIR, "./dist/bundle.js"),
content: makeBundle(`
var util = "DUMMY-UTIL";
console.log(\`[DUMMY] $\{util}\`); // eslint-disable-line no-console
`.trim())
}]);
let fn = _ => compile("dummy/src/does_not_exist.js", target);
assert.throws(fn, /exit 1/); // aborts with "could not resolve"
fn = _ => compile(entryPoint, "dist/bundle.js");
assert.throws(fn, /exit 1/); // aborts with "path must be relative"
});
});
it("should build when the provided path is part of the bundle", () => {
let config = [{
source: "./src/index.js",
target: "./dist/bundle.js"
}];
let assetManager = new MockAssetManager(FIXTURES_DIR);
let buildJS = faucetJS(config, assetManager, DEFAULT_OPTIONS);
let relevantModule = path.join(FIXTURES_DIR, "src/util.js");
return buildJS().
then(_ => buildJS([relevantModule])).
then(_ => {
assetManager.assertWriteCount(2);
});
});
it("should not build when the provided path is not part of the bundle", () => {
let config = [{
source: "./src/index.js",
target: "./dist/bundle.js"
}];
let assetManager = new MockAssetManager(FIXTURES_DIR);
let buildJS = faucetJS(config, assetManager, DEFAULT_OPTIONS);
let unusedModule = path.join(FIXTURES_DIR, "src/alt.js");
return buildJS().
then(_ => buildJS([unusedModule])).
then(_ => {
assetManager.assertWriteCount(1);
});
});
});