Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions test/configCases/asset-modules/webpack-ignore/file.css
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
body { color: red; }
1 change: 1 addition & 0 deletions test/configCases/asset-modules/webpack-ignore/file.html
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<div>test</div>
1 change: 1 addition & 0 deletions test/configCases/asset-modules/webpack-ignore/file.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export default "test";
3 changes: 3 additions & 0 deletions test/configCases/asset-modules/webpack-ignore/file.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"foo": "bar"
}
1 change: 1 addition & 0 deletions test/configCases/asset-modules/webpack-ignore/file.text
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
a Ā 𐀀 文 🦄 Text
28 changes: 28 additions & 0 deletions test/configCases/asset-modules/webpack-ignore/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
it("should work", async () => {
const decoder = new TextDecoder("utf-8");

const textFile = (await import(/* webpackIgnore: true */ "./file.text", { with: { type: "bytes" } })).default;
const textFileContent = decoder.decode(textFile);

expect(textFileContent.trim()).toBe("a Ā 𐀀 文 🦄 Text");

const jsonFile = (await import(/* webpackIgnore: true */ "./file.json", { with: { type: "bytes" } })).default;
const jsonFileContent = decoder.decode(jsonFile);

expect(JSON.parse(jsonFileContent.trim())).toStrictEqual({ foo: "bar" });

const jsFile = (await import(/* webpackIgnore: true */ "./file.js", { with: { type: "bytes" } })).default;
const jsFileContent = decoder.decode(jsFile);

expect(jsFileContent.trim()).toBe("export default \"test\";");

const cssFile = (await import(/* webpackIgnore: true */ "./file.css", { with: { type: "bytes" } })).default;
const cssFileContent = decoder.decode(cssFile);

expect(cssFileContent.trim()).toBe("body { color: red; }");

const htmlFile = (await import(/* webpackIgnore: true */ "./file.html", { with: { type: "bytes" } })).default;
const htmlFileContent = decoder.decode(htmlFile);

expect(htmlFileContent.trim()).toBe("<div>test</div>");
});
5 changes: 5 additions & 0 deletions test/configCases/asset-modules/webpack-ignore/test.filter.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
"use strict";

const supportsTypeBytes = require("../../../helpers/supportsTypeBytes");

module.exports = () => supportsTypeBytes();
61 changes: 61 additions & 0 deletions test/configCases/asset-modules/webpack-ignore/webpack.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
"use strict";

const path = require("path");

/** @typedef {import("../../../../lib/util/fs").InputFileSystem} InputFileSystem */
/** @typedef {import("../../../../lib/util/fs").ReadFileSync} ReadFileSync */

/** @type {import("../../../../").Configuration} */
module.exports = {
mode: "development",
devtool: false,
experiments: {
outputModule: true
},
output: {
module: true
},
plugins: [
{
apply(compiler) {
compiler.hooks.compilation.tap("Test", (compilation) => {
compilation.hooks.processAssets.tap(
{
name: "TestCopyPlugin",
stage:
compiler.webpack.Compilation.PROCESS_ASSETS_STAGE_ADDITIONAL
},
() => {
if (!compiler.inputFileSystem) {
throw new Error("Expected `compiler.inputFileSystem`");
}

const files = [
"file.text",
"file.json",
"file.js",
"file.css",
"file.html"
];

for (const file of files) {
const testFile = path.resolve(__dirname, file);
const content =
/** @type {ReadFileSync} */
(
/** @type {InputFileSystem} */ (compiler.inputFileSystem)
.readFileSync
)(testFile);

compilation.emitAsset(
file,
new compiler.webpack.sources.RawSource(content)
);
}
}
);
});
}
}
]
};
7 changes: 7 additions & 0 deletions test/helpers/supportsTypeBytes.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
"use strict";

module.exports = function supportsTypeBytes() {
const [major] = process.versions.node.split(".").map(Number);

return major >= 20;
};
25 changes: 23 additions & 2 deletions test/runner/asModule.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,36 @@ const LINKER = () => {};
* @param {vm.SourceTextModule | vm.Module | EXPECTED_ANY} something module or object
* @param {EXPECTED_ANY} context context
* @param {{ esmReturnStatus?: boolean }=} options options
* @returns {Promise<vm.SourceTextModule>} module
* @param {Record<string, string>=} importAttributes import attributes
* @returns {Promise<vm.SourceTextModule> | Promise<vm.SyntheticModule>} module
*/
module.exports = async (something, context, options = {}) => {
module.exports = async (
something,
context,
options = {},
importAttributes = {}
) => {
if (
something instanceof (vm.Module || /* node.js 10 */ vm.SourceTextModule)
) {
return something;
}

if (importAttributes && importAttributes.type === "bytes") {
const byteModule = new vm.SyntheticModule(
["default"],
function evaluateCallback() {
this.setExport("default", something);
},
{ context }
);

await byteModule.link(() => {});
await byteModule.evaluate();

return byteModule;
}

context[SYNTHETIC_MODULES_STORE] = context[SYNTHETIC_MODULES_STORE] || [];
const i = context[SYNTHETIC_MODULES_STORE].length;
context[SYNTHETIC_MODULES_STORE].push(something);
Expand Down
34 changes: 28 additions & 6 deletions test/runner/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,8 @@ class TestRunner {
cjs: this.createCjsRunner(),
esm: this.createEsmRunner(),
json: this.createJSONRunner(),
raw: this.createRawRunner()
raw: this.createRawRunner(),
bytes: this.createBytesRunner()
};
}

Expand Down Expand Up @@ -186,7 +187,9 @@ class TestRunner {
clearTimeout,
setImmediate,
URL,
Buffer
Buffer,
TextEncoder: typeof TextEncoder !== "undefined" ? TextEncoder : undefined,
TextDecoder: typeof TextDecoder !== "undefined" ? TextDecoder : undefined
};
return base;
}
Expand Down Expand Up @@ -250,9 +253,10 @@ class TestRunner {
* @param {string} currentDirectory current directory
* @param {string | string[]} module module
* @param {RequireContext=} context context
* @param {Record<string, string>=} importAttributes import attributes
* @returns {EXPECTED_ANY} require result
*/
require(currentDirectory, module, context = {}) {
require(currentDirectory, module, context = {}, importAttributes = {}) {
if (this.testConfig.modules && module in this.testConfig.modules) {
return this.testConfig.modules[module];
}
Expand All @@ -272,6 +276,9 @@ class TestRunner {
return rawRequire(module.startsWith("node:") ? module.slice(5) : module);
}
const { modulePath } = moduleInfo;
if (importAttributes && importAttributes.type === "bytes") {
return this._moduleRunners.bytes(moduleInfo, context);
}
if (
modulePath.endsWith(".mjs") &&
this.webpackOptions.experiments &&
Expand Down Expand Up @@ -402,7 +409,11 @@ class TestRunner {
meta.dirname = path.dirname(identifier);
}
},
importModuleDynamically: async (specifier, module) => {
importModuleDynamically: async (
specifier,
module,
importAttributes
) => {
const normalizedSpecifier = specifier.startsWith("file:")
? `./${path.relative(
path.dirname(identifier),
Expand All @@ -418,10 +429,16 @@ class TestRunner {
normalizedSpecifier,
{
esmReturnStatus: ESModuleStatus.Evaluated
}
},
importAttributes
);

return await asModule(res, module.context);
return await asModule(
res,
module.context,
undefined,
importAttributes
);
}
});
esmCache.set(identifier, instance);
Expand All @@ -445,6 +462,7 @@ class TestRunner {
const { esmReturnStatus } = context;

const esm = getModuleInstance(modulePath, content);

if (esmReturnStatus === ESModuleStatus.Unlinked) return esm;

const link = async () => {
Expand Down Expand Up @@ -507,6 +525,10 @@ class TestRunner {
return (moduleInfo) => moduleInfo.content;
}

createBytesRunner() {
return (moduleInfo) => new Uint8Array(Buffer.from(moduleInfo.content));
}

/**
* @returns {EXPECTED_ANY} env
*/
Expand Down
Loading