-
Notifications
You must be signed in to change notification settings - Fork 12
/
index.js
126 lines (102 loc) · 3.09 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
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
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
var _ = require('lodash');
var Marty = tryRequire('marty');
var React = tryRequire('react');
var Router = tryRequire('react-router');
var ServerCookies = require('./serverCookies');
var HEADERS_TO_IGNORE = [
'accept',
'accept-encoding',
'host',
'connection'
];
module.exports = function (options) {
options = options || {};
if (!options.routes) {
throw new Error('routes is required');
}
if (!_.isFunction(options.application)) {
throw new Error('Must specify application type');
}
Marty.CookieStateSource.setCookieFactory(function (app) {
return new ServerCookies(app.req, app.res);
});
Marty.LocationStateSource.setLocationFactory(function (app) {
return _.pick(app.req, 'url', 'protocol', 'query', 'path', 'hostname');
});
Marty.HttpStateSource.addHook({
id: 'marty-express-http-state-source',
priority: 0.00000000001,
before: function (req) {
var app = this.app;
if (!app || !app.req) {
return;
}
// Don't change fully qualified urls
if (!/^https?:\/\//.test(req.url)) {
req.url = getBaseUrl(app.req) + req.url;
}
// Add all headers from original request
_.extend(req.headers, headers());
function getBaseUrl(req) {
return req.protocol + '://' + req.get('host');
}
function headers() {
return _.omit(app.req.headers, HEADERS_TO_IGNORE);
}
}
});
return function (req, res, next) {
var router = Router.create({
location: req.url,
routes: options.routes,
onAbort: onAbort
});
if (!router.match(req.url)) {
return next();
}
router.run(function (Handler, state) {
var app = new options.application({
req: req,
res: res
});
var element = React.createElement(Marty.ApplicationContainer, { app: app },
React.createElement(Handler, state.params)
);
app.renderToString(element, options)
.then(onRendered)
.catch(onFailedToRender);
function onRendered(renderResult) {
var locals = {};
locals[options.body || 'body'] = renderResult.htmlBody.trim();
locals[options.state || 'state'] = renderResult.htmlState.trim();
var notfound = _.find(state.routes, { isNotFound : true });
res.status(notfound ? 404 : 200).render(options.view || 'index', locals);
if (_.isFunction(options.rendered)) {
options.rendered(_.extend({
req: req
}, renderResult));
}
}
function onFailedToRender(error) {
if (_.isFunction(options.error)) {
options.error(req, res, next, error);
} else {
console.error('Failed to render ' + req.url, error.stack);
res.sendStatus(500).end();
}
}
});
function onAbort(abortReason) {
if (abortReason.constructor.name === 'Redirect') {
return res.redirect(302, router.makePath(abortReason.to, abortReason.params, abortReason.query));
}
}
};
};
function tryRequire(dep) {
try {
return module.parent.require(dep);
} catch (e) {
return require(dep);
}
}