From f0b9f4243e7308451173cea16ec0234dddb017ad Mon Sep 17 00:00:00 2001 From: Stephen Belanger Date: Tue, 11 Apr 2017 16:30:08 -0700 Subject: [PATCH 1/3] src: let preloaded modules set source transformer This feature simply passes the content and filename through a transformer function which could be used for things like applying AST transforms to the source before it is run. --- lib/internal/bootstrap_node.js | 8 ++++++++ lib/module.js | 4 ++++ test/fixtures/process-module-wrap.js | 4 ++++ test/parallel/test-preload.js | 10 ++++++++++ 4 files changed, 26 insertions(+) create mode 100644 test/fixtures/process-module-wrap.js diff --git a/lib/internal/bootstrap_node.js b/lib/internal/bootstrap_node.js index b4ed16573e1e07..1df92bfe1dcf8b 100644 --- a/lib/internal/bootstrap_node.js +++ b/lib/internal/bootstrap_node.js @@ -412,6 +412,10 @@ function preloadModules() { if (process._preload_modules) { NativeModule.require('module')._preloadModules(process._preload_modules); + if (process.moduleWrap) { + NativeModule.preloadModuleWrap = process.moduleWrap; + delete process.moduleWrap; + } } } @@ -474,6 +478,7 @@ } NativeModule._source = process.binding('natives'); + NativeModule.preloadModuleWrap = null; NativeModule._cache = {}; NativeModule.require = function(id) { @@ -544,6 +549,9 @@ NativeModule.prototype.compile = function() { var source = NativeModule.getSource(this.id); + if (NativeModule.preloadModuleWrap !== null) { + source = NativeModule.preloadModuleWrap(source, this.filename); + } source = NativeModule.wrap(source); this.loading = true; diff --git a/lib/module.js b/lib/module.js index fe83cd0ecb8a26..e71640d438cb59 100644 --- a/lib/module.js +++ b/lib/module.js @@ -537,6 +537,10 @@ var resolvedArgv; // the file. // Returns exception, if any. Module.prototype._compile = function(content, filename) { + if (NativeModule.preloadModuleWrap !== null) { + content = NativeModule.preloadModuleWrap(content, filename); + } + // Remove shebang var contLen = content.length; if (contLen >= 2) { diff --git a/test/fixtures/process-module-wrap.js b/test/fixtures/process-module-wrap.js new file mode 100644 index 00000000000000..ab041c34b0ca82 --- /dev/null +++ b/test/fixtures/process-module-wrap.js @@ -0,0 +1,4 @@ +process.moduleWrap = function(content, filename) { + if (filename !== 'http.js') return content + return content + '\nmodule.exports.hello = "hi";' +} diff --git a/test/parallel/test-preload.js b/test/parallel/test-preload.js index 8dc64cc6c60168..ccfb195ef7480a 100644 --- a/test/parallel/test-preload.js +++ b/test/parallel/test-preload.js @@ -29,6 +29,7 @@ const fixtureA = fixture('printA.js'); const fixtureB = fixture('printB.js'); const fixtureC = fixture('printC.js'); const fixtureD = fixture('define-global.js'); +const fixtureE = fixture('process-module-wrap.js'); const fixtureThrows = fixture('throws_error4.js'); // test preloading a single module works @@ -146,3 +147,12 @@ childProcess.exec( assert.ok(/worker terminated with code 43/.test(stdout)); } ); + +// test that preload can be used with --eval +childProcess.exec( + nodeBinary + ' ' + preloadOption([fixtureE]) + '-p "require(\'http\').hello"', + function(err, stdout, stderr) { + assert.ifError(err); + assert.strictEqual(stdout, 'hi\n'); + } +); From 6b6ca10558c126d44cf2dcba72c0325eaeb7b698 Mon Sep 17 00:00:00 2001 From: Stephen Belanger Date: Thu, 13 Apr 2017 10:44:35 -0700 Subject: [PATCH 2/3] doc: Document `process.moduleWrap()` --- doc/api/process.md | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/doc/api/process.md b/doc/api/process.md index 306f555e4fcfce..fd975e4432745b 100644 --- a/doc/api/process.md +++ b/doc/api/process.md @@ -1187,6 +1187,45 @@ Will generate: `external` refers to the memory usage of C++ objects bound to JavaScript objects managed by V8. +## process.moduleWrap(content, filepath) + +* `content` {String} The file contents +* `filepath` {String} The full path of the file +* Returns: {String} The replacement content + +The `process.moduleWrap()` method, which only exists while preloading modules +with the `--require` flag, will receive the text content of any file to be +loaded with `require()` and will replace it with the return value. This method +may be set to apply pre-compile transformations such as transpiling code, +replacing an interface with mock functions for testing or instrumenting code +for purposes such as gathering code coverage metrics or tracing the flow of +an application. + +This is an example of replacing a function with one which has been instrumented +to log execution time: + +```js +process.moduleWrap = function(content, filepath) { + // Only apply the transform to a specific file + if (!/my\-module\.js$/.test(filename)) { + return content + } + return ` + ${content} + const originalFunction = exports.someFunction + exports.someFunction = function myMockedFunction(first, second, callback) { + var start = process.hrtime() + function wrappedCallback() { + var end = process.hrtime(start) + console.log('execution time: %ds', end[0] + (end[1] / 1000000000)) + return callback(this, arguments) + } + return someFunction.call(null, first, second, wrappedCallback) + } + ` +} +``` + ## process.nextTick(callback[, ...args])