UNPKG

5.37 kBJavaScriptView Raw
1#!/usr/bin/env node
2
3'use strict';
4
5/* eslint-disable
6 import/order,
7 import/no-extraneous-dependencies,
8 global-require,
9 no-shadow,
10 no-console,
11 multiline-ternary,
12 arrow-parens,
13 array-bracket-spacing,
14 space-before-function-paren
15*/
16const debug = require('debug')('webpack-dev-server');
17
18const fs = require('fs');
19const net = require('net');
20
21const portfinder = require('portfinder');
22const importLocal = require('import-local');
23
24const yargs = require('yargs');
25const webpack = require('webpack');
26
27const options = require('./options');
28
29const { colors, status, version, bonjour } = require('./utils');
30
31const Server = require('../lib/Server');
32
33const addEntries = require('../lib/utils/addEntries');
34const createDomain = require('../lib/utils/createDomain');
35const createLogger = require('../lib/utils/createLogger');
36const createConfig = require('../lib/utils/createConfig');
37
38let server;
39
40const signals = ['SIGINT', 'SIGTERM'];
41
42signals.forEach((signal) => {
43 process.on(signal, () => {
44 if (server) {
45 server.close(() => {
46 // eslint-disable-next-line no-process-exit
47 process.exit();
48 });
49 } else {
50 // eslint-disable-next-line no-process-exit
51 process.exit();
52 }
53 });
54});
55
56// Prefer the local installation of webpack-dev-server
57if (importLocal(__filename)) {
58 debug('Using local install of webpack-dev-server');
59
60 return;
61}
62
63try {
64 require.resolve('webpack-cli');
65} catch (err) {
66 console.error('The CLI moved into a separate package: webpack-cli');
67 console.error(
68 "Please install 'webpack-cli' in addition to webpack itself to use the CLI"
69 );
70 console.error('-> When using npm: npm i -D webpack-cli');
71 console.error('-> When using yarn: yarn add -D webpack-cli');
72
73 process.exitCode = 1;
74}
75
76yargs.usage(
77 `${version()}\nUsage: https://webpack.js.org/configuration/dev-server/`
78);
79
80require('webpack-cli/bin/config-yargs')(yargs);
81// It is important that this is done after the webpack yargs config,
82// so it overrides webpack's version info.
83yargs.version(version());
84yargs.options(options);
85
86const argv = yargs.argv;
87
88const config = require('webpack-cli/bin/convert-argv')(yargs, argv, {
89 outputFilename: '/bundle.js',
90});
91
92// Taken out of yargs because we must know if
93// it wasn't given by the user, in which case
94// we should use portfinder.
95const DEFAULT_PORT = 8080;
96
97function processOptions(config) {
98 // processOptions {Promise}
99 if (typeof config.then === 'function') {
100 config.then(processOptions).catch((err) => {
101 console.error(err.stack || err);
102 // eslint-disable-next-line no-process-exit
103 process.exit();
104 });
105
106 return;
107 }
108
109 const options = createConfig(config, argv, { port: DEFAULT_PORT });
110
111 portfinder.basePort = DEFAULT_PORT;
112
113 if (options.port != null) {
114 startDevServer(config, options);
115
116 return;
117 }
118
119 portfinder.getPort((err, port) => {
120 if (err) {
121 throw err;
122 }
123
124 options.port = port;
125
126 startDevServer(config, options);
127 });
128}
129
130function startDevServer(config, options) {
131 const log = createLogger(options);
132
133 addEntries(config, options);
134
135 let compiler;
136
137 try {
138 compiler = webpack(config);
139 } catch (err) {
140 if (err instanceof webpack.WebpackOptionsValidationError) {
141 log.error(colors.error(options.stats.colors, err.message));
142 // eslint-disable-next-line no-process-exit
143 process.exit(1);
144 }
145
146 throw err;
147 }
148
149 if (options.progress) {
150 new webpack.ProgressPlugin({
151 profile: argv.profile,
152 }).apply(compiler);
153 }
154
155 const suffix =
156 options.inline !== false || options.lazy === true
157 ? '/'
158 : '/webpack-dev-server/';
159
160 try {
161 server = new Server(compiler, options, log);
162 } catch (err) {
163 if (err.name === 'ValidationError') {
164 log.error(colors.error(options.stats.colors, err.message));
165 // eslint-disable-next-line no-process-exit
166 process.exit(1);
167 }
168
169 throw err;
170 }
171
172 if (options.socket) {
173 server.listeningApp.on('error', (e) => {
174 if (e.code === 'EADDRINUSE') {
175 const clientSocket = new net.Socket();
176
177 clientSocket.on('error', (err) => {
178 if (err.code === 'ECONNREFUSED') {
179 // No other server listening on this socket so it can be safely removed
180 fs.unlinkSync(options.socket);
181
182 server.listen(options.socket, options.host, (error) => {
183 if (error) {
184 throw error;
185 }
186 });
187 }
188 });
189
190 clientSocket.connect({ path: options.socket }, () => {
191 throw new Error('This socket is already used');
192 });
193 }
194 });
195
196 server.listen(options.socket, options.host, (err) => {
197 if (err) {
198 throw err;
199 }
200 // chmod 666 (rw rw rw)
201 const READ_WRITE = 438;
202
203 fs.chmod(options.socket, READ_WRITE, (err) => {
204 if (err) {
205 throw err;
206 }
207
208 const uri = createDomain(options, server.listeningApp) + suffix;
209
210 status(uri, options, log, argv.color);
211 });
212 });
213 } else {
214 server.listen(options.port, options.host, (err) => {
215 if (err) {
216 throw err;
217 }
218
219 if (options.bonjour) {
220 bonjour(options);
221 }
222
223 const uri = createDomain(options, server.listeningApp) + suffix;
224
225 status(uri, options, log, argv.color);
226 });
227 }
228}
229
230processOptions(config);