UNPKG

rollup-plugin-serve

Version:
174 lines (149 loc) 5.21 kB
import { readFile } from 'fs'; import { createServer } from 'https'; import { createServer as createServer$1 } from 'http'; import { resolve, posix } from 'path'; import { Mime } from 'mime/lite'; import standardTypes from 'mime/types/standard.js'; import otherTypes from 'mime/types/other.js'; import opener from 'opener'; var server; /** * Serve your rolled up bundle like webpack-dev-server * @param {import('..').RollupServeOptions} options */ function serve (options) { if ( options === void 0 ) options = { contentBase: '' }; var mime = new Mime(standardTypes, otherTypes); if (Array.isArray(options) || typeof options === 'string') { options = { contentBase: options }; } options.contentBase = Array.isArray(options.contentBase) ? options.contentBase : [options.contentBase || '']; options.port = options.port || 10001; options.headers = options.headers || {}; options.https = options.https || false; options.openPage = options.openPage || ''; options.onListening = options.onListening || function noop () { }; if (options.mimeTypes) { mime.define(options.mimeTypes, true); } var requestListener = function (request, response) { // Remove querystring var unsafePath = decodeURI(request.url.split('?')[0]); // Don't allow path traversal var urlPath = posix.normalize(unsafePath); Object.keys(options.headers).forEach(function (key) { response.setHeader(key, options.headers[key]); }); readFileFromContentBase(options.contentBase, urlPath, function (error, content, filePath) { if (!error) { return found(response, mime.getType(filePath), content) } if (error.code !== 'ENOENT') { response.writeHead(500); response.end('500 Internal Server Error' + '\n\n' + filePath + '\n\n' + Object.values(error).join('\n') + '\n\n(rollup-plugin-serve)', 'utf-8'); return } if (options.historyApiFallback) { var fallbackPath = typeof options.historyApiFallback === 'string' ? options.historyApiFallback : '/index.html'; readFileFromContentBase(options.contentBase, fallbackPath, function (error, content, filePath) { if (error) { notFound(response, filePath); } else { found(response, mime.getType(filePath), content); } }); } else { notFound(response, filePath); } }); }; // release previous server instance if rollup is reloading configuration in watch mode if (server) { server.close(); } else { closeServerOnTermination(); } // If HTTPS options are available, create an HTTPS server server = options.https ? createServer(options.https, requestListener) : createServer$1(requestListener); server.listen(options.port, options.host, function () { return options.onListening(server); }); // Assemble url for error and info messages var url = (options.https ? 'https' : 'http') + '://' + (options.host || 'localhost') + ':' + options.port; // Handle common server errors server.on('error', function (e) { if (e.code === 'EADDRINUSE') { console.error(url + ' is in use, either stop the other server or use a different port.'); process.exit(); } else { throw e } }); var first = true; return { name: 'serve', generateBundle: function generateBundle () { if (first) { first = false; // Log which url to visit if (options.verbose !== false) { options.contentBase.forEach(function (base) { console.log(green(url) + ' -> ' + resolve(base)); }); } // Open browser if (options.open) { if (/https?:\/\/.+/.test(options.openPage)) { opener(options.openPage); } else { opener(url + options.openPage); } } } } } } function readFileFromContentBase (contentBase, urlPath, callback) { var filePath = resolve(contentBase[0] || '.', '.' + urlPath); // Load index.html in directories if (urlPath.endsWith('/')) { filePath = resolve(filePath, 'index.html'); } readFile(filePath, function (error, content) { if (error && contentBase.length > 1) { // Try to read from next contentBase readFileFromContentBase(contentBase.slice(1), urlPath, callback); } else { // We know enough callback(error, content, filePath); } }); } function notFound (response, filePath) { response.writeHead(404); response.end('404 Not Found' + '\n\n' + filePath + '\n\n(rollup-plugin-serve)', 'utf-8'); } function found (response, mimeType, content) { response.writeHead(200, { 'Content-Type': mimeType || 'text/plain' }); response.end(content, 'utf-8'); } function green (text) { return '\u001b[1m\u001b[32m' + text + '\u001b[39m\u001b[22m' } function closeServerOnTermination () { var terminationSignals = ['SIGINT', 'SIGTERM', 'SIGQUIT', 'SIGHUP']; terminationSignals.forEach(function (signal) { process.on(signal, function () { if (server) { server.close(); process.exit(); } }); }); } export { serve as default };