1 | 'use strict';
|
2 |
|
3 | Object.defineProperty(exports, "__esModule", {
|
4 | value: true
|
5 | });
|
6 |
|
7 | var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
|
8 |
|
9 | var _Compiler = require('./compiler/Compiler');
|
10 |
|
11 | var _Compiler2 = _interopRequireDefault(_Compiler);
|
12 |
|
13 | var _Router = require('./router/Router');
|
14 |
|
15 | var _Router2 = _interopRequireDefault(_Router);
|
16 |
|
17 | var _EntryPoint = require('./EntryPoint');
|
18 |
|
19 | var _EntryPoint2 = _interopRequireDefault(_EntryPoint);
|
20 |
|
21 | var _ServerHttpRequest = require('./http/ServerHttpRequest');
|
22 |
|
23 | var _ServerHttpRequest2 = _interopRequireDefault(_ServerHttpRequest);
|
24 |
|
25 | var _Provider = require('./Provider.js');
|
26 |
|
27 | var _Provider2 = _interopRequireDefault(_Provider);
|
28 |
|
29 | var _CookieJar = require('./http/CookieJar.js');
|
30 |
|
31 | var _CookieJar2 = _interopRequireDefault(_CookieJar);
|
32 |
|
33 | var _ServerCookieJar = require('./http/ServerCookieJar.js');
|
34 |
|
35 | var _ServerCookieJar2 = _interopRequireDefault(_ServerCookieJar);
|
36 |
|
37 | var _fs = require('fs');
|
38 |
|
39 | var _fs2 = _interopRequireDefault(_fs);
|
40 |
|
41 | var _path = require('path');
|
42 |
|
43 | var _path2 = _interopRequireDefault(_path);
|
44 |
|
45 | var _http = require('http');
|
46 |
|
47 | var _http2 = _interopRequireDefault(_http);
|
48 |
|
49 | var _domain = require('domain');
|
50 |
|
51 | var _domain2 = _interopRequireDefault(_domain);
|
52 |
|
53 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
54 |
|
55 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
|
56 |
|
57 |
|
58 |
|
59 |
|
60 |
|
61 |
|
62 |
|
63 |
|
64 |
|
65 |
|
66 |
|
67 |
|
68 |
|
69 |
|
70 |
|
71 |
|
72 |
|
73 |
|
74 |
|
75 |
|
76 |
|
77 |
|
78 |
|
79 |
|
80 |
|
81 | var Application = function () {
|
82 |
|
83 | |
84 |
|
85 |
|
86 |
|
87 |
|
88 |
|
89 |
|
90 |
|
91 |
|
92 |
|
93 |
|
94 |
|
95 |
|
96 |
|
97 | |
98 |
|
99 |
|
100 |
|
101 |
|
102 |
|
103 |
|
104 |
|
105 |
|
106 |
|
107 | |
108 |
|
109 |
|
110 |
|
111 |
|
112 | |
113 |
|
114 |
|
115 |
|
116 |
|
117 | |
118 |
|
119 |
|
120 |
|
121 |
|
122 | |
123 |
|
124 |
|
125 |
|
126 |
|
127 | |
128 |
|
129 |
|
130 |
|
131 |
|
132 | |
133 |
|
134 |
|
135 | function Application(logger, componentRegister, routes, router, reverseRouter, errorHandler, compiler, frameworkConfig, serverConfig, clientConfig) {
|
136 | _classCallCheck(this, Application);
|
137 |
|
138 |
|
139 | this._addReplace(frameworkConfig, 'soya/lib/client/Register', 'soya/lib/client/RegisterClient');
|
140 |
|
141 |
|
142 | this._addReplace(frameworkConfig, 'soya/lib/page/react/ReactRenderer', 'soya/lib/page/react/ReactRendererClient');
|
143 |
|
144 |
|
145 | this._addReplace(frameworkConfig, 'soya/lib/scope', 'soya/lib/scope-client');
|
146 |
|
147 |
|
148 | if (frameworkConfig.routerNodeRegistrationAbsolutePath) {
|
149 | this._addReplace(frameworkConfig, 'soya/lib/server/registerRouterNodes', frameworkConfig.routerNodeRegistrationAbsolutePath);
|
150 | }
|
151 |
|
152 | this._logger = logger;
|
153 | this._serverCreated = false;
|
154 | this._componentRegister = componentRegister;
|
155 | this._compiler = compiler;
|
156 | this._frameworkConfig = frameworkConfig;
|
157 | this._serverConfig = serverConfig;
|
158 | this._clientConfig = clientConfig;
|
159 | this._router = router;
|
160 | this._errorHandler = errorHandler;
|
161 | this._pages = {};
|
162 | this._routeForPages = {};
|
163 | this._entryPoints = [];
|
164 | this._pageClasses = {};
|
165 | this._provider = new _Provider2.default(serverConfig, reverseRouter, true);
|
166 | this._absoluteClientDepFile = _path2.default.join(this._frameworkConfig.absoluteProjectDir, 'build/dep.json');
|
167 |
|
168 | var cookieJar = new _CookieJar2.default();
|
169 | var i,
|
170 | pageCmpt,
|
171 | page,
|
172 | pageComponents = componentRegister.getPages();
|
173 | var routeRequirements, j, routeId;
|
174 |
|
175 | for (i in pageComponents) {
|
176 | if (!pageComponents.hasOwnProperty(i)) continue;
|
177 | pageCmpt = pageComponents[i];
|
178 |
|
179 |
|
180 | this._entryPoints.push(new _EntryPoint2.default(pageCmpt.name, pageCmpt.absDir));
|
181 | this._pageClasses[pageCmpt.name] = pageCmpt.clazz;
|
182 |
|
183 | try {
|
184 |
|
185 |
|
186 |
|
187 |
|
188 | page = new pageCmpt.clazz(this._provider, cookieJar, true);
|
189 | } catch (e) {
|
190 | throw e;
|
191 | }
|
192 |
|
193 | this._routeForPages[pageCmpt.name] = {};
|
194 | if (typeof pageCmpt.clazz.getRouteRequirements == 'function') {
|
195 | routeRequirements = pageCmpt.clazz.getRouteRequirements();
|
196 | for (j = 0; j < routeRequirements.length; j++) {
|
197 | routeId = routeRequirements[j];
|
198 | if (!routes.hasOwnProperty(routeId)) {
|
199 | throw new Error('Page ' + pageCmpt.name + ' has dependencies to unknown route: ' + routeId + '.');
|
200 | }
|
201 | this._routeForPages[pageCmpt.name][routeId] = routes[routeId];
|
202 | }
|
203 | }
|
204 | }
|
205 |
|
206 | this._middlewares = [];
|
207 | }
|
208 |
|
209 | |
210 |
|
211 |
|
212 |
|
213 |
|
214 |
|
215 |
|
216 | |
217 |
|
218 |
|
219 |
|
220 |
|
221 | |
222 |
|
223 |
|
224 |
|
225 |
|
226 | |
227 |
|
228 |
|
229 |
|
230 |
|
231 | |
232 |
|
233 |
|
234 |
|
235 |
|
236 | |
237 |
|
238 |
|
239 |
|
240 |
|
241 | |
242 |
|
243 |
|
244 |
|
245 |
|
246 | |
247 |
|
248 |
|
249 |
|
250 | |
251 |
|
252 |
|
253 |
|
254 |
|
255 | _createClass(Application, [{
|
256 | key: '_addReplace',
|
257 | value: function _addReplace(frameworkConfig, source, replacement) {
|
258 | frameworkConfig.clientReplace[source] = replacement;
|
259 | frameworkConfig.clientReplace[source + '.js'] = replacement;
|
260 | }
|
261 |
|
262 | |
263 |
|
264 |
|
265 |
|
266 | }, {
|
267 | key: 'start',
|
268 | value: function start() {
|
269 | var _this = this;
|
270 |
|
271 |
|
272 |
|
273 | if (this._frameworkConfig.precompileClient && _fs2.default.existsSync(this._absoluteClientDepFile)) {
|
274 | this._middlewares = this._compiler.run(this._entryPoints, null, false);
|
275 | this._compileResult = JSON.parse(_fs2.default.readFileSync(this._absoluteClientDepFile));
|
276 | } else {
|
277 |
|
278 |
|
279 |
|
280 | this._middlewares = this._compiler.run(this._entryPoints, function (compileResult) {
|
281 | _this._compileResult = compileResult;
|
282 | });
|
283 | }
|
284 |
|
285 |
|
286 | this._middlewares.push(this.handle.bind(this));
|
287 |
|
288 | return this._middlewares;
|
289 | }
|
290 |
|
291 | |
292 |
|
293 |
|
294 |
|
295 | }, {
|
296 | key: 'buildClient',
|
297 | value: function buildClient() {
|
298 | var _this2 = this;
|
299 |
|
300 | this._compiler.run(this._entryPoints, function (compileResult) {
|
301 | _fs2.default.writeFileSync(_this2._absoluteClientDepFile, JSON.stringify(compileResult), 'utf8');
|
302 | });
|
303 | }
|
304 | }, {
|
305 | key: 'createServer',
|
306 | value: function createServer() {
|
307 | var _this3 = this;
|
308 |
|
309 | if (this._serverCreated) {
|
310 |
|
311 | return;
|
312 | }
|
313 |
|
314 |
|
315 | this._serverCreated = true;
|
316 |
|
317 |
|
318 | _http2.default.createServer(function (request, response) {
|
319 |
|
320 | if (request.method === 'GET' && request.url === '/favicon.ico') {
|
321 | var faviconPath = _path2.default.join(_this3._frameworkConfig.absoluteProjectDir, 'favicon.ico');
|
322 | if (_fs2.default.existsSync(faviconPath)) {
|
323 | response.writeHead(200, { 'Content-Type': 'image/x-icon' });
|
324 | response.end(_fs2.default.readFileSync(faviconPath), 'binary');
|
325 | return;
|
326 | }
|
327 | }
|
328 | var d = _domain2.default.create().on('error', function (error) {
|
329 | _this3.handleError(error, request, response);
|
330 | });
|
331 | d.run(function () {
|
332 | var index = 0;
|
333 | var runMiddleware = function runMiddleware() {
|
334 | var middleware = _this3._middlewares[index++];
|
335 | if (!middleware) return;
|
336 | middleware(request, response, runMiddleware);
|
337 | };
|
338 |
|
339 |
|
340 | runMiddleware();
|
341 | });
|
342 | }).listen(this._frameworkConfig.port, function () {
|
343 | if (process && typeof process.send === 'function') process.send('ready');
|
344 | _this3._logger.info('Server listening at port: ' + _this3._frameworkConfig.port + '.');
|
345 | });
|
346 | }
|
347 |
|
348 | |
349 |
|
350 |
|
351 |
|
352 |
|
353 |
|
354 | }, {
|
355 | key: 'handle',
|
356 | value: function handle(request, response, next) {
|
357 |
|
358 | if (request.url.indexOf("_next") !== -1) {
|
359 | next();
|
360 | return;
|
361 | }
|
362 |
|
363 | var httpRequest = new _ServerHttpRequest2.default(request, this._frameworkConfig.maxRequestBodyLength);
|
364 | var routeResult = this._router.route(httpRequest);
|
365 |
|
366 | if (routeResult == null) {
|
367 | next();
|
368 | return;
|
369 | }
|
370 |
|
371 | var pageClass = this._pageClasses[routeResult.pageName];
|
372 | if (!pageClass) {
|
373 | throw new Error('Unable to route request, page ' + routeResult.pageName + ' doesn\'t exist');
|
374 | }
|
375 |
|
376 |
|
377 |
|
378 | var cookieJar = new _ServerCookieJar2.default(request);
|
379 | var page = new pageClass(this._provider, cookieJar, true);
|
380 | var store = page.createStore(null);
|
381 |
|
382 | this._logger.debug('Rendering page: ' + routeResult.pageName + '.', null);
|
383 | page.render(httpRequest, routeResult.routeArgs, store, this._handleRenderResult.bind(this, routeResult, request, httpRequest, response, store, cookieJar));
|
384 | }
|
385 |
|
386 | |
387 |
|
388 |
|
389 |
|
390 |
|
391 |
|
392 |
|
393 |
|
394 |
|
395 |
|
396 | }, {
|
397 | key: '_handleRenderResult',
|
398 | value: function _handleRenderResult(routeResult, request, httpRequest, response, store, cookieJar, renderResult) {
|
399 | var _this4 = this;
|
400 |
|
401 | var pageDep = this._compileResult.pages[routeResult.pageName];
|
402 | if (!pageDep) {
|
403 | throw new Error('Unable to render page server side, dependencies unknown for entry point: ' + routeResult.componentName);
|
404 | }
|
405 |
|
406 | var promise = Promise.resolve(null);
|
407 |
|
408 | if (store) {
|
409 | if (store._shouldRenderBeforeServerHydration()) {
|
410 | store._startRender();
|
411 |
|
412 |
|
413 |
|
414 | renderResult.contentRenderer.render(routeResult.routeArgs, this._routeForPages[routeResult.pageName], this._clientConfig, null, pageDep);
|
415 | store._endRender();
|
416 | }
|
417 |
|
418 |
|
419 | promise = store.hydrate();
|
420 | }
|
421 |
|
422 | var handlePromiseError = function handlePromiseError(error) {
|
423 |
|
424 | error = _this4._ensureError(error);
|
425 | _this4.handleError(error, request, response);
|
426 | };
|
427 |
|
428 | var storeResolve = function storeResolve() {
|
429 | var state = null;
|
430 | if (store) {
|
431 | state = store._getState();
|
432 |
|
433 | store._startRender();
|
434 | }
|
435 |
|
436 | var htmlResult = renderResult.contentRenderer.render(routeResult.routeArgs, _this4._routeForPages[routeResult.pageName], _this4._clientConfig, state, pageDep);
|
437 |
|
438 | if (store) store._endRender();
|
439 |
|
440 | response.statusCode = renderResult.httpStatusCode;
|
441 | response.statusMessage = renderResult.httpStatusMessage;
|
442 |
|
443 |
|
444 | response.setHeader('Content-Length', Buffer.byteLength(htmlResult, 'utf8'));
|
445 | response.setHeader('Content-Type', 'text/html;charset=UTF-8');
|
446 |
|
447 |
|
448 | var key,
|
449 | headerData = renderResult.httpHeaders.getAll();
|
450 | for (key in headerData) {
|
451 | if (!headerData.hasOwnProperty(key)) continue;
|
452 | response.setHeader(key, headerData[key]);
|
453 | }
|
454 |
|
455 |
|
456 | var cookieValues = cookieJar.generateHeaderValues();
|
457 | if (cookieValues.length > 0) {
|
458 | response.setHeader('Set-Cookie', cookieValues);
|
459 | }
|
460 |
|
461 |
|
462 | response.end(htmlResult);
|
463 | };
|
464 |
|
465 | promise.then(storeResolve).catch(handlePromiseError);
|
466 | }
|
467 |
|
468 | |
469 |
|
470 |
|
471 |
|
472 |
|
473 |
|
474 | }, {
|
475 | key: 'handleError',
|
476 | value: function handleError(error, request, response) {
|
477 | if (response.headersSent) {
|
478 | this._errorHandler.responseSentError(error, request, response);
|
479 | return;
|
480 | }
|
481 |
|
482 | this._errorHandler.responseNotSentError(error, request, response);
|
483 | }
|
484 |
|
485 | |
486 |
|
487 |
|
488 |
|
489 |
|
490 | }, {
|
491 | key: '_ensureError',
|
492 | value: function _ensureError(error) {
|
493 | if (error instanceof Error) return error;
|
494 | if (typeof error == 'string') return new Error(error);
|
495 | return new Error('Error when resolving store promise! Unable to convert reject arg: ' + error);
|
496 | }
|
497 | }]);
|
498 |
|
499 | return Application;
|
500 | }();
|
501 |
|
502 | exports.default = Application;
|
503 |
|
\ | No newline at end of file |