diff --git a/.travis.yml b/.travis.yml index 88d4a24..881201e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,6 +4,8 @@ node_js: - "6" - "8" - "10" + - "12" + - "14" - node script: npm run travis diff --git a/lib/LoaderRunner.js b/lib/LoaderRunner.js index aee5d45..9feedbf 100644 --- a/lib/LoaderRunner.js +++ b/lib/LoaderRunner.js @@ -72,9 +72,10 @@ function createLoaderObject(loader) { obj.ident = undefined; } else { if(!value.loader) - throw new Error("request should be a string or object with loader and object (" + JSON.stringify(value) + ")"); + throw new Error("request should be a string or object with loader and options (" + JSON.stringify(value) + ")"); obj.path = value.loader; obj.fragment = value.fragment || ""; + obj.type = value.type; obj.options = value.options; obj.ident = value.ident; if(obj.options === null) diff --git a/lib/loadLoader.js b/lib/loadLoader.js index 7550652..1210353 100644 --- a/lib/loadLoader.js +++ b/lib/loadLoader.js @@ -1,23 +1,42 @@ var LoaderLoadingError = require("./LoaderLoadingError"); +var url; module.exports = function loadLoader(loader, callback) { - try { - var module = require(loader.path); - } catch(e) { - // it is possible for node to choke on a require if the FD descriptor - // limit has been reached. give it a chance to recover. - if(e instanceof Error && e.code === "EMFILE") { - var retry = loadLoader.bind(null, loader, callback); - if(typeof setImmediate === "function") { - // node >= 0.9.0 - return setImmediate(retry); - } else { - // node < 0.9.0 - return process.nextTick(retry); + if(loader.type === "module") { + try { + if(url === undefined) url = require("url"); + var loaderUrl = url.pathToFileURL(loader.path); + var modulePromise = eval("import(" + JSON.stringify(loaderUrl.toString()) + ")"); + modulePromise.then(function(module) { + handleResult(loader, module, callback); + }, callback); + return; + } catch(e) { + callback(e); + } + } else { + try { + var module = require(loader.path); + } catch(e) { + // it is possible for node to choke on a require if the FD descriptor + // limit has been reached. give it a chance to recover. + if(e instanceof Error && e.code === "EMFILE") { + var retry = loadLoader.bind(null, loader, callback); + if(typeof setImmediate === "function") { + // node >= 0.9.0 + return setImmediate(retry); + } else { + // node < 0.9.0 + return process.nextTick(retry); + } } + return callback(e); } - return callback(e); + return handleResult(loader, module, callback); } +}; + +function handleResult(loader, module, callback) { if(typeof module !== "function" && typeof module !== "object") { return callback(new LoaderLoadingError( "Module '" + loader.path + "' is not a loader (export function or es6 module)" @@ -32,4 +51,4 @@ module.exports = function loadLoader(loader, callback) { )); } callback(); -}; +} diff --git a/test/fixtures/esm-loader.mjs b/test/fixtures/esm-loader.mjs new file mode 100644 index 0000000..2b15064 --- /dev/null +++ b/test/fixtures/esm-loader.mjs @@ -0,0 +1,3 @@ +export default function(source) { + return source + "-esm"; +}; diff --git a/test/runLoaders.js b/test/runLoaders.js index 634e806..b9a26e6 100644 --- a/test/runLoaders.js +++ b/test/runLoaders.js @@ -607,6 +607,28 @@ describe("runLoaders", function() { }); delete global.System; }); + if(+process.versions.modules >= 83) { + it("should load a loader using import()", function(done) { + runLoaders({ + resource: path.resolve(fixtures, "resource.bin"), + loaders: [ + { + loader: path.resolve(fixtures, "esm-loader.mjs"), + type: "module" + } + ] + }, function(err, result) { + if(err) return done(err); + result.result.should.be.eql(["resource-esm"]); + result.cacheable.should.be.eql(true); + result.fileDependencies.should.be.eql([ + path.resolve(fixtures, "resource.bin") + ]); + result.contextDependencies.should.be.eql([]); + done(); + }); + }); + } describe("getContext", function() { var TESTS = [ ["/", "/"],