Skip to content

Commit

Permalink
feat(bundler): stub core Node.js modules just like browserify and web…
Browse files Browse the repository at this point in the history
…pack
  • Loading branch information
3cp committed Sep 27, 2018
1 parent 3c796ac commit 19aafee
Show file tree
Hide file tree
Showing 5 changed files with 128 additions and 2 deletions.
19 changes: 17 additions & 2 deletions lib/build/bundler.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ const path = require('path');
const Utils = require('./utils');
const logger = require('aurelia-logging').getLogger('Bundler');
const knownExtensions = require('./known-extensions');
const stubCoreNodejsModule = require('./stub-core-nodejs-module');

exports.Bundler = class {
constructor(project, packageAnalyzer, packageInstaller) {
Expand Down Expand Up @@ -261,13 +262,27 @@ exports.Bundler = class {
return depInclusion.traceMain();
}

return this.configureDependency(nodeId)
let stub = stubCoreNodejsModule(nodeId);
if (typeof stub === 'string') {
this.addFile({
path: path.resolve(this.project.paths.root, nodeId + '.js'),
contents: stub
});
return Promise.resolve();
}

return this.configureDependency(stub || nodeId)
.then(description => {
if (resourceId) {
description.loaderConfig.lazyMain = true;
}

logger.info(`Auto tracing npm package: ${nodeId}`);
if (stub) {
logger.info(`Auto stubbing core Node.js module: ${nodeId}`);
} else {
logger.info(`Auto tracing npm package: ${nodeId}`);
}

return this.configTargetBundle.addDependency(description);
})
.then(inclusion => {
Expand Down
67 changes: 67 additions & 0 deletions lib/build/stub-core-nodejs-module.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
'use strict';

const logger = require('aurelia-logging').getLogger('StubNodejs');

// stub core Node.js modules based on https://github.com/webpack/node-libs-browser/blob/master/index.js
// no need stub for following modules, they got same name on npm package
//
// assert
// buffer
// events
// punycode
// process
// string_decoder
// url
// util (note: got small problem on ./support/isBuffer, read util package.json browser field)

// fail on following core modules has no stub
const UNAVAIABLE_CORE_MODULES = [
'child_process',
'cluster',
'dgram',
'dns',
'fs',
'net',
'readline',
'repl',
'tls'
];

const EMPTY_MODULE = 'define(function(){});';

// note all paths here assumes local node_modules folder
// TODO use require.resolve to get correct node_modules folder. (to support yarn workspaces for instance)
module.exports = function(moduleId) {
// with subfix -browserify
if (['crypto', 'https', 'os', 'path', 'stream', 'timers', 'tty', 'vm'].indexOf(moduleId) !== -1) {
return {name: moduleId, path: `../node_modules/${moduleId}-browserify`};
}

if (moduleId === 'domain') {
logger.warn('core Node.js module "domain" is deprecated');
return {name: 'domain', path: '../node_modules/domain-browser'};
}

if (moduleId === 'http') {
return {name: 'http', path: '../node_modules/stream-http'};
}

if (moduleId === 'querystring') {
// using querystring-es3 next version 1.0.0-0
return {name: 'querystring', path: '../node_modules/querystring-es3'};
}

if (moduleId === 'sys') {
logger.warn('core Node.js module "sys" is deprecated, the stub is disabled in CLI bundler due to conflicts with "util"');
}

if (moduleId === 'zlib') {
return {name: 'zlib', path: '../node_modules/browserify-zlib'};
}

if (UNAVAIABLE_CORE_MODULES.indexOf(moduleId) !== -1) {
logger.warn(`No avaiable stub for core Node.js module "${moduleId}", stubbed with empty module`);
return EMPTY_MODULE;
}
};

2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,11 @@
"glob": "^7.1.1",
"gulp": "^4.0.0",
"htmlparser2": "^3.9.2",
"node-libs-browser": "^2.1.0",
"npm-which": "^3.0.1",
"opn": "^5.0.0",
"preprocess": "^3.1.0",
"querystring-es3": "1.0.0-0",
"rfc6902": "^2.4.0",
"semver": "^5.3.0",
"terser": "^3.8.1",
Expand Down
22 changes: 22 additions & 0 deletions spec/lib/build/package-analyzer.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,28 @@ describe('The PackageAnalyzer', () => {
.catch(e => done.fail(e));
});

it('sets source to custom when node_modules is found in the path, but packageRoot is set', done => {
// setup mock package.json
const fsConfig = {};
fsConfig[path.join('node_modules/my-package', 'package.json')] = '{ }';
fsConfig[path.join('node_modules/my-package', 'index.js')] = 'some content';
mockfs(fsConfig);

let loaderConfig = {
name: 'my-package',
path: '../node_modules/my-package',
packageRoot: '../node_modules/my-package'
};

sut.reverseEngineer(loaderConfig)
.then(description => {
expect(description.source).toBe('custom');
expect(description.loaderConfig).toEqual(Object.assign({main: 'index'}, loaderConfig));
done();
})
.catch(e => done.fail(e));
});

it('sets source to custom when node_modules is not found in the path, and packageRoot is missing', done => {
// setup mock package.json
const fsConfig = {};
Expand Down
20 changes: 20 additions & 0 deletions spec/lib/build/stub-core-nodejs-module.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
'use strict';

const stubCoreNodejsModule = require('../../../lib/build/stub-core-nodejs-module');

describe('StubCoreNodejsModule', () => {
it('stubs some core module with subfix -browserify', () => {
expect(stubCoreNodejsModule('os')).toEqual({
name: 'os',
path: '../node_modules/os-browserify'
});
});

it('ignores sys', () => {
expect(stubCoreNodejsModule('sys')).toBeUndefined();
});

it('stubs empty module for some core module', () => {
expect(stubCoreNodejsModule('fs')).toBe('define(function(){});');
});
});

0 comments on commit 19aafee

Please sign in to comment.