Skip to content

Commit 3f31702

Browse files
authored
refactor: add mjs support (#2172)
1 parent f411aed commit 3f31702

File tree

17 files changed

+137
-8
lines changed

17 files changed

+137
-8
lines changed

.eslintignore

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,5 +14,5 @@ test/**/bin/
1414
test/**/binary/
1515
test/**/index.js
1616
test/typescript/webpack.config.ts
17-
test/config/error/syntax-error.js
18-
test/config/error-array/webpack.config.js
17+
test/config/error-commonjs/syntax-error.js
18+
test/config/error-mjs/syntax-error.mjs

.prettierignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ test/**/dist/
44
test/**/bin/
55
test/**/binary/
66
test/**/index.js
7-
test/config/error/syntax-error.js
7+
test/config/error-commonjs/syntax-error.js
8+
test/config/error-mjs/syntax-error.mjs
89
packages/webpack-cli/__tests__/test-assets/.yo-rc.json
910
test/build-errors/stats.json

packages/webpack-cli/lib/webpack-cli.js

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,18 +22,40 @@ class WebpackCLI {
2222
constructor() {}
2323

2424
async resolveConfig(args) {
25-
const loadConfig = (configPath) => {
25+
const loadConfig = async (configPath) => {
2626
const ext = extname(configPath);
2727
const interpreted = Object.keys(jsVariants).find((variant) => variant === ext);
2828

2929
if (interpreted) {
3030
rechoir.prepare(extensions, configPath);
3131
}
3232

33-
let options;
33+
const { pathToFileURL } = require('url');
34+
35+
let importESM;
3436

3537
try {
36-
options = require(configPath);
38+
importESM = new Function('id', 'return import(id);');
39+
} catch (e) {
40+
importESM = null;
41+
}
42+
43+
let options;
44+
try {
45+
try {
46+
options = require(configPath);
47+
} catch (error) {
48+
if (pathToFileURL && importESM && error.code === 'ERR_REQUIRE_ESM') {
49+
const urlForConfig = pathToFileURL(configPath);
50+
51+
options = await importESM(urlForConfig);
52+
options = options.default;
53+
54+
return { options, path: configPath };
55+
}
56+
57+
throw error;
58+
}
3759
} catch (error) {
3860
logger.error(`Failed to load '${configPath}'`);
3961
logger.error(error);
@@ -91,7 +113,7 @@ class WebpackCLI {
91113
process.exit(2);
92114
}
93115

94-
const loadedConfig = loadConfig(configPath);
116+
const loadedConfig = await loadConfig(configPath);
95117

96118
return evaluateConfig(loadedConfig, args);
97119
}),
@@ -136,7 +158,7 @@ class WebpackCLI {
136158
}
137159

138160
if (foundDefaultConfigFile) {
139-
const loadedConfig = loadConfig(foundDefaultConfigFile.path);
161+
const loadedConfig = await loadConfig(foundDefaultConfigFile.path);
140162
const evaluatedConfig = await evaluateConfig(loadedConfig, args);
141163

142164
config.options = evaluatedConfig.options;

test/config-format/mjs/main.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
console.log('You know who');

test/config-format/mjs/mjs.test.js

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
const { run } = require('../../utils/test-utils');
2+
3+
describe('webpack cli', () => {
4+
it('should support mjs config format', () => {
5+
const { exitCode, stderr, stdout } = run(__dirname, ['-c', 'webpack.config.mjs'], false, [], { DISABLE_V8_COMPILE_CACHE: true });
6+
7+
if (exitCode === 0) {
8+
expect(exitCode).toBe(0);
9+
expect(stderr).toContain('Compilation starting...');
10+
expect(stderr).toContain('Compilation finished');
11+
expect(stdout).toBeTruthy();
12+
} else {
13+
expect(exitCode).toBe(2);
14+
expect(/Cannot use import statement outside a module/.test(stderr) || /Unexpected token/.test(stderr)).toBe(true);
15+
expect(stdout).toBeFalsy();
16+
}
17+
});
18+
});
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import { fileURLToPath } from 'url';
2+
import path from 'path';
3+
4+
export default {
5+
mode: 'production',
6+
entry: './main.js',
7+
output: {
8+
path: path.resolve(path.dirname(fileURLToPath(import.meta.url)), 'dist'),
9+
filename: 'foo.bundle.js',
10+
},
11+
};
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
const fs = require('fs');
2+
const path = require('path');
3+
const { run, isWebpack5 } = require('../../../utils/test-utils');
4+
5+
describe('Default Config:', () => {
6+
it('Should be able to pick mjs config by default', () => {
7+
const { exitCode, stderr, stdout } = run(__dirname, [], false, [], { DISABLE_V8_COMPILE_CACHE: true });
8+
9+
if (exitCode === 0) {
10+
expect(exitCode).toEqual(0);
11+
expect(stderr).toContain('Compilation starting...');
12+
expect(stderr).toContain('Compilation finished');
13+
// default entry should be used
14+
expect(stdout).toContain('./src/index.js');
15+
// should pick up the output path from config
16+
expect(stdout).toContain('test-output');
17+
18+
if (!isWebpack5) {
19+
expect(stdout).toContain('Hash');
20+
expect(stdout).toContain('Version');
21+
expect(stdout).toContain('Built at');
22+
expect(stdout).toContain('Time');
23+
}
24+
25+
// check that the output file exists
26+
expect(fs.existsSync(path.join(__dirname, '/dist/test-output.js'))).toBeTruthy();
27+
} else {
28+
expect(exitCode).toEqual(2);
29+
expect(stderr).toContain('Unexpected token');
30+
expect(stdout).toBeFalsy();
31+
}
32+
});
33+
});
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
console.log("Jotaro Kujo")
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
export default {
2+
mode: 'development',
3+
output: {
4+
filename: 'test-output.js',
5+
},
6+
};

0 commit comments

Comments
 (0)