-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathindex.js
153 lines (132 loc) · 4.79 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
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
const fs = require('fs');
const path = require('path');
const crypto = require('crypto');
const express = require('express');
const webpack = require('webpack');
const devMiddleware = require('webpack-dev-middleware');
const hotMiddleware = require('webpack-hot-middleware');
const webpackConfig = require('./webpack.dev.js');
const hostname = process.argv[3] || '127.0.0.1';
const port = 3000;
const webflowDomain = process.argv[2] || 'webflow.bitrise.io';
const importedWorkers = {};
/**
* @param {string} workerPath
* @returns {Promise<Function>}
*/
async function importWorker(workerPath) {
const workerContent = (await fs.promises.readFile(workerPath, 'utf8'))
.toString()
.replaceAll('webflow.bitrise.io', webflowDomain)
.replaceAll(/\/\*(.|[\n\r])*?\*\//gm, '')
.replaceAll(/\/\/.*$/g, '');
const workerName = `${workerPath}-${crypto.createHash('md5').update(workerContent).digest('hex')}`;
if (!importedWorkers[workerName]) {
if (workerContent.match(/addEventListener\('fetch',/)) {
// Service Worker Syntax
eval(`(() => {
function addEventListener(_, cb) {
importedWorkers['${workerName}'] = { type: "Service" };
importedWorkers['${workerName}'].handler = cb;
};
${workerContent}
})();`);
}
if (workerContent.match(/export default {/)) {
// ES6 Module Syntax
eval(`(() => {
${workerContent.replace(
/export default {/,
`
importedWorkers['${workerName}'] = { type: "ES6 Module" };
importedWorkers['${workerName}'].handler = {`,
)}
})();`);
}
process.stdout.write(`[info] Registered new ${importedWorkers[workerName].type} Worker: ${workerName}\n`);
}
return importedWorkers[workerName];
}
/**
* @param {URL} urlObject
* @returns {Promise<{ type: string; handler: Function; }>}
*/
async function getWorker(urlObject) {
if (urlObject.pathname.match(/^\/integrations/)) {
return importWorker('./src/js/integrations/worker.js');
}
if (urlObject.pathname.match(/^\/changelog/)) {
return importWorker('./src/js/changelog/worker.js');
}
if (urlObject.pathname.match(/^\/stacks/)) {
return importWorker('./src/js/stacks/worker.js');
}
return {
type: 'ES6 Module',
handler: {
async fetch(request) {
const url = new URL(request.url);
url.hostname = webflowDomain;
return fetch(url);
},
},
};
}
const compiler = webpack(webpackConfig);
const devMiddlewareOptions = {
// writeToDisk: true,
};
const app = express();
app.use(devMiddleware(compiler, devMiddlewareOptions));
if (webpackConfig.mode === 'development') app.use(hotMiddleware(compiler));
app.get(/\/.*/, async (req, res) => {
const urlObject = new URL(`http://${req.hostname}${req.url}`);
process.stdout.write(`[info] Handling request to ${urlObject}\n`);
try {
const filePath = `./dist${urlObject.pathname}`;
const content = await fs.promises.readFile(filePath);
res.statusCode = 200;
const extname = path.extname(urlObject.pathname);
if (extname === '.js') res.setHeader('Content-Type', 'text/javascript');
if (extname === '.html') res.setHeader('Content-Type', 'text/html');
if (extname === '.json') res.setHeader('Content-Type', 'application/json');
process.stdout.write(`[info] Serving local file ${filePath}\n`);
res.end(content);
} catch (error) {
const requestHandler = await getWorker(urlObject);
process.stdout.write(`[info] Using request handler ${requestHandler.type}\n`);
const fetchEvent = {
request: {
url: urlObject,
},
respondWith: async (buffer) => {
const response = await buffer;
res.statusCode = response.status;
const responseContentType = response.headers.get('Content-Type');
if (responseContentType) res.setHeader('Content-Type', response.headers.get('Content-Type'));
const responseLocation = response.headers.get('Location');
if (responseLocation)
res.setHeader(
'Location',
responseLocation.replace(webflowDomain, `${hostname}:${port}`).replace('https', 'http'),
);
const text = await response.text();
process.stdout.write(`[info] Serving response with status ${res.statusCode}\n`);
res.end(
text
.replace("document.location.host === 'test-e93bfd.webflow.io'", 'true')
.replace('https://webflow-scripts.bitrise.io/', '/'),
);
},
};
if (requestHandler.type === 'Service') {
requestHandler.handler(fetchEvent);
}
if (requestHandler.type === 'ES6 Module') {
fetchEvent.respondWith(requestHandler.handler.fetch(fetchEvent.request));
}
}
});
app.listen(port, hostname, () => {
process.stdout.write(`Server running at http://${hostname}:${port}/\n`);
});