Skip to content

Commit

Permalink
fix: respect the output.publicPath option for the servecommand (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
alexander-akait committed Dec 30, 2020
1 parent 0595603 commit a3092ef
Show file tree
Hide file tree
Showing 12 changed files with 302 additions and 32 deletions.
Expand Up @@ -4,6 +4,7 @@ exports[`startDevServer should set default port and host if not provided 1`] = `
Object {
"host": "localhost",
"port": 8080,
"publicPath": "/",
}
`;

Expand All @@ -22,6 +23,7 @@ Object {
"hot": true,
"port": 9000,
"progress": true,
"publicPath": "/",
}
`;

Expand All @@ -40,6 +42,7 @@ Object {
"hot": true,
"port": 9000,
"progress": true,
"publicPath": "/",
}
`;

Expand All @@ -56,6 +59,7 @@ Object {
"host": "localhost",
"port": 9000,
"progress": true,
"publicPath": "/",
}
`;

Expand All @@ -64,6 +68,7 @@ Object {
"host": "localhost",
"port": 9001,
"progress": true,
"publicPath": "/",
}
`;

Expand Down
73 changes: 43 additions & 30 deletions packages/serve/src/startDevServer.ts
Expand Up @@ -11,10 +11,7 @@ import { devServerOptionsType } from './types';
* @returns {Object[]} array of resulting servers
*/
export default async function startDevServer(compiler, cliOptions, logger): Promise<object[]> {
let isDevServer4 = false,
devServerVersion,
Server,
findPort;
let devServerVersion, Server, findPort;

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

isDevServer4 = devServerVersion.startsWith('4');

const defaultOpts = {};
const devServerOptions = [];
const compilers = compiler.compilers || [compiler];

compilers.forEach((compiler) => {
if (compiler.options.devServer) {
devServerOptions.push(compiler.options.devServer);
}
});

if (devServerOptions.length === 0) {
devServerOptions.push(defaultOpts);
}

const servers = [];
const usedPorts: number[] = [];
const mergeOptions = (cliOptions: devServerOptionsType, devServerOptions: devServerOptionsType): devServerOptionsType => {
// CLI options should take precedence over devServer options,
// and CLI options should have no default values included
Expand All @@ -60,35 +39,69 @@ export default async function startDevServer(compiler, cliOptions, logger): Prom
return options;
};

for (const devServerOpts of devServerOptions) {
const options = mergeOptions(cliOptions, devServerOpts);
const isMultiCompiler = Boolean(compiler.compilers);

let compilersWithDevServerOption;

if (isMultiCompiler) {
compilersWithDevServerOption = compiler.compilers.filter((compiler) => compiler.options.devServer);

// No compilers found with the `devServer` option, let's use first compiler
if (compilersWithDevServerOption.length === 0) {
compilersWithDevServerOption = [compiler.compilers[0]];
}
} else {
compilersWithDevServerOption = [compiler];
}

const isDevServer4 = devServerVersion.startsWith('4');
const usedPorts = [];
const devServersOptions = [];

for (const compilerWithDevServerOption of compilersWithDevServerOption) {
const options = mergeOptions(cliOptions, compilerWithDevServerOption.options.devServer || {});

if (isDevServer4) {
options.port = await findPort(options.port);
options.client = options.client || {};
options.client.port = options.client.port || options.port;
} else {
if (!options.publicPath) {
options.publicPath =
typeof compilerWithDevServerOption.options.output.publicPath === 'undefined' ||
compilerWithDevServerOption.options.output.publicPath === 'auto'
? '/'
: compilerWithDevServerOption.options.output.publicPath;
}

options.host = options.host || 'localhost';
options.port = options.port || 8080;
}

if (options.port) {
const portNum = +options.port;
const portNumber = Number(options.port);

if (usedPorts.find((port) => portNum === port)) {
if (usedPorts.find((port) => portNumber === port)) {
throw new Error(
'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.',
);
}

usedPorts.push(portNum);
usedPorts.push(portNumber);
}

devServersOptions.push({ compiler, options });
}

const servers = [];

for (const devServerOptions of devServersOptions) {
const { compiler, options } = devServerOptions;
const server = new Server(compiler, options);

server.listen(options.port, options.host, (err): void => {
if (err) {
throw err;
server.listen(options.port, options.host, (error): void => {
if (error) {
throw error;
}
});

Expand Down
1 change: 1 addition & 0 deletions packages/serve/src/types.ts
Expand Up @@ -27,6 +27,7 @@ export type devServerOptionsType = {
static?: boolean | string | object | (string | object)[];
transportMode?: object | string;
useLocalIp?: boolean;
publicPath?: undefined;
};

type devServerClientOptions = {
Expand Down
13 changes: 13 additions & 0 deletions test/serve/basic/dev-server-output-public-path.config.js
@@ -0,0 +1,13 @@
const WebpackCLITestPlugin = require('../../utils/webpack-cli-test-plugin');

module.exports = {
mode: 'development',
devtool: false,
output: {
publicPath: '/my-public-path/',
},
devServer: {
publicPath: '/dev-server-my-public-path/',
},
plugins: [new WebpackCLITestPlugin(['mode', 'output'], false, 'hooks.compilation.taps')],
};
26 changes: 26 additions & 0 deletions test/serve/basic/multi-dev-server-output-public-path.config.js
@@ -0,0 +1,26 @@
const WebpackCLITestPlugin = require('../../utils/webpack-cli-test-plugin');

module.exports = [
{
name: 'one',
mode: 'development',
devtool: false,
entry: './src/other.js',
output: {
filename: 'first-output/[name].js',
},
},
{
name: 'two',
mode: 'development',
devtool: false,
output: {
publicPath: '/my-public-path/',
filename: 'second-output/[name].js',
},
devServer: {
publicPath: '/dev-server-my-public-path/',
},
plugins: [new WebpackCLITestPlugin(['mode', 'output'], false, 'hooks.compilation.taps')],
},
];
32 changes: 32 additions & 0 deletions test/serve/basic/multi-dev-server.config.js
@@ -0,0 +1,32 @@
const getPort = require('get-port');

const WebpackCLITestPlugin = require('../../utils/webpack-cli-test-plugin');

module.exports = async () => [
{
name: 'one',
mode: 'development',
devtool: false,
output: {
filename: 'first-output/[name].js',
},
devServer: {
port: await getPort(),
publicPath: '/one-dev-server-my-public-path/',
},
plugins: [new WebpackCLITestPlugin(['mode', 'output'], false, 'hooks.compilation.taps')],
},
{
name: 'two',
mode: 'development',
devtool: false,
entry: './src/other.js',
output: {
filename: 'second-output/[name].js',
},
devServer: {
port: await getPort(),
publicPath: '/two-dev-server-my-public-path/',
},
},
];
23 changes: 23 additions & 0 deletions test/serve/basic/multi-output-public-path.config.js
@@ -0,0 +1,23 @@
const WebpackCLITestPlugin = require('../../utils/webpack-cli-test-plugin');

module.exports = [
{
name: 'one',
mode: 'development',
devtool: false,
output: {
publicPath: '/my-public-path/',
filename: 'first-output/[name].js',
},
plugins: [new WebpackCLITestPlugin(['mode', 'output'], false, 'hooks.compilation.taps')],
},
{
name: 'two',
mode: 'development',
devtool: false,
entry: './src/other.js',
output: {
filename: 'second-output/[name].js',
},
},
];
25 changes: 25 additions & 0 deletions test/serve/basic/multi.config.js
@@ -0,0 +1,25 @@
const WebpackCLITestPlugin = require('../../utils/webpack-cli-test-plugin');

module.exports = [
{
name: 'one',
mode: 'development',
devtool: false,
output: {
filename: 'first-output/[name].js',
},
devServer: {
publicPath: '/dev-server-my-public-path/',
},
plugins: [new WebpackCLITestPlugin(['mode', 'output'], false, 'hooks.compilation.taps')],
},
{
name: 'two',
mode: 'development',
devtool: false,
entry: './src/other.js',
output: {
filename: 'second-output/[name].js',
},
},
];
29 changes: 29 additions & 0 deletions test/serve/basic/multiple-dev-server.config.js
@@ -0,0 +1,29 @@
const WebpackCLITestPlugin = require('../../utils/webpack-cli-test-plugin');

module.exports = [
{
name: 'one',
mode: 'development',
devtool: false,
output: {
filename: 'first-output/[name].js',
},
devServer: {
publicPath: '/dev-server-my-public-path/',
},
plugins: [new WebpackCLITestPlugin(['mode', 'output'], false)],
},
{
name: 'two',
mode: 'development',
devtool: false,
entry: './src/other.js',
output: {
filename: 'first-output/[name].js',
},
devServer: {
publicPath: '/dev-server-my-public-path/',
},
plugins: [new WebpackCLITestPlugin(['mode', 'output'], false)],
},
];
10 changes: 10 additions & 0 deletions test/serve/basic/output-public-path.config.js
@@ -0,0 +1,10 @@
const WebpackCLITestPlugin = require('../../utils/webpack-cli-test-plugin');

module.exports = {
mode: 'development',
devtool: false,
output: {
publicPath: '/my-public-path/',
},
plugins: [new WebpackCLITestPlugin(['mode', 'output'], false, 'hooks.compilation.taps')],
};

0 comments on commit a3092ef

Please sign in to comment.