rollup-plugin-serve
Advanced tools
Comparing version 2.0.0-beta.0 to 2.0.0
@@ -5,8 +5,3 @@ 'use strict'; | ||
var Express = _interopDefault(require('express')); | ||
var killable = _interopDefault(require('killable')); | ||
var compress = _interopDefault(require('compression')); | ||
var serveIndex = _interopDefault(require('serve-index')); | ||
var historyApiFallback = _interopDefault(require('connect-history-api-fallback')); | ||
var httpProxyMiddleware = require('http-proxy-middleware'); | ||
var fs = require('fs'); | ||
var https = require('https'); | ||
@@ -19,3 +14,2 @@ var http = require('http'); | ||
var server; | ||
var app; | ||
@@ -33,3 +27,2 @@ /** | ||
options.contentBase = Array.isArray(options.contentBase) ? options.contentBase : [options.contentBase || '']; | ||
options.contentBasePublicPath = options.contentBasePublicPath || '/'; | ||
options.port = options.port || 10001; | ||
@@ -39,123 +32,50 @@ options.headers = options.headers || {}; | ||
options.openPage = options.openPage || ''; | ||
options.compress = !!options.compress; | ||
options.serveIndex = options.serveIndex || (options.serveIndex === undefined); | ||
options.onListening = options.onListening || function noop () { }; | ||
mime.default_type = 'text/plain'; | ||
function setupProxy () { | ||
/** | ||
* Assume a proxy configuration specified as: | ||
* proxy: { | ||
* 'context': { options } | ||
* } | ||
* OR | ||
* proxy: { | ||
* 'context': 'target' | ||
* } | ||
*/ | ||
if (!Array.isArray(options.proxy)) { | ||
if (Object.prototype.hasOwnProperty.call(options.proxy, 'target')) { | ||
options.proxy = [options.proxy]; | ||
} else { | ||
options.proxy = Object.keys(options.proxy).map(function (context) { | ||
var proxyOptions; | ||
// For backwards compatibility reasons. | ||
var correctedContext = context | ||
.replace(/^\*$/, '**') | ||
.replace(/\/\*$/, ''); | ||
if (options.mimeTypes) { | ||
mime.define(options.mimeTypes, true); | ||
} | ||
if (typeof options.proxy[context] === 'string') { | ||
proxyOptions = { | ||
context: correctedContext, | ||
target: options.proxy[context] | ||
}; | ||
} else { | ||
proxyOptions = Object.assign({}, options.proxy[context]); | ||
proxyOptions.context = correctedContext; | ||
} | ||
var requestListener = function (request, response) { | ||
// Remove querystring | ||
var unsafePath = decodeURI(request.url.split('?')[0]); | ||
proxyOptions.logLevel = proxyOptions.logLevel || 'warn'; | ||
// Don't allow path traversal | ||
var urlPath = path.posix.normalize(unsafePath); | ||
return proxyOptions | ||
}); | ||
} | ||
} | ||
Object.keys(options.headers).forEach(function (key) { | ||
response.setHeader(key, options.headers[key]); | ||
}); | ||
var getProxyMiddleware = function (proxyConfig) { | ||
var context = proxyConfig.context || proxyConfig.path; | ||
// It is possible to use the `bypass` method without a `target`. | ||
// However, the proxy middleware has no use in this case, and will fail to instantiate. | ||
if (proxyConfig.target) { | ||
return httpProxyMiddleware.createProxyMiddleware(context, proxyConfig) | ||
readFileFromContentBase(options.contentBase, urlPath, function (error, content, filePath) { | ||
if (!error) { | ||
return found(response, filePath, content) | ||
} | ||
}; | ||
/** | ||
* Assume a proxy configuration specified as: | ||
* proxy: [ | ||
* { | ||
* context: ..., | ||
* ...options... | ||
* }, | ||
* // or: | ||
* function() { | ||
* return { | ||
* context: ..., | ||
* ...options... | ||
* }; | ||
* } | ||
* ] | ||
*/ | ||
options.proxy.forEach(function (proxyConfigOrCallback) { | ||
var proxyMiddleware; | ||
var proxyConfig = | ||
typeof proxyConfigOrCallback === 'function' | ||
? proxyConfigOrCallback() | ||
: proxyConfigOrCallback; | ||
proxyMiddleware = getProxyMiddleware(proxyConfig); | ||
function proxyHandle (req, res, next) { | ||
if (typeof proxyConfigOrCallback === 'function') { | ||
var newProxyConfig = proxyConfigOrCallback(); | ||
if (newProxyConfig !== proxyConfig) { | ||
proxyConfig = newProxyConfig; | ||
proxyMiddleware = getProxyMiddleware(proxyConfig); | ||
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, filePath, content); | ||
} | ||
} | ||
// - Check if we have a bypass function defined | ||
// - In case the bypass function is defined we'll retrieve the | ||
// bypassUrl from it otherwise bypassUrl would be null | ||
var isByPassFuncDefined = typeof proxyConfig.bypass === 'function'; | ||
var bypassUrl = isByPassFuncDefined | ||
? proxyConfig.bypass(req, res, proxyConfig) | ||
: null; | ||
if (typeof bypassUrl === 'boolean') { | ||
// skip the proxy | ||
req.url = null; | ||
next(); | ||
} else if (typeof bypassUrl === 'string') { | ||
// byPass to that url | ||
req.url = bypassUrl; | ||
next(); | ||
} else if (proxyMiddleware) { | ||
return proxyMiddleware(req, res, next) | ||
} else { | ||
next(); | ||
} | ||
}); | ||
} else { | ||
notFound(response, filePath); | ||
} | ||
app.use(proxyHandle); | ||
// Also forward error requests to the proxy so it can handle them. | ||
// eslint-disable-next-line handle-callback-err | ||
app.use(function (error, req, res, next) { return proxyHandle(req, res, next); }); | ||
}); | ||
} | ||
}; | ||
// release previous server instance if rollup is reloading configuration in watch mode | ||
if (server) { | ||
server.kill(); | ||
server.close(); | ||
} else { | ||
@@ -165,138 +85,35 @@ closeServerOnTermination(); | ||
app = new Express(); | ||
// 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); }); | ||
// Implement webpack-dev-server features | ||
var features = { | ||
compress: function () { | ||
if (options.compress) { | ||
app.use(compress()); | ||
} | ||
}, | ||
proxy: function () { | ||
if (options.proxy) { | ||
setupProxy(); | ||
} | ||
}, | ||
historyApiFallback: function () { | ||
if (options.historyApiFallback) { | ||
var fallback = | ||
typeof options.historyApiFallback === 'object' | ||
? options.historyApiFallback | ||
: typeof options.historyApiFallback === 'string' | ||
? { index: options.historyApiFallback, disableDotRule: true } : null; | ||
// Assemble url for error and info messages | ||
var url = (options.https ? 'https' : 'http') + '://' + (options.host || 'localhost') + ':' + options.port; | ||
app.use(historyApiFallback(fallback)); | ||
} | ||
}, | ||
contentBaseFiles: function () { | ||
if (Array.isArray(options.contentBase)) { | ||
options.contentBase.forEach(function (item) { | ||
app.use(options.contentBasePublicPath, Express.static(item)); | ||
}); | ||
} else { | ||
app.use( | ||
options.contentBasePublicPath, | ||
Express.static(options.contentBase, options.staticOptions) | ||
); | ||
} | ||
}, | ||
contentBaseIndex: function () { | ||
if (options.contentBase && options.serveIndex) { | ||
var getHandler = function (item) { return function indexHandler (req, res, next) { | ||
// serve-index doesn't fallthrough non-get/head request to next middleware | ||
if (req.method !== 'GET' && req.method !== 'HEAD') { | ||
return next() | ||
} | ||
serveIndex(item)(req, res, next); | ||
}; }; | ||
if (Array.isArray(options.contentBase)) { | ||
options.contentBase.forEach(function (item) { | ||
app.use(options.contentBasePublicPath, getHandler(item)); | ||
}); | ||
} else { | ||
app.use(options.contentBasePublicPath, getHandler(options.contentBase)); | ||
} | ||
} | ||
}, | ||
before: function () { | ||
if (typeof options.before === 'function') { | ||
options.before(app); | ||
} | ||
}, | ||
after: function () { | ||
if (typeof options.after === 'function') { | ||
options.after(app); | ||
} | ||
}, | ||
headers: function () { | ||
app.all('*', function headersHandler (req, res, next) { | ||
if (options.headers) { | ||
for (var name in options.headers) { | ||
res.setHeader(name, options.headers[name]); | ||
} | ||
} | ||
next(); | ||
}); | ||
// 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 runnableFeatures = []; | ||
if (options.compress) { | ||
runnableFeatures.push('compress'); | ||
} | ||
runnableFeatures.push('before', 'headers'); | ||
if (options.proxy) { | ||
runnableFeatures.push('proxy'); | ||
} | ||
if (options.contentBase !== false) { | ||
runnableFeatures.push('contentBaseFiles'); | ||
} | ||
if (options.historyApiFallback) { | ||
runnableFeatures.push('historyApiFallback'); | ||
if (options.contentBase !== false) { | ||
runnableFeatures.push('contentBaseFiles'); | ||
} | ||
} | ||
if (options.contentBase && options.serveIndex) { | ||
runnableFeatures.push('contentBaseIndex'); | ||
} | ||
if (options.after) { | ||
runnableFeatures.push('after'); | ||
} | ||
(options.features || runnableFeatures).forEach(function (feature) { | ||
features[feature](); | ||
}); | ||
// If HTTPS options are available, create an HTTPS server | ||
if (options.https) { | ||
server = https.createServer(options.https, app).listen(options.port, options.host); | ||
} else { | ||
server = http.createServer(app).listen(options.port, options.host); | ||
} | ||
var first = true; | ||
killable(server); | ||
var running = options.verbose === false; | ||
return { | ||
name: 'serve', | ||
generateBundle: function generateBundle () { | ||
if (!running) { | ||
running = true; | ||
if (first) { | ||
first = false; | ||
// Log which url to visit | ||
var url = (options.https ? 'https' : 'http') + '://' + (options.host || 'localhost') + ':' + options.port; | ||
options.contentBase.forEach(function (base) { | ||
console.log(green(url) + ' -> ' + path.resolve(base)); | ||
}); | ||
if (options.verbose !== false) { | ||
options.contentBase.forEach(function (base) { | ||
console.log(green(url) + ' -> ' + path.resolve(base)); | ||
}); | ||
} | ||
@@ -316,2 +133,33 @@ // Open browser | ||
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, filePath, content) { | ||
response.writeHead(200, { 'Content-Type': mime.getType(filePath) }); | ||
response.end(content, 'utf-8'); | ||
} | ||
function green (text) { | ||
@@ -326,3 +174,3 @@ return '\u001b[1m\u001b[32m' + text + '\u001b[39m\u001b[22m' | ||
if (server) { | ||
server.kill(); | ||
server.close(); | ||
process.exit(); | ||
@@ -343,2 +191,3 @@ } | ||
* @property {number} [port=10001] Server port (default: `10001`) | ||
* @property {function} [onListening] Execute a function when server starts listening for connections on a port | ||
* @property {ServeOptionsHttps} [https=false] By default server will be served over HTTP (https: `false`). It can optionally be served over HTTPS | ||
@@ -345,0 +194,0 @@ * @property {{[header:string]: string}} [headers] Set headers |
@@ -1,10 +0,5 @@ | ||
import Express from 'express'; | ||
import killable from 'killable'; | ||
import compress from 'compression'; | ||
import serveIndex from 'serve-index'; | ||
import historyApiFallback from 'connect-history-api-fallback'; | ||
import { createProxyMiddleware } from 'http-proxy-middleware'; | ||
import { readFile } from 'fs'; | ||
import { createServer } from 'https'; | ||
import { createServer as createServer$1 } from 'http'; | ||
import { resolve } from 'path'; | ||
import { resolve, posix } from 'path'; | ||
import mime from 'mime'; | ||
@@ -14,3 +9,2 @@ import opener from 'opener'; | ||
var server; | ||
var app; | ||
@@ -28,3 +22,2 @@ /** | ||
options.contentBase = Array.isArray(options.contentBase) ? options.contentBase : [options.contentBase || '']; | ||
options.contentBasePublicPath = options.contentBasePublicPath || '/'; | ||
options.port = options.port || 10001; | ||
@@ -34,123 +27,50 @@ options.headers = options.headers || {}; | ||
options.openPage = options.openPage || ''; | ||
options.compress = !!options.compress; | ||
options.serveIndex = options.serveIndex || (options.serveIndex === undefined); | ||
options.onListening = options.onListening || function noop () { }; | ||
mime.default_type = 'text/plain'; | ||
function setupProxy () { | ||
/** | ||
* Assume a proxy configuration specified as: | ||
* proxy: { | ||
* 'context': { options } | ||
* } | ||
* OR | ||
* proxy: { | ||
* 'context': 'target' | ||
* } | ||
*/ | ||
if (!Array.isArray(options.proxy)) { | ||
if (Object.prototype.hasOwnProperty.call(options.proxy, 'target')) { | ||
options.proxy = [options.proxy]; | ||
} else { | ||
options.proxy = Object.keys(options.proxy).map(function (context) { | ||
var proxyOptions; | ||
// For backwards compatibility reasons. | ||
var correctedContext = context | ||
.replace(/^\*$/, '**') | ||
.replace(/\/\*$/, ''); | ||
if (options.mimeTypes) { | ||
mime.define(options.mimeTypes, true); | ||
} | ||
if (typeof options.proxy[context] === 'string') { | ||
proxyOptions = { | ||
context: correctedContext, | ||
target: options.proxy[context] | ||
}; | ||
} else { | ||
proxyOptions = Object.assign({}, options.proxy[context]); | ||
proxyOptions.context = correctedContext; | ||
} | ||
var requestListener = function (request, response) { | ||
// Remove querystring | ||
var unsafePath = decodeURI(request.url.split('?')[0]); | ||
proxyOptions.logLevel = proxyOptions.logLevel || 'warn'; | ||
// Don't allow path traversal | ||
var urlPath = posix.normalize(unsafePath); | ||
return proxyOptions | ||
}); | ||
} | ||
} | ||
Object.keys(options.headers).forEach(function (key) { | ||
response.setHeader(key, options.headers[key]); | ||
}); | ||
var getProxyMiddleware = function (proxyConfig) { | ||
var context = proxyConfig.context || proxyConfig.path; | ||
// It is possible to use the `bypass` method without a `target`. | ||
// However, the proxy middleware has no use in this case, and will fail to instantiate. | ||
if (proxyConfig.target) { | ||
return createProxyMiddleware(context, proxyConfig) | ||
readFileFromContentBase(options.contentBase, urlPath, function (error, content, filePath) { | ||
if (!error) { | ||
return found(response, filePath, content) | ||
} | ||
}; | ||
/** | ||
* Assume a proxy configuration specified as: | ||
* proxy: [ | ||
* { | ||
* context: ..., | ||
* ...options... | ||
* }, | ||
* // or: | ||
* function() { | ||
* return { | ||
* context: ..., | ||
* ...options... | ||
* }; | ||
* } | ||
* ] | ||
*/ | ||
options.proxy.forEach(function (proxyConfigOrCallback) { | ||
var proxyMiddleware; | ||
var proxyConfig = | ||
typeof proxyConfigOrCallback === 'function' | ||
? proxyConfigOrCallback() | ||
: proxyConfigOrCallback; | ||
proxyMiddleware = getProxyMiddleware(proxyConfig); | ||
function proxyHandle (req, res, next) { | ||
if (typeof proxyConfigOrCallback === 'function') { | ||
var newProxyConfig = proxyConfigOrCallback(); | ||
if (newProxyConfig !== proxyConfig) { | ||
proxyConfig = newProxyConfig; | ||
proxyMiddleware = getProxyMiddleware(proxyConfig); | ||
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, filePath, content); | ||
} | ||
} | ||
// - Check if we have a bypass function defined | ||
// - In case the bypass function is defined we'll retrieve the | ||
// bypassUrl from it otherwise bypassUrl would be null | ||
var isByPassFuncDefined = typeof proxyConfig.bypass === 'function'; | ||
var bypassUrl = isByPassFuncDefined | ||
? proxyConfig.bypass(req, res, proxyConfig) | ||
: null; | ||
if (typeof bypassUrl === 'boolean') { | ||
// skip the proxy | ||
req.url = null; | ||
next(); | ||
} else if (typeof bypassUrl === 'string') { | ||
// byPass to that url | ||
req.url = bypassUrl; | ||
next(); | ||
} else if (proxyMiddleware) { | ||
return proxyMiddleware(req, res, next) | ||
} else { | ||
next(); | ||
} | ||
}); | ||
} else { | ||
notFound(response, filePath); | ||
} | ||
app.use(proxyHandle); | ||
// Also forward error requests to the proxy so it can handle them. | ||
// eslint-disable-next-line handle-callback-err | ||
app.use(function (error, req, res, next) { return proxyHandle(req, res, next); }); | ||
}); | ||
} | ||
}; | ||
// release previous server instance if rollup is reloading configuration in watch mode | ||
if (server) { | ||
server.kill(); | ||
server.close(); | ||
} else { | ||
@@ -160,138 +80,35 @@ closeServerOnTermination(); | ||
app = new Express(); | ||
// 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); }); | ||
// Implement webpack-dev-server features | ||
var features = { | ||
compress: function () { | ||
if (options.compress) { | ||
app.use(compress()); | ||
} | ||
}, | ||
proxy: function () { | ||
if (options.proxy) { | ||
setupProxy(); | ||
} | ||
}, | ||
historyApiFallback: function () { | ||
if (options.historyApiFallback) { | ||
var fallback = | ||
typeof options.historyApiFallback === 'object' | ||
? options.historyApiFallback | ||
: typeof options.historyApiFallback === 'string' | ||
? { index: options.historyApiFallback, disableDotRule: true } : null; | ||
// Assemble url for error and info messages | ||
var url = (options.https ? 'https' : 'http') + '://' + (options.host || 'localhost') + ':' + options.port; | ||
app.use(historyApiFallback(fallback)); | ||
} | ||
}, | ||
contentBaseFiles: function () { | ||
if (Array.isArray(options.contentBase)) { | ||
options.contentBase.forEach(function (item) { | ||
app.use(options.contentBasePublicPath, Express.static(item)); | ||
}); | ||
} else { | ||
app.use( | ||
options.contentBasePublicPath, | ||
Express.static(options.contentBase, options.staticOptions) | ||
); | ||
} | ||
}, | ||
contentBaseIndex: function () { | ||
if (options.contentBase && options.serveIndex) { | ||
var getHandler = function (item) { return function indexHandler (req, res, next) { | ||
// serve-index doesn't fallthrough non-get/head request to next middleware | ||
if (req.method !== 'GET' && req.method !== 'HEAD') { | ||
return next() | ||
} | ||
serveIndex(item)(req, res, next); | ||
}; }; | ||
if (Array.isArray(options.contentBase)) { | ||
options.contentBase.forEach(function (item) { | ||
app.use(options.contentBasePublicPath, getHandler(item)); | ||
}); | ||
} else { | ||
app.use(options.contentBasePublicPath, getHandler(options.contentBase)); | ||
} | ||
} | ||
}, | ||
before: function () { | ||
if (typeof options.before === 'function') { | ||
options.before(app); | ||
} | ||
}, | ||
after: function () { | ||
if (typeof options.after === 'function') { | ||
options.after(app); | ||
} | ||
}, | ||
headers: function () { | ||
app.all('*', function headersHandler (req, res, next) { | ||
if (options.headers) { | ||
for (var name in options.headers) { | ||
res.setHeader(name, options.headers[name]); | ||
} | ||
} | ||
next(); | ||
}); | ||
// 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 runnableFeatures = []; | ||
if (options.compress) { | ||
runnableFeatures.push('compress'); | ||
} | ||
runnableFeatures.push('before', 'headers'); | ||
if (options.proxy) { | ||
runnableFeatures.push('proxy'); | ||
} | ||
if (options.contentBase !== false) { | ||
runnableFeatures.push('contentBaseFiles'); | ||
} | ||
if (options.historyApiFallback) { | ||
runnableFeatures.push('historyApiFallback'); | ||
if (options.contentBase !== false) { | ||
runnableFeatures.push('contentBaseFiles'); | ||
} | ||
} | ||
if (options.contentBase && options.serveIndex) { | ||
runnableFeatures.push('contentBaseIndex'); | ||
} | ||
if (options.after) { | ||
runnableFeatures.push('after'); | ||
} | ||
(options.features || runnableFeatures).forEach(function (feature) { | ||
features[feature](); | ||
}); | ||
// If HTTPS options are available, create an HTTPS server | ||
if (options.https) { | ||
server = createServer(options.https, app).listen(options.port, options.host); | ||
} else { | ||
server = createServer$1(app).listen(options.port, options.host); | ||
} | ||
var first = true; | ||
killable(server); | ||
var running = options.verbose === false; | ||
return { | ||
name: 'serve', | ||
generateBundle: function generateBundle () { | ||
if (!running) { | ||
running = true; | ||
if (first) { | ||
first = false; | ||
// Log which url to visit | ||
var url = (options.https ? 'https' : 'http') + '://' + (options.host || 'localhost') + ':' + options.port; | ||
options.contentBase.forEach(function (base) { | ||
console.log(green(url) + ' -> ' + resolve(base)); | ||
}); | ||
if (options.verbose !== false) { | ||
options.contentBase.forEach(function (base) { | ||
console.log(green(url) + ' -> ' + resolve(base)); | ||
}); | ||
} | ||
@@ -311,2 +128,33 @@ // Open browser | ||
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, filePath, content) { | ||
response.writeHead(200, { 'Content-Type': mime.getType(filePath) }); | ||
response.end(content, 'utf-8'); | ||
} | ||
function green (text) { | ||
@@ -321,3 +169,3 @@ return '\u001b[1m\u001b[32m' + text + '\u001b[39m\u001b[22m' | ||
if (server) { | ||
server.kill(); | ||
server.close(); | ||
process.exit(); | ||
@@ -338,2 +186,3 @@ } | ||
* @property {number} [port=10001] Server port (default: `10001`) | ||
* @property {function} [onListening] Execute a function when server starts listening for connections on a port | ||
* @property {ServeOptionsHttps} [https=false] By default server will be served over HTTP (https: `false`). It can optionally be served over HTTPS | ||
@@ -340,0 +189,0 @@ * @property {{[header:string]: string}} [headers] Set headers |
{ | ||
"name": "rollup-plugin-serve", | ||
"version": "2.0.0-beta.0", | ||
"version": "2.0.0", | ||
"description": "Serve your rolled up bundle", | ||
@@ -8,2 +8,7 @@ "main": "dist/index.cjs.js", | ||
"jsnext:main": "dist/index.es.js", | ||
"types": "index.d.ts", | ||
"exports": { | ||
"import": "./dist/index.mjs", | ||
"default": "./dist/index.cjs" | ||
}, | ||
"scripts": { | ||
@@ -14,3 +19,3 @@ "build": "rollup -c", | ||
"prepare": "yarn lint && yarn build", | ||
"test": "cd test && rollup -c || cd .." | ||
"test": "cd test && rollup -cw || cd .." | ||
}, | ||
@@ -38,16 +43,10 @@ "keywords": [ | ||
"dependencies": { | ||
"compression": "^1.7.4", | ||
"connect-history-api-fallback": "^1.6.0", | ||
"express": "^4.17.1", | ||
"http-proxy-middleware": "^1.0.0", | ||
"killable": "^1.0.1", | ||
"mime": ">=2.0.3", | ||
"opener": "1", | ||
"serve-index": "^1.9.1" | ||
"mime": ">=2.4.6", | ||
"opener": "1" | ||
}, | ||
"devDependencies": { | ||
"rollup": "1", | ||
"rollup-plugin-buble": "^0.15.0", | ||
"standard": "14" | ||
"@rollup/plugin-buble": "0.21.3", | ||
"rollup": "2", | ||
"standard": "17" | ||
} | ||
} |
@@ -20,11 +20,11 @@ # Rollup plugin to serve the bundle | ||
## Installation | ||
``` | ||
# Rollup v0.60+ and v1+ | ||
npm install --save-dev rollup-plugin-serve | ||
# Rollup v0.59 and below | ||
npm install --save-dev rollup-plugin-serve@0 | ||
yarn add rollup-plugin-serve | ||
``` | ||
## Usage | ||
```js | ||
@@ -49,2 +49,3 @@ // rollup.config.js | ||
By default it serves the current project folder. Change it by passing a string: | ||
```js | ||
@@ -93,3 +94,17 @@ serve('public') // will be used as contentBase | ||
foo: 'bar' | ||
}, | ||
// set custom mime types, usage https://github.com/broofa/mime#mimedefinetypemap-force--false | ||
mimeTypes: { | ||
'application/javascript': ['js_commonjs-proxy'] | ||
} | ||
// execute function after server has begun listening | ||
onListening: function (server) { | ||
const address = server.address() | ||
const host = address.address === '::' ? 'localhost' : address.address | ||
// by using a bound function, we can access options as `this` | ||
const protocol = this.https ? 'https' : 'http' | ||
console.log(`Server listening at ${protocol}://${host}:${address.port}/`) | ||
} | ||
}) | ||
@@ -109,6 +124,7 @@ ``` | ||
To get it running: | ||
1. Clone the project. | ||
2. `npm install` | ||
3. `npm run build` | ||
1. Clone the project. | ||
2. `npm install` | ||
3. `npm run build` | ||
## Credits | ||
@@ -115,0 +131,0 @@ |
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Network access
Supply chain riskThis module accesses the network.
Found 1 instance in 1 package
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
31642
2
7
672
0
138
4
9
- Removedcompression@^1.7.4
- Removedconnect-history-api-fallback@^1.6.0
- Removedexpress@^4.17.1
- Removedhttp-proxy-middleware@^1.0.0
- Removedkillable@^1.0.1
- Removedserve-index@^1.9.1
- Removed@types/http-proxy@1.17.15(transitive)
- Removed@types/node@22.10.10(transitive)
- Removedaccepts@1.3.8(transitive)
- Removedarray-flatten@1.1.1(transitive)
- Removedbatch@0.6.1(transitive)
- Removedbody-parser@1.20.3(transitive)
- Removedbraces@3.0.3(transitive)
- Removedbytes@3.1.2(transitive)
- Removedcall-bind-apply-helpers@1.0.1(transitive)
- Removedcall-bound@1.0.3(transitive)
- Removedcompressible@2.0.18(transitive)
- Removedcompression@1.7.5(transitive)
- Removedconnect-history-api-fallback@1.6.0(transitive)
- Removedcontent-disposition@0.5.4(transitive)
- Removedcontent-type@1.0.5(transitive)
- Removedcookie@0.7.1(transitive)
- Removedcookie-signature@1.0.6(transitive)
- Removeddebug@2.6.9(transitive)
- Removeddepd@1.1.22.0.0(transitive)
- Removeddestroy@1.2.0(transitive)
- Removeddunder-proto@1.0.1(transitive)
- Removedee-first@1.1.1(transitive)
- Removedencodeurl@1.0.22.0.0(transitive)
- Removedes-define-property@1.0.1(transitive)
- Removedes-errors@1.3.0(transitive)
- Removedes-object-atoms@1.1.1(transitive)
- Removedescape-html@1.0.3(transitive)
- Removedetag@1.8.1(transitive)
- Removedeventemitter3@4.0.7(transitive)
- Removedexpress@4.21.2(transitive)
- Removedfill-range@7.1.1(transitive)
- Removedfinalhandler@1.3.1(transitive)
- Removedfollow-redirects@1.15.9(transitive)
- Removedforwarded@0.2.0(transitive)
- Removedfresh@0.5.2(transitive)
- Removedfunction-bind@1.1.2(transitive)
- Removedget-intrinsic@1.2.7(transitive)
- Removedget-proto@1.0.1(transitive)
- Removedgopd@1.2.0(transitive)
- Removedhas-symbols@1.1.0(transitive)
- Removedhasown@2.0.2(transitive)
- Removedhttp-errors@1.6.32.0.0(transitive)
- Removedhttp-proxy@1.18.1(transitive)
- Removedhttp-proxy-middleware@1.3.1(transitive)
- Removediconv-lite@0.4.24(transitive)
- Removedinherits@2.0.32.0.4(transitive)
- Removedipaddr.js@1.9.1(transitive)
- Removedis-extglob@2.1.1(transitive)
- Removedis-glob@4.0.3(transitive)
- Removedis-number@7.0.0(transitive)
- Removedis-plain-obj@3.0.0(transitive)
- Removedkillable@1.0.1(transitive)
- Removedmath-intrinsics@1.1.0(transitive)
- Removedmedia-typer@0.3.0(transitive)
- Removedmerge-descriptors@1.0.3(transitive)
- Removedmethods@1.1.2(transitive)
- Removedmicromatch@4.0.8(transitive)
- Removedmime@1.6.0(transitive)
- Removedmime-db@1.52.01.53.0(transitive)
- Removedmime-types@2.1.35(transitive)
- Removedms@2.0.02.1.3(transitive)
- Removednegotiator@0.6.30.6.4(transitive)
- Removedobject-inspect@1.13.3(transitive)
- Removedon-finished@2.4.1(transitive)
- Removedon-headers@1.0.2(transitive)
- Removedparseurl@1.3.3(transitive)
- Removedpath-to-regexp@0.1.12(transitive)
- Removedpicomatch@2.3.1(transitive)
- Removedproxy-addr@2.0.7(transitive)
- Removedqs@6.13.0(transitive)
- Removedrange-parser@1.2.1(transitive)
- Removedraw-body@2.5.2(transitive)
- Removedrequires-port@1.0.0(transitive)
- Removedsafe-buffer@5.2.1(transitive)
- Removedsafer-buffer@2.1.2(transitive)
- Removedsend@0.19.0(transitive)
- Removedserve-index@1.9.1(transitive)
- Removedserve-static@1.16.2(transitive)
- Removedsetprototypeof@1.1.01.2.0(transitive)
- Removedside-channel@1.1.0(transitive)
- Removedside-channel-list@1.0.0(transitive)
- Removedside-channel-map@1.0.1(transitive)
- Removedside-channel-weakmap@1.0.2(transitive)
- Removedstatuses@1.5.02.0.1(transitive)
- Removedto-regex-range@5.0.1(transitive)
- Removedtoidentifier@1.0.1(transitive)
- Removedtype-is@1.6.18(transitive)
- Removedundici-types@6.20.0(transitive)
- Removedunpipe@1.0.0(transitive)
- Removedutils-merge@1.0.1(transitive)
- Removedvary@1.1.2(transitive)
Updatedmime@>=2.4.6