diff --git a/package-lock.json b/package-lock.json index 62e9c57..1509d37 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "loader-runner", - "version": "4.3.1", + "version": "4.3.2", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "loader-runner", - "version": "4.3.1", + "version": "4.3.2", "license": "MIT", "devDependencies": { "@eslint/js": "^9.28.0", diff --git a/test/fixtures/esm-invalid-loader.mjs b/test/fixtures/esm-invalid-loader.mjs new file mode 100644 index 0000000..9cf3c27 --- /dev/null +++ b/test/fixtures/esm-invalid-loader.mjs @@ -0,0 +1 @@ +export default ""; diff --git a/test/fixtures/esm-pitching-loader.mjs b/test/fixtures/esm-pitching-loader.mjs new file mode 100644 index 0000000..d8d882d --- /dev/null +++ b/test/fixtures/esm-pitching-loader.mjs @@ -0,0 +1,3 @@ +export function pitch(remainingRequest, previousRequest) { + return [remainingRequest, previousRequest].join(":"); +} diff --git a/test/fixtures/esm-raw-loader.mjs b/test/fixtures/esm-raw-loader.mjs new file mode 100644 index 0000000..8bc655a --- /dev/null +++ b/test/fixtures/esm-raw-loader.mjs @@ -0,0 +1,8 @@ +export default function (source) { + return Buffer.from( + source.toString("hex") + source.toString("utf-8"), + "utf-8" + ); +} + +export const raw = true; diff --git a/test/runLoaders.js b/test/runLoaders.js index e00d923..d6d9946 100644 --- a/test/runLoaders.js +++ b/test/runLoaders.js @@ -738,6 +738,154 @@ describe("runLoaders", () => { ); }); } + + const [nodeMajor, nodeMinor] = process.versions.node.split(".").map(Number); + // `require(esm)` is enabled by default starting from Node.js 22.12.0 + if (nodeMajor > 22 || (nodeMajor === 22 && nodeMinor >= 12)) { + it("should load an esm loader using require()", (done) => { + runLoaders( + { + resource: path.resolve(fixtures, "resource.bin"), + loaders: [path.resolve(fixtures, "esm-loader.mjs")], + }, + (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(); + } + ); + }); + } + + if (Number(process.versions.modules) >= 83) { + it("should load a commonjs loader using import()", (done) => { + runLoaders( + { + resource: path.resolve(fixtures, "resource.bin"), + loaders: [ + { + loader: path.resolve(fixtures, "simple-loader.js"), + type: "module", + }, + ], + }, + (err, result) => { + if (err) return done(err); + result.result.should.be.eql(["resource-simple"]); + result.cacheable.should.be.eql(true); + result.fileDependencies.should.be.eql([ + path.resolve(fixtures, "resource.bin"), + ]); + result.contextDependencies.should.be.eql([]); + done(); + } + ); + }); + + it("should process an esm pitching loader using import()", (done) => { + runLoaders( + { + resource: path.resolve(fixtures, "resource.bin"), + loaders: [ + path.resolve(fixtures, "simple-loader.js"), + { + loader: path.resolve(fixtures, "esm-pitching-loader.mjs"), + type: "module", + }, + path.resolve(fixtures, "simple-async-loader.js"), + ], + }, + (err, result) => { + if (err) return done(err); + result.result.should.be.eql([ + `${path.resolve(fixtures, "simple-async-loader.js")}!${path.resolve( + fixtures, + "resource.bin" + )}:${path.resolve(fixtures, "simple-loader.js")}-simple`, + ]); + result.cacheable.should.be.eql(true); + result.fileDependencies.should.be.eql([]); + result.contextDependencies.should.be.eql([]); + done(); + } + ); + }); + + it("should process an esm raw loader using import()", (done) => { + runLoaders( + { + resource: path.resolve(fixtures, "bom.bin"), + loaders: [ + { + loader: path.resolve(fixtures, "esm-raw-loader.mjs"), + type: "module", + }, + ], + }, + (err, result) => { + if (err) return done(err); + result.result[0].toString("utf8").should.be.eql("efbbbf62c3b66dböm"); + done(); + } + ); + }); + + it("should not return dependencies when an esm loader is not found", (done) => { + runLoaders( + { + resource: path.resolve(fixtures, "resource.bin"), + loaders: [ + { + loader: path.resolve(fixtures, "does-not-exist-loader.mjs"), + type: "module", + }, + ], + }, + (err, result) => { + err.should.be.instanceOf(Error); + result.should.be.eql({ + cacheable: false, + fileDependencies: [], + contextDependencies: [], + missingDependencies: [], + }); + done(); + } + ); + }); + + it("should not return dependencies when an esm loader has an invalid default export", (done) => { + runLoaders( + { + resource: path.resolve(fixtures, "resource.bin"), + loaders: [ + { + loader: path.resolve(fixtures, "esm-invalid-loader.mjs"), + type: "module", + }, + ], + }, + (err, result) => { + err.should.be.instanceOf(Error); + err.message.should.match( + /esm-invalid-loader\.mjs' is not a loader \(must have normal or pitch function\)$/ + ); + result.should.be.eql({ + cacheable: false, + fileDependencies: [], + contextDependencies: [], + missingDependencies: [], + }); + done(); + } + ); + }); + } it("should support escaping in resource", (done) => { runLoaders( {