1 | "use strict";
|
2 | var __importDefault = (this && this.__importDefault) || function (mod) {
|
3 | return (mod && mod.__esModule) ? mod : { "default": mod };
|
4 | };
|
5 | const fs_1 = __importDefault(require("fs"));
|
6 | const url_1 = __importDefault(require("url"));
|
7 | const path_1 = __importDefault(require("path"));
|
8 | const mime_types_1 = __importDefault(require("mime-types"));
|
9 | const handlebars_1 = __importDefault(require("handlebars"));
|
10 | const resolvePath = require('resolve-path');
|
11 | const ansiHTML = require('ansi-html');
|
12 |
|
13 |
|
14 | ansiHTML.setColors({
|
15 | reset: ['#000', '#fff'],
|
16 | });
|
17 | const errorTemplate = handlebars_1.default.compile(fs_1.default.readFileSync(path_1.default.resolve(__dirname, 'templates/error.html')).toString());
|
18 | const dirTemplate = handlebars_1.default.compile(fs_1.default.readFileSync(path_1.default.resolve(__dirname, 'templates/dir.html')).toString());
|
19 |
|
20 |
|
21 |
|
22 |
|
23 |
|
24 |
|
25 |
|
26 |
|
27 | function handleRequest(outputPath, request, response, next, options) {
|
28 | const urlObj = url_1.default.parse(request.url);
|
29 | let pathname = urlObj.pathname || '';
|
30 | let filename, stat, lastModified, buffer;
|
31 | try {
|
32 | filename = decodeURIComponent(pathname);
|
33 | if (!filename) {
|
34 | response.writeHead(400);
|
35 | response.end();
|
36 | return;
|
37 | }
|
38 | filename = resolvePath(outputPath, filename.substr(1));
|
39 | }
|
40 | catch (err) {
|
41 | response.writeHead(err.status || 500);
|
42 | response.end();
|
43 | return;
|
44 | }
|
45 | try {
|
46 | stat = fs_1.default.statSync(filename);
|
47 | }
|
48 | catch (e) {
|
49 |
|
50 | next();
|
51 | return;
|
52 | }
|
53 | if (stat.isDirectory()) {
|
54 | const indexFilename = path_1.default.join(filename, 'index.html');
|
55 | const hasIndex = fs_1.default.existsSync(indexFilename);
|
56 | if (!hasIndex && !options.autoIndex) {
|
57 | next();
|
58 | return;
|
59 | }
|
60 | if (pathname[pathname.length - 1] !== '/') {
|
61 | urlObj.pathname += '/';
|
62 | urlObj.host = request.headers['host'];
|
63 | urlObj.protocol = request.socket.encrypted ? 'https' : 'http';
|
64 | response.setHeader('Location', url_1.default.format(urlObj));
|
65 | response.setHeader('Cache-Control', 'private, max-age=0, must-revalidate');
|
66 | response.writeHead(301);
|
67 | response.end();
|
68 | return;
|
69 | }
|
70 | if (!hasIndex) {
|
71 |
|
72 | const context = {
|
73 | url: request.url,
|
74 | files: fs_1.default
|
75 | .readdirSync(filename)
|
76 | .sort()
|
77 | .map(child => {
|
78 | const stat = fs_1.default.statSync(path_1.default.join(filename, child)), isDir = stat.isDirectory();
|
79 | return {
|
80 | href: child + (isDir ? '/' : ''),
|
81 | type: isDir
|
82 | ? 'dir'
|
83 | : path_1.default
|
84 | .extname(child)
|
85 | .replace('.', '')
|
86 | .toLowerCase(),
|
87 | };
|
88 | }),
|
89 | liveReloadPath: options.liveReloadPath,
|
90 | };
|
91 | response.setHeader('Content-Type', 'text/html; charset=utf-8');
|
92 | response.setHeader('Cache-Control', 'private, max-age=0, must-revalidate');
|
93 | response.writeHead(200);
|
94 | response.end(dirTemplate(context));
|
95 | return;
|
96 | }
|
97 |
|
98 | filename = indexFilename;
|
99 | stat = fs_1.default.statSync(filename);
|
100 | }
|
101 | lastModified = stat.mtime.toUTCString();
|
102 | response.setHeader('Last-Modified', lastModified);
|
103 |
|
104 | if (request.headers['if-modified-since'] === lastModified) {
|
105 | response.writeHead(304);
|
106 | response.end();
|
107 | return;
|
108 | }
|
109 | response.setHeader('Cache-Control', 'private, max-age=0, must-revalidate');
|
110 | response.setHeader('Content-Length', stat.size);
|
111 | response.setHeader('Content-Type', mime_types_1.default.contentType(path_1.default.extname(filename)));
|
112 |
|
113 |
|
114 | buffer = fs_1.default.readFileSync(filename);
|
115 | response.writeHead(200);
|
116 | response.end(buffer);
|
117 | }
|
118 | module.exports = function getMiddleware(watcher, options = {}) {
|
119 | if (options.autoIndex == null)
|
120 | options.autoIndex = true;
|
121 | const outputPath = path_1.default.resolve(watcher.builder.outputPath);
|
122 | return async function broccoliMiddleware(request, response, next) {
|
123 | if (watcher.currentBuild == null) {
|
124 | throw new Error('Waiting for initial build to start');
|
125 | }
|
126 | try {
|
127 | await watcher.currentBuild;
|
128 | handleRequest(outputPath, request, response, next, options);
|
129 | }
|
130 | catch (error) {
|
131 |
|
132 |
|
133 | const context = {
|
134 | stack: ansiHTML(error.stack || ''),
|
135 | liveReloadPath: options.liveReloadPath,
|
136 | payload: error.broccoliPayload,
|
137 | };
|
138 | response.setHeader('Content-Type', 'text/html; charset=utf-8');
|
139 | response.writeHead(500);
|
140 | response.end(errorTemplate(context));
|
141 | return error.stack;
|
142 | }
|
143 | };
|
144 | };
|
145 |
|
\ | No newline at end of file |