diff --git a/packages/webpack-cli/lib/groups/ConfigGroup.js b/packages/webpack-cli/lib/groups/ConfigGroup.js index d88d7bc3c9c..b52c05b877f 100644 --- a/packages/webpack-cli/lib/groups/ConfigGroup.js +++ b/packages/webpack-cli/lib/groups/ConfigGroup.js @@ -6,6 +6,7 @@ const rechoir = require('rechoir'); const { arrayToObject } = require('../utils/arg-utils'); const ConfigError = require('../utils/errors/ConfigError'); const logger = require('../utils/logger'); +const { pathToFileURL } = require('url'); // Order defines the priority, in increasing order // example - config file lookup will be in order of .webpack/webpack.config.development.js -> webpack.config.development.js -> webpack.config.js @@ -70,14 +71,26 @@ const requireLoader = (extension, path) => { }; // Reads a config file given the config metadata -const requireConfig = (configModule) => { +const requireConfig = async (configModule) => { const extension = Object.keys(jsVariants).find((t) => configModule.ext.endsWith(t)); - - if (extension) { - requireLoader(extension, configModule.path); + let config; + + if (extension == '.mjs') { + try { + const url = pathToFileURL(configModule.path); + const ESMImport = new Function('url', 'return import(url)'); + config = await ESMImport(url); + } catch (err) { + logger.warn('Cannot import ESM configuration'); + throw err; + } + } else { + if (extension) { + requireLoader(extension, configModule.path); + } + config = require(configModule.path); } - let config = require(configModule.path); if (config.default) { config = config.default; } @@ -101,7 +114,7 @@ const resolveConfigFiles = async (args) => { throw new ConfigError(`The specified config file doesn't exist in ${configPath}`); } const foundConfig = configFiles[0]; - const resolvedConfig = requireConfig(foundConfig); + const resolvedConfig = await requireConfig(foundConfig); return finalize(resolvedConfig, args); }); // resolve all the configs @@ -125,7 +138,11 @@ const resolveConfigFiles = async (args) => { return existsSync(file.path); }); - const configFiles = tmpConfigFiles.map(requireConfig); + const configFiles = []; + for await (const tmpConfigFile of tmpConfigFiles) { + configFiles.push(await requireConfig(tmpConfigFile)); + } + if (configFiles.length) { const defaultConfig = configFiles.find((p) => p.path.includes(mode) || p.path.includes(modeAlias[mode])); if (defaultConfig) { diff --git a/packages/webpack-cli/package.json b/packages/webpack-cli/package.json index 5244225ae06..76eef5151a9 100644 --- a/packages/webpack-cli/package.json +++ b/packages/webpack-cli/package.json @@ -23,9 +23,9 @@ "web" ], "dependencies": { - "@webpack-cli/package-utils": "^1.0.1-alpha.4", "@webpack-cli/info": "^1.0.1-alpha.4", "@webpack-cli/init": "^1.0.1-alpha.5", + "@webpack-cli/package-utils": "^1.0.1-alpha.4", "@webpack-cli/serve": "^1.0.1-alpha.5", "ansi-escapes": "^4.3.1", "colorette": "^1.2.1", @@ -34,7 +34,7 @@ "enquirer": "^2.3.4", "execa": "^4.0.0", "import-local": "^3.0.2", - "interpret": "^2.0.0", + "interpret": "^2.2.0", "rechoir": "^0.7.0", "v8-compile-cache": "^2.1.0", "webpack-merge": "^4.2.2" diff --git a/test/config-format/mjs/main.js b/test/config-format/mjs/main.js new file mode 100644 index 00000000000..8ed93e41fb2 --- /dev/null +++ b/test/config-format/mjs/main.js @@ -0,0 +1 @@ +console.log('Hoshiumi'); diff --git a/test/config-format/mjs/mjs-config.test.js b/test/config-format/mjs/mjs-config.test.js new file mode 100644 index 00000000000..bbfd4a7bea6 --- /dev/null +++ b/test/config-format/mjs/mjs-config.test.js @@ -0,0 +1,13 @@ +const { run } = require('../../utils/test-utils'); +const { existsSync } = require('fs'); +const { resolve } = require('path'); + +describe('webpack cli', () => { + it('should support mjs file', () => { + const { stderr, stdout } = run(__dirname, ['-c', 'webpack.config.mjs'], false); + expect(stderr).toBeFalsy(); + expect(stdout).toBeTruthy(); + console.log({ stderr, stdout }); + expect(existsSync(resolve(__dirname, 'dist/foo.bundle.js'))).toBeTruthy(); + }); +}); diff --git a/test/config-format/mjs/webpack.config.mjs b/test/config-format/mjs/webpack.config.mjs new file mode 100644 index 00000000000..829043efe49 --- /dev/null +++ b/test/config-format/mjs/webpack.config.mjs @@ -0,0 +1,8 @@ +export default { + mode: 'production', + entry: './main.js', + output: { + path: './dist', + filename: 'foo.bundle.js', + }, +}; diff --git a/yarn.lock b/yarn.lock index 6bc7d5f9ad9..ce80aa1cb52 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7022,7 +7022,7 @@ interpret@^1.0.0: resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.2.0.tgz#d5061a6224be58e8083985f5014d844359576296" integrity sha512-mT34yGKMNceBQUoVn7iCDKDntA7SC6gycMAWzGx1z/CMCTV7b2AAtXlo3nRyHZ1FelRkQbQjprHSYGwzLtkVbw== -interpret@^2.0.0: +interpret@^2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/interpret/-/interpret-2.2.0.tgz#1a78a0b5965c40a5416d007ad6f50ad27c417df9" integrity sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw==