UNPKG

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