UNPKG

4.18 kBJavaScriptView Raw
1/*
2 Copyright © 2018 Andrew Powell
3
4 This Source Code Form is subject to the terms of the Mozilla Public
5 License, v. 2.0. If a copy of the MPL was not distributed with this
6 file, You can obtain one at http://mozilla.org/MPL/2.0/.
7
8 The above copyright notice and this permission notice shall be
9 included in all copies or substantial portions of this Source Code Form.
10*/
11const convert = require('koa-connect');
12const historyApiFallback = require('connect-history-api-fallback');
13const koaCompress = require('koa-compress');
14const koaStatic = require('koa-static');
15const onetime = require('onetime');
16const { createProxyMiddleware } = require('http-proxy-middleware');
17
18const { middleware: wsMiddleware } = require('./ws');
19
20let staticPaths = [];
21
22const render404 = (ctx) => {
23 const faqUrl =
24 'https://github.com/shellscape/webpack-plugin-serve/blob/master/.github/FAQ.md#what-does-the-not-found--404-error-mean';
25 const body = `<h1>Not Found / 404</h1>
26<p>
27 You may be seeing this error due to misconfigured options.<br/>
28 Please see <a href="${faqUrl}">this FAQ question</a> for information on possible causes and remedies.
29</p>
30<h2>Static Paths</h2>
31<code>${staticPaths.join('</code><code>')}</code>`;
32 const css = `<style>
33 @import url('https://fonts.googleapis.com/css?family=Open+Sans:400,700');
34
35 *, html {
36 font-size: 10px;
37 margin: 0;
38 }
39
40
41 body {
42 background: #282d35;
43 color: #fff;
44 font-family: 'Open Sans', Helvetica, Arial, sans-serif;
45 padding: 2rem;
46 }
47
48 h1 {
49 font-size: 5rem;
50 padding-bottom: 2rem;
51 }
52
53 p {
54 color: #eee;
55 font-size: 1.6rem;
56 padding: 1rem 0 3rem 0;
57 }
58
59 a, a:visited, a:hover {
60 color: #ffbd2e;
61 font-size: 1.6rem;
62 text-decoration: none;
63 }
64
65 h2 {
66 color: #eee;
67 font-size: 1.5rem;
68 padding: 1rem 0;
69 }
70
71 code {
72 color: #eee;
73 font-size: 1.4rem;
74 padding: 0.4rem 1rem;
75 }
76</style>`;
77 const html = `<!doctype><html><head>${css}</head><body>${body}</body></html>`;
78
79 ctx.body = html; // eslint-disable-line no-param-reassign
80 ctx.status = 404; // eslint-disable-line no-param-reassign
81};
82
83const getBuiltins = (app, options) => {
84 const compress = (opts) => {
85 // only enable compress middleware if the user has explictly enabled it
86 if (opts || options.compress) {
87 app.use(koaCompress(opts || options.compress));
88 }
89 };
90
91 const four0four = (fn = () => {}) => {
92 app.use(async (ctx, next) => {
93 await next();
94 if (ctx.status === 404) {
95 render404(ctx);
96 fn(ctx);
97 }
98 });
99 };
100
101 const headers = (reqHeaders) => {
102 const headrs = reqHeaders || (options.headers || {});
103 app.use(async (ctx, next) => {
104 await next();
105 for (const headr of Object.keys(headrs)) {
106 ctx.set(headr, headrs[headr]);
107 }
108 });
109 };
110
111 const historyFallback = () => {
112 if (options.historyFallback) {
113 // https://github.com/shellscape/webpack-plugin-serve/issues/94
114 // When using Firefox, the browser sends an accept header for /wps when using connect-history-api-fallback
115 app.use(async (ctx, next) => {
116 if (ctx.path.match(/^\/wps/)) {
117 const { accept, ...reqHeaders } = ctx.request.header;
118 ctx.request.header = reqHeaders; // eslint-disable-line no-param-reassign
119 }
120 await next();
121 });
122
123 app.use(convert(historyApiFallback(options.historyFallback)));
124 }
125 };
126
127 const statik = (root, opts = {}) => {
128 const paths = [].concat(root || options.static);
129 staticPaths = paths;
130 for (const path of paths) {
131 app.use(koaStatic(path, opts));
132 }
133 };
134
135 const proxy = (...args) => convert(createProxyMiddleware(...args));
136 const websocket = () => app.use(wsMiddleware);
137
138 proxy.skip = true;
139
140 // by default, middleware are executed in the order they appear here.
141 // the order of the properties returned in this object are important.
142 return {
143 compress: onetime(compress),
144 headers: onetime(headers),
145 historyFallback: onetime(historyFallback),
146 static: onetime(statik),
147 websocket: onetime(websocket),
148 proxy,
149 four0four: onetime(four0four)
150 };
151};
152
153module.exports = { getBuiltins };