how to require from URL in Node.js
Javascriptnode.jsJavascript Problem Overview
Is there a standard way to require a Node module located at some URL (not on the local filesystem)?
Something like:
require('http://example.com/nodejsmodules/myModule.js');
Currently, I am simply fetching the file into a temporary file, and requiring that.
Javascript Solutions
Solution 1 - Javascript
You can fetch module using http.get method and execute it in the sandbox using vm module methods runInThisContext and runInNewContext.
Example
var http = require('http')
, vm = require('vm')
, concat = require('concat-stream'); // this is just a helper to receive the
// http payload in a single callback
// see https://www.npmjs.com/package/concat-stream
http.get({
host: 'example.com',
port: 80,
path: '/hello.js'
},
function(res) {
res.setEncoding('utf8');
res.pipe(concat({ encoding: 'string' }, function(remoteSrc) {
vm.runInThisContext(remoteSrc, 'remote_modules/hello.js');
}));
});
IMO, execution of the remote code inside server application runtime may be reasonable in the case without alternatives. And only if you trust to the remote service and the network between.
Solution 2 - Javascript
Install the module first :
npm install require-from-url
And then put in your file :
var requireFromUrl = require('require-from-url/sync');
requireFromUrl("http://example.com/nodejsmodules/myModule.js");
Solution 3 - Javascript
0 dependency version (node 6+ required, you can simply change it back to ES5)
const http = require('http'), vm = require('vm');
['http://example.com/nodejsmodules/myModule.js'].forEach(url => {
http.get(url, res => {
if (res.statusCode === 200 && /\/javascript/.test(res.headers['content-type'])) {
let rawData = '';
res.setEncoding('utf8');
res.on('data', chunk => { rawData += chunk; });
res.on('end', () => { vm.runInThisContext(rawData, url); });
}
});
});
It is still the asynchronous version, if sync load is the case, a sync http request module
for example should be required
Solution 4 - Javascript
If you want something more like require
, you can do this:
var http = require('http')
, vm = require('vm')
, concat = require('concat-stream')
, async = require('async');
function http_require(url, callback) {
http.get(url, function(res) {
// console.log('fetching: ' + url)
res.setEncoding('utf8');
res.pipe(concat({encoding: 'string'}, function(data) {
callback(null, vm.runInThisContext(data));
}));
})
}
urls = [
'http://example.com/nodejsmodules/myModule1.js',
'http://example.com/nodejsmodules/myModule2.js',
'http://example.com/nodejsmodules/myModule3.js',
]
async.map(urls, http_require, function(err, results) {
// `results` is an array of values returned by `runInThisContext`
// the rest of your program logic
});
Solution 5 - Javascript
You could overwrite the default require handler for .js files:
require.extensions['.js'] = function (module, filename) {
// ...
}
You might want to checkout better-require as it does pretty much this for many file formats. (I wrote it)
Solution 6 - Javascript
const localeSrc = 'https://www.trip.com/m/i18n/100012631/zh-HK.js';
const http = require('http');
const vm = require('vm');
const concat = require('concat-stream');
http.get(
localeSrc,
res => {
res.setEncoding('utf8');
res.pipe(
concat({ encoding: 'string' }, remoteSrc => {
let context = {};
const script = new vm.Script(remoteSrc);
script.runInNewContext(context);
console.log(context);
}),
);
},
err => {
console.log('err', err);
},
);