Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit c08d0a5

Browse files
committedApr 16, 2019
refactor(@embark/api): in dev use cockpit redirect instead of proxy
Embark API server's development proxy from port 55555 to 3000 was attempting to inappropriately forward an `/embark-api/` endpoint for the blockchain process logs to Create React App's development server. Why it was only happening for the one endpoint is not known but probably has to do with timing around registration of the API server's express routes. The problem can be fixed with a one-line `filter:` function in the options for `express-http-proxy`. However, it was realized that to fix an unrelated problem, whereby the proxy doesn't forward websockets to CRA such that hot reload doesn't work when accessing `embark-ui` in development on port 55555, a switch to `http-proxy-middleware` would be required. That was quickly attempted (easy switch) but there are outstanding [difficulties][bug] with `webpack-dev-server` and `node-http-proxy` that cause CRA to crash. Switch strategies and refactor the API module to serve a page on port 55555 (in development only) that alerts the developer `embark-ui` should be accessed on port 3000. The page redirects (client-side) after 10 seconds, with URL query params and/or hash preserved. A future version could instead do client-side polling of port 3000 with `fetch` and then redirect only once it's available. The reason for not redirecting immediately is that the intermediate page makes it more obvious what needs to be done, e.g. CRA dev server may need to be started with `yarn start`. [bug]: webpack/webpack-dev-server#1642
1 parent 3988fb4 commit c08d0a5

File tree

3 files changed

+72
-70
lines changed

3 files changed

+72
-70
lines changed
 

‎packages/embark/package.json

-1
Original file line numberDiff line numberDiff line change
@@ -191,7 +191,6 @@
191191
"@types/body-parser": "1.17.0",
192192
"@types/cors": "2.8.4",
193193
"@types/express": "4.16.0",
194-
"@types/express-http-proxy": "1.5.1",
195194
"@types/express-ws": "3.0.0",
196195
"@types/find-up": "2.1.0",
197196
"@types/globule": "1.1.3",

‎packages/embark/src/lib/modules/api/server.ts

+72-61
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ import bodyParser from "body-parser";
22
import cors from "cors";
33
import {Embark, Plugins} from "embark";
44
import express, {NextFunction, Request, Response} from "express";
5-
import proxy from "express-http-proxy";
65
import expressWs from "express-ws";
76
import findUp from "find-up";
87
import helmet from "helmet";
@@ -87,15 +86,12 @@ export default class Server {
8786
});
8887
}
8988

90-
private makePage(reloadSeconds: number, body: string) {
89+
private makePage(body: string) {
9190
return (`
9291
<!doctype html>
9392
<html lang="en">
9493
<head>
9594
<meta charset="utf-8" />
96-
${this.isInsideMonorepo ? `
97-
<meta http-equiv="refresh" content="${reloadSeconds}">
98-
` : ""}
9995
<title>Embark API Server</title>
10096
<style type="text/css">
10197
code {
@@ -112,47 +108,76 @@ export default class Server {
112108
</head>
113109
<body>
114110
${body}
115-
${this.isInsideMonorepo ? `
116-
<p>this page will automatically reload
117-
in <span id="timer">${reloadSeconds}</span> seconds</p>
118-
<script>
119-
let timeLeft = ${reloadSeconds};
120-
const span = document.querySelector("#timer");
121-
setInterval(() => {
122-
if (timeLeft >= 1) { timeLeft -= 1; }
123-
span.innerText = \`\${timeLeft}\`;
124-
}, 1000);
125-
</script>
126-
` : ""}
127111
</body>
128112
</html>
129113
`.trim().split("\n").map((str) => str.trim()).filter((str) => str).join("\n"));
130114
}
131115

132116
private makePage404(reloadSeconds: number, envReport: string, inside: string, notice: string) {
133-
return this.makePage(reloadSeconds, `
117+
return this.makePage(`
134118
${envReport}
135119
<p>missing build for package <code>embark-ui</code> ${inside}</p>
136120
${notice}
121+
${this.isInsideMonorepo ? `
122+
<p>this page will automatically reload
123+
in <span id="timer">${reloadSeconds}</span> seconds</p>
124+
<script>
125+
let timeLeft = ${reloadSeconds};
126+
const span = document.querySelector("#timer");
127+
const timer = window.setInterval(() => {
128+
if (timeLeft >= 1) {
129+
timeLeft -= 1;
130+
span.innerText = \`\${timeLeft}\`;
131+
}
132+
if (!timeLeft) {
133+
window.clearInterval(timer);
134+
window.location.reload(true);
135+
}
136+
}, 1000);
137+
</script>
138+
` : ""}
137139
`);
138140
}
139141

140-
private makePageEConnError(reloadSeconds: number, waitingFor: string) {
141-
return this.makePage(reloadSeconds, `
142-
<p><code>lib/modules/api/server</code> inside the monorepo at
143-
<code>${path.join(this.monorepoRootDir, "packages/embark")}</code> is
144-
waiting for the Create React App development server of package
145-
<code>embark-ui</code> to ${waitingFor} at
146-
<code>localhost:55555</code></p>
147-
${waitingFor === "become available" ? `
148-
<p>please run either:</p>
149-
<p><code>cd ${this.monorepoRootDir} && yarn start</code><br />
150-
or<br />
151-
<code>cd ${path.join(this.monorepoRootDir, "packages/embark-ui")}
152-
&& yarn start</code></p>
142+
private makePage503(redirectSeconds: number) {
143+
return this.makePage(`
144+
<p><code>lib/modules/api/server</code> is inside the monorepo at
145+
<code>${path.join(this.monorepoRootDir, "packages/embark")}</code></p>
146+
<p>to access <code>embark-ui</code> in development use port
147+
<code>3000</code></p>
148+
<p>if you haven't already, please run either:</p>
149+
<p><code>cd ${this.monorepoRootDir} && yarn start</code><br />
150+
or<br />
151+
<code>cd ${path.join(this.monorepoRootDir, "packages/embark-ui")} &&
152+
yarn start</code></p>
153153
<p>to instead use a static build from the monorepo, restart embark with:
154154
<code>EMBARK_UI_STATIC=t embark run</code></p>
155-
` : ""}
155+
<p>this page will automatically redirect to <a id="redirect" href="">
156+
<span></span></a> in <span id="timer">${redirectSeconds}</span>
157+
seconds</p>
158+
<script>
159+
window.embarkApiRedirect = window.location.href.replace(
160+
"http://localhost:55555",
161+
"http://localhost:3000"
162+
);
163+
document.querySelector("#redirect").href = window.embarkApiRedirect;
164+
document.querySelector("#redirect span").innerText =
165+
window.embarkApiRedirect;
166+
</script>
167+
<script>
168+
let timeLeft = ${redirectSeconds};
169+
const span = document.querySelector("#timer");
170+
const timer = window.setInterval(() => {
171+
if (timeLeft >= 1) {
172+
timeLeft -= 1;
173+
span.innerText = \`\${timeLeft}\`;
174+
}
175+
if (!timeLeft) {
176+
window.clearInterval(timer);
177+
window.location.href = window.embarkApiRedirect;
178+
}
179+
}, 1000);
180+
</script>
156181
`);
157182
}
158183

@@ -195,7 +220,7 @@ export default class Server {
195220
if (!this.isInsideMonorepo || process.env.EMBARK_UI_STATIC) {
196221
if (existsSync(path.join(this.embarkUiBuildDir, "index.html"))) {
197222
instance.app.use("/", express.static(this.embarkUiBuildDir));
198-
instance.app.get("/*", (_req, res) => {
223+
instance.app.get(/^\/(?!embark-api).*$/, (_req, res) => {
199224
res.sendFile(path.join(this.embarkUiBuildDir, "index.html"));
200225
});
201226
} else {
@@ -204,7 +229,9 @@ export default class Server {
204229
in <code>${path.dirname(this.embarkUiBuildDir)}</code>
205230
`;
206231
let notice = `
207-
<p>this distribution of <code>embark-ui</code> appears to be broken</p>
232+
<p>this distribution of <code>embark-ui</code> appears to be broken,
233+
please <a href="https://github.com/embark-framework/embark/issues">
234+
file an issue</a></p>
208235
`;
209236
if (this.isInsideMonorepo) {
210237
envReport = `
@@ -223,40 +250,24 @@ export default class Server {
223250
&& yarn build</code></p>
224251
<p>restart <code>embark run</code> after building
225252
<code>embark-ui</code></p>
226-
<p>to instead use a live development build from the monorepo, unset
227-
the environment variable <code>EMBARK_UI_STATIC</code> and restart
228-
embark</p>
253+
<p>to instead use a live development build from the monorepo: unset
254+
the environment variable <code>EMBARK_UI_STATIC</code>, restart
255+
embark, and visit
256+
<a href="http://localhost:3000">http://localhost:3000</a></p>
229257
`;
230258
}
231-
const page404 = this.makePage404(3, envReport, inside, notice);
259+
const page404 = this.makePage404(10, envReport, inside, notice);
232260
const missingBuildHandler = (_req: Request, res: Response) => {
233261
res.status(404).send(page404);
234262
};
235-
instance.app.get("/", missingBuildHandler);
236-
instance.app.get("/*", missingBuildHandler);
263+
instance.app.get(/^\/(?!embark-api).*$/, missingBuildHandler);
237264
}
238265
} else {
239-
const page503 = this.makePageEConnError(3, "become available");
240-
const page504 = this.makePageEConnError(3, "become responsive");
241-
instance.app.use("/", proxy("http://localhost:3000", {
242-
// @ts-ignore
243-
proxyErrorHandler: (err, res, next) => {
244-
switch (err && err.code) {
245-
case "ECONNREFUSED": {
246-
return res.status(503).send(page503);
247-
}
248-
case "ECONNRESET": {
249-
if (err.message === "socket hang up") {
250-
return res.status(504).send(page504);
251-
}
252-
}
253-
default: {
254-
next(err);
255-
}
256-
}
257-
},
258-
timeout: 1000,
259-
}));
266+
const page503 = this.makePage503(10);
267+
const unavailableBuildHandler = (_req: Request, res: Response) => {
268+
res.status(503).send(page503);
269+
};
270+
instance.app.get(/^\/(?!embark-api).*$/, unavailableBuildHandler);
260271
}
261272

262273
return instance;

‎yarn.lock

-8
Original file line numberDiff line numberDiff line change
@@ -2723,14 +2723,6 @@
27232723
resolved "https://registry.yarnpkg.com/@types/events/-/events-1.2.0.tgz#81a6731ce4df43619e5c8c945383b3e62a89ea86"
27242724
integrity sha512-KEIlhXnIutzKwRbQkGWb/I4HFqBuUykAdHgDED6xqwXJfONCjF5VoE0cXEiurh3XauygxzeDzgtXUqvLkxFzzA==
27252725

2726-
"@types/express-http-proxy@1.5.1":
2727-
version "1.5.1"
2728-
resolved "https://registry.yarnpkg.com/@types/express-http-proxy/-/express-http-proxy-1.5.1.tgz#0184017b1cfc8ab2a4954d35f90c9b4cc3d7ffcc"
2729-
integrity sha512-9SOGqwVzbudT5nzF4TjKOu0cWE0HRaTVVivwxUxYMN/7mas6Wt/W5pz53dZIs7Y0fZBjAI3RTDDr+dXtXrv+hA==
2730-
dependencies:
2731-
"@types/express" "*"
2732-
"@types/express-serve-static-core" "*"
2733-
27342726
"@types/express-serve-static-core@*":
27352727
version "4.16.0"
27362728
resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-4.16.0.tgz#fdfe777594ddc1fe8eb8eccce52e261b496e43e7"

0 commit comments

Comments
 (0)
Please sign in to comment.