webpack-dev-server.js 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  1. #!/usr/bin/env node
  2. 'use strict';
  3. /* eslint-disable no-shadow, no-console */
  4. const fs = require('fs');
  5. const net = require('net');
  6. const debug = require('debug')('webpack-dev-server');
  7. const importLocal = require('import-local');
  8. const yargs = require('yargs');
  9. const webpack = require('webpack');
  10. const Server = require('../lib/Server');
  11. const setupExitSignals = require('../lib/utils/setupExitSignals');
  12. const colors = require('../lib/utils/colors');
  13. const processOptions = require('../lib/utils/processOptions');
  14. const createLogger = require('../lib/utils/createLogger');
  15. const getVersions = require('../lib/utils/getVersions');
  16. const options = require('./options');
  17. let server;
  18. const serverData = {
  19. server: null,
  20. };
  21. // we must pass an object that contains the server object as a property so that
  22. // we can update this server property later, and setupExitSignals will be able to
  23. // recognize that the server has been instantiated, because we will set
  24. // serverData.server to the new server object.
  25. setupExitSignals(serverData);
  26. // Prefer the local installation of webpack-dev-server
  27. if (importLocal(__filename)) {
  28. debug('Using local install of webpack-dev-server');
  29. return;
  30. }
  31. try {
  32. require.resolve('webpack-cli');
  33. } catch (err) {
  34. console.error('The CLI moved into a separate package: webpack-cli');
  35. console.error(
  36. "Please install 'webpack-cli' in addition to webpack itself to use the CLI"
  37. );
  38. console.error('-> When using npm: npm i -D webpack-cli');
  39. console.error('-> When using yarn: yarn add -D webpack-cli');
  40. process.exitCode = 1;
  41. }
  42. yargs.usage(
  43. `${getVersions()}\nUsage: https://webpack.js.org/configuration/dev-server/`
  44. );
  45. // webpack-cli@3.3 path : 'webpack-cli/bin/config/config-yargs'
  46. let configYargsPath;
  47. try {
  48. require.resolve('webpack-cli/bin/config/config-yargs');
  49. configYargsPath = 'webpack-cli/bin/config/config-yargs';
  50. } catch (e) {
  51. configYargsPath = 'webpack-cli/bin/config-yargs';
  52. }
  53. // eslint-disable-next-line import/no-extraneous-dependencies
  54. // eslint-disable-next-line import/no-dynamic-require
  55. require(configYargsPath)(yargs);
  56. // It is important that this is done after the webpack yargs config,
  57. // so it overrides webpack's version info.
  58. yargs.version(getVersions());
  59. yargs.options(options);
  60. const argv = yargs.argv;
  61. // webpack-cli@3.3 path : 'webpack-cli/bin/utils/convert-argv'
  62. let convertArgvPath;
  63. try {
  64. require.resolve('webpack-cli/bin/utils/convert-argv');
  65. convertArgvPath = 'webpack-cli/bin/utils/convert-argv';
  66. } catch (e) {
  67. convertArgvPath = 'webpack-cli/bin/convert-argv';
  68. }
  69. // eslint-disable-next-line import/no-extraneous-dependencies
  70. // eslint-disable-next-line import/no-dynamic-require
  71. const config = require(convertArgvPath)(yargs, argv, {
  72. outputFilename: '/bundle.js',
  73. });
  74. function startDevServer(config, options) {
  75. const log = createLogger(options);
  76. let compiler;
  77. try {
  78. compiler = webpack(config);
  79. } catch (err) {
  80. if (err instanceof webpack.WebpackOptionsValidationError) {
  81. log.error(colors.error(options.stats.colors, err.message));
  82. // eslint-disable-next-line no-process-exit
  83. process.exit(1);
  84. }
  85. throw err;
  86. }
  87. try {
  88. server = new Server(compiler, options, log);
  89. serverData.server = server;
  90. } catch (err) {
  91. if (err.name === 'ValidationError') {
  92. log.error(colors.error(options.stats.colors, err.message));
  93. // eslint-disable-next-line no-process-exit
  94. process.exit(1);
  95. }
  96. throw err;
  97. }
  98. if (options.socket) {
  99. server.listeningApp.on('error', (e) => {
  100. if (e.code === 'EADDRINUSE') {
  101. const clientSocket = new net.Socket();
  102. clientSocket.on('error', (err) => {
  103. if (err.code === 'ECONNREFUSED') {
  104. // No other server listening on this socket so it can be safely removed
  105. fs.unlinkSync(options.socket);
  106. server.listen(options.socket, options.host, (error) => {
  107. if (error) {
  108. throw error;
  109. }
  110. });
  111. }
  112. });
  113. clientSocket.connect({ path: options.socket }, () => {
  114. throw new Error('This socket is already used');
  115. });
  116. }
  117. });
  118. server.listen(options.socket, options.host, (err) => {
  119. if (err) {
  120. throw err;
  121. }
  122. // chmod 666 (rw rw rw)
  123. const READ_WRITE = 438;
  124. fs.chmod(options.socket, READ_WRITE, (err) => {
  125. if (err) {
  126. throw err;
  127. }
  128. });
  129. });
  130. } else {
  131. server.listen(options.port, options.host, (err) => {
  132. if (err) {
  133. throw err;
  134. }
  135. });
  136. }
  137. }
  138. processOptions(config, argv, (config, options) => {
  139. startDevServer(config, options);
  140. });