1 | #!/usr/bin/env node
|
2 |
|
3 | 'use strict';
|
4 |
|
5 |
|
6 |
|
7 |
|
8 |
|
9 |
|
10 |
|
11 |
|
12 |
|
13 |
|
14 |
|
15 |
|
16 | const debug = require('debug')('webpack-dev-server');
|
17 |
|
18 | const fs = require('fs');
|
19 | const net = require('net');
|
20 |
|
21 | const portfinder = require('portfinder');
|
22 | const importLocal = require('import-local');
|
23 |
|
24 | const yargs = require('yargs');
|
25 | const webpack = require('webpack');
|
26 |
|
27 | const options = require('./options');
|
28 |
|
29 | const { colors, status, version, bonjour } = require('./utils');
|
30 |
|
31 | const Server = require('../lib/Server');
|
32 |
|
33 | const addEntries = require('../lib/utils/addEntries');
|
34 | const createDomain = require('../lib/utils/createDomain');
|
35 | const createLogger = require('../lib/utils/createLogger');
|
36 | const createConfig = require('../lib/utils/createConfig');
|
37 |
|
38 | let server;
|
39 |
|
40 | const signals = ['SIGINT', 'SIGTERM'];
|
41 |
|
42 | signals.forEach((signal) => {
|
43 | process.on(signal, () => {
|
44 | if (server) {
|
45 | server.close(() => {
|
46 |
|
47 | process.exit();
|
48 | });
|
49 | } else {
|
50 |
|
51 | process.exit();
|
52 | }
|
53 | });
|
54 | });
|
55 |
|
56 |
|
57 | if (importLocal(__filename)) {
|
58 | debug('Using local install of webpack-dev-server');
|
59 |
|
60 | return;
|
61 | }
|
62 |
|
63 | try {
|
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 |
|
76 | yargs.usage(
|
77 | `${version()}\nUsage: https://webpack.js.org/configuration/dev-server/`
|
78 | );
|
79 |
|
80 | require('webpack-cli/bin/config-yargs')(yargs);
|
81 |
|
82 |
|
83 | yargs.version(version());
|
84 | yargs.options(options);
|
85 |
|
86 | const argv = yargs.argv;
|
87 |
|
88 | const config = require('webpack-cli/bin/convert-argv')(yargs, argv, {
|
89 | outputFilename: '/bundle.js',
|
90 | });
|
91 |
|
92 |
|
93 |
|
94 |
|
95 | const DEFAULT_PORT = 8080;
|
96 |
|
97 | function processOptions(config) {
|
98 |
|
99 | if (typeof config.then === 'function') {
|
100 | config.then(processOptions).catch((err) => {
|
101 | console.error(err.stack || err);
|
102 |
|
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 |
|
130 | function 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 |
|
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 |
|
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 |
|
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 |
|
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 |
|
230 | processOptions(config);
|