Development server plugin for Rollup that serves bundled files during development
npx @tessl/cli install tessl/npm-rollup-plugin-serve@3.0.0Rollup Plugin Serve is a development server plugin for Rollup that serves bundled files during development, similar to webpack-dev-server. It provides static file serving with features like HTTPS support, history API fallback, custom headers, MIME types, and browser auto-opening.
npm install --save-dev rollup-plugin-serveimport serve from "rollup-plugin-serve";For CommonJS:
const serve = require("rollup-plugin-serve");// rollup.config.js
import serve from "rollup-plugin-serve";
export default {
input: "src/main.js",
output: {
file: "dist/bundle.js",
format: "cjs"
},
plugins: [
serve("dist") // Serve files from dist directory
]
};The plugin creates an HTTP/HTTPS server during Rollup's build process and integrates with Rollup's plugin system through the generateBundle hook. Key components include:
Creates a Rollup plugin instance that provides development server functionality.
/**
* Serve your rolled up bundle like webpack-dev-server
* @param options - Configuration options, string shorthand for contentBase, or array of contentBase paths
* @returns Rollup plugin object
*/
function serve(options?: RollupServeOptions | string | string[]): Plugin;
**Shorthand Usage:**
```javascript
// String shorthand for contentBase
serve("public");
// Array shorthand for multiple contentBase paths
serve(["dist", "static"]);Advanced Configuration:
serve({
contentBase: ["dist", "static"],
port: 3000,
host: "0.0.0.0",
open: true,
openPage: "/dashboard",
historyApiFallback: true,
https: {
key: fs.readFileSync("server.key"),
cert: fs.readFileSync("server.crt")
},
headers: {
"Access-Control-Allow-Origin": "*",
"Cache-Control": "no-cache"
},
mimeTypes: {
"application/javascript": ["js_proxy"]
},
onListening: (server) => {
const address = server.address();
console.log(`Server running at http://localhost:${address.port}`);
}
});Complete configuration interface for the serve plugin.
interface RollupServeOptions {
/** Launch browser after first bundle is generated (default: false) */
open?: boolean;
/**
* Page to open when browser launches. Must start with '/'.
* Only used when open=true (default: '')
*/
openPage?: string;
/** Show server address in console (default: true) */
verbose?: boolean;
/**
* Folder(s) to serve static files from.
* Supports string or array of strings (default: current directory)
*/
contentBase?: string | string[];
/**
* Return index.html (200) instead of 404 for SPA routing.
* Use true for default '/index.html' or string for custom fallback path
*/
historyApiFallback?: boolean | string;
/** Server host address (default: 'localhost') */
host?: string;
/** Server port number (default: 10001) */
port?: number | string;
/** HTTPS server configuration from Node.js https module */
https?: ServerOptions;
/** Custom HTTP response headers */
headers?: IncomingHttpHeaders | OutgoingHttpHeaders | {
[name: string]: number | string | ReadonlyArray<string>;
};
/** Custom MIME type definitions using mime package format */
mimeTypes?: TypeMap;
/** Callback executed after server begins listening */
onListening?: (server: Server) => void;
}The contentBase option supports multiple patterns for serving static files:
// Single directory
serve({ contentBase: "dist" });
// Multiple directories (fallback order)
serve({ contentBase: ["dist", "public", "assets"] });
// Current directory (default)
serve({ contentBase: "" });When multiple content bases are specified, the server attempts to serve files from each directory in order until a file is found.
For single-page applications with client-side routing:
// Default fallback to /index.html
serve({ historyApiFallback: true });
// Custom fallback page
serve({ historyApiFallback: "/app.html" });
// Conditional fallback with contentBase priority
serve({
contentBase: ["dist", "public"],
historyApiFallback: "/fallback.html"
});Enable HTTPS with SSL/TLS certificates:
import fs from "fs";
serve({
https: {
key: fs.readFileSync("path/to/private-key.pem"),
cert: fs.readFileSync("path/to/certificate.pem"),
ca: fs.readFileSync("path/to/ca-certificate.pem") // Optional
},
port: 443
});Set response headers for all served files:
serve({
headers: {
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Methods": "GET, POST, PUT, DELETE",
"Cache-Control": "no-cache, no-store, must-revalidate",
"X-Custom-Header": "development-server"
}
});Define custom MIME types for file extensions:
serve({
mimeTypes: {
"application/javascript": ["js_commonjs-proxy", "js_module"],
"text/x-custom": ["custom", "cst"],
"application/wasm": ["wasm"]
}
});Handle server events and customize behavior:
serve({
onListening: function(server) {
const address = server.address();
const protocol = this.https ? "https" : "http";
const host = address.address === "::" ? "localhost" : address.address;
console.log(`🚀 Server ready at ${protocol}://${host}:${address.port}`);
// Access plugin options via 'this'
if (this.verbose) {
console.log("Serving from:", this.contentBase);
}
}
});// From Node.js net module (used by http.Server)
interface AddressInfo {
address: string;
family: string;
port: number;
}
// From Node.js http module
interface Server {
listen(port: number, host?: string, callback?: () => void): void;
close(callback?: () => void): void;
address(): AddressInfo | string | null;
on(event: string, listener: Function): void;
}
// From Node.js https module
interface ServerOptions {
key?: string | Buffer | Array<string | Buffer>;
cert?: string | Buffer | Array<string | Buffer>;
ca?: string | Buffer | Array<string | Buffer>;
// Additional HTTPS options...
}
// From Node.js http module
interface IncomingHttpHeaders {
[header: string]: string | string[] | undefined;
}
interface OutgoingHttpHeaders {
[header: string]: number | string | string[] | undefined;
}
// From mime package
interface TypeMap {
[mimeType: string]: string[];
}
// Rollup Plugin interface
interface Plugin {
name: string;
generateBundle?: () => void;
}
// Server Error interface (Node.js)
interface ServerError extends Error {
code?: string;
errno?: number;
syscall?: string;
address?: string;
port?: number;
}The plugin handles common server errors automatically:
process.exit()posix.normalize() to prevent directory traversal attacksCommon error scenarios:
// Error handling is automatic, but you can detect port conflicts:
serve({
port: 8080,
onListening: (server) => {
console.log("Server started successfully");
}
});
// If port 8080 is in use, the plugin will log:
// "http://localhost:8080 is in use, either stop the other server or use a different port."