index.js 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264
  1. /*!
  2. Stencil Dev Server v2.18.1 | MIT Licensed | https://stenciljs.com
  3. */
  4. 'use strict';
  5. const path = require('path');
  6. const child_process = require('child_process');
  7. function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
  8. function _interopNamespace(e) {
  9. if (e && e.__esModule) return e;
  10. var n = Object.create(null);
  11. if (e) {
  12. Object.keys(e).forEach(function (k) {
  13. if (k !== 'default') {
  14. var d = Object.getOwnPropertyDescriptor(e, k);
  15. Object.defineProperty(n, k, d.get ? d : {
  16. enumerable: true,
  17. get: function () {
  18. return e[k];
  19. }
  20. });
  21. }
  22. });
  23. }
  24. n['default'] = e;
  25. return Object.freeze(n);
  26. }
  27. const path__default = /*#__PURE__*/_interopDefaultLegacy(path);
  28. function initServerProcessWorkerProxy(sendToMain) {
  29. const workerPath = require.resolve(path__default['default'].join(__dirname, 'server-worker-thread.js'));
  30. const filteredExecArgs = process.execArgv.filter((v) => !/^--(debug|inspect)/.test(v));
  31. const forkOpts = {
  32. execArgv: filteredExecArgs,
  33. env: process.env,
  34. cwd: process.cwd(),
  35. stdio: ['pipe', 'pipe', 'pipe', 'ipc'],
  36. };
  37. // start a new child process of the CLI process
  38. // for the http and web socket server
  39. let serverProcess = child_process.fork(workerPath, [], forkOpts);
  40. const receiveFromMain = (msg) => {
  41. // get a message from main to send to the worker
  42. if (serverProcess) {
  43. serverProcess.send(msg);
  44. }
  45. else if (msg.closeServer) {
  46. sendToMain({ serverClosed: true });
  47. }
  48. };
  49. // get a message from the worker and send it to main
  50. serverProcess.on('message', (msg) => {
  51. if (msg.serverClosed && serverProcess) {
  52. serverProcess.kill('SIGINT');
  53. serverProcess = null;
  54. }
  55. sendToMain(msg);
  56. });
  57. serverProcess.stdout.on('data', (data) => {
  58. // the child server process has console logged data
  59. console.log(`dev server: ${data}`);
  60. });
  61. serverProcess.stderr.on('data', (data) => {
  62. // the child server process has console logged an error
  63. sendToMain({ error: { message: 'stderr: ' + data } });
  64. });
  65. return receiveFromMain;
  66. }
  67. function start(stencilDevServerConfig, logger, watcher) {
  68. return new Promise(async (resolve, reject) => {
  69. try {
  70. const devServerConfig = {
  71. devServerDir: __dirname,
  72. ...stencilDevServerConfig,
  73. };
  74. if (!path__default['default'].isAbsolute(devServerConfig.root)) {
  75. devServerConfig.root = path__default['default'].join(process.cwd(), devServerConfig.root);
  76. }
  77. let initServerProcess;
  78. if (stencilDevServerConfig.worker === true || stencilDevServerConfig.worker === undefined) {
  79. // fork a worker process
  80. initServerProcess = initServerProcessWorkerProxy;
  81. }
  82. else {
  83. // same process
  84. const devServerProcess = await Promise.resolve().then(function () { return /*#__PURE__*/_interopNamespace(require('./server-process.js')); });
  85. initServerProcess = devServerProcess.initServerProcess;
  86. }
  87. startServer(devServerConfig, logger, watcher, initServerProcess, resolve, reject);
  88. }
  89. catch (e) {
  90. reject(e);
  91. }
  92. });
  93. }
  94. function startServer(devServerConfig, logger, watcher, initServerProcess, resolve, reject) {
  95. var _a;
  96. const timespan = logger.createTimeSpan(`starting dev server`, true);
  97. const startupTimeout = logger.getLevel() !== 'debug' || devServerConfig.startupTimeout !== 0
  98. ? setTimeout(() => {
  99. reject(`dev server startup timeout`);
  100. }, (_a = devServerConfig.startupTimeout) !== null && _a !== void 0 ? _a : 15000)
  101. : null;
  102. let isActivelyBuilding = false;
  103. let lastBuildResults = null;
  104. let devServer = null;
  105. let removeWatcher = null;
  106. let closeResolve = null;
  107. let hasStarted = false;
  108. let browserUrl = '';
  109. let sendToWorker = null;
  110. const closePromise = new Promise((resolve) => (closeResolve = resolve));
  111. const close = async () => {
  112. clearTimeout(startupTimeout);
  113. isActivelyBuilding = false;
  114. if (removeWatcher) {
  115. removeWatcher();
  116. }
  117. if (devServer) {
  118. devServer = null;
  119. }
  120. if (sendToWorker) {
  121. sendToWorker({
  122. closeServer: true,
  123. });
  124. sendToWorker = null;
  125. }
  126. return closePromise;
  127. };
  128. const emit = async (eventName, data) => {
  129. if (sendToWorker) {
  130. if (eventName === 'buildFinish') {
  131. isActivelyBuilding = false;
  132. lastBuildResults = { ...data };
  133. sendToWorker({ buildResults: { ...lastBuildResults }, isActivelyBuilding });
  134. }
  135. else if (eventName === 'buildLog') {
  136. sendToWorker({
  137. buildLog: { ...data },
  138. });
  139. }
  140. else if (eventName === 'buildStart') {
  141. isActivelyBuilding = true;
  142. }
  143. }
  144. };
  145. const serverStarted = (msg) => {
  146. hasStarted = true;
  147. clearTimeout(startupTimeout);
  148. devServerConfig = msg.serverStarted;
  149. devServer = {
  150. address: devServerConfig.address,
  151. basePath: devServerConfig.basePath,
  152. browserUrl: devServerConfig.browserUrl,
  153. protocol: devServerConfig.protocol,
  154. port: devServerConfig.port,
  155. root: devServerConfig.root,
  156. emit,
  157. close,
  158. };
  159. browserUrl = devServerConfig.browserUrl;
  160. timespan.finish(`dev server started: ${browserUrl}`);
  161. resolve(devServer);
  162. };
  163. const requestLog = (msg) => {
  164. if (devServerConfig.logRequests) {
  165. if (msg.requestLog.status >= 500) {
  166. logger.info(logger.red(`${msg.requestLog.method} ${msg.requestLog.url} (${msg.requestLog.status})`));
  167. }
  168. else if (msg.requestLog.status >= 400) {
  169. logger.info(logger.dim(logger.red(`${msg.requestLog.method} ${msg.requestLog.url} (${msg.requestLog.status})`)));
  170. }
  171. else if (msg.requestLog.status >= 300) {
  172. logger.info(logger.dim(logger.magenta(`${msg.requestLog.method} ${msg.requestLog.url} (${msg.requestLog.status})`)));
  173. }
  174. else {
  175. logger.info(logger.dim(`${logger.cyan(msg.requestLog.method)} ${msg.requestLog.url}`));
  176. }
  177. }
  178. };
  179. const serverError = async (msg) => {
  180. if (hasStarted) {
  181. logger.error(msg.error.message + ' ' + msg.error.stack);
  182. }
  183. else {
  184. await close();
  185. reject(msg.error.message);
  186. }
  187. };
  188. const requestBuildResults = () => {
  189. // we received a request to send up the latest build results
  190. if (sendToWorker) {
  191. if (lastBuildResults != null) {
  192. // we do have build results, so let's send them to the child process
  193. const msg = {
  194. buildResults: { ...lastBuildResults },
  195. isActivelyBuilding: isActivelyBuilding,
  196. };
  197. // but don't send any previous live reload data
  198. delete msg.buildResults.hmr;
  199. sendToWorker(msg);
  200. }
  201. else {
  202. sendToWorker({
  203. isActivelyBuilding: true,
  204. });
  205. }
  206. }
  207. };
  208. const compilerRequest = async (compilerRequestPath) => {
  209. if (watcher && watcher.request && sendToWorker) {
  210. const compilerRequestResults = await watcher.request({ path: compilerRequestPath });
  211. sendToWorker({ compilerRequestResults });
  212. }
  213. };
  214. const receiveFromWorker = (msg) => {
  215. try {
  216. if (msg.serverStarted) {
  217. serverStarted(msg);
  218. }
  219. else if (msg.serverClosed) {
  220. logger.debug(`dev server closed: ${browserUrl}`);
  221. closeResolve();
  222. }
  223. else if (msg.requestBuildResults) {
  224. requestBuildResults();
  225. }
  226. else if (msg.compilerRequestPath) {
  227. compilerRequest(msg.compilerRequestPath);
  228. }
  229. else if (msg.requestLog) {
  230. requestLog(msg);
  231. }
  232. else if (msg.error) {
  233. serverError(msg);
  234. }
  235. else {
  236. logger.debug(`server msg not handled: ${JSON.stringify(msg)}`);
  237. }
  238. }
  239. catch (e) {
  240. logger.error('receiveFromWorker: ' + e);
  241. }
  242. };
  243. try {
  244. if (watcher) {
  245. removeWatcher = watcher.on(emit);
  246. }
  247. sendToWorker = initServerProcess(receiveFromWorker);
  248. sendToWorker({
  249. startServer: devServerConfig,
  250. });
  251. }
  252. catch (e) {
  253. close();
  254. reject(e);
  255. }
  256. }
  257. exports.start = start;