Skip to content

Commit a3092ef

Browse files
fix: respect the output.publicPath option for the servecommand (#2271)
1 parent 0595603 commit a3092ef

12 files changed

+302
-32
lines changed

packages/serve/__tests__/__snapshots__/startDevServer.test.ts.snap

+5
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ exports[`startDevServer should set default port and host if not provided 1`] = `
44
Object {
55
"host": "localhost",
66
"port": 8080,
7+
"publicPath": "/",
78
}
89
`;
910

@@ -22,6 +23,7 @@ Object {
2223
"hot": true,
2324
"port": 9000,
2425
"progress": true,
26+
"publicPath": "/",
2527
}
2628
`;
2729

@@ -40,6 +42,7 @@ Object {
4042
"hot": true,
4143
"port": 9000,
4244
"progress": true,
45+
"publicPath": "/",
4346
}
4447
`;
4548

@@ -56,6 +59,7 @@ Object {
5659
"host": "localhost",
5760
"port": 9000,
5861
"progress": true,
62+
"publicPath": "/",
5963
}
6064
`;
6165

@@ -64,6 +68,7 @@ Object {
6468
"host": "localhost",
6569
"port": 9001,
6670
"progress": true,
71+
"publicPath": "/",
6772
}
6873
`;
6974

packages/serve/src/startDevServer.ts

+43-30
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,7 @@ import { devServerOptionsType } from './types';
1111
* @returns {Object[]} array of resulting servers
1212
*/
1313
export default async function startDevServer(compiler, cliOptions, logger): Promise<object[]> {
14-
let isDevServer4 = false,
15-
devServerVersion,
16-
Server,
17-
findPort;
14+
let devServerVersion, Server, findPort;
1815

1916
try {
2017
// eslint-disable-next-line node/no-extraneous-require
@@ -28,24 +25,6 @@ export default async function startDevServer(compiler, cliOptions, logger): Prom
2825
process.exit(2);
2926
}
3027

31-
isDevServer4 = devServerVersion.startsWith('4');
32-
33-
const defaultOpts = {};
34-
const devServerOptions = [];
35-
const compilers = compiler.compilers || [compiler];
36-
37-
compilers.forEach((compiler) => {
38-
if (compiler.options.devServer) {
39-
devServerOptions.push(compiler.options.devServer);
40-
}
41-
});
42-
43-
if (devServerOptions.length === 0) {
44-
devServerOptions.push(defaultOpts);
45-
}
46-
47-
const servers = [];
48-
const usedPorts: number[] = [];
4928
const mergeOptions = (cliOptions: devServerOptionsType, devServerOptions: devServerOptionsType): devServerOptionsType => {
5029
// CLI options should take precedence over devServer options,
5130
// and CLI options should have no default values included
@@ -60,35 +39,69 @@ export default async function startDevServer(compiler, cliOptions, logger): Prom
6039
return options;
6140
};
6241

63-
for (const devServerOpts of devServerOptions) {
64-
const options = mergeOptions(cliOptions, devServerOpts);
42+
const isMultiCompiler = Boolean(compiler.compilers);
43+
44+
let compilersWithDevServerOption;
45+
46+
if (isMultiCompiler) {
47+
compilersWithDevServerOption = compiler.compilers.filter((compiler) => compiler.options.devServer);
48+
49+
// No compilers found with the `devServer` option, let's use first compiler
50+
if (compilersWithDevServerOption.length === 0) {
51+
compilersWithDevServerOption = [compiler.compilers[0]];
52+
}
53+
} else {
54+
compilersWithDevServerOption = [compiler];
55+
}
56+
57+
const isDevServer4 = devServerVersion.startsWith('4');
58+
const usedPorts = [];
59+
const devServersOptions = [];
60+
61+
for (const compilerWithDevServerOption of compilersWithDevServerOption) {
62+
const options = mergeOptions(cliOptions, compilerWithDevServerOption.options.devServer || {});
6563

6664
if (isDevServer4) {
6765
options.port = await findPort(options.port);
6866
options.client = options.client || {};
6967
options.client.port = options.client.port || options.port;
7068
} else {
69+
if (!options.publicPath) {
70+
options.publicPath =
71+
typeof compilerWithDevServerOption.options.output.publicPath === 'undefined' ||
72+
compilerWithDevServerOption.options.output.publicPath === 'auto'
73+
? '/'
74+
: compilerWithDevServerOption.options.output.publicPath;
75+
}
76+
7177
options.host = options.host || 'localhost';
7278
options.port = options.port || 8080;
7379
}
7480

7581
if (options.port) {
76-
const portNum = +options.port;
82+
const portNumber = Number(options.port);
7783

78-
if (usedPorts.find((port) => portNum === port)) {
84+
if (usedPorts.find((port) => portNumber === port)) {
7985
throw new Error(
8086
'Unique ports must be specified for each devServer option in your webpack configuration. Alternatively, run only 1 devServer config using the --config-name flag to specify your desired config.',
8187
);
8288
}
8389

84-
usedPorts.push(portNum);
90+
usedPorts.push(portNumber);
8591
}
8692

93+
devServersOptions.push({ compiler, options });
94+
}
95+
96+
const servers = [];
97+
98+
for (const devServerOptions of devServersOptions) {
99+
const { compiler, options } = devServerOptions;
87100
const server = new Server(compiler, options);
88101

89-
server.listen(options.port, options.host, (err): void => {
90-
if (err) {
91-
throw err;
102+
server.listen(options.port, options.host, (error): void => {
103+
if (error) {
104+
throw error;
92105
}
93106
});
94107

packages/serve/src/types.ts

+1
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ export type devServerOptionsType = {
2727
static?: boolean | string | object | (string | object)[];
2828
transportMode?: object | string;
2929
useLocalIp?: boolean;
30+
publicPath?: undefined;
3031
};
3132

3233
type devServerClientOptions = {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
const WebpackCLITestPlugin = require('../../utils/webpack-cli-test-plugin');
2+
3+
module.exports = {
4+
mode: 'development',
5+
devtool: false,
6+
output: {
7+
publicPath: '/my-public-path/',
8+
},
9+
devServer: {
10+
publicPath: '/dev-server-my-public-path/',
11+
},
12+
plugins: [new WebpackCLITestPlugin(['mode', 'output'], false, 'hooks.compilation.taps')],
13+
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
const WebpackCLITestPlugin = require('../../utils/webpack-cli-test-plugin');
2+
3+
module.exports = [
4+
{
5+
name: 'one',
6+
mode: 'development',
7+
devtool: false,
8+
entry: './src/other.js',
9+
output: {
10+
filename: 'first-output/[name].js',
11+
},
12+
},
13+
{
14+
name: 'two',
15+
mode: 'development',
16+
devtool: false,
17+
output: {
18+
publicPath: '/my-public-path/',
19+
filename: 'second-output/[name].js',
20+
},
21+
devServer: {
22+
publicPath: '/dev-server-my-public-path/',
23+
},
24+
plugins: [new WebpackCLITestPlugin(['mode', 'output'], false, 'hooks.compilation.taps')],
25+
},
26+
];
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
const getPort = require('get-port');
2+
3+
const WebpackCLITestPlugin = require('../../utils/webpack-cli-test-plugin');
4+
5+
module.exports = async () => [
6+
{
7+
name: 'one',
8+
mode: 'development',
9+
devtool: false,
10+
output: {
11+
filename: 'first-output/[name].js',
12+
},
13+
devServer: {
14+
port: await getPort(),
15+
publicPath: '/one-dev-server-my-public-path/',
16+
},
17+
plugins: [new WebpackCLITestPlugin(['mode', 'output'], false, 'hooks.compilation.taps')],
18+
},
19+
{
20+
name: 'two',
21+
mode: 'development',
22+
devtool: false,
23+
entry: './src/other.js',
24+
output: {
25+
filename: 'second-output/[name].js',
26+
},
27+
devServer: {
28+
port: await getPort(),
29+
publicPath: '/two-dev-server-my-public-path/',
30+
},
31+
},
32+
];
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
const WebpackCLITestPlugin = require('../../utils/webpack-cli-test-plugin');
2+
3+
module.exports = [
4+
{
5+
name: 'one',
6+
mode: 'development',
7+
devtool: false,
8+
output: {
9+
publicPath: '/my-public-path/',
10+
filename: 'first-output/[name].js',
11+
},
12+
plugins: [new WebpackCLITestPlugin(['mode', 'output'], false, 'hooks.compilation.taps')],
13+
},
14+
{
15+
name: 'two',
16+
mode: 'development',
17+
devtool: false,
18+
entry: './src/other.js',
19+
output: {
20+
filename: 'second-output/[name].js',
21+
},
22+
},
23+
];

test/serve/basic/multi.config.js

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
const WebpackCLITestPlugin = require('../../utils/webpack-cli-test-plugin');
2+
3+
module.exports = [
4+
{
5+
name: 'one',
6+
mode: 'development',
7+
devtool: false,
8+
output: {
9+
filename: 'first-output/[name].js',
10+
},
11+
devServer: {
12+
publicPath: '/dev-server-my-public-path/',
13+
},
14+
plugins: [new WebpackCLITestPlugin(['mode', 'output'], false, 'hooks.compilation.taps')],
15+
},
16+
{
17+
name: 'two',
18+
mode: 'development',
19+
devtool: false,
20+
entry: './src/other.js',
21+
output: {
22+
filename: 'second-output/[name].js',
23+
},
24+
},
25+
];
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
const WebpackCLITestPlugin = require('../../utils/webpack-cli-test-plugin');
2+
3+
module.exports = [
4+
{
5+
name: 'one',
6+
mode: 'development',
7+
devtool: false,
8+
output: {
9+
filename: 'first-output/[name].js',
10+
},
11+
devServer: {
12+
publicPath: '/dev-server-my-public-path/',
13+
},
14+
plugins: [new WebpackCLITestPlugin(['mode', 'output'], false)],
15+
},
16+
{
17+
name: 'two',
18+
mode: 'development',
19+
devtool: false,
20+
entry: './src/other.js',
21+
output: {
22+
filename: 'first-output/[name].js',
23+
},
24+
devServer: {
25+
publicPath: '/dev-server-my-public-path/',
26+
},
27+
plugins: [new WebpackCLITestPlugin(['mode', 'output'], false)],
28+
},
29+
];
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
const WebpackCLITestPlugin = require('../../utils/webpack-cli-test-plugin');
2+
3+
module.exports = {
4+
mode: 'development',
5+
devtool: false,
6+
output: {
7+
publicPath: '/my-public-path/',
8+
},
9+
plugins: [new WebpackCLITestPlugin(['mode', 'output'], false, 'hooks.compilation.taps')],
10+
};

0 commit comments

Comments
 (0)