From fba127f5d6df2e7c367153659c97313a23ea2fbc Mon Sep 17 00:00:00 2001 From: Chunpeng Huo Date: Mon, 23 Dec 2024 09:29:42 +1000 Subject: [PATCH] fix: fix local require check in npm package --- lib/index.js | 6 +- lib/modules-todo.js | 23 +- test/bundler.esm.spec.js | 265 +-- test/bundler.spec.js | 3249 ++++++++++++++++++++----------------- test/mock.js | 39 + test/modules-todo.spec.js | 56 +- 6 files changed, 2024 insertions(+), 1614 deletions(-) diff --git a/lib/index.js b/lib/index.js index 3b4d551..1015769 100644 --- a/lib/index.js +++ b/lib/index.js @@ -265,6 +265,7 @@ module.exports = class Bundler { const checkUserSpace = opts.user; const checkPackageSpace = opts.package; const requiredBy = opts.requiredBy; + const isRelative = opts.isRelative; const parsedId = parse(mapId(id, this._paths)); if (parsedId.bareId.match(/^(?:https?:)?\//)) { @@ -338,11 +339,8 @@ module.exports = class Bundler { }); } - const parsedRequiredBy = requiredBy.map(id => parse(mapId(id, this._paths))); - const isLocalRequire = parsedRequiredBy.findIndex(parsed => parsed.parts[0] === packageName) !== -1; - return this.packageReaderFor(stub || {name: packageName}) - .then(reader => resource ? reader.readResource(resource, isLocalRequire) : reader.readMain()) + .then(reader => resource ? reader.readResource(resource, isRelative) : reader.readMain()) .then(unit => this.capture(unit)) .catch(err => { error('Resolving failed for module ' + bareId); diff --git a/lib/modules-todo.js b/lib/modules-todo.js index 00ca8c6..6a52cd2 100644 --- a/lib/modules-todo.js +++ b/lib/modules-todo.js @@ -26,6 +26,7 @@ module.exports = class ModulesTodo { const {moduleId, packageName, deps} = unit; deps.forEach(d => { + const isRelative = parse(d).bareId.startsWith('.') ? 1 : 0; const parsedId = parse(resolveModuleId(moduleId, d)); if (!parsedId.prefix && ( @@ -41,7 +42,7 @@ module.exports = class ModulesTodo { let space; if (packageName) { space = PACKAGE; - } else if (isRelative(d)) { + } else if (isRelative) { // local relative space = USER; } else { @@ -58,12 +59,13 @@ module.exports = class ModulesTodo { let pluginSpace = space; if (space !== PACKAGE) pluginSpace = USER_OR_PACKAGE; - const key = pluginSpace + ':' + pluginName; + const isRelativePlugin = pluginName.startsWith('.') ? 1 : 0; + const key = pluginSpace + ':' + pluginName + ':' + isRelativePlugin; if (!this.todos[key]) this.todos[key] = []; this.todos[key].push(moduleId); } - const key = space + ':' + parsedId.cleanId; + const key = space + ':' + parsedId.cleanId + ':' + isRelative; if (!this.todos[key]) this.todos[key] = []; this.todos[key].push(moduleId); }); @@ -85,7 +87,7 @@ module.exports = class ModulesTodo { groups[SERIAL_GROUP] = []; keys.forEach(key => { - const [space, id] = spaceAndId(key); + const [space, id] = key.split(':'); // Don't need the parallel optimization when running // in nodejs. @@ -106,13 +108,14 @@ module.exports = class ModulesTodo { let p = Promise.resolve(); keys.forEach(key => { - const [space, id] = spaceAndId(key); + const [space, id, isRelative] = key.split(':'); const requiredBy = todos[key]; p = p.then(() => cb(id, { user: space !== PACKAGE, package: space !== USER, - requiredBy + requiredBy, + isRelative: isRelative === '1' })); }); @@ -120,11 +123,3 @@ module.exports = class ModulesTodo { })); } }; - -function spaceAndId(key) { - return [key.slice(0, 1), key.slice(2)]; -} - -function isRelative(id) { - return parse(id).bareId.startsWith('.'); -} diff --git a/test/bundler.esm.spec.js b/test/bundler.esm.spec.js index 1019716..0dc17d4 100644 --- a/test/bundler.esm.spec.js +++ b/test/bundler.esm.spec.js @@ -1,118 +1,197 @@ -const {test} = require('zora'); -const Bundler = require('../lib/index'); -const {contentOrFile} = require('../lib/shared'); -const {mockResolve, buildReadFile, mockPackageFileReader} = require('./mock'); +const { test } = require("zora"); +const { mockBundler } = require("./mock"); -function mockContentOrFile(fakeReader) { - return pathOrContent => contentOrFile(pathOrContent, {readFile: fakeReader}); -} - -function deleteSourceMap(file) { - delete file.sourceMap; -} - -function createBundler(fakeFs = {}, opts = {}) { - // don't use cache in test - if (!opts.cache) opts.cache = false; - const fakeReader = buildReadFile(fakeFs); - opts.packageFileReader = mockPackageFileReader(fakeReader); - - const bundler = new Bundler(opts, { - resolve: mockResolve, - contentOrFile: mockContentOrFile(fakeReader) +test("Bundler traces mixed mjs and cjs npm packages", async (t) => { + const fakeFs = { + "local/setup.js": "setup", + "local/after.js": "after", + "node_modules/dumber-module-loader/dist/index.debug.js": + "dumber-module-loader", + "node_modules/foo/package.json": JSON.stringify({ + name: "foo", + main: "index.cjs", + }), + "node_modules/foo/index.cjs": "require('loo');", + "node_modules/loo/package.json": JSON.stringify({ + name: "loo", + main: "./loo.mjs", + }), + "node_modules/loo/loo.mjs": "", + }; + const bundler = mockBundler(fakeFs, { + prepends: ["var pre = 1;", "", undefined, false, "local/setup.js", null], + appends: ["local/after.js", "var ape = 1;"], }); - const oldBundle = bundler.bundle.bind(bundler); - bundler.bundle = function() { - // don't test source map - const bundleMap = oldBundle(); - Object.keys(bundleMap).forEach(key => { - if (bundleMap[key].files) { - bundleMap[key].files.forEach(deleteSourceMap); - } - if (bundleMap[key].appendFiles) { - bundleMap[key].appendFiles.forEach(deleteSourceMap); - } - }); - return bundleMap; - }; - return bundler; -} + return Promise.resolve() + .then(() => + bundler.capture({ + path: "src/app.js", + contents: "require('foo');", + moduleId: "app.js", + }) + ) + .then(() => bundler.resolve()) + .then(() => bundler.bundle()) + .then( + (bundleMap) => { + t.deepEqual(bundleMap, { + "entry-bundle": { + files: [ + { + contents: "var pre = 1;", + }, + { + path: "local/setup.js", + contents: "setup;", + }, + { + path: "node_modules/dumber-module-loader/dist/index.debug.js", + contents: "dumber-module-loader;", + }, + { + contents: "define.switchToUserSpace();", + }, + { + path: "src/app.js", + contents: + "define('app.js',['require','exports','module','foo'],function (require, exports, module) {\nrequire('foo');\n});\n", + }, + { + contents: "define.switchToPackageSpace();", + }, + { + path: "node_modules/foo/index.cjs", + contents: + "define('foo/index.cjs',['require','exports','module','loo'],function (require, exports, module) {\nrequire('loo');\n});\n\n;define.alias('foo','foo/index.cjs');", + }, + { + path: "node_modules/loo/loo.mjs", + contents: + "define('loo/loo.mjs',['require','exports','module'],function (require, exports, module) {\n\n});\n\n;define.alias('loo','loo/loo.mjs');", + }, + { + contents: "define.switchToUserSpace();", + }, + ], + appendFiles: [ + { + path: "local/after.js", + contents: "after;", + }, + { + contents: "var ape = 1;", + }, + ], + config: { + baseUrl: "/dist", + paths: {}, + bundles: {}, + }, + }, + }); + }, + (err) => t.fail(err.stack) + ); +}); -test('Bundler traces mixed mjs and cjs npm packages', async t => { +test("Bundler bundles npm package with exports field", async (t) => { const fakeFs = { - 'local/setup.js': 'setup', - 'local/after.js': 'after', - 'node_modules/dumber-module-loader/dist/index.debug.js': 'dumber-module-loader', - 'node_modules/foo/package.json': JSON.stringify({name: 'foo', main: 'index.cjs'}), - 'node_modules/foo/index.cjs': "require('loo');", - 'node_modules/loo/package.json': JSON.stringify({name: 'loo', main: './loo.mjs'}), - 'node_modules/loo/loo.mjs': '', + "node_modules/dumber-module-loader/dist/index.debug.js": + "dumber-module-loader", + "node_modules/esm-env/package.json": JSON.stringify({ + name: "esm-env", + type: "module", + exports: { + ".": { + types: "./index.d.ts", + default: "./index.js", + }, + "./browser": { + browser: "./true.js", + development: "./false.js", + production: "./false.js", + default: "./browser-fallback.js", + }, + "./development": { + development: "./true.js", + production: "./false.js", + default: "./dev-fallback.js", + }, + "./node": { + node: "./true.js", + default: "./false.js", + }, + }, + }), + "node_modules/esm-env/index.js": `export { default as BROWSER } from 'esm-env/browser'; +export { default as DEV } from 'esm-env/development'; +export { default as NODE } from 'esm-env/node'; +`, + "node_modules/esm-env/true.js": "export default true;\n", + "node_modules/esm-env/false.js": "export default false;\n", + "node_modules/esm-env/dev-fallback.js": + "export default typeof DEV !== 'undefined';\n", }; - const bundler = createBundler(fakeFs, { - prepends: ['var pre = 1;', '', undefined, false, 'local/setup.js', null], - appends: ['local/after.js', 'var ape = 1;'] + + const bundler = mockBundler(fakeFs, { + onRequire: (id) => { + if (id.startsWith("tslib")) { + return false; + } + }, }); return Promise.resolve() - .then(() => bundler.capture({path: 'src/app.js', contents: "require('foo');", moduleId: 'app.js'})) - .then(() => bundler.resolve()) - .then(() => bundler.bundle()) - .then( - bundleMap => { + .then(() => + bundler.capture({ + path: "src/app.js", + contents: + "import {BROWSER, DEV, NODE} from 'esm-env';\nconsole.log(BROWSER, DEV, NODE);\n", + moduleId: "app.js", + }) + ) + .then(() => bundler.resolve()) + .then(() => bundler.bundle()) + .then((bundleMap) => { t.deepEqual(bundleMap, { "entry-bundle": { - "files": [ - { - "contents": "var pre = 1;" - }, - { - "path": "local/setup.js", - "contents": "setup;" - }, - { - "path": "node_modules/dumber-module-loader/dist/index.debug.js", - "contents": "dumber-module-loader;" - }, + files: [ { - "contents": "define.switchToUserSpace();" + path: "node_modules/dumber-module-loader/dist/index.debug.js", + contents: "dumber-module-loader;", }, + { contents: "define.switchToUserSpace();" }, { - "path": "src/app.js", - "contents": "define('app.js',['require','exports','module','foo'],function (require, exports, module) {\nrequire('foo');\n});\n" + path: "src/app.js", + contents: + "define('app.js',['require','exports','module','esm-env'],function (require, exports, module) {\n\"use strict\";\nObject.defineProperty(exports, \"__esModule\", { value: true });\nconst esm_env_1 = require(\"esm-env\");\nconsole.log(esm_env_1.BROWSER, esm_env_1.DEV, esm_env_1.NODE);\n\n});\n", }, + { contents: "define.switchToPackageSpace();" }, { - "contents": "define.switchToPackageSpace();" + path: "node_modules/esm-env/dev-fallback.js", + contents: + "define('esm-env/dev-fallback.js',['require','exports','module'],function (require, exports, module) {\n\"use strict\";\nObject.defineProperty(exports, \"__esModule\", { value: true });\nexports.default = typeof DEV !== 'undefined';\n\n});\n\n;define.alias('esm-env/development','esm-env/dev-fallback.js');", }, { - "path": "node_modules/foo/index.cjs", - "contents": "define('foo/index.cjs',['require','exports','module','loo'],function (require, exports, module) {\nrequire('loo');\n});\n\n;define.alias('foo','foo/index.cjs');" + path: "node_modules/esm-env/false.js", + contents: + "define('esm-env/false.js',['require','exports','module'],function (require, exports, module) {\n\"use strict\";\nObject.defineProperty(exports, \"__esModule\", { value: true });\nexports.default = false;\n\n});\n\n;define.alias('esm-env/node','esm-env/false.js');", }, { - "path": "node_modules/loo/loo.mjs", - "contents": "define('loo/loo.mjs',['require','exports','module'],function (require, exports, module) {\n\n});\n\n;define.alias('loo','loo/loo.mjs');" + path: "node_modules/esm-env/index.js", + contents: + "define('esm-env/index.js',['require','exports','module','tslib','esm-env/browser','esm-env/development','esm-env/node'],function (require, exports, module) {\n\"use strict\";\nObject.defineProperty(exports, \"__esModule\", { value: true });\nexports.NODE = exports.DEV = exports.BROWSER = void 0;\nconst tslib_1 = require(\"tslib\");\nvar browser_1 = require(\"esm-env/browser\");\nObject.defineProperty(exports, \"BROWSER\", { enumerable: true, get: function () { return tslib_1.__importDefault(browser_1).default; } });\nvar development_1 = require(\"esm-env/development\");\nObject.defineProperty(exports, \"DEV\", { enumerable: true, get: function () { return tslib_1.__importDefault(development_1).default; } });\nvar node_1 = require(\"esm-env/node\");\nObject.defineProperty(exports, \"NODE\", { enumerable: true, get: function () { return tslib_1.__importDefault(node_1).default; } });\n\n});\n\n;define.alias('esm-env','esm-env/index.js');", }, { - "contents": "define.switchToUserSpace();" - } - ], - "appendFiles": [ - { - "path": "local/after.js", - "contents": "after;" + path: "node_modules/esm-env/true.js", + contents: + "define('esm-env/true.js',['require','exports','module'],function (require, exports, module) {\n\"use strict\";\nObject.defineProperty(exports, \"__esModule\", { value: true });\nexports.default = true;\n\n});\n\n;define.alias('esm-env/browser','esm-env/true.js');", }, - { - "contents": "var ape = 1;" - } + { contents: "define.switchToUserSpace();" }, ], - "config": { - "baseUrl": "/dist", - "paths": {}, - "bundles": {} - } - } - }) - }, - err => t.fail(err.stack) - ); + config: { baseUrl: "/dist", paths: {}, bundles: {} }, + }, + }); + }); }); diff --git a/test/bundler.spec.js b/test/bundler.spec.js index 61e0613..e432ac5 100644 --- a/test/bundler.spec.js +++ b/test/bundler.spec.js @@ -1,1661 +1,1960 @@ -const {test} = require('zora'); -const Bundler = require('../lib/index'); -const {contentOrFile} = require('../lib/shared'); -const {mockResolve, buildReadFile, mockPackageFileReader} = require('./mock'); +const { test } = require("zora"); +const { mockBundler } = require("./mock"); -function mockContentOrFile(fakeReader) { - return pathOrContent => contentOrFile(pathOrContent, {readFile: fakeReader}); -} - -function deleteSourceMap(file) { - delete file.sourceMap; -} - -function createBundler(fakeFs = {}, opts = {}) { - // don't use cache in test - if (!opts.cache) opts.cache = false; - const fakeReader = buildReadFile(fakeFs); - opts.packageFileReader = mockPackageFileReader(fakeReader); - - const bundler = new Bundler(opts, { - resolve: mockResolve, - contentOrFile: mockContentOrFile(fakeReader) - }); - - const oldBundle = bundler.bundle.bind(bundler); - bundler.bundle = function() { - // don't test source map - const bundleMap = oldBundle(); - Object.keys(bundleMap).forEach(key => { - if (bundleMap[key].files) { - bundleMap[key].files.forEach(deleteSourceMap); - } - if (bundleMap[key].appendFiles) { - bundleMap[key].appendFiles.forEach(deleteSourceMap); - } - }); - return bundleMap; - }; - return bundler; -} - -test('Bundler traces files', async t => { +test("Bundler traces files", async (t) => { const fakeFs = { - 'local/setup.js': 'setup', - 'local/after.js': 'after', - 'node_modules/dumber-module-loader/dist/index.debug.js': 'dumber-module-loader', - 'node_modules/foo/package.json': JSON.stringify({name: 'foo', main: 'index'}), - 'node_modules/foo/index.js': "require('loo');", - 'node_modules/foo/bar.js': '', - 'node_modules/loo/package.json': JSON.stringify({name: 'loo', main: './loo'}), - 'node_modules/loo/loo.js': '', + "local/setup.js": "setup", + "local/after.js": "after", + "node_modules/dumber-module-loader/dist/index.debug.js": + "dumber-module-loader", + "node_modules/foo/package.json": JSON.stringify({ + name: "foo", + main: "index", + }), + "node_modules/foo/index.js": "require('loo');", + "node_modules/foo/bar.js": "", + "node_modules/loo/package.json": JSON.stringify({ + name: "loo", + main: "./loo", + }), + "node_modules/loo/loo.js": "", }; - const bundler = createBundler(fakeFs, { - prepends: ['var pre = 1;', '', undefined, false, 'local/setup.js', null], - appends: ['local/after.js', 'var ape = 1;'] + const bundler = mockBundler(fakeFs, { + prepends: ["var pre = 1;", "", undefined, false, "local/setup.js", null], + appends: ["local/after.js", "var ape = 1;"], }); return Promise.resolve() - .then(() => bundler.capture({path: 'src/app.js', contents: "require('foo');require('page/one');", moduleId: 'app.js'})) - .then(() => bundler.capture({path: 'src/page/one.js', contents: "require('foo/bar');require('loo');", moduleId: 'page/one.js'})) - .then(() => bundler.resolve()) - .then(() => bundler.bundle()) - .then( - bundleMap => { - t.deepEqual(bundleMap, { - "entry-bundle": { - "files": [ - { - "contents": "var pre = 1;" - }, - { - "path": "local/setup.js", - "contents": "setup;" - }, - { - "path": "node_modules/dumber-module-loader/dist/index.debug.js", - "contents": "dumber-module-loader;" - }, - { - "contents": "define.switchToUserSpace();" - }, - { - "path": "src/app.js", - "contents": "define('app.js',['require','exports','module','foo','page/one'],function (require, exports, module) {\nrequire('foo');require('page/one');\n});\n" - }, - { - "path": "src/page/one.js", - "contents": "define('page/one.js',['require','exports','module','foo/bar','loo'],function (require, exports, module) {\nrequire('foo/bar');require('loo');\n});\n" - }, - { - "contents": "define.switchToPackageSpace();" - }, - { - "path": "node_modules/foo/bar.js", - "contents": "define('foo/bar.js',['require','exports','module'],function (require, exports, module) {\n\n});\n" - }, - { - "path": "node_modules/foo/index.js", - "contents": "define('foo/index.js',['require','exports','module','loo'],function (require, exports, module) {\nrequire('loo');\n});\n\n;define.alias('foo','foo/index.js');" - }, - { - "path": "node_modules/loo/loo.js", - "contents": "define('loo/loo.js',['require','exports','module'],function (require, exports, module) {\n\n});\n\n;define.alias('loo','loo/loo.js');" - }, - { - "contents": "define.switchToUserSpace();" - } - ], - "appendFiles": [ - { - "path": "local/after.js", - "contents": "after;" - }, - { - "contents": "var ape = 1;" - } - ], - "config": { - "baseUrl": "/dist", - "paths": {}, - "bundles": {} - } - } + .then(() => + bundler.capture({ + path: "src/app.js", + contents: "require('foo');require('page/one');", + moduleId: "app.js", }) - }, - err => t.fail(err.stack) - ); + ) + .then(() => + bundler.capture({ + path: "src/page/one.js", + contents: "require('foo/bar');require('loo');", + moduleId: "page/one.js", + }) + ) + .then(() => bundler.resolve()) + .then(() => bundler.bundle()) + .then( + (bundleMap) => { + t.deepEqual(bundleMap, { + "entry-bundle": { + files: [ + { + contents: "var pre = 1;", + }, + { + path: "local/setup.js", + contents: "setup;", + }, + { + path: "node_modules/dumber-module-loader/dist/index.debug.js", + contents: "dumber-module-loader;", + }, + { + contents: "define.switchToUserSpace();", + }, + { + path: "src/app.js", + contents: + "define('app.js',['require','exports','module','foo','page/one'],function (require, exports, module) {\nrequire('foo');require('page/one');\n});\n", + }, + { + path: "src/page/one.js", + contents: + "define('page/one.js',['require','exports','module','foo/bar','loo'],function (require, exports, module) {\nrequire('foo/bar');require('loo');\n});\n", + }, + { + contents: "define.switchToPackageSpace();", + }, + { + path: "node_modules/foo/bar.js", + contents: + "define('foo/bar.js',['require','exports','module'],function (require, exports, module) {\n\n});\n", + }, + { + path: "node_modules/foo/index.js", + contents: + "define('foo/index.js',['require','exports','module','loo'],function (require, exports, module) {\nrequire('loo');\n});\n\n;define.alias('foo','foo/index.js');", + }, + { + path: "node_modules/loo/loo.js", + contents: + "define('loo/loo.js',['require','exports','module'],function (require, exports, module) {\n\n});\n\n;define.alias('loo','loo/loo.js');", + }, + { + contents: "define.switchToUserSpace();", + }, + ], + appendFiles: [ + { + path: "local/after.js", + contents: "after;", + }, + { + contents: "var ape = 1;", + }, + ], + config: { + baseUrl: "/dist", + paths: {}, + bundles: {}, + }, + }, + }); + }, + (err) => t.fail(err.stack) + ); }); -test('Bundler can optionally skip dumber-module-loader', async t => { +test("Bundler can optionally skip dumber-module-loader", async (t) => { const fakeFs = { - 'local/setup.js': 'setup', - 'local/after.js': 'after', - + "local/setup.js": "setup", + "local/after.js": "after", }; - const bundler = createBundler(fakeFs, { + const bundler = mockBundler(fakeFs, { skipModuleLoader: true, - prepends: ['dev-dumber-module-loader'] + prepends: ["dev-dumber-module-loader"], }); return Promise.resolve() - .then(() => bundler.capture({path: 'src/app.js', contents: '', moduleId: 'app.js'})) - .then(() => bundler.resolve()) - .then(() => bundler.bundle()) - .then( - bundleMap => { - t.deepEqual(bundleMap, { - "entry-bundle": { - "files": [ - { - "contents": "dev-dumber-module-loader;" - }, - { - "contents": "define.switchToUserSpace();" - }, - { - "path": "src/app.js", - "contents": "define('app.js',['require','exports','module'],function (require, exports, module) {\n\n});\n" - } - ], - "config": { - "baseUrl": "/dist", - "paths": {}, - "bundles": {} - } - } - }); - }, - err => t.fail(err.stack) - ); + .then(() => + bundler.capture({ path: "src/app.js", contents: "", moduleId: "app.js" }) + ) + .then(() => bundler.resolve()) + .then(() => bundler.bundle()) + .then( + (bundleMap) => { + t.deepEqual(bundleMap, { + "entry-bundle": { + files: [ + { + contents: "dev-dumber-module-loader;", + }, + { + contents: "define.switchToUserSpace();", + }, + { + path: "src/app.js", + contents: + "define('app.js',['require','exports','module'],function (require, exports, module) {\n\n});\n", + }, + ], + config: { + baseUrl: "/dist", + paths: {}, + bundles: {}, + }, + }, + }); + }, + (err) => t.fail(err.stack) + ); }); -test('Bundler traces files, split bundles', async t => { +test("Bundler traces files, split bundles", async (t) => { const fakeFs = { - 'local/setup.js': 'setup', - 'local/after.js': 'after', - 'node_modules/dumber-module-loader/dist/index.debug.js': 'dumber-module-loader', - 'node_modules/foo/package.json': JSON.stringify({name: 'foo', main: 'index'}), - 'node_modules/foo/index.js': "require('loo');", - 'node_modules/foo/bar.js': '', - 'node_modules/loo/package.json': JSON.stringify({name: 'loo', main: './loo'}), - 'node_modules/loo/loo.js': '', + "local/setup.js": "setup", + "local/after.js": "after", + "node_modules/dumber-module-loader/dist/index.debug.js": + "dumber-module-loader", + "node_modules/foo/package.json": JSON.stringify({ + name: "foo", + main: "index", + }), + "node_modules/foo/index.js": "require('loo');", + "node_modules/foo/bar.js": "", + "node_modules/loo/package.json": JSON.stringify({ + name: "loo", + main: "./loo", + }), + "node_modules/loo/loo.js": "", }; - const bundler = createBundler(fakeFs, { - prepends: ['var pre = 1;', 'local/setup.js'], - appends: ['local/after.js', 'var ape = 1;'], + const bundler = mockBundler(fakeFs, { + prepends: ["var pre = 1;", "local/setup.js"], + appends: ["local/after.js", "var ape = 1;"], codeSplit: (moduleId, packageName) => { - if (packageName) return 'vendor'; - } + if (packageName) return "vendor"; + }, }); return Promise.resolve() - .then(() => bundler.capture({path: 'src/app.js', contents: "require('foo');require('page/one');", moduleId: 'app.js'})) - .then(() => bundler.capture({path: 'src/page/one.js', contents: "require('foo/bar');require('loo');", moduleId: 'page/one.js'})) - .then(() => bundler.resolve()) - .then(() => bundler.bundle()) - .then( - bundleMap => { - t.deepEqual(bundleMap, { - "entry-bundle": { - "files": [ - { - "contents": "var pre = 1;" - }, - { - "path": "local/setup.js", - "contents": "setup;" - }, - { - "path": "node_modules/dumber-module-loader/dist/index.debug.js", - "contents": "dumber-module-loader;" - }, - { - "contents": "define.switchToUserSpace();" - }, - { - "path": "src/app.js", - "contents": "define('app.js',['require','exports','module','foo','page/one'],function (require, exports, module) {\nrequire('foo');require('page/one');\n});\n" - }, - { - "path": "src/page/one.js", - "contents": "define('page/one.js',['require','exports','module','foo/bar','loo'],function (require, exports, module) {\nrequire('foo/bar');require('loo');\n});\n" - } - ], - "appendFiles": [ - { - "path": "local/after.js", - "contents": "after;" - }, - { - "contents": "var ape = 1;" - } - ], - "config": { - "baseUrl": "/dist", - "paths": {}, - "bundles": { - "vendor": { - "user": [], - "package": [ - "foo", - "foo/bar.js", - "foo/index.js", - "loo", - "loo/loo.js" - ] - } - } - } - }, - "vendor": { - "files": [ - { - "contents": "define.switchToPackageSpace();" - }, - { - "path": "node_modules/foo/bar.js", - "contents": "define('foo/bar.js',['require','exports','module'],function (require, exports, module) {\n\n});\n" - }, - { - "path": "node_modules/foo/index.js", - "contents": "define('foo/index.js',['require','exports','module','loo'],function (require, exports, module) {\nrequire('loo');\n});\n\n;define.alias('foo','foo/index.js');" - }, - { - "path": "node_modules/loo/loo.js", - "contents": "define('loo/loo.js',['require','exports','module'],function (require, exports, module) {\n\n});\n\n;define.alias('loo','loo/loo.js');" + .then(() => + bundler.capture({ + path: "src/app.js", + contents: "require('foo');require('page/one');", + moduleId: "app.js", + }) + ) + .then(() => + bundler.capture({ + path: "src/page/one.js", + contents: "require('foo/bar');require('loo');", + moduleId: "page/one.js", + }) + ) + .then(() => bundler.resolve()) + .then(() => bundler.bundle()) + .then( + (bundleMap) => { + t.deepEqual(bundleMap, { + "entry-bundle": { + files: [ + { + contents: "var pre = 1;", + }, + { + path: "local/setup.js", + contents: "setup;", + }, + { + path: "node_modules/dumber-module-loader/dist/index.debug.js", + contents: "dumber-module-loader;", + }, + { + contents: "define.switchToUserSpace();", + }, + { + path: "src/app.js", + contents: + "define('app.js',['require','exports','module','foo','page/one'],function (require, exports, module) {\nrequire('foo');require('page/one');\n});\n", + }, + { + path: "src/page/one.js", + contents: + "define('page/one.js',['require','exports','module','foo/bar','loo'],function (require, exports, module) {\nrequire('foo/bar');require('loo');\n});\n", + }, + ], + appendFiles: [ + { + path: "local/after.js", + contents: "after;", + }, + { + contents: "var ape = 1;", + }, + ], + config: { + baseUrl: "/dist", + paths: {}, + bundles: { + vendor: { + user: [], + package: [ + "foo", + "foo/bar.js", + "foo/index.js", + "loo", + "loo/loo.js", + ], + }, + }, }, - { - "contents": "define.switchToUserSpace();" - } - ] - } - }); - }, - err => t.fail(err.stack) - ); + }, + vendor: { + files: [ + { + contents: "define.switchToPackageSpace();", + }, + { + path: "node_modules/foo/bar.js", + contents: + "define('foo/bar.js',['require','exports','module'],function (require, exports, module) {\n\n});\n", + }, + { + path: "node_modules/foo/index.js", + contents: + "define('foo/index.js',['require','exports','module','loo'],function (require, exports, module) {\nrequire('loo');\n});\n\n;define.alias('foo','foo/index.js');", + }, + { + path: "node_modules/loo/loo.js", + contents: + "define('loo/loo.js',['require','exports','module'],function (require, exports, module) {\n\n});\n\n;define.alias('loo','loo/loo.js');", + }, + { + contents: "define.switchToUserSpace();", + }, + ], + }, + }); + }, + (err) => t.fail(err.stack) + ); }); -test('Bundler traces files, split bundles, case2', async t => { +test("Bundler traces files, split bundles, case2", async (t) => { const fakeFs = { - 'local/setup.js': 'setup', - 'local/after.js': 'after', - 'node_modules/dumber-module-loader/dist/index.debug.js': 'dumber-module-loader', - 'node_modules/foo/package.json': JSON.stringify({name: 'foo', main: 'index'}), - 'node_modules/foo/index.js': "require('loo');", - 'node_modules/foo/bar.js': '', - 'node_modules/loo/package.json': JSON.stringify({name: 'loo', main: './loo'}), - 'node_modules/loo/loo.js': '', + "local/setup.js": "setup", + "local/after.js": "after", + "node_modules/dumber-module-loader/dist/index.debug.js": + "dumber-module-loader", + "node_modules/foo/package.json": JSON.stringify({ + name: "foo", + main: "index", + }), + "node_modules/foo/index.js": "require('loo');", + "node_modules/foo/bar.js": "", + "node_modules/loo/package.json": JSON.stringify({ + name: "loo", + main: "./loo", + }), + "node_modules/loo/loo.js": "", }; - const bundler = createBundler(fakeFs, { - prepends: ['var pre = 1;', 'local/setup.js'], - appends: ['local/after.js', 'var ape = 1;'], - entryBundle: 'main', - baseUrl: 'scripts', + const bundler = mockBundler(fakeFs, { + prepends: ["var pre = 1;", "local/setup.js"], + appends: ["local/after.js", "var ape = 1;"], + entryBundle: "main", + baseUrl: "scripts", codeSplit: (moduleId, packageName) => { if (packageName) { - if (packageName === 'loo') return 'app'; - return 'vendor'; + if (packageName === "loo") return "app"; + return "vendor"; } else { - return 'app'; + return "app"; } - } + }, }); return Promise.resolve() - .then(() => bundler.capture({path: 'src/app.js', contents: "require('foo');require('page/one');", moduleId: 'app.js'})) - .then(() => bundler.capture({path: 'src/page/one.js', contents: "require('foo/bar');require('loo');", moduleId: 'page/one.js'})) - .then(() => bundler.resolve()) - .then(() => bundler.bundle()) - .then( - bundleMap => { - t.deepEqual(bundleMap, { - "main": { - "files": [ - { - "contents": "var pre = 1;" - }, - { - "path": "local/setup.js", - "contents": "setup;" - }, - { - "path": "node_modules/dumber-module-loader/dist/index.debug.js", - "contents": "dumber-module-loader;" - } - ], - "appendFiles": [ - { - "path": "local/after.js", - "contents": "after;" - }, - { - "contents": "var ape = 1;" - } - ], - "config": { - "baseUrl": "scripts", - "paths": {}, - "bundles": { - "app": { - "user": [ - "app.js", - "page/one.js" - ], - "package": [ - "loo", - "loo/loo.js" - ] - }, - "vendor": { - "user": [], - "package": [ - "foo", - "foo/bar.js", - "foo/index.js" - ] - } - } - } - }, - "app": { - "files": [ - { - "contents": "define.switchToUserSpace();" - }, - { - "path": "src/app.js", - "contents": "define('app.js',['require','exports','module','foo','page/one'],function (require, exports, module) {\nrequire('foo');require('page/one');\n});\n" - }, - { - "path": "src/page/one.js", - "contents": "define('page/one.js',['require','exports','module','foo/bar','loo'],function (require, exports, module) {\nrequire('foo/bar');require('loo');\n});\n" - }, - { - "contents": "define.switchToPackageSpace();" - }, - { - "path": "node_modules/loo/loo.js", - "contents": "define('loo/loo.js',['require','exports','module'],function (require, exports, module) {\n\n});\n\n;define.alias('loo','loo/loo.js');" - }, - { - "contents": "define.switchToUserSpace();" - } - ] - }, - "vendor": { - "files": [ - { - "contents": "define.switchToPackageSpace();" - }, - { - "path": "node_modules/foo/bar.js", - "contents": "define('foo/bar.js',['require','exports','module'],function (require, exports, module) {\n\n});\n" - }, - { - "path": "node_modules/foo/index.js", - "contents": "define('foo/index.js',['require','exports','module','loo'],function (require, exports, module) {\nrequire('loo');\n});\n\n;define.alias('foo','foo/index.js');" + .then(() => + bundler.capture({ + path: "src/app.js", + contents: "require('foo');require('page/one');", + moduleId: "app.js", + }) + ) + .then(() => + bundler.capture({ + path: "src/page/one.js", + contents: "require('foo/bar');require('loo');", + moduleId: "page/one.js", + }) + ) + .then(() => bundler.resolve()) + .then(() => bundler.bundle()) + .then( + (bundleMap) => { + t.deepEqual(bundleMap, { + main: { + files: [ + { + contents: "var pre = 1;", + }, + { + path: "local/setup.js", + contents: "setup;", + }, + { + path: "node_modules/dumber-module-loader/dist/index.debug.js", + contents: "dumber-module-loader;", + }, + ], + appendFiles: [ + { + path: "local/after.js", + contents: "after;", + }, + { + contents: "var ape = 1;", + }, + ], + config: { + baseUrl: "scripts", + paths: {}, + bundles: { + app: { + user: ["app.js", "page/one.js"], + package: ["loo", "loo/loo.js"], + }, + vendor: { + user: [], + package: ["foo", "foo/bar.js", "foo/index.js"], + }, + }, }, - { - "contents": "define.switchToUserSpace();" - } - ] - } - }); - }, - err => t.fail(err.stack) - ); + }, + app: { + files: [ + { + contents: "define.switchToUserSpace();", + }, + { + path: "src/app.js", + contents: + "define('app.js',['require','exports','module','foo','page/one'],function (require, exports, module) {\nrequire('foo');require('page/one');\n});\n", + }, + { + path: "src/page/one.js", + contents: + "define('page/one.js',['require','exports','module','foo/bar','loo'],function (require, exports, module) {\nrequire('foo/bar');require('loo');\n});\n", + }, + { + contents: "define.switchToPackageSpace();", + }, + { + path: "node_modules/loo/loo.js", + contents: + "define('loo/loo.js',['require','exports','module'],function (require, exports, module) {\n\n});\n\n;define.alias('loo','loo/loo.js');", + }, + { + contents: "define.switchToUserSpace();", + }, + ], + }, + vendor: { + files: [ + { + contents: "define.switchToPackageSpace();", + }, + { + path: "node_modules/foo/bar.js", + contents: + "define('foo/bar.js',['require','exports','module'],function (require, exports, module) {\n\n});\n", + }, + { + path: "node_modules/foo/index.js", + contents: + "define('foo/index.js',['require','exports','module','loo'],function (require, exports, module) {\nrequire('loo');\n});\n\n;define.alias('foo','foo/index.js');", + }, + { + contents: "define.switchToUserSpace();", + }, + ], + }, + }); + }, + (err) => t.fail(err.stack) + ); }); -test('Bundler traces files, sorts shim', async t => { +test("Bundler traces files, sorts shim", async (t) => { const fakeFs = { - 'node_modules/dumber-module-loader/dist/index.debug.js': 'dumber-module-loader', - 'node_modules/jquery/package.json': JSON.stringify({name: 'jquery', main: 'dist/jquery'}), - 'node_modules/jquery/dist/jquery.js': 'define("jquery",[],function(){});', - 'node_modules/bootstrap/package.json': JSON.stringify({name: 'bootstrap', main: './dist/bootstrap'}), - 'node_modules/bootstrap/dist/bootstrap.js': '', - 'node_modules/fs-browser-stub/package.json': JSON.stringify({name: 'fs-browser-stub', main: 'index.js'}), - 'node_modules/fs-browser-stub/index.js': '' + "node_modules/dumber-module-loader/dist/index.debug.js": + "dumber-module-loader", + "node_modules/jquery/package.json": JSON.stringify({ + name: "jquery", + main: "dist/jquery", + }), + "node_modules/jquery/dist/jquery.js": 'define("jquery",[],function(){});', + "node_modules/bootstrap/package.json": JSON.stringify({ + name: "bootstrap", + main: "./dist/bootstrap", + }), + "node_modules/bootstrap/dist/bootstrap.js": "", + "node_modules/fs-browser-stub/package.json": JSON.stringify({ + name: "fs-browser-stub", + main: "index.js", + }), + "node_modules/fs-browser-stub/index.js": "", }; - const bundler = createBundler(fakeFs, { - deps: [ - {name: 'bootstrap', deps: ['jquery'], 'exports': 'jQuery'} - ] + const bundler = mockBundler(fakeFs, { + deps: [{ name: "bootstrap", deps: ["jquery"], exports: "jQuery" }], }); return Promise.resolve() - .then(() => bundler.capture({path: 'src/app.js', contents: "require('fs');require('bootstrap');", moduleId: 'app.js'})) - .then(() => bundler.resolve()) - .then(() => bundler.bundle()) - .then( - bundleMap => { - t.deepEqual(bundleMap, { - "entry-bundle": { - "files": [ - { - "path": "node_modules/dumber-module-loader/dist/index.debug.js", - "contents": "dumber-module-loader;" - }, - { - "contents": "define.switchToUserSpace();" - }, - { - "path": "src/app.js", - "contents": "define('app.js',['require','exports','module','fs','bootstrap'],function (require, exports, module) {\nrequire('fs');require('bootstrap');\n});\n" - }, - { - "contents": "define.switchToPackageSpace();" - }, - { - "path": "node_modules/jquery/dist/jquery.js", - "contents": "define(\"jquery\",[],function(){});" - }, - { - "path": "node_modules/bootstrap/dist/bootstrap.js", - "contents": ";\ndefine('bootstrap/dist/bootstrap.js',['jquery'],(function (global) {\n return function () {\n return global.jQuery;\n };\n}(this)));\n\n;define.alias('bootstrap','bootstrap/dist/bootstrap.js');" - }, - { - "path": "node_modules/fs-browser-stub/index.js", - "contents": "define('fs/index.js',['require','exports','module'],function (require, exports, module) {\n\n});\n\n;define.alias('fs','fs/index.js');" - }, - { - "contents": "define.switchToUserSpace();" - } - ], - "config": { - "baseUrl": "/dist", - "paths": {}, - "bundles": {} - } - } - }); - }, - err => t.fail(err.stack) - ); + .then(() => + bundler.capture({ + path: "src/app.js", + contents: "require('fs');require('bootstrap');", + moduleId: "app.js", + }) + ) + .then(() => bundler.resolve()) + .then(() => bundler.bundle()) + .then( + (bundleMap) => { + t.deepEqual(bundleMap, { + "entry-bundle": { + files: [ + { + path: "node_modules/dumber-module-loader/dist/index.debug.js", + contents: "dumber-module-loader;", + }, + { + contents: "define.switchToUserSpace();", + }, + { + path: "src/app.js", + contents: + "define('app.js',['require','exports','module','fs','bootstrap'],function (require, exports, module) {\nrequire('fs');require('bootstrap');\n});\n", + }, + { + contents: "define.switchToPackageSpace();", + }, + { + path: "node_modules/jquery/dist/jquery.js", + contents: 'define("jquery",[],function(){});', + }, + { + path: "node_modules/bootstrap/dist/bootstrap.js", + contents: + ";\ndefine('bootstrap/dist/bootstrap.js',['jquery'],(function (global) {\n return function () {\n return global.jQuery;\n };\n}(this)));\n\n;define.alias('bootstrap','bootstrap/dist/bootstrap.js');", + }, + { + path: "node_modules/fs-browser-stub/index.js", + contents: + "define('fs/index.js',['require','exports','module'],function (require, exports, module) {\n\n});\n\n;define.alias('fs','fs/index.js');", + }, + { + contents: "define.switchToUserSpace();", + }, + ], + config: { + baseUrl: "/dist", + paths: {}, + bundles: {}, + }, + }, + }); + }, + (err) => t.fail(err.stack) + ); }); -test('Bundler traces files, always sort jquery and moment on top', async t => { +test("Bundler traces files, always sort jquery and moment on top", async (t) => { const fakeFs = { - 'node_modules/dumber-module-loader/dist/index.debug.js': 'dumber-module-loader', - 'node_modules/jquery/package.json': JSON.stringify({name: 'jquery', main: 'dist/jquery'}), - 'node_modules/jquery/dist/jquery.js': 'define("jquery",[],function(){});', - 'node_modules/moment/package.json': JSON.stringify({name: 'moment', main: './moment'}), - 'node_modules/moment/moment.js': '', - 'node_modules/aaa/package.json': JSON.stringify({name: 'aaa', main: './aaa'}), - 'node_modules/aaa/aaa.js': '', + "node_modules/dumber-module-loader/dist/index.debug.js": + "dumber-module-loader", + "node_modules/jquery/package.json": JSON.stringify({ + name: "jquery", + main: "dist/jquery", + }), + "node_modules/jquery/dist/jquery.js": 'define("jquery",[],function(){});', + "node_modules/moment/package.json": JSON.stringify({ + name: "moment", + main: "./moment", + }), + "node_modules/moment/moment.js": "", + "node_modules/aaa/package.json": JSON.stringify({ + name: "aaa", + main: "./aaa", + }), + "node_modules/aaa/aaa.js": "", }; - const bundler = createBundler(fakeFs); + const bundler = mockBundler(fakeFs); return Promise.resolve() - .then(() => bundler.capture({path: 'src/app.js', contents: "require('aaa');require('jquery');require('moment');", moduleId: 'app.js'})) - .then(() => bundler.resolve()) - .then(() => bundler.bundle()) - .then( - bundleMap => { - t.deepEqual(bundleMap, { - "entry-bundle": { - "files": [ - { - "path": "node_modules/dumber-module-loader/dist/index.debug.js", - "contents": "dumber-module-loader;" - }, - { - "contents": "define.switchToUserSpace();" - }, - { - "path": "src/app.js", - "contents": "define('app.js',['require','exports','module','aaa','jquery','moment'],function (require, exports, module) {\nrequire('aaa');require('jquery');require('moment');\n});\n" - }, - { - "contents": "define.switchToPackageSpace();" - }, - { - "path": "node_modules/jquery/dist/jquery.js", - "contents": "define(\"jquery\",[],function(){});" - }, - { - "path": "node_modules/moment/moment.js", - "contents": "define('moment/moment.js',['require','exports','module'],function (require, exports, module) {\n\n});\n\n;define.alias('moment','moment/moment.js');" - }, - { - "path": "node_modules/aaa/aaa.js", - "contents": "define('aaa/aaa.js',['require','exports','module'],function (require, exports, module) {\n\n});\n\n;define.alias('aaa','aaa/aaa.js');" - }, - { - "contents": "define.switchToUserSpace();" - } - ], - "config": { - "baseUrl": "/dist", - "paths": {}, - "bundles": {} - } - } - }); - }, - err => t.fail(err.stack) - ); + .then(() => + bundler.capture({ + path: "src/app.js", + contents: "require('aaa');require('jquery');require('moment');", + moduleId: "app.js", + }) + ) + .then(() => bundler.resolve()) + .then(() => bundler.bundle()) + .then( + (bundleMap) => { + t.deepEqual(bundleMap, { + "entry-bundle": { + files: [ + { + path: "node_modules/dumber-module-loader/dist/index.debug.js", + contents: "dumber-module-loader;", + }, + { + contents: "define.switchToUserSpace();", + }, + { + path: "src/app.js", + contents: + "define('app.js',['require','exports','module','aaa','jquery','moment'],function (require, exports, module) {\nrequire('aaa');require('jquery');require('moment');\n});\n", + }, + { + contents: "define.switchToPackageSpace();", + }, + { + path: "node_modules/jquery/dist/jquery.js", + contents: 'define("jquery",[],function(){});', + }, + { + path: "node_modules/moment/moment.js", + contents: + "define('moment/moment.js',['require','exports','module'],function (require, exports, module) {\n\n});\n\n;define.alias('moment','moment/moment.js');", + }, + { + path: "node_modules/aaa/aaa.js", + contents: + "define('aaa/aaa.js',['require','exports','module'],function (require, exports, module) {\n\n});\n\n;define.alias('aaa','aaa/aaa.js');", + }, + { + contents: "define.switchToUserSpace();", + }, + ], + config: { + baseUrl: "/dist", + paths: {}, + bundles: {}, + }, + }, + }); + }, + (err) => t.fail(err.stack) + ); }); -test('Bundler ignores module when onRequire returns false', async t => { +test("Bundler ignores module when onRequire returns false", async (t) => { const fakeFs = { - 'node_modules/dumber-module-loader/dist/index.debug.js': 'dumber-module-loader', + "node_modules/dumber-module-loader/dist/index.debug.js": + "dumber-module-loader", }; - const bundler = createBundler(fakeFs, { + const bundler = mockBundler(fakeFs, { onRequire(moduleId) { - if (moduleId === 'foo') return false; - } + if (moduleId === "foo") return false; + }, }); return Promise.resolve() - .then(() => bundler.capture({path: 'src/app.js', contents: "require('foo');", moduleId: 'app.js'})) - .then(() => bundler.resolve()) - .then(() => bundler.bundle()) - .then( - bundleMap => { - t.deepEqual(bundleMap, { - "entry-bundle": { - "files": [ - { - "path": "node_modules/dumber-module-loader/dist/index.debug.js", - "contents": "dumber-module-loader;" - }, - { - "contents": "define.switchToUserSpace();" - }, - { - "path": "src/app.js", - "contents": "define('app.js',['require','exports','module','foo'],function (require, exports, module) {\nrequire('foo');\n});\n" - } - ], - "config": { - "baseUrl": "/dist", - "paths": {}, - "bundles": {} - } - } - }); - }, - err => t.fail(err.stack) - ); + .then(() => + bundler.capture({ + path: "src/app.js", + contents: "require('foo');", + moduleId: "app.js", + }) + ) + .then(() => bundler.resolve()) + .then(() => bundler.bundle()) + .then( + (bundleMap) => { + t.deepEqual(bundleMap, { + "entry-bundle": { + files: [ + { + path: "node_modules/dumber-module-loader/dist/index.debug.js", + contents: "dumber-module-loader;", + }, + { + contents: "define.switchToUserSpace();", + }, + { + path: "src/app.js", + contents: + "define('app.js',['require','exports','module','foo'],function (require, exports, module) {\nrequire('foo');\n});\n", + }, + ], + config: { + baseUrl: "/dist", + paths: {}, + bundles: {}, + }, + }, + }); + }, + (err) => t.fail(err.stack) + ); }); -test('Bundler replaces deps when onRequire returns array', async t => { +test("Bundler replaces deps when onRequire returns array", async (t) => { const fakeFs = { - 'node_modules/dumber-module-loader/dist/index.debug.js': 'dumber-module-loader', - 'node_modules/bar/package.json': '{"name":"bar"}', - 'node_modules/bar/index.js': '', - 'node_modules/loo/package.json': '{"name":"loo","main":"loo"}', - 'node_modules/loo/loo.js': '', + "node_modules/dumber-module-loader/dist/index.debug.js": + "dumber-module-loader", + "node_modules/bar/package.json": '{"name":"bar"}', + "node_modules/bar/index.js": "", + "node_modules/loo/package.json": '{"name":"loo","main":"loo"}', + "node_modules/loo/loo.js": "", }; - const bundler = createBundler(fakeFs, { + const bundler = mockBundler(fakeFs, { onRequire(moduleId) { - if (moduleId === 'foo') return ['bar', 'loo']; - } + if (moduleId === "foo") return ["bar", "loo"]; + }, }); return Promise.resolve() - .then(() => bundler.capture({path: 'src/app.js', contents: "require('foo');", moduleId: 'app.js'})) - .then(() => bundler.resolve()) - .then(() => bundler.bundle()) - .then( - bundleMap => { - t.deepEqual(bundleMap, { - "entry-bundle": { - "files": [ - { - "path": "node_modules/dumber-module-loader/dist/index.debug.js", - "contents": "dumber-module-loader;" - }, - { - "contents": "define.switchToUserSpace();" - }, - { - "path": "src/app.js", - "contents": "define('app.js',['require','exports','module','foo'],function (require, exports, module) {\nrequire('foo');\n});\n" - }, - { - "contents": "define.switchToPackageSpace();" - }, - { - "path": "node_modules/bar/index.js", - "contents": "define('bar/index.js',['require','exports','module'],function (require, exports, module) {\n\n});\n\n;define.alias('bar','bar/index.js');" - }, - { - "path": "node_modules/loo/loo.js", - "contents": "define('loo/loo.js',['require','exports','module'],function (require, exports, module) {\n\n});\n\n;define.alias('loo','loo/loo.js');" - }, - { - "contents": "define.switchToUserSpace();" - } - ], - "config": { - "baseUrl": "/dist", - "paths": {}, - "bundles": {} - } - } - }); - }, - err => t.fail(err.stack) - ); + .then(() => + bundler.capture({ + path: "src/app.js", + contents: "require('foo');", + moduleId: "app.js", + }) + ) + .then(() => bundler.resolve()) + .then(() => bundler.bundle()) + .then( + (bundleMap) => { + t.deepEqual(bundleMap, { + "entry-bundle": { + files: [ + { + path: "node_modules/dumber-module-loader/dist/index.debug.js", + contents: "dumber-module-loader;", + }, + { + contents: "define.switchToUserSpace();", + }, + { + path: "src/app.js", + contents: + "define('app.js',['require','exports','module','foo'],function (require, exports, module) {\nrequire('foo');\n});\n", + }, + { + contents: "define.switchToPackageSpace();", + }, + { + path: "node_modules/bar/index.js", + contents: + "define('bar/index.js',['require','exports','module'],function (require, exports, module) {\n\n});\n\n;define.alias('bar','bar/index.js');", + }, + { + path: "node_modules/loo/loo.js", + contents: + "define('loo/loo.js',['require','exports','module'],function (require, exports, module) {\n\n});\n\n;define.alias('loo','loo/loo.js');", + }, + { + contents: "define.switchToUserSpace();", + }, + ], + config: { + baseUrl: "/dist", + paths: {}, + bundles: {}, + }, + }, + }); + }, + (err) => t.fail(err.stack) + ); }); -test('Bundler supports implementation returned by onRequire', async t => { +test("Bundler supports implementation returned by onRequire", async (t) => { const fakeFs = { - 'node_modules/dumber-module-loader/dist/index.debug.js': 'dumber-module-loader', - 'node_modules/loo/package.json': '{"name":"loo","main":"loo"}', - 'node_modules/loo/loo.js': '', + "node_modules/dumber-module-loader/dist/index.debug.js": + "dumber-module-loader", + "node_modules/loo/package.json": '{"name":"loo","main":"loo"}', + "node_modules/loo/loo.js": "", }; - const bundler = createBundler(fakeFs, { + const bundler = mockBundler(fakeFs, { onRequire(moduleId) { // onRequire can return a Promise to resolve to false, array, or string. - if (moduleId === 'foo') return Promise.resolve("require('loo');"); - } + if (moduleId === "foo") return Promise.resolve("require('loo');"); + }, }); return Promise.resolve() - .then(() => bundler.capture({path: 'src/app.js', contents: "require('foo');", moduleId: 'app.js'})) - .then(() => bundler.resolve()) - .then(() => bundler.bundle()) - .then( - bundleMap => { - t.deepEqual(bundleMap, { - "entry-bundle": { - "files": [ - { - "path": "node_modules/dumber-module-loader/dist/index.debug.js", - "contents": "dumber-module-loader;" - }, - { - "contents": "define.switchToUserSpace();" - }, - { - "path": "src/app.js", - "contents": "define('app.js',['require','exports','module','foo'],function (require, exports, module) {\nrequire('foo');\n});\n" - }, - { - "contents": "define.switchToPackageSpace();" - }, - { - "path": "__on_require__/foo.js", - "contents": "define('foo',['require','exports','module','loo'],function (require, exports, module) {\nrequire('loo');\n});\n" - }, - { - "path": "node_modules/loo/loo.js", - "contents": "define('loo/loo.js',['require','exports','module'],function (require, exports, module) {\n\n});\n\n;define.alias('loo','loo/loo.js');" - }, - { - "contents": "define.switchToUserSpace();" - } - ], - "config": { - "baseUrl": "/dist", - "paths": {}, - "bundles": {} - } - } - }); - }, - err => t.fail(err.stack) - ); + .then(() => + bundler.capture({ + path: "src/app.js", + contents: "require('foo');", + moduleId: "app.js", + }) + ) + .then(() => bundler.resolve()) + .then(() => bundler.bundle()) + .then( + (bundleMap) => { + t.deepEqual(bundleMap, { + "entry-bundle": { + files: [ + { + path: "node_modules/dumber-module-loader/dist/index.debug.js", + contents: "dumber-module-loader;", + }, + { + contents: "define.switchToUserSpace();", + }, + { + path: "src/app.js", + contents: + "define('app.js',['require','exports','module','foo'],function (require, exports, module) {\nrequire('foo');\n});\n", + }, + { + contents: "define.switchToPackageSpace();", + }, + { + path: "__on_require__/foo.js", + contents: + "define('foo',['require','exports','module','loo'],function (require, exports, module) {\nrequire('loo');\n});\n", + }, + { + path: "node_modules/loo/loo.js", + contents: + "define('loo/loo.js',['require','exports','module'],function (require, exports, module) {\n\n});\n\n;define.alias('loo','loo/loo.js');", + }, + { + contents: "define.switchToUserSpace();", + }, + ], + config: { + baseUrl: "/dist", + paths: {}, + bundles: {}, + }, + }, + }); + }, + (err) => t.fail(err.stack) + ); }); -test('Bundler swallows onRequire exception', async t => { +test("Bundler swallows onRequire exception", async (t) => { const fakeFs = { - 'node_modules/dumber-module-loader/dist/index.debug.js': 'dumber-module-loader', - 'node_modules/foo/package.json': '{"name":"foo","main":"foo"}', - 'node_modules/foo/foo.js': '', + "node_modules/dumber-module-loader/dist/index.debug.js": + "dumber-module-loader", + "node_modules/foo/package.json": '{"name":"foo","main":"foo"}', + "node_modules/foo/foo.js": "", }; - const bundler = createBundler(fakeFs, { + const bundler = mockBundler(fakeFs, { onRequire(moduleId) { - if (moduleId === 'foo') throw new Error("haha"); - } + if (moduleId === "foo") throw new Error("haha"); + }, }); return Promise.resolve() - .then(() => bundler.capture({path: 'src/app.js', contents: "require('foo');", moduleId: 'app.js'})) - .then(() => bundler.resolve()) - .then(() => bundler.bundle()) - .then( - bundleMap => { - t.deepEqual(bundleMap, { - "entry-bundle": { - "files": [ - { - "path": "node_modules/dumber-module-loader/dist/index.debug.js", - "contents": "dumber-module-loader;" - }, - { - "contents": "define.switchToUserSpace();" - }, - { - "path": "src/app.js", - "contents": "define('app.js',['require','exports','module','foo'],function (require, exports, module) {\nrequire('foo');\n});\n" - }, - { - "contents": "define.switchToPackageSpace();" - }, - { - "path": "node_modules/foo/foo.js", - "contents": "define('foo/foo.js',['require','exports','module'],function (require, exports, module) {\n\n});\n\n;define.alias('foo','foo/foo.js');" - }, - { - "contents": "define.switchToUserSpace();" - } - ], - "config": { - "baseUrl": "/dist", - "paths": {}, - "bundles": {} - } - } - }); - }, - err => t.fail(err.stack) - ); + .then(() => + bundler.capture({ + path: "src/app.js", + contents: "require('foo');", + moduleId: "app.js", + }) + ) + .then(() => bundler.resolve()) + .then(() => bundler.bundle()) + .then( + (bundleMap) => { + t.deepEqual(bundleMap, { + "entry-bundle": { + files: [ + { + path: "node_modules/dumber-module-loader/dist/index.debug.js", + contents: "dumber-module-loader;", + }, + { + contents: "define.switchToUserSpace();", + }, + { + path: "src/app.js", + contents: + "define('app.js',['require','exports','module','foo'],function (require, exports, module) {\nrequire('foo');\n});\n", + }, + { + contents: "define.switchToPackageSpace();", + }, + { + path: "node_modules/foo/foo.js", + contents: + "define('foo/foo.js',['require','exports','module'],function (require, exports, module) {\n\n});\n\n;define.alias('foo','foo/foo.js');", + }, + { + contents: "define.switchToUserSpace();", + }, + ], + config: { + baseUrl: "/dist", + paths: {}, + bundles: {}, + }, + }, + }); + }, + (err) => t.fail(err.stack) + ); }); -test('Bundler swallows onRequire promise rejection', async t => { +test("Bundler swallows onRequire promise rejection", async (t) => { const fakeFs = { - 'node_modules/dumber-module-loader/dist/index.debug.js': 'dumber-module-loader', - 'node_modules/foo/package.json': '{"name":"foo","main":"foo"}', - 'node_modules/foo/foo.js': '', + "node_modules/dumber-module-loader/dist/index.debug.js": + "dumber-module-loader", + "node_modules/foo/package.json": '{"name":"foo","main":"foo"}', + "node_modules/foo/foo.js": "", }; - const bundler = createBundler(fakeFs, { + const bundler = mockBundler(fakeFs, { onRequire(moduleId) { - if (moduleId === 'foo') return Promise.reject(new Error("haha")); - } + if (moduleId === "foo") return Promise.reject(new Error("haha")); + }, }); return Promise.resolve() - .then(() => bundler.capture({path: 'src/app.js', contents: "require('foo');", moduleId: 'app.js'})) - .then(() => bundler.resolve()) - .then(() => bundler.bundle()) - .then( - bundleMap => { - t.deepEqual(bundleMap, { - "entry-bundle": { - "files": [ - { - "path": "node_modules/dumber-module-loader/dist/index.debug.js", - "contents": "dumber-module-loader;" - }, - { - "contents": "define.switchToUserSpace();" - }, - { - "path": "src/app.js", - "contents": "define('app.js',['require','exports','module','foo'],function (require, exports, module) {\nrequire('foo');\n});\n" - }, - { - "contents": "define.switchToPackageSpace();" - }, - { - "path": "node_modules/foo/foo.js", - "contents": "define('foo/foo.js',['require','exports','module'],function (require, exports, module) {\n\n});\n\n;define.alias('foo','foo/foo.js');" - }, - { - "contents": "define.switchToUserSpace();" - } - ], - "config": { - "baseUrl": "/dist", - "paths": {}, - "bundles": {} - } - } - }); - }, - err => t.fail(err.stack) - ); + .then(() => + bundler.capture({ + path: "src/app.js", + contents: "require('foo');", + moduleId: "app.js", + }) + ) + .then(() => bundler.resolve()) + .then(() => bundler.bundle()) + .then( + (bundleMap) => { + t.deepEqual(bundleMap, { + "entry-bundle": { + files: [ + { + path: "node_modules/dumber-module-loader/dist/index.debug.js", + contents: "dumber-module-loader;", + }, + { + contents: "define.switchToUserSpace();", + }, + { + path: "src/app.js", + contents: + "define('app.js',['require','exports','module','foo'],function (require, exports, module) {\nrequire('foo');\n});\n", + }, + { + contents: "define.switchToPackageSpace();", + }, + { + path: "node_modules/foo/foo.js", + contents: + "define('foo/foo.js',['require','exports','module'],function (require, exports, module) {\n\n});\n\n;define.alias('foo','foo/foo.js');", + }, + { + contents: "define.switchToUserSpace();", + }, + ], + config: { + baseUrl: "/dist", + paths: {}, + bundles: {}, + }, + }, + }); + }, + (err) => t.fail(err.stack) + ); }); -test('Bundler can use cache', t => { - const bundler = createBundler({}, {cache: true}); +test("Bundler can use cache", (t) => { + const bundler = mockBundler({}, { cache: true }); t.ok(bundler._cache); }); -test('Bundler can turn off cache', t => { - const bundler = createBundler({}, {cache: false}); +test("Bundler can turn off cache", (t) => { + const bundler = mockBundler({}, { cache: false }); t.notOk(bundler._cache); }); -test('Bundler can customise cache implementation', t => { +test("Bundler can customise cache implementation", (t) => { const getCache = () => {}; const setCache = () => {}; const clearCache = () => {}; - const bundler = createBundler({}, {cache: {getCache, setCache, clearCache}}); - t.deepEqual(bundler._cache, {getCache, setCache, clearCache}); + const bundler = mockBundler( + {}, + { cache: { getCache, setCache, clearCache } } + ); + t.deepEqual(bundler._cache, { getCache, setCache, clearCache }); }); -test('Bundler traces files, split bundles, continuously update bundles in watch mode', async t => { +test("Bundler traces files, split bundles, continuously update bundles in watch mode", async (t) => { const fakeFs = { - 'node_modules/dumber-module-loader/dist/index.debug.js': 'dumber-module-loader', - 'node_modules/foo/package.json': JSON.stringify({name: 'foo', main: 'index'}), - 'node_modules/foo/index.js': '', - 'node_modules/foo/bar.js': '', - 'node_modules/loo/package.json': JSON.stringify({name: 'loo', main: './loo'}), - 'node_modules/loo/loo.js': '', + "node_modules/dumber-module-loader/dist/index.debug.js": + "dumber-module-loader", + "node_modules/foo/package.json": JSON.stringify({ + name: "foo", + main: "index", + }), + "node_modules/foo/index.js": "", + "node_modules/foo/bar.js": "", + "node_modules/loo/package.json": JSON.stringify({ + name: "loo", + main: "./loo", + }), + "node_modules/loo/loo.js": "", }; - const bundler = createBundler(fakeFs, { + const bundler = mockBundler(fakeFs, { codeSplit: (moduleId, packageName) => { if (packageName) { - if (packageName !== 'loo') return 'vendor-bundle'; + if (packageName !== "loo") return "vendor-bundle"; } else { - if (moduleId.startsWith('page/')) return 'page-bundle'; - return 'app-bundle'; + if (moduleId.startsWith("page/")) return "page-bundle"; + return "app-bundle"; } - } + }, }); return Promise.resolve() - .then(() => bundler.capture({path: 'src/app.js', contents: "require('foo');require('page/one');", moduleId: 'app.js'})) - .then(() => bundler.capture({path: 'src/page/one.js', contents: '', moduleId: 'page/one.js'})) - .then(() => bundler.resolve()) - .then(() => bundler.bundle()) - .then( - bundleMap => { - t.deepEqual(bundleMap, { - "entry-bundle": { - "files": [ - { - "path": "node_modules/dumber-module-loader/dist/index.debug.js", - "contents": "dumber-module-loader;" - } - ], - "config": { - "baseUrl": "/dist", - "paths": {}, - "bundles": { - "app-bundle": { - "user": [ - "app.js" - ], - "package": [] - }, - "page-bundle": { - "user": [ - "page/one.js" - ], - "package": [] - }, - "vendor-bundle": { - "user": [], - "package": [ - "foo", - "foo/index.js" - ] - } - } - } - }, - "app-bundle": { - "files": [ - { - "contents": "define.switchToUserSpace();" - }, - { - "path": "src/app.js", - "contents": "define('app.js',['require','exports','module','foo','page/one'],function (require, exports, module) {\nrequire('foo');require('page/one');\n});\n" - } - ] - }, - "page-bundle": { - "files": [ - { - "contents": "define.switchToUserSpace();" - }, - { - "path": "src/page/one.js", - "contents": "define('page/one.js',['require','exports','module'],function (require, exports, module) {\n\n});\n" - } - ] - }, - "vendor-bundle": { - "files": [ - { - "contents": "define.switchToPackageSpace();" - }, - { - "path": "node_modules/foo/index.js", - "contents": "define('foo/index.js',['require','exports','module'],function (require, exports, module) {\n\n});\n\n;define.alias('foo','foo/index.js');" - }, - { - "contents": "define.switchToUserSpace();" - } - ] - } - }); - }, - err => t.fail(err.stack) - ) - .then(() => bundler.capture({path: 'src/page/one.js', contents: "require('foo/bar');require('loo');", moduleId: 'page/one.js'})) - .then(() => bundler.resolve()) - .then(() => bundler.bundle()) - .then( - bundleMap => { - t.deepEqual(bundleMap, { - "entry-bundle": { - "files": [ - { - "path": "node_modules/dumber-module-loader/dist/index.debug.js", - "contents": "dumber-module-loader;" - }, - { - "contents": "define.switchToPackageSpace();" - }, - { - "path": "node_modules/loo/loo.js", - "contents": "define('loo/loo.js',['require','exports','module'],function (require, exports, module) {\n\n});\n\n;define.alias('loo','loo/loo.js');" - }, - { - "contents": "define.switchToUserSpace();" - } - ], - "config": { - "baseUrl": "/dist", - "paths": {}, - "bundles": { - "app-bundle": { - "user": [ - "app.js" - ], - "package": [] - }, - "page-bundle": { - "user": [ - "page/one.js" - ], - "package": [] - }, - "vendor-bundle": { - "user": [], - "package": [ - "foo", - "foo/bar.js", - "foo/index.js" - ] - } - } - } - }, - "page-bundle": { - "files": [ - { - "contents": "define.switchToUserSpace();" - }, - { - "path": "src/page/one.js", - "contents": "define('page/one.js',['require','exports','module','foo/bar','loo'],function (require, exports, module) {\nrequire('foo/bar');require('loo');\n});\n" - } - ] - }, - "vendor-bundle": { - "files": [ - { - "contents": "define.switchToPackageSpace();" - }, - { - "path": "node_modules/foo/bar.js", - "contents": "define('foo/bar.js',['require','exports','module'],function (require, exports, module) {\n\n});\n" - }, - { - "path": "node_modules/foo/index.js", - "contents": "define('foo/index.js',['require','exports','module'],function (require, exports, module) {\n\n});\n\n;define.alias('foo','foo/index.js');" - }, - { - "contents": "define.switchToUserSpace();" - } - ] - } - }); - }, - err => t.fail(err.stack) - ) - .then(() => bundler.capture({path: 'src/goo.js', contents: '', moduleId: 'goo.js'})) - .then(() => bundler.capture({path: 'src/goo2.js', contents: '', moduleId: 'goo2.js'})) - .then(() => bundler.resolve()) - .then(() => bundler.bundle()) - .then( - bundleMap => { - t.deepEqual(bundleMap, { - "entry-bundle": { - "files": [ - { - "path": "node_modules/dumber-module-loader/dist/index.debug.js", - "contents": "dumber-module-loader;" - }, - { - "contents": "define.switchToPackageSpace();" - }, - { - "path": "node_modules/loo/loo.js", - "contents": "define('loo/loo.js',['require','exports','module'],function (require, exports, module) {\n\n});\n\n;define.alias('loo','loo/loo.js');" - }, - { - "contents": "define.switchToUserSpace();" - } - ], - "config": { - "baseUrl": "/dist", - "paths": {}, - "bundles": { - "app-bundle": { - "user": [ - "app.js", - "goo.js", - "goo2.js" - ], - "package": [] - }, - "page-bundle": { - "user": [ - "page/one.js" - ], - "package": [] - }, - "vendor-bundle": { - "user": [], - "package": [ - "foo", - "foo/bar.js", - "foo/index.js" - ] - } - } - } - }, - "app-bundle": { - "files": [ - { - "contents": "define.switchToUserSpace();" + .then(() => + bundler.capture({ + path: "src/app.js", + contents: "require('foo');require('page/one');", + moduleId: "app.js", + }) + ) + .then(() => + bundler.capture({ + path: "src/page/one.js", + contents: "", + moduleId: "page/one.js", + }) + ) + .then(() => bundler.resolve()) + .then(() => bundler.bundle()) + .then( + (bundleMap) => { + t.deepEqual(bundleMap, { + "entry-bundle": { + files: [ + { + path: "node_modules/dumber-module-loader/dist/index.debug.js", + contents: "dumber-module-loader;", + }, + ], + config: { + baseUrl: "/dist", + paths: {}, + bundles: { + "app-bundle": { + user: ["app.js"], + package: [], + }, + "page-bundle": { + user: ["page/one.js"], + package: [], + }, + "vendor-bundle": { + user: [], + package: ["foo", "foo/index.js"], + }, + }, }, - { - "path": "src/app.js", - "contents": "define('app.js',['require','exports','module','foo','page/one'],function (require, exports, module) {\nrequire('foo');require('page/one');\n});\n" + }, + "app-bundle": { + files: [ + { + contents: "define.switchToUserSpace();", + }, + { + path: "src/app.js", + contents: + "define('app.js',['require','exports','module','foo','page/one'],function (require, exports, module) {\nrequire('foo');require('page/one');\n});\n", + }, + ], + }, + "page-bundle": { + files: [ + { + contents: "define.switchToUserSpace();", + }, + { + path: "src/page/one.js", + contents: + "define('page/one.js',['require','exports','module'],function (require, exports, module) {\n\n});\n", + }, + ], + }, + "vendor-bundle": { + files: [ + { + contents: "define.switchToPackageSpace();", + }, + { + path: "node_modules/foo/index.js", + contents: + "define('foo/index.js',['require','exports','module'],function (require, exports, module) {\n\n});\n\n;define.alias('foo','foo/index.js');", + }, + { + contents: "define.switchToUserSpace();", + }, + ], + }, + }); + }, + (err) => t.fail(err.stack) + ) + .then(() => + bundler.capture({ + path: "src/page/one.js", + contents: "require('foo/bar');require('loo');", + moduleId: "page/one.js", + }) + ) + .then(() => bundler.resolve()) + .then(() => bundler.bundle()) + .then( + (bundleMap) => { + t.deepEqual(bundleMap, { + "entry-bundle": { + files: [ + { + path: "node_modules/dumber-module-loader/dist/index.debug.js", + contents: "dumber-module-loader;", + }, + { + contents: "define.switchToPackageSpace();", + }, + { + path: "node_modules/loo/loo.js", + contents: + "define('loo/loo.js',['require','exports','module'],function (require, exports, module) {\n\n});\n\n;define.alias('loo','loo/loo.js');", + }, + { + contents: "define.switchToUserSpace();", + }, + ], + config: { + baseUrl: "/dist", + paths: {}, + bundles: { + "app-bundle": { + user: ["app.js"], + package: [], + }, + "page-bundle": { + user: ["page/one.js"], + package: [], + }, + "vendor-bundle": { + user: [], + package: ["foo", "foo/bar.js", "foo/index.js"], + }, + }, }, - { - "path": "src/goo.js", - "contents": "define('goo.js',['require','exports','module'],function (require, exports, module) {\n\n});\n" + }, + "page-bundle": { + files: [ + { + contents: "define.switchToUserSpace();", + }, + { + path: "src/page/one.js", + contents: + "define('page/one.js',['require','exports','module','foo/bar','loo'],function (require, exports, module) {\nrequire('foo/bar');require('loo');\n});\n", + }, + ], + }, + "vendor-bundle": { + files: [ + { + contents: "define.switchToPackageSpace();", + }, + { + path: "node_modules/foo/bar.js", + contents: + "define('foo/bar.js',['require','exports','module'],function (require, exports, module) {\n\n});\n", + }, + { + path: "node_modules/foo/index.js", + contents: + "define('foo/index.js',['require','exports','module'],function (require, exports, module) {\n\n});\n\n;define.alias('foo','foo/index.js');", + }, + { + contents: "define.switchToUserSpace();", + }, + ], + }, + }); + }, + (err) => t.fail(err.stack) + ) + .then(() => + bundler.capture({ path: "src/goo.js", contents: "", moduleId: "goo.js" }) + ) + .then(() => + bundler.capture({ + path: "src/goo2.js", + contents: "", + moduleId: "goo2.js", + }) + ) + .then(() => bundler.resolve()) + .then(() => bundler.bundle()) + .then( + (bundleMap) => { + t.deepEqual(bundleMap, { + "entry-bundle": { + files: [ + { + path: "node_modules/dumber-module-loader/dist/index.debug.js", + contents: "dumber-module-loader;", + }, + { + contents: "define.switchToPackageSpace();", + }, + { + path: "node_modules/loo/loo.js", + contents: + "define('loo/loo.js',['require','exports','module'],function (require, exports, module) {\n\n});\n\n;define.alias('loo','loo/loo.js');", + }, + { + contents: "define.switchToUserSpace();", + }, + ], + config: { + baseUrl: "/dist", + paths: {}, + bundles: { + "app-bundle": { + user: ["app.js", "goo.js", "goo2.js"], + package: [], + }, + "page-bundle": { + user: ["page/one.js"], + package: [], + }, + "vendor-bundle": { + user: [], + package: ["foo", "foo/bar.js", "foo/index.js"], + }, + }, }, - { - "path": "src/goo2.js", - "contents": "define('goo2.js',['require','exports','module'],function (require, exports, module) {\n\n});\n" - } - ] - } - }); - }, - err => t.fail(err.stack) - ); + }, + "app-bundle": { + files: [ + { + contents: "define.switchToUserSpace();", + }, + { + path: "src/app.js", + contents: + "define('app.js',['require','exports','module','foo','page/one'],function (require, exports, module) {\nrequire('foo');require('page/one');\n});\n", + }, + { + path: "src/goo.js", + contents: + "define('goo.js',['require','exports','module'],function (require, exports, module) {\n\n});\n", + }, + { + path: "src/goo2.js", + contents: + "define('goo2.js',['require','exports','module'],function (require, exports, module) {\n\n});\n", + }, + ], + }, + }); + }, + (err) => t.fail(err.stack) + ); }); -test('Bundler supports inject css by default', async t => { +test("Bundler supports inject css by default", async (t) => { const fakeFs = { - 'node_modules/dumber-module-loader/dist/index.debug.js': 'dumber-module-loader', - 'node_modules/dumber/package.json': JSON.stringify({name: 'dumber', main: './dist/index'}), - 'node_modules/dumber/lib/inject-css.js': '', + "node_modules/dumber-module-loader/dist/index.debug.js": + "dumber-module-loader", + "node_modules/dumber/package.json": JSON.stringify({ + name: "dumber", + main: "./dist/index", + }), + "node_modules/dumber/lib/inject-css.js": "", }; - const bundler = createBundler(fakeFs, { - }); + const bundler = mockBundler(fakeFs, {}); return Promise.resolve() - .then(() => bundler.capture({path: 'src/app.js', contents: "require('c.css')", moduleId: 'app.js'})) - .then(() => bundler.capture({path: 'src/c.css', contents: 'lorem', moduleId: 'c.css'})) - .then(() => bundler.resolve()) - .then(() => bundler.bundle()) - .then( - bundleMap => { - t.deepEqual(bundleMap, { - "entry-bundle": { - "files": [ - { - "path": "node_modules/dumber-module-loader/dist/index.debug.js", - "contents": "dumber-module-loader;" - }, - { - "contents": "define.switchToUserSpace();" - }, - { - "path": "src/app.js", - "contents": "define('app.js',['require','exports','module','c.css'],function (require, exports, module) {\nrequire('c.css')\n});\n" - }, - { - "path": "src/c.css", - "contents": "define('text!c.css',function(){return \"lorem\";});" - }, - { - "path": "__stub__/ext-css.js", - "contents": "define('ext:css',['dumber/lib/inject-css'],function(m){return m;});\n;define.alias('ext:less','ext:css');\n;define.alias('ext:scss','ext:css');\n;define.alias('ext:sass','ext:css');\n;define.alias('ext:styl','ext:css');" - }, - { - "contents": "define.switchToPackageSpace();" - }, - { - "path": "node_modules/dumber/lib/inject-css.js", - "contents": "define('dumber/lib/inject-css.js',['require','exports','module'],function (require, exports, module) {\n\n});\n" - }, - { - "contents": "define.switchToUserSpace();" - } - ], - "config": { - "baseUrl": "/dist", - "paths": {}, - "bundles": {} - } - } - }); - }, - err => t.fail(err.stack) - ); + .then(() => + bundler.capture({ + path: "src/app.js", + contents: "require('c.css')", + moduleId: "app.js", + }) + ) + .then(() => + bundler.capture({ + path: "src/c.css", + contents: "lorem", + moduleId: "c.css", + }) + ) + .then(() => bundler.resolve()) + .then(() => bundler.bundle()) + .then( + (bundleMap) => { + t.deepEqual(bundleMap, { + "entry-bundle": { + files: [ + { + path: "node_modules/dumber-module-loader/dist/index.debug.js", + contents: "dumber-module-loader;", + }, + { + contents: "define.switchToUserSpace();", + }, + { + path: "src/app.js", + contents: + "define('app.js',['require','exports','module','c.css'],function (require, exports, module) {\nrequire('c.css')\n});\n", + }, + { + path: "src/c.css", + contents: "define('text!c.css',function(){return \"lorem\";});", + }, + { + path: "__stub__/ext-css.js", + contents: + "define('ext:css',['dumber/lib/inject-css'],function(m){return m;});\n;define.alias('ext:less','ext:css');\n;define.alias('ext:scss','ext:css');\n;define.alias('ext:sass','ext:css');\n;define.alias('ext:styl','ext:css');", + }, + { + contents: "define.switchToPackageSpace();", + }, + { + path: "node_modules/dumber/lib/inject-css.js", + contents: + "define('dumber/lib/inject-css.js',['require','exports','module'],function (require, exports, module) {\n\n});\n", + }, + { + contents: "define.switchToUserSpace();", + }, + ], + config: { + baseUrl: "/dist", + paths: {}, + bundles: {}, + }, + }, + }); + }, + (err) => t.fail(err.stack) + ); }); -test('Bundler supports inject css (relative path) by default', async t => { +test("Bundler supports inject css (relative path) by default", async (t) => { const fakeFs = { - 'node_modules/dumber-module-loader/dist/index.debug.js': 'dumber-module-loader', - 'node_modules/dumber/package.json': JSON.stringify({name: 'dumber', main: './dist/index'}), - 'node_modules/dumber/lib/inject-css.js': '', + "node_modules/dumber-module-loader/dist/index.debug.js": + "dumber-module-loader", + "node_modules/dumber/package.json": JSON.stringify({ + name: "dumber", + main: "./dist/index", + }), + "node_modules/dumber/lib/inject-css.js": "", }; - const bundler = createBundler(fakeFs, { - }); + const bundler = mockBundler(fakeFs, {}); return Promise.resolve() - .then(() => bundler.capture({path: 'src/app.js', contents: "require('./c.scss')", moduleId: 'app.js'})) - .then(() => bundler.capture({path: 'src/c.css', contents: 'lorem', moduleId: 'c.css'})) - .then(() => bundler.resolve()) - .then(() => bundler.bundle()) - .then( - bundleMap => { - t.deepEqual(bundleMap, { - "entry-bundle": { - "files": [ - { - "path": "node_modules/dumber-module-loader/dist/index.debug.js", - "contents": "dumber-module-loader;" - }, - { - "contents": "define.switchToUserSpace();" - }, - { - "path": "src/app.js", - "contents": "define('app.js',['require','exports','module','./c.scss'],function (require, exports, module) {\nrequire('./c.scss')\n});\n" - }, - { - "path": "src/c.css", - "contents": "define('text!c.css',function(){return \"lorem\";});" - }, - { - "path": "__stub__/ext-css.js", - "contents": "define('ext:css',['dumber/lib/inject-css'],function(m){return m;});\n;define.alias('ext:less','ext:css');\n;define.alias('ext:scss','ext:css');\n;define.alias('ext:sass','ext:css');\n;define.alias('ext:styl','ext:css');" - }, - { - "contents": "define.switchToPackageSpace();" - }, - { - "path": "node_modules/dumber/lib/inject-css.js", - "contents": "define('dumber/lib/inject-css.js',['require','exports','module'],function (require, exports, module) {\n\n});\n" - }, - { - "contents": "define.switchToUserSpace();" - } - ], - "config": { - "baseUrl": "/dist", - "paths": {}, - "bundles": {} - } - } - }); - }, - err => t.fail(err.stack) - ); + .then(() => + bundler.capture({ + path: "src/app.js", + contents: "require('./c.scss')", + moduleId: "app.js", + }) + ) + .then(() => + bundler.capture({ + path: "src/c.css", + contents: "lorem", + moduleId: "c.css", + }) + ) + .then(() => bundler.resolve()) + .then(() => bundler.bundle()) + .then( + (bundleMap) => { + t.deepEqual(bundleMap, { + "entry-bundle": { + files: [ + { + path: "node_modules/dumber-module-loader/dist/index.debug.js", + contents: "dumber-module-loader;", + }, + { + contents: "define.switchToUserSpace();", + }, + { + path: "src/app.js", + contents: + "define('app.js',['require','exports','module','./c.scss'],function (require, exports, module) {\nrequire('./c.scss')\n});\n", + }, + { + path: "src/c.css", + contents: "define('text!c.css',function(){return \"lorem\";});", + }, + { + path: "__stub__/ext-css.js", + contents: + "define('ext:css',['dumber/lib/inject-css'],function(m){return m;});\n;define.alias('ext:less','ext:css');\n;define.alias('ext:scss','ext:css');\n;define.alias('ext:sass','ext:css');\n;define.alias('ext:styl','ext:css');", + }, + { + contents: "define.switchToPackageSpace();", + }, + { + path: "node_modules/dumber/lib/inject-css.js", + contents: + "define('dumber/lib/inject-css.js',['require','exports','module'],function (require, exports, module) {\n\n});\n", + }, + { + contents: "define.switchToUserSpace();", + }, + ], + config: { + baseUrl: "/dist", + paths: {}, + bundles: {}, + }, + }, + }); + }, + (err) => t.fail(err.stack) + ); }); -test('Bundler can optionally turn off inject css', async t => { +test("Bundler can optionally turn off inject css", async (t) => { const fakeFs = { - 'node_modules/dumber-module-loader/dist/index.debug.js': 'dumber-module-loader', - 'node_modules/dumber/package.json': JSON.stringify({name: 'dumber', main: './dist/index'}), - 'node_modules/dumber/lib/inject-css.js': '', + "node_modules/dumber-module-loader/dist/index.debug.js": + "dumber-module-loader", + "node_modules/dumber/package.json": JSON.stringify({ + name: "dumber", + main: "./dist/index", + }), + "node_modules/dumber/lib/inject-css.js": "", }; - const bundler = createBundler(fakeFs, { - injectCss: false + const bundler = mockBundler(fakeFs, { + injectCss: false, }); return Promise.resolve() - .then(() => bundler.capture({path: 'src/app.js', contents: "require('c.css')", moduleId: 'app.js'})) - .then(() => bundler.capture({path: 'src/c.css', contents: 'lorem', moduleId: 'c.css'})) - .then(() => bundler.resolve()) - .then(() => bundler.bundle()) - .then( - bundleMap => { - t.deepEqual(bundleMap, { - "entry-bundle": { - "files": [ - { - "path": "node_modules/dumber-module-loader/dist/index.debug.js", - "contents": "dumber-module-loader;" - }, - { - "contents": "define.switchToUserSpace();" - }, - { - "path": "src/app.js", - "contents": "define('app.js',['require','exports','module','c.css'],function (require, exports, module) {\nrequire('c.css')\n});\n" - }, - { - "path": "src/c.css", - "contents": "define('text!c.css',function(){return \"lorem\";});" - } - ], - "config": { - "baseUrl": "/dist", - "paths": {}, - "bundles": {} - } - } - }); - }, - err => t.fail(err.stack) - ); + .then(() => + bundler.capture({ + path: "src/app.js", + contents: "require('c.css')", + moduleId: "app.js", + }) + ) + .then(() => + bundler.capture({ + path: "src/c.css", + contents: "lorem", + moduleId: "c.css", + }) + ) + .then(() => bundler.resolve()) + .then(() => bundler.bundle()) + .then( + (bundleMap) => { + t.deepEqual(bundleMap, { + "entry-bundle": { + files: [ + { + path: "node_modules/dumber-module-loader/dist/index.debug.js", + contents: "dumber-module-loader;", + }, + { + contents: "define.switchToUserSpace();", + }, + { + path: "src/app.js", + contents: + "define('app.js',['require','exports','module','c.css'],function (require, exports, module) {\nrequire('c.css')\n});\n", + }, + { + path: "src/c.css", + contents: "define('text!c.css',function(){return \"lorem\";});", + }, + ], + config: { + baseUrl: "/dist", + paths: {}, + bundles: {}, + }, + }, + }); + }, + (err) => t.fail(err.stack) + ); }); -test('Bundler traces files with paths mapping', async t => { +test("Bundler traces files with paths mapping", async (t) => { const fakeFs = { - 'node_modules/dumber-module-loader/dist/index.debug.js': 'dumber-module-loader', - 'node_modules/foo/package.json': JSON.stringify({name: 'foo', main: 'index'}), - 'node_modules/foo/index.js': "require('loo');", - 'node_modules/bar/package.json': JSON.stringify({name: 'bar', main: 'index'}), - 'node_modules/bar/index.js': 'exports.bar = 1;', - 'node_modules/bar/el.js': 'exports.el = 1;', + "node_modules/dumber-module-loader/dist/index.debug.js": + "dumber-module-loader", + "node_modules/foo/package.json": JSON.stringify({ + name: "foo", + main: "index", + }), + "node_modules/foo/index.js": "require('loo');", + "node_modules/bar/package.json": JSON.stringify({ + name: "bar", + main: "index", + }), + "node_modules/bar/index.js": "exports.bar = 1;", + "node_modules/bar/el.js": "exports.el = 1;", }; - const bundler = createBundler(fakeFs, { + const bundler = mockBundler(fakeFs, { paths: { - 'foo': 'common/foo', - 'el': 'bar/el', - '../src': '' - } + foo: "common/foo", + el: "bar/el", + "../src": "", + }, }); return Promise.resolve() - .then(() => bundler.capture({path: 'src/app.js', contents: "import 'el!foo';", moduleId: 'app.js'})) - .then(() => bundler.capture({path: 'src/common/foo.js', contents: '', moduleId: 'common/foo.js'})) - .then(() => bundler.capture({path: 'test/app.spec.js', contents: "import '../src/app';", moduleId: '../test/app.spec.js'})) - .then(() => bundler.resolve()) - .then(() => bundler.bundle()) - .then( - bundleMap => { - t.deepEqual(bundleMap, { - "entry-bundle": { - "files": [ - { - "path": "node_modules/dumber-module-loader/dist/index.debug.js", - "contents": "dumber-module-loader;" - }, - { - "contents": "define.switchToUserSpace();" - }, - { - "path": "test/app.spec.js", - "contents": 'define(\'../test/app.spec.js\',[\'require\',\'exports\',\'module\',\'../src/app\'],function (require, exports, module) {\n"use strict";\nObject.defineProperty(exports, "__esModule", { value: true });\nrequire("../src/app");\n\n});\n' - }, - { - "path": "src/app.js", - "contents": 'define(\'app.js\',[\'require\',\'exports\',\'module\',\'el!foo\'],function (require, exports, module) {\n"use strict";\nObject.defineProperty(exports, "__esModule", { value: true });\nrequire("el!foo");\n\n});\n' - }, - { - "path": "src/common/foo.js", - "contents": "define('common/foo.js',['require','exports','module'],function (require, exports, module) {\n\n});\n" - }, - { - "contents": "define.switchToPackageSpace();" - }, - { - "path": "node_modules/bar/el.js", - "contents": "define('bar/el.js',['require','exports','module'],function (require, exports, module) {\nexports.el = 1;\n});\n" - }, - { - "contents": "define.switchToUserSpace();" - } - ], - "config": { - "baseUrl": "/dist", - "paths": { - "foo": "common/foo", - "el": "bar/el", - "../src": "" + .then(() => + bundler.capture({ + path: "src/app.js", + contents: "import 'el!foo';", + moduleId: "app.js", + }) + ) + .then(() => + bundler.capture({ + path: "src/common/foo.js", + contents: "", + moduleId: "common/foo.js", + }) + ) + .then(() => + bundler.capture({ + path: "test/app.spec.js", + contents: "import '../src/app';", + moduleId: "../test/app.spec.js", + }) + ) + .then(() => bundler.resolve()) + .then(() => bundler.bundle()) + .then( + (bundleMap) => { + t.deepEqual(bundleMap, { + "entry-bundle": { + files: [ + { + path: "node_modules/dumber-module-loader/dist/index.debug.js", + contents: "dumber-module-loader;", + }, + { + contents: "define.switchToUserSpace();", + }, + { + path: "test/app.spec.js", + contents: + "define('../test/app.spec.js',['require','exports','module','../src/app'],function (require, exports, module) {\n\"use strict\";\nObject.defineProperty(exports, \"__esModule\", { value: true });\nrequire(\"../src/app\");\n\n});\n", + }, + { + path: "src/app.js", + contents: + "define('app.js',['require','exports','module','el!foo'],function (require, exports, module) {\n\"use strict\";\nObject.defineProperty(exports, \"__esModule\", { value: true });\nrequire(\"el!foo\");\n\n});\n", + }, + { + path: "src/common/foo.js", + contents: + "define('common/foo.js',['require','exports','module'],function (require, exports, module) {\n\n});\n", + }, + { + contents: "define.switchToPackageSpace();", + }, + { + path: "node_modules/bar/el.js", + contents: + "define('bar/el.js',['require','exports','module'],function (require, exports, module) {\nexports.el = 1;\n});\n", + }, + { + contents: "define.switchToUserSpace();", + }, + ], + config: { + baseUrl: "/dist", + paths: { + foo: "common/foo", + el: "bar/el", + "../src": "", + }, + bundles: {}, }, - "bundles": {} - } - } - }); - }, - err => t.fail(err.stack) - ); + }, + }); + }, + (err) => t.fail(err.stack) + ); }); -test('Bundler allows same modules in both user and package space', async t => { +test("Bundler allows same modules in both user and package space", async (t) => { const fakeFs = { - 'node_modules/dumber-module-loader/dist/index.debug.js': 'dumber-module-loader', - 'node_modules/foo/package.json': JSON.stringify({name: 'foo', main: 'index'}), - 'node_modules/foo/index.js': "require('util');", - 'node_modules/foo/bar.js': 'exports.bar = 1;', - 'node_modules/util/package.json': JSON.stringify({name: 'util', main: './util'}), - 'node_modules/util/util.js': 'exports.util = 1;', + "node_modules/dumber-module-loader/dist/index.debug.js": + "dumber-module-loader", + "node_modules/foo/package.json": JSON.stringify({ + name: "foo", + main: "index", + }), + "node_modules/foo/index.js": "require('util');", + "node_modules/foo/bar.js": "exports.bar = 1;", + "node_modules/util/package.json": JSON.stringify({ + name: "util", + main: "./util", + }), + "node_modules/util/util.js": "exports.util = 1;", }; - const bundler = createBundler(fakeFs); + const bundler = mockBundler(fakeFs); return Promise.resolve() - .then(() => bundler.capture({path: 'src/app.js', contents: "import 'foo';\nimport './util'", moduleId: 'app.js'})) - .then(() => bundler.capture({path: 'src/util.js', contents: 'export default function(){}', moduleId: 'util.js'})) - .then(() => bundler.resolve()) - .then(() => bundler.bundle()) - .then( - bundleMap => { - t.deepEqual(bundleMap, { - "entry-bundle": { - "files": [ - { - "path": "node_modules/dumber-module-loader/dist/index.debug.js", - "contents": "dumber-module-loader;" - }, - { - "contents": "define.switchToUserSpace();" - }, - { - "path": "src/app.js", - "contents": 'define(\'app.js\',[\'require\',\'exports\',\'module\',\'foo\',\'./util\'],function (require, exports, module) {\n"use strict";\nObject.defineProperty(exports, "__esModule", { value: true });\nrequire("foo");\nrequire("./util");\n\n});\n' - }, - { - "path": "src/util.js", - "contents": 'define(\'util.js\',[\'require\',\'exports\',\'module\'],function (require, exports, module) {\n"use strict";\nObject.defineProperty(exports, "__esModule", { value: true });\nexports.default = default_1;\nfunction default_1() { }\n\n});\n' - }, - { - "contents": "define.switchToPackageSpace();" - }, - { - "path": "node_modules/foo/index.js", - "contents": "define('foo/index.js',['require','exports','module','util'],function (require, exports, module) {\nrequire('util');\n});\n\n;define.alias('foo','foo/index.js');" - }, - { - "path": "node_modules/util/util.js", - "contents": "define('util/util.js',['require','exports','module'],function (require, exports, module) {\nexports.util = 1;\n});\n\n;define.alias('util','util/util.js');" - }, - { - "contents": "define.switchToUserSpace();" - } - ], - "config": { - "baseUrl": "/dist", - "paths": {}, - "bundles": {} - } - } - }); - }, - err => t.fail(err.stack) - ); + .then(() => + bundler.capture({ + path: "src/app.js", + contents: "import 'foo';\nimport './util'", + moduleId: "app.js", + }) + ) + .then(() => + bundler.capture({ + path: "src/util.js", + contents: "export default function(){}", + moduleId: "util.js", + }) + ) + .then(() => bundler.resolve()) + .then(() => bundler.bundle()) + .then( + (bundleMap) => { + t.deepEqual(bundleMap, { + "entry-bundle": { + files: [ + { + path: "node_modules/dumber-module-loader/dist/index.debug.js", + contents: "dumber-module-loader;", + }, + { + contents: "define.switchToUserSpace();", + }, + { + path: "src/app.js", + contents: + "define('app.js',['require','exports','module','foo','./util'],function (require, exports, module) {\n\"use strict\";\nObject.defineProperty(exports, \"__esModule\", { value: true });\nrequire(\"foo\");\nrequire(\"./util\");\n\n});\n", + }, + { + path: "src/util.js", + contents: + "define('util.js',['require','exports','module'],function (require, exports, module) {\n\"use strict\";\nObject.defineProperty(exports, \"__esModule\", { value: true });\nexports.default = default_1;\nfunction default_1() { }\n\n});\n", + }, + { + contents: "define.switchToPackageSpace();", + }, + { + path: "node_modules/foo/index.js", + contents: + "define('foo/index.js',['require','exports','module','util'],function (require, exports, module) {\nrequire('util');\n});\n\n;define.alias('foo','foo/index.js');", + }, + { + path: "node_modules/util/util.js", + contents: + "define('util/util.js',['require','exports','module'],function (require, exports, module) {\nexports.util = 1;\n});\n\n;define.alias('util','util/util.js');", + }, + { + contents: "define.switchToUserSpace();", + }, + ], + config: { + baseUrl: "/dist", + paths: {}, + bundles: {}, + }, + }, + }); + }, + (err) => t.fail(err.stack) + ); }); -test('Bundler supports deps alias', async t => { +test("Bundler supports deps alias", async (t) => { const fakeFs = { - 'node_modules/dumber-module-loader/dist/index.debug.js': 'dumber-module-loader', - 'node_modules/foo/package.json': JSON.stringify({name: 'foo', main: 'index'}), - 'node_modules/foo/index.js': 'exports.foo = 1;', - 'node_modules/foo/bar.js': 'exports.bar = 1;' + "node_modules/dumber-module-loader/dist/index.debug.js": + "dumber-module-loader", + "node_modules/foo/package.json": JSON.stringify({ + name: "foo", + main: "index", + }), + "node_modules/foo/index.js": "exports.foo = 1;", + "node_modules/foo/bar.js": "exports.bar = 1;", }; - const bundler = createBundler(fakeFs, { + const bundler = mockBundler(fakeFs, { cache: false, - deps: [{ - name: 'bar', - location: 'node_modules/foo' - }] + deps: [ + { + name: "bar", + location: "node_modules/foo", + }, + ], }); return Promise.resolve() - .then(() => bundler.capture({path: 'src/app.js', contents: "import 'bar';", moduleId: 'app.js'})) - .then(() => bundler.capture({path: 'src/foo.js', contents: "import 'bar/bar';", moduleId: 'foo.js'})) - .then(() => bundler.resolve()) - .then(() => bundler.bundle()) - .then( - bundleMap => { - t.deepEqual(bundleMap, { - "entry-bundle": { - "files": [ - { - "path": "node_modules/dumber-module-loader/dist/index.debug.js", - "contents": "dumber-module-loader;" - }, - { - "contents": "define.switchToUserSpace();" - }, - { - "path": "src/app.js", - "contents": 'define(\'app.js\',[\'require\',\'exports\',\'module\',\'bar\'],function (require, exports, module) {\n"use strict";\nObject.defineProperty(exports, "__esModule", { value: true });\nrequire("bar");\n\n});\n' - }, - { - "path": "src/foo.js", - "contents": 'define(\'foo.js\',[\'require\',\'exports\',\'module\',\'bar/bar\'],function (require, exports, module) {\n"use strict";\nObject.defineProperty(exports, "__esModule", { value: true });\nrequire("bar/bar");\n\n});\n' - }, - { - "contents": "define.switchToPackageSpace();" - }, - { - "path": "node_modules/foo/bar.js", - "contents": "define('bar/bar.js',['require','exports','module'],function (require, exports, module) {\nexports.bar = 1;\n});\n" - }, - { - "path": "node_modules/foo/index.js", - "contents": "define('bar/index.js',['require','exports','module'],function (require, exports, module) {\nexports.foo = 1;\n});\n\n;define.alias('bar','bar/index.js');" - }, - { - "contents": "define.switchToUserSpace();" - } - ], - "config": { - "baseUrl": "/dist", - "paths": {}, - "bundles": {} - } - } - }); - }, - err => t.fail(err.stack) - ); + .then(() => + bundler.capture({ + path: "src/app.js", + contents: "import 'bar';", + moduleId: "app.js", + }) + ) + .then(() => + bundler.capture({ + path: "src/foo.js", + contents: "import 'bar/bar';", + moduleId: "foo.js", + }) + ) + .then(() => bundler.resolve()) + .then(() => bundler.bundle()) + .then( + (bundleMap) => { + t.deepEqual(bundleMap, { + "entry-bundle": { + files: [ + { + path: "node_modules/dumber-module-loader/dist/index.debug.js", + contents: "dumber-module-loader;", + }, + { + contents: "define.switchToUserSpace();", + }, + { + path: "src/app.js", + contents: + "define('app.js',['require','exports','module','bar'],function (require, exports, module) {\n\"use strict\";\nObject.defineProperty(exports, \"__esModule\", { value: true });\nrequire(\"bar\");\n\n});\n", + }, + { + path: "src/foo.js", + contents: + "define('foo.js',['require','exports','module','bar/bar'],function (require, exports, module) {\n\"use strict\";\nObject.defineProperty(exports, \"__esModule\", { value: true });\nrequire(\"bar/bar\");\n\n});\n", + }, + { + contents: "define.switchToPackageSpace();", + }, + { + path: "node_modules/foo/bar.js", + contents: + "define('bar/bar.js',['require','exports','module'],function (require, exports, module) {\nexports.bar = 1;\n});\n", + }, + { + path: "node_modules/foo/index.js", + contents: + "define('bar/index.js',['require','exports','module'],function (require, exports, module) {\nexports.foo = 1;\n});\n\n;define.alias('bar','bar/index.js');", + }, + { + contents: "define.switchToUserSpace();", + }, + ], + config: { + baseUrl: "/dist", + paths: {}, + bundles: {}, + }, + }, + }); + }, + (err) => t.fail(err.stack) + ); }); -test('Bundler supports package alias with lazyMain mode', async t => { +test("Bundler supports package alias with lazyMain mode", async (t) => { const fakeFs = { - 'node_modules/dumber-module-loader/dist/index.debug.js': 'dumber-module-loader', - 'node_modules/foo/package.json': JSON.stringify({name: 'foo', main: 'index'}), - 'node_modules/foo/index.js': 'exports.foo = 1;', - 'node_modules/foo/bar.js': 'exports.bar = 1;' + "node_modules/dumber-module-loader/dist/index.debug.js": + "dumber-module-loader", + "node_modules/foo/package.json": JSON.stringify({ + name: "foo", + main: "index", + }), + "node_modules/foo/index.js": "exports.foo = 1;", + "node_modules/foo/bar.js": "exports.bar = 1;", }; - const bundler = createBundler(fakeFs, { - deps: [{ - name: 'bar', - location: 'node_modules/foo', - lazyMain: true - }] + const bundler = mockBundler(fakeFs, { + deps: [ + { + name: "bar", + location: "node_modules/foo", + lazyMain: true, + }, + ], }); return Promise.resolve() - .then(() => bundler.capture({path: 'src/app.js', contents: "import 'bar/bar';", moduleId: 'app.js'})) - .then(() => bundler.resolve()) - .then(() => bundler.bundle()) - .then( - bundleMap => { - t.deepEqual(bundleMap, { - "entry-bundle": { - "files": [ - { - "path": "node_modules/dumber-module-loader/dist/index.debug.js", - "contents": "dumber-module-loader;" - }, - { - "contents": "define.switchToUserSpace();" - }, - { - "path": "src/app.js", - "contents": 'define(\'app.js\',[\'require\',\'exports\',\'module\',\'bar/bar\'],function (require, exports, module) {\n"use strict";\nObject.defineProperty(exports, "__esModule", { value: true });\nrequire("bar/bar");\n\n});\n' - }, - { - "contents": "define.switchToPackageSpace();" - }, - { - "path": "node_modules/foo/bar.js", - "contents": "define('bar/bar.js',['require','exports','module'],function (require, exports, module) {\nexports.bar = 1;\n});\n" - }, - { - "contents": "define.switchToUserSpace();" - } - ], - "config": { - "baseUrl": "/dist", - "paths": {}, - "bundles": {} - } - } - }); - }, - err => t.fail(err.stack) - ); + .then(() => + bundler.capture({ + path: "src/app.js", + contents: "import 'bar/bar';", + moduleId: "app.js", + }) + ) + .then(() => bundler.resolve()) + .then(() => bundler.bundle()) + .then( + (bundleMap) => { + t.deepEqual(bundleMap, { + "entry-bundle": { + files: [ + { + path: "node_modules/dumber-module-loader/dist/index.debug.js", + contents: "dumber-module-loader;", + }, + { + contents: "define.switchToUserSpace();", + }, + { + path: "src/app.js", + contents: + "define('app.js',['require','exports','module','bar/bar'],function (require, exports, module) {\n\"use strict\";\nObject.defineProperty(exports, \"__esModule\", { value: true });\nrequire(\"bar/bar\");\n\n});\n", + }, + { + contents: "define.switchToPackageSpace();", + }, + { + path: "node_modules/foo/bar.js", + contents: + "define('bar/bar.js',['require','exports','module'],function (require, exports, module) {\nexports.bar = 1;\n});\n", + }, + { + contents: "define.switchToUserSpace();", + }, + ], + config: { + baseUrl: "/dist", + paths: {}, + bundles: {}, + }, + }, + }); + }, + (err) => t.fail(err.stack) + ); }); -test('Bundler creates correct alias for named AMD module which does not match package name', async t => { +test("Bundler creates correct alias for named AMD module which does not match package name", async (t) => { const fakeFs = { - 'node_modules/dumber-module-loader/dist/index.debug.js': 'dumber-module-loader', - 'node_modules/noty/package.json': JSON.stringify({name: 'noty', main: 'lib/noty.js'}), - 'node_modules/noty/lib/noty.js': 'define("Noty",[],function(){});', + "node_modules/dumber-module-loader/dist/index.debug.js": + "dumber-module-loader", + "node_modules/noty/package.json": JSON.stringify({ + name: "noty", + main: "lib/noty.js", + }), + "node_modules/noty/lib/noty.js": 'define("Noty",[],function(){});', }; - const bundler = createBundler(fakeFs); + const bundler = mockBundler(fakeFs); return Promise.resolve() - .then(() => bundler.capture({path: 'src/app.js', contents: "require('noty');", moduleId: 'app.js'})) - .then(() => bundler.resolve()) - .then(() => bundler.bundle()) - .then( - bundleMap => { - t.deepEqual(bundleMap, { - "entry-bundle": { - "files": [ - { - "path": "node_modules/dumber-module-loader/dist/index.debug.js", - "contents": "dumber-module-loader;" - }, - { - "contents": "define.switchToUserSpace();" - }, - { - "path": "src/app.js", - "contents": "define('app.js',['require','exports','module','noty'],function (require, exports, module) {\nrequire('noty');\n});\n" - }, - { - "contents": "define.switchToPackageSpace();" - }, - { - "path": "node_modules/noty/lib/noty.js", - "contents": "define(\"Noty\",[],function(){});\n;define.alias('noty','Noty');" - }, - { - "contents": "define.switchToUserSpace();" - } - ], - "config": { - "baseUrl": "/dist", - "paths": {}, - "bundles": {} - } - } - }); - }, - err => t.fail(err.stack) - ); + .then(() => + bundler.capture({ + path: "src/app.js", + contents: "require('noty');", + moduleId: "app.js", + }) + ) + .then(() => bundler.resolve()) + .then(() => bundler.bundle()) + .then( + (bundleMap) => { + t.deepEqual(bundleMap, { + "entry-bundle": { + files: [ + { + path: "node_modules/dumber-module-loader/dist/index.debug.js", + contents: "dumber-module-loader;", + }, + { + contents: "define.switchToUserSpace();", + }, + { + path: "src/app.js", + contents: + "define('app.js',['require','exports','module','noty'],function (require, exports, module) {\nrequire('noty');\n});\n", + }, + { + contents: "define.switchToPackageSpace();", + }, + { + path: "node_modules/noty/lib/noty.js", + contents: + "define(\"Noty\",[],function(){});\n;define.alias('noty','Noty');", + }, + { + contents: "define.switchToUserSpace();", + }, + ], + config: { + baseUrl: "/dist", + paths: {}, + bundles: {}, + }, + }, + }); + }, + (err) => t.fail(err.stack) + ); }); -test('Bundler ignores runtime modules mapped by paths', async t => { +test("Bundler ignores runtime modules mapped by paths", async (t) => { const fakeFs = { - 'node_modules/dumber-module-loader/dist/index.debug.js': 'dumber-module-loader', + "node_modules/dumber-module-loader/dist/index.debug.js": + "dumber-module-loader", }; - const bundler = createBundler(fakeFs, { + const bundler = mockBundler(fakeFs, { paths: { - foo: '/path/to/foo/', - bar: 'https://some.cdn.com/bar/' - } + foo: "/path/to/foo/", + bar: "https://some.cdn.com/bar/", + }, }); return Promise.resolve() - .then(() => bundler.capture({path: 'src/app.js', contents: "require('foo');require('bar');", moduleId: 'app.js'})) - .then(() => bundler.resolve()) - .then(() => bundler.bundle()) - .then( - bundleMap => { - t.deepEqual(bundleMap, { - "entry-bundle": { - "files": [ - { - "path": "node_modules/dumber-module-loader/dist/index.debug.js", - "contents": "dumber-module-loader;" - }, - { - "contents": "define.switchToUserSpace();" - }, - { - "path": "src/app.js", - "contents": "define('app.js',['require','exports','module','foo','bar'],function (require, exports, module) {\nrequire('foo');require('bar');\n});\n" - } - ], - "config": { - "baseUrl": "/dist", - "paths": { - foo: '/path/to/foo', - bar: 'https://some.cdn.com/bar' + .then(() => + bundler.capture({ + path: "src/app.js", + contents: "require('foo');require('bar');", + moduleId: "app.js", + }) + ) + .then(() => bundler.resolve()) + .then(() => bundler.bundle()) + .then( + (bundleMap) => { + t.deepEqual(bundleMap, { + "entry-bundle": { + files: [ + { + path: "node_modules/dumber-module-loader/dist/index.debug.js", + contents: "dumber-module-loader;", + }, + { + contents: "define.switchToUserSpace();", + }, + { + path: "src/app.js", + contents: + "define('app.js',['require','exports','module','foo','bar'],function (require, exports, module) {\nrequire('foo');require('bar');\n});\n", + }, + ], + config: { + baseUrl: "/dist", + paths: { + foo: "/path/to/foo", + bar: "https://some.cdn.com/bar", + }, + bundles: {}, }, - "bundles": {} - } - } - }); - }, - err => t.fail(err.stack) - ); + }, + }); + }, + (err) => t.fail(err.stack) + ); }); -test('Bundler ignores runtime modules', async t => { +test("Bundler ignores runtime modules", async (t) => { const fakeFs = { - 'node_modules/dumber-module-loader/dist/index.debug.js': 'dumber-module-loader', + "node_modules/dumber-module-loader/dist/index.debug.js": + "dumber-module-loader", }; - const bundler = createBundler(fakeFs); + const bundler = mockBundler(fakeFs); return Promise.resolve() - .then(() => bundler.capture({path: 'src/app.js', contents: "require('https://some.cdn.com/foo.js');", moduleId: 'app.js'})) - .then(() => bundler.resolve()) - .then(() => bundler.bundle()) - .then( - bundleMap => { - t.deepEqual(bundleMap, { - "entry-bundle": { - "files": [ - { - "path": "node_modules/dumber-module-loader/dist/index.debug.js", - "contents": "dumber-module-loader;" - }, - { - "contents": "define.switchToUserSpace();" - }, - { - "path": "src/app.js", - "contents": "define('app.js',['require','exports','module','https://some.cdn.com/foo.js'],function (require, exports, module) {\nrequire('https://some.cdn.com/foo.js');\n});\n" - } - ], - "config": { - "baseUrl": "/dist", - "paths": {}, - "bundles": {} - } - } - }); - }, - err => t.fail(err.stack) - ); + .then(() => + bundler.capture({ + path: "src/app.js", + contents: "require('https://some.cdn.com/foo.js');", + moduleId: "app.js", + }) + ) + .then(() => bundler.resolve()) + .then(() => bundler.bundle()) + .then( + (bundleMap) => { + t.deepEqual(bundleMap, { + "entry-bundle": { + files: [ + { + path: "node_modules/dumber-module-loader/dist/index.debug.js", + contents: "dumber-module-loader;", + }, + { + contents: "define.switchToUserSpace();", + }, + { + path: "src/app.js", + contents: + "define('app.js',['require','exports','module','https://some.cdn.com/foo.js'],function (require, exports, module) {\nrequire('https://some.cdn.com/foo.js');\n});\n", + }, + ], + config: { + baseUrl: "/dist", + paths: {}, + bundles: {}, + }, + }, + }); + }, + (err) => t.fail(err.stack) + ); }); diff --git a/test/mock.js b/test/mock.js index f6edae7..73a2016 100644 --- a/test/mock.js +++ b/test/mock.js @@ -1,5 +1,7 @@ const path = require('path'); +const {contentOrFile} = require('../lib/shared'); const _defaultReader = require('../lib/package-file-reader/node'); +const Bundler = require('../lib/index'); function mockResolve(path) { return 'node_modules/' + path; @@ -25,6 +27,43 @@ function mockPackageFileReader(fakeReader) { return packageConfig => _defaultReader(packageConfig, {resolve: mockResolve, readFile: fakeReader, exists: fakeReader.exists}); } +function mockContentOrFile(fakeReader) { + return pathOrContent => contentOrFile(pathOrContent, {readFile: fakeReader}); +} + +function deleteSourceMap(file) { + delete file.sourceMap; +} + +function mockBundler(fakeFs = {}, opts = {}) { + // don't use cache in test + if (!opts.cache) opts.cache = false; + const fakeReader = buildReadFile(fakeFs); + opts.packageFileReader = mockPackageFileReader(fakeReader); + + const bundler = new Bundler(opts, { + resolve: mockResolve, + contentOrFile: mockContentOrFile(fakeReader) + }); + + const oldBundle = bundler.bundle.bind(bundler); + bundler.bundle = function() { + // don't test source map + const bundleMap = oldBundle(); + Object.keys(bundleMap).forEach(key => { + if (bundleMap[key].files) { + bundleMap[key].files.forEach(deleteSourceMap); + } + if (bundleMap[key].appendFiles) { + bundleMap[key].appendFiles.forEach(deleteSourceMap); + } + }); + return bundleMap; + }; + return bundler; +} + exports.mockResolve = mockResolve; exports.buildReadFile = buildReadFile; exports.mockPackageFileReader = mockPackageFileReader; +exports.mockBundler = mockBundler; diff --git a/test/modules-todo.spec.js b/test/modules-todo.spec.js index 93e9985..d114e70 100644 --- a/test/modules-todo.spec.js +++ b/test/modules-todo.spec.js @@ -14,11 +14,11 @@ test('ModulesTodo process traced unit', t => { }); t.deepEqual(Object.assign({}, md.todos), { - '0:text!foo.html': ['foo'], - '2:some-plugin': ['foo'], - '0:some-plugin!readme.md': ['foo'], - '2:bar': ['foo'], - '1:bar/lo': ['bar/index'] + '0:text!foo.html:1': ['foo'], + '2:some-plugin:0': ['foo'], + '0:some-plugin!readme.md:1': ['foo'], + '2:bar:0': ['foo'], + '1:bar/lo:1': ['bar/index'] }); t.notOk(md.needCssInjection); t.ok(md.hasTodo()); @@ -50,9 +50,9 @@ test('ModulesTodo sequentially calls acquire callback', async t => { return md.acquire(cb).then( () => { t.deepEqual(log, [ - {id: 'text!foo.html', user: true, package: false, requiredBy: ['foo']}, - {id: 'bar/lo', user: false, package: true, requiredBy: ['bar/index']}, - {id: 'bar', user: true, package: true, requiredBy: ['foo']} + {id: 'text!foo.html', user: true, package: false, requiredBy: ['foo'], isRelative: true}, + {id: 'bar/lo', user: false, package: true, requiredBy: ['bar/index'], isRelative: true}, + {id: 'bar', user: true, package: true, requiredBy: ['foo'], isRelative: false} ]); t.notOk(md.needCssInjection); t.notOk(md.hasTodo()); @@ -103,40 +103,40 @@ test('ModulesTodo handles additional todos, set needCssInjection', async t => { return md.acquire(cb).then(() => { t.deepEqual(log, [ - {id: 'text!foo.html', user: true, package: false, requiredBy: ['foo']}, - {id: 'bar/lo', user: false, package: true, requiredBy: ['bar/index']}, - {id: 'bar', user: true, package: true, requiredBy: ['foo']} + {id: 'text!foo.html', user: true, package: false, requiredBy: ['foo'], isRelative: true}, + {id: 'bar/lo', user: false, package: true, requiredBy: ['bar/index'], isRelative: true}, + {id: 'bar', user: true, package: true, requiredBy: ['foo'], isRelative: false} ]); t.notOk(md.needCssInjection); t.deepEqual(Object.assign({}, md.todos), { - '1:bar/lor': ['bar/lo'], + '1:bar/lor:1': ['bar/lo'], }); t.ok(md.hasTodo()); return md.acquire(cb); }).then(() => { t.deepEqual(log, [ - {id: 'text!foo.html', user: true, package: false, requiredBy: ['foo']}, - {id: 'bar/lo', user: false, package: true, requiredBy: ['bar/index']}, - {id: 'bar', user: true, package: true, requiredBy: ['foo']}, - {id: 'bar/lor', user: false, package: true, requiredBy: ['bar/lo']} + {id: 'text!foo.html', user: true, package: false, requiredBy: ['foo'], isRelative: true}, + {id: 'bar/lo', user: false, package: true, requiredBy: ['bar/index'], isRelative: true}, + {id: 'bar', user: true, package: true, requiredBy: ['foo'], isRelative: false}, + {id: 'bar/lor', user: false, package: true, requiredBy: ['bar/lo'], isRelative: true}, ]); t.ok(md.needCssInjection); t.deepEqual(Object.assign({}, md.todos), { - '1:bar/lor/tool.css': ['bar/lor/index'], - '1:bar/lor/tool2': ['bar/lor/index'] + '1:bar/lor/tool.css:1': ['bar/lor/index'], + '1:bar/lor/tool2:1': ['bar/lor/index'] }); t.ok(md.hasTodo()); return md.acquire(cb); }).then(() => { t.deepEqual(log, [ - {id: 'text!foo.html', user: true, package: false, requiredBy: ['foo']}, - {id: 'bar/lo', user: false, package: true, requiredBy: ['bar/index']}, - {id: 'bar', user: true, package: true, requiredBy: ['foo']}, - {id: 'bar/lor', user: false, package: true, requiredBy: ['bar/lo']}, - {id: 'bar/lor/tool.css', user: false, package: true, requiredBy: ['bar/lor/index']}, - {id: 'bar/lor/tool2', user: false, package: true, requiredBy: ['bar/lor/index']}, + {id: 'text!foo.html', user: true, package: false, requiredBy: ['foo'], isRelative: true}, + {id: 'bar/lo', user: false, package: true, requiredBy: ['bar/index'], isRelative: true}, + {id: 'bar', user: true, package: true, requiredBy: ['foo'], isRelative: false}, + {id: 'bar/lor', user: false, package: true, requiredBy: ['bar/lo'], isRelative: true}, + {id: 'bar/lor/tool.css', user: false, package: true, requiredBy: ['bar/lor/index'], isRelative: true}, + {id: 'bar/lor/tool2', user: false, package: true, requiredBy: ['bar/lor/index'], isRelative: true}, ]); t.ok(md.needCssInjection); t.deepEqual(Object.assign({}, md.todos), {}); @@ -154,7 +154,7 @@ test('ModulesTodo sets needCssInjection for less module', t => { }); t.deepEqual(Object.assign({}, md.todos), { - '0:foo.less': ['foo'] + '0:foo.less:1': ['foo'] }); t.ok(md.needCssInjection); t.ok(md.hasTodo()); @@ -168,7 +168,7 @@ test('ModulesTodo sets needCssInjection for scss module', t => { }); t.deepEqual(Object.assign({}, md.todos), { - '0:foo.scss': ['foo'] + '0:foo.scss:1': ['foo'] }); t.ok(md.needCssInjection); t.ok(md.hasTodo()); @@ -182,7 +182,7 @@ test('ModulesTodo sets needCssInjection for sass module', t => { }); t.deepEqual(Object.assign({}, md.todos), { - '0:foo.sass': ['foo'] + '0:foo.sass:1': ['foo'] }); t.ok(md.needCssInjection); t.ok(md.hasTodo()); @@ -196,7 +196,7 @@ test('ModulesTodo sets needCssInjection for styl module', t => { }); t.deepEqual(Object.assign({}, md.todos), { - '0:foo.styl': ['foo'] + '0:foo.styl:1': ['foo'] }); t.ok(md.needCssInjection); t.ok(md.hasTodo());