Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 2 additions & 4 deletions lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -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?:)?\//)) {
Expand Down Expand Up @@ -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);
Expand Down
23 changes: 9 additions & 14 deletions lib/modules-todo.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 && (
Expand All @@ -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 {
Expand All @@ -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);
});
Expand All @@ -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.
Expand All @@ -106,25 +108,18 @@ 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'
}));
});

return p;
}));
}
};

function spaceAndId(key) {
return [key.slice(0, 1), key.slice(2)];
}

function isRelative(id) {
return parse(id).bareId.startsWith('.');
}
265 changes: 172 additions & 93 deletions test/bundler.esm.spec.js
Original file line number Diff line number Diff line change
@@ -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: {} },
},
});
});
});
Loading
Loading