1 | import { readFile } from 'fs';
|
2 | import { createServer } from 'https';
|
3 | import { createServer as createServer$1 } from 'http';
|
4 | import { resolve } from 'path';
|
5 | import mime from 'mime';
|
6 | import opener from 'opener';
|
7 |
|
8 | function serve (options) {
|
9 | if ( options === void 0 ) options = { contentBase: '' };
|
10 |
|
11 | if (Array.isArray(options) || typeof options === 'string') {
|
12 | options = { contentBase: options };
|
13 | }
|
14 | options.contentBase = Array.isArray(options.contentBase) ? options.contentBase : [options.contentBase];
|
15 | options.host = options.host || 'localhost';
|
16 | options.port = options.port || 10001;
|
17 | options.headers = options.headers || {};
|
18 | options.https = options.https || false;
|
19 | mime.default_type = 'text/plain';
|
20 |
|
21 | var server;
|
22 |
|
23 | var PROTOCOL = (options.https && 'https://') || 'http://';
|
24 | var requestListener = function (request, response) {
|
25 |
|
26 | var urlPath = decodeURI(request.url.split('?')[0]);
|
27 |
|
28 | Object.keys(options.headers).forEach(function (key) {
|
29 | response.setHeader(key, options.headers[key]);
|
30 | });
|
31 |
|
32 | readFileFromContentBase(options.contentBase, urlPath, function (error, content, filePath) {
|
33 | if (!error) {
|
34 | return found(response, filePath, content)
|
35 | }
|
36 | if (error.code !== 'ENOENT') {
|
37 | response.writeHead(500);
|
38 | response.end('500 Internal Server Error' +
|
39 | '\n\n' + filePath +
|
40 | '\n\n' + Object.keys(error).map(function (k) {
|
41 | return error[k]
|
42 | }).join('\n') +
|
43 | '\n\n(rollup-plugin-serve)', 'utf-8');
|
44 | return
|
45 | }
|
46 | if (request.url === '/favicon.ico') {
|
47 | filePath = resolve(__dirname, '../dist/favicon.ico');
|
48 | readFile(filePath, function (error, content) {
|
49 | if (error) {
|
50 | notFound(response, filePath);
|
51 | } else {
|
52 | found(response, filePath, content);
|
53 | }
|
54 | });
|
55 | } else if (options.historyApiFallback) {
|
56 | readFileFromContentBase(options.contentBase, '/index.html', function (error, content, filePath) {
|
57 | if (error) {
|
58 | notFound(response, filePath);
|
59 | } else {
|
60 | found(response, filePath, content);
|
61 | }
|
62 | });
|
63 | } else {
|
64 | notFound(response, filePath);
|
65 | }
|
66 | });
|
67 | };
|
68 |
|
69 | if (options.https) {
|
70 | server = createServer(options.https, requestListener).listen(options.port);
|
71 | } else {
|
72 | server = createServer$1(requestListener).listen(options.port);
|
73 | }
|
74 |
|
75 | closeServerOnTermination(server);
|
76 |
|
77 | var running = options.verbose === false;
|
78 |
|
79 | return {
|
80 | name: 'serve',
|
81 | ongenerate: function ongenerate () {
|
82 | if (!running) {
|
83 | running = true;
|
84 |
|
85 |
|
86 | var url = (PROTOCOL + options.host) + ":" + (options.port);
|
87 | options.contentBase.forEach(function (base) {
|
88 | console.log(green(url) + ' -> ' + resolve(base));
|
89 | });
|
90 |
|
91 |
|
92 | if (options.open) {
|
93 | opener(url);
|
94 | }
|
95 | }
|
96 | }
|
97 | }
|
98 | }
|
99 |
|
100 | function readFileFromContentBase (contentBase, urlPath, callback) {
|
101 | var filePath = resolve(contentBase[0] || '.', '.' + urlPath);
|
102 |
|
103 |
|
104 | if (urlPath.endsWith('/')) {
|
105 | filePath = resolve(filePath, 'index.html');
|
106 | }
|
107 |
|
108 | readFile(filePath, function (error, content) {
|
109 | if (error && contentBase.length > 1) {
|
110 |
|
111 | readFileFromContentBase(contentBase.slice(1), urlPath, callback);
|
112 | } else {
|
113 |
|
114 | callback(error, content, filePath);
|
115 | }
|
116 | });
|
117 | }
|
118 |
|
119 | function notFound (response, filePath) {
|
120 | response.writeHead(404);
|
121 | response.end('404 Not Found' +
|
122 | '\n\n' + filePath +
|
123 | '\n\n(rollup-plugin-serve)', 'utf-8');
|
124 | }
|
125 |
|
126 | function found (response, filePath, content) {
|
127 | response.writeHead(200, { 'Content-Type': mime.lookup(filePath) });
|
128 | response.end(content, 'utf-8');
|
129 | }
|
130 |
|
131 | function green (text) {
|
132 | return '\u001b[1m\u001b[32m' + text + '\u001b[39m\u001b[22m'
|
133 | }
|
134 |
|
135 | function closeServerOnTermination (server) {
|
136 | var terminationSignals = ['SIGINT', 'SIGTERM'];
|
137 | terminationSignals.forEach(function (signal) {
|
138 | process.on(signal, function () {
|
139 | server.close();
|
140 | process.exit();
|
141 | });
|
142 | });
|
143 | }
|
144 |
|
145 | export default serve;
|