rollup-plugin-serve
Version:
Serve your rolled up bundle
182 lines (154 loc) • 5.63 kB
JavaScript
;
var fs = require('fs');
var https = require('https');
var http = require('http');
var path = require('path');
var lite = require('mime/lite');
var standardTypes = require('mime/types/standard.js');
var otherTypes = require('mime/types/other.js');
var opener = require('opener');
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
var standardTypes__default = /*#__PURE__*/_interopDefaultLegacy(standardTypes);
var otherTypes__default = /*#__PURE__*/_interopDefaultLegacy(otherTypes);
var opener__default = /*#__PURE__*/_interopDefaultLegacy(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 lite.Mime(standardTypes__default["default"], otherTypes__default["default"]);
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 = path.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
? https.createServer(options.https, requestListener)
: http.createServer(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) + ' -> ' + path.resolve(base));
});
}
// Open browser
if (options.open) {
if (/https?:\/\/.+/.test(options.openPage)) {
opener__default["default"](options.openPage);
} else {
opener__default["default"](url + options.openPage);
}
}
}
}
}
}
function readFileFromContentBase (contentBase, urlPath, callback) {
var filePath = path.resolve(contentBase[0] || '.', '.' + urlPath);
// Load index.html in directories
if (urlPath.endsWith('/')) {
filePath = path.resolve(filePath, 'index.html');
}
fs.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();
}
});
});
}
module.exports = serve;