-
Notifications
You must be signed in to change notification settings - Fork 29
/
handler.js
149 lines (119 loc) · 6.31 KB
/
handler.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
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
// http://docs.aws.amazon.com/lambda/latest/dg/lambda-edge.html
// http://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/lambda-at-the-edge.html
// http://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/cloudfront-limits.html#limits-lambda-at-edge
"use strict";
const ViewerRequestInterface = require("./lib/ViewerRequestInterface");
const OriginRequestInterface = require("./lib/OriginRequestInterface");
const prerendercloud = require("prerendercloud");
const resetPrerenderCloud = () => {
prerendercloud.resetOptions();
// default prerender.cloud timeout is 10s
// - so if it takes longer than 11s, either prerender.cloud is down or backed up
// max Lambda@Edge timeout is 30s
prerendercloud.set("retries", 1);
prerendercloud.set("timeout", 11000);
// * CONFIGURATION *
// 1. prerenderToken (API token, you'll be rate limited without it)
// Get it after signing up at https://www.prerender.cloud/
// note: Lambda@Edge doesn't support env vars, so hardcoding is your only option.
// prerendercloud.set("prerenderToken", "mySecretToken")
// 2. protocol (optional, default is https)
// use this to force a certain protocol for requests from service.prerender.cloud to your origin
// example use case: if your origin is http only
// prerendercloud.set("protocol", "http");
// 3. host (mandatory)
// Set this to your custom domain (something like example.com)
// or if you don't have one, then the CloudFront distribution URL (something like d1pxreml448ujs.cloudfront.net)
// This is what service.prerender.cloud will prerender, and if we didn't
// set it, the only info we'd have access to during Lambda@Edge runtime is the host of the origin (S3)
// which would require additional configuration to make it publicly accessible (and it just makes things more confusing).
// example value: example.com or d1pxreml448ujs.cloudfront.net (don't include the protocol)
// prerendercloud.set("host", "");
// 4. removeTrailingSlash (recommended)
// Removes trailing slash from URLs to increase prerender.cloud server cache hit rate
// the only reason not to enable this is if you use "strict routing"
// that is, you treat /docs/ differently than /docs (trailing slash) which is rare
// prerendercloud.set("removeTrailingSlash", true);
// 5. whitelistQueryParams (recommended)
// improves cache hit rate by dropping query params not in the whitelist
// must be a function that returns null or array
// * default (null) preserves all query params
// * empty array drops all query params
// prerendercloud.set("whitelistQueryParams", req => ["page"]);
// 6. botsOnly
// generally not recommended due to potential google SEO cloaking penalties no one fully understands
// prerendercloud.set("botsOnly", true);
// 7. removeScriptsTag (not recommended)
// Removes all scripts/JS, useful if:
// - trying to get under 1MB Lambda@Edge limit
// - having problems with your JS app taking over from the pre-rendered content
// Huge caveat: this also means your app will no longer be a "single-page app" since
// all of the JavaScript will be gone
// prerendercloud.set("removeScriptTags", true);
// 8. disableServerCache
// Disable the cache on prerender.cloud (default is enabled with 5 minute duration).
// It probably makes sense to disable the prerender.cloud server cache
// since CloudFront is caching things for you.
// Pros/Cons of disabling prerender.cloud server cache:
// Pros
// - when you invalidate CloudFront, the next page load will be guaranteed fresh
// Cons
// - when you invalid CloudFront each page load will require a new prerender call
// (so if you regularly invalidate even if the content hasn't changed, you're slowing
// things down unnecessarily)
// prerendercloud.set('disableServerCache', true);
// 9. blacklistPaths
// the viewer-request function can't see what files exist on origin so you may need this
// if you have HTML files that should not be pre-rendered (e.g. google/apple/fb verification files)
// prerendercloud.set('blacklistPaths', req => ['/facebook-domain-verification.html']);
// 10. see all configuration options here: https://github.com/sanfrancesco/prerendercloud-nodejs
// for tests
if (prerenderCloudOption) prerenderCloudOption(prerendercloud);
};
module.exports.viewerRequest = (event, context, callback) => {
resetPrerenderCloud();
const cloudFrontRequest = event.Records[0].cf.request;
console.log("viewerRequest", JSON.stringify(cloudFrontRequest));
prerendercloud.set("beforeRender", (req, done) => {
// FYI: if this block is called, it means we shouldPrerender
// force the middleware to call res.writeHead and res.end immediately
// instead of the remote prerender. (this allows us to use most of the
// code from the prerendercloud lib and bail out at last moment)
done(null, "noop");
});
const { req, res, next } = ViewerRequestInterface.create(
cloudFrontRequest,
callback
);
prerendercloud(req, res, next);
};
module.exports.originRequest = (event, context, callback) => {
resetPrerenderCloud();
// temporary until timeout function of prerendercloud or got is fixed
// so it cancels request when timeout is reached
// https://github.com/sindresorhus/got/issues/344
// https://github.com/sindresorhus/got/pull/360
context.callbackWaitsForEmptyEventLoop = false;
const cloudFrontRequest = event.Records[0].cf.request;
console.log("originRequest", JSON.stringify(cloudFrontRequest));
const { req, res, next, shouldPrerender } = OriginRequestInterface.create(
cloudFrontRequest,
callback
);
// we override the prerendercloud lib's default userAgent logic
// for deciding when to prerender because we've already computed it
// in the viewer-request, and encoded it into the URI, which is now in the `shouldPrerender` var
prerendercloud.set("shouldPrerender", () => shouldPrerender);
console.log("originRequest calling service.prerender.cloud:", {
host: req.headers.host,
url: req.url
});
prerendercloud(req, res, next);
};
// for tests
var prerenderCloudOption;
module.exports.setPrerenderCloudOption = cb => {
prerenderCloudOption = cb;
};
// for validation
module.exports.resetPrerenderCloud = resetPrerenderCloud;