Next-generation ES module bundler that compiles small pieces of code into larger, more complex applications or libraries
—
AST parsing, logging, and debugging utilities for advanced use cases and tool development. Rollup provides several utility functions as separate entry points for specialized scenarios.
Standalone AST parsing utilities that use Rollup's internal parser, available for external tooling and plugin development.
/**
* Synchronous AST parsing utility
* @param input - JavaScript/TypeScript code to parse
* @param options - Parser configuration options
* @returns Parsed AST program node
*/
function parseAst(
input: string,
options?: {
/** Allow return statements outside functions */
allowReturnOutsideFunction?: boolean;
/** Enable JSX parsing */
jsx?: boolean;
}
): ProgramNode;
/**
* Asynchronous AST parsing utility with cancellation support
* @param input - JavaScript/TypeScript code to parse
* @param options - Parser configuration options with abort signal
* @returns Promise resolving to parsed AST program node
*/
function parseAstAsync(
input: string,
options?: {
/** Allow return statements outside functions */
allowReturnOutsideFunction?: boolean;
/** Enable JSX parsing */
jsx?: boolean;
/** Abort signal for cancellation */
signal?: AbortSignal;
}
): Promise<ProgramNode>;Usage Examples:
import { parseAst, parseAstAsync } from "rollup/parseAst";
// Synchronous parsing
const code = `
import { foo } from './bar.js';
export default function main() {
return foo();
}
`;
const ast = parseAst(code);
console.log(ast.type); // 'Program'
console.log(ast.body.length); // 2 (import + export)
// JSX parsing
const jsxCode = `
function Component() {
return <div>Hello World</div>;
}
`;
const jsxAst = parseAst(jsxCode, { jsx: true });
// Asynchronous parsing with cancellation
const controller = new AbortController();
const asyncAst = await parseAstAsync(code, {
allowReturnOutsideFunction: true,
signal: controller.signal
});
// Cancel parsing if needed
// controller.abort();Utility for creating log filtering functions based on filter expressions, useful for custom logging implementations and debugging.
/**
* Creates a log filtering function based on filter expressions
* @param filters - Array of filter strings
* @returns Function that tests whether a log should be included
*/
function getLogFilter(filters: string[]): (log: RollupLog) => boolean;Usage Examples:
import { getLogFilter } from "rollup/getLogFilter";
// Create filter for warnings only
const warningsOnly = getLogFilter(['level:warn']);
// Create filter excluding specific plugins
const excludePlugin = getLogFilter(['!plugin:my-plugin']);
// Complex filtering with multiple conditions
const complexFilter = getLogFilter([
'level:warn&!code:UNUSED_EXTERNAL_IMPORT',
'level:error'
]);
// Usage with custom logging
const customLogger = (level, log) => {
const filter = getLogFilter(['!plugin:verbose-plugin']);
if (filter(log)) {
console.log(`[${level}] ${log.message}`);
}
};
// Filter pattern examples:
// 'level:warn' - Only warnings
// 'plugin:typescript' - Only from typescript plugin
// 'code:CIRCULAR_DEPENDENCY' - Only circular dependency warnings
// '!plugin:commonjs' - Exclude commonjs plugin logs
// 'level:warn&plugin:typescript' - Warnings from typescript plugin only
// 'message:*deprecat*' - Messages containing 'deprecat'Current version constant for runtime version checking and compatibility verification.
/**
* Current Rollup version string
*/
const VERSION: string;Usage Examples:
import { VERSION } from "rollup";
console.log(`Using Rollup ${VERSION}`);
// Version compatibility checking
const requiredVersion = '4.0.0';
const currentMajor = parseInt(VERSION.split('.')[0]);
const requiredMajor = parseInt(requiredVersion.split('.')[0]);
if (currentMajor < requiredMajor) {
throw new Error(`Requires Rollup ${requiredVersion}+, got ${VERSION}`);
}
// Plugin compatibility
const myPlugin = () => ({
name: 'my-plugin',
buildStart() {
console.log(`Plugin initialized with Rollup ${VERSION}`);
}
});import { parseAst } from "rollup/parseAst";
function analyzeImports(code) {
const ast = parseAst(code);
const imports = [];
for (const node of ast.body) {
if (node.type === 'ImportDeclaration') {
imports.push({
source: node.source.value,
specifiers: node.specifiers.map(spec => ({
type: spec.type,
imported: spec.imported?.name,
local: spec.local.name
}))
});
}
}
return imports;
}
// Usage
const code = `
import React from 'react';
import { useState, useEffect } from 'react';
import * as utils from './utils.js';
`;
const imports = analyzeImports(code);
console.log(imports);
// [
// { source: 'react', specifiers: [{ type: 'ImportDefaultSpecifier', local: 'React' }] },
// { source: 'react', specifiers: [
// { type: 'ImportSpecifier', imported: 'useState', local: 'useState' },
// { type: 'ImportSpecifier', imported: 'useEffect', local: 'useEffect' }
// ]},
// { source: './utils.js', specifiers: [{ type: 'ImportNamespaceSpecifier', local: 'utils' }]}
// ]import { getLogFilter } from "rollup/getLogFilter";
class LogManager {
constructor(filterExpressions = []) {
this.filter = getLogFilter(filterExpressions);
this.logs = [];
}
handleLog(level, log) {
if (this.filter(log)) {
const entry = {
timestamp: Date.now(),
level,
...log
};
this.logs.push(entry);
this.outputLog(level, entry);
}
}
outputLog(level, log) {
const color = {
warn: '\x1b[33m', // Yellow
error: '\x1b[31m', // Red
info: '\x1b[36m', // Cyan
debug: '\x1b[37m' // White
}[level] || '\x1b[0m';
console.log(`${color}[${level.toUpperCase()}] ${log.message}\x1b[0m`);
if (log.frame) {
console.log(log.frame);
}
}
getFilteredLogs(additionalFilters = []) {
const filter = getLogFilter(additionalFilters);
return this.logs.filter(filter);
}
exportLogs(format = 'json') {
switch (format) {
case 'json':
return JSON.stringify(this.logs, null, 2);
case 'csv':
return this.logs.map(log =>
`${log.timestamp},${log.level},"${log.message}",${log.plugin || ''}"`
).join('\n');
default:
return this.logs;
}
}
}
// Usage
const logManager = new LogManager([
'!code:UNUSED_EXTERNAL_IMPORT', // Ignore unused external import warnings
'level:warn|level:error' // Only warnings and errors
]);
// In rollup config
export default {
input: 'src/main.js',
output: { file: 'dist/bundle.js', format: 'esm' },
onLog: (level, log, defaultHandler) => {
logManager.handleLog(level, log);
}
};import { parseAst, getLogFilter, VERSION } from "rollup";
class RollupDevTools {
constructor() {
this.logFilter = getLogFilter(['level:debug']);
this.buildStats = {
version: VERSION,
builds: [],
errors: []
};
}
analyzeBundleStructure(code) {
try {
const ast = parseAst(code);
return {
imports: this.extractImports(ast),
exports: this.extractExports(ast),
functions: this.extractFunctions(ast),
complexity: this.calculateComplexity(ast)
};
} catch (error) {
console.error('AST analysis failed:', error);
return null;
}
}
extractImports(ast) {
return ast.body
.filter(node => node.type === 'ImportDeclaration')
.map(node => ({
source: node.source.value,
specifiers: node.specifiers.length,
dynamic: false
}));
}
extractExports(ast) {
return ast.body
.filter(node =>
node.type === 'ExportDefaultDeclaration' ||
node.type === 'ExportNamedDeclaration'
)
.map(node => ({
type: node.type,
name: this.getExportName(node)
}));
}
extractFunctions(ast) {
const functions = [];
const walk = (node) => {
if (node.type === 'FunctionDeclaration' || node.type === 'FunctionExpression') {
functions.push({
name: node.id?.name || 'anonymous',
params: node.params.length,
async: node.async,
generator: node.generator
});
}
// Recursively walk child nodes
for (const key in node) {
const child = node[key];
if (Array.isArray(child)) {
child.forEach(walk);
} else if (child && typeof child === 'object' && child.type) {
walk(child);
}
}
};
walk(ast);
return functions;
}
calculateComplexity(ast) {
// Simple complexity calculation based on node types
let complexity = 0;
const walk = (node) => {
if (['IfStatement', 'ForStatement', 'WhileStatement', 'SwitchCase'].includes(node.type)) {
complexity++;
}
for (const key in node) {
const child = node[key];
if (Array.isArray(child)) {
child.forEach(walk);
} else if (child && typeof child === 'object' && child.type) {
walk(child);
}
}
};
walk(ast);
return complexity;
}
recordBuild(inputOptions, outputOptions, result) {
this.buildStats.builds.push({
timestamp: Date.now(),
input: inputOptions.input,
output: outputOptions.file || outputOptions.dir,
format: outputOptions.format,
duration: result.duration,
size: result.output[0]?.code?.length || 0
});
}
generateReport() {
return {
...this.buildStats,
summary: {
totalBuilds: this.buildStats.builds.length,
totalErrors: this.buildStats.errors.length,
averageBuildTime: this.buildStats.builds.reduce((sum, build) =>
sum + (build.duration || 0), 0) / this.buildStats.builds.length,
formats: [...new Set(this.buildStats.builds.map(b => b.format))]
}
};
}
}
// Usage
const devTools = new RollupDevTools();
export default {
input: 'src/main.js',
output: { file: 'dist/bundle.js', format: 'esm' },
plugins: [{
name: 'dev-tools',
buildStart(options) {
console.log(`Build starting with Rollup ${VERSION}`);
},
generateBundle(options, bundle) {
const mainChunk = Object.values(bundle).find(chunk => chunk.type === 'chunk');
if (mainChunk) {
const analysis = devTools.analyzeBundleStructure(mainChunk.code);
console.log('Bundle analysis:', analysis);
}
}
}]
};/**
* AST Program node type
*/
type ProgramNode = RollupAstNode<estree.Program>;
interface RollupAstNode<T> extends Omit<T, 'loc' | 'range' | 'leadingComments' | 'trailingComments' | 'innerComments' | 'comments'> {
start: number;
end: number;
}
/**
* Error interface extending RollupLog
*/
interface RollupError extends RollupLog {
/** Error name */
name?: string;
/** Stack trace */
stack?: string;
/** Files being watched when error occurred */
watchFiles?: string[];
}
/**
* Log entry interface
*/
interface RollupLog {
/** Log message */
message: string;
/** Log code identifier */
code?: string;
/** Related file ID */
id?: string;
/** Source location */
loc?: {
column: number;
file?: string;
line: number;
};
/** Code frame showing context */
frame?: string;
/** Related plugin name */
plugin?: string;
/** Additional metadata */
meta?: any;
/** Source position */
pos?: number;
/** URL reference */
url?: string;
/** Error binding */
binding?: string;
/** Error cause */
cause?: unknown;
/** Module exporter */
exporter?: string;
/** Related module IDs */
ids?: string[];
/** Export names */
names?: string[];
/** Plugin-specific code */
pluginCode?: unknown;
/** Re-exporter module */
reexporter?: string;
/** Stack trace */
stack?: string;
}
/**
* Logging function type
*/
type LoggingFunction = (log: RollupLog | string | (() => RollupLog | string)) => void;
/**
* Log levels
*/
type LogLevel = 'warn' | 'info' | 'debug';Install with Tessl CLI
npx tessl i tessl/npm-rollup