A set of utility functions commonly used by Rollup plugins
—
Utilities for generating valid JavaScript code, identifiers, and ES modules from data structures. These functions help create bundle-safe code and transform data into tree-shakable modules.
Converts strings into valid JavaScript identifiers that are safe for use in bundles. Handles special characters, reserved words, and naming conflicts.
/**
* Constructs a bundle-safe identifier from a string
* Converts invalid characters and handles reserved words
* @param str - The string to convert to a legal identifier
* @returns A valid JavaScript identifier
*/
function makeLegalIdentifier(str: string): string;Parameters:
str (string): The string to convert to a legal JavaScript identifierReturns: A valid JavaScript identifier string
Transformation Rules:
'foo-bar' → 'fooBar''123abc' → '_123abc''typeof' → '_typeof''_' for empty stringsUsage Examples:
import { makeLegalIdentifier } from "@rollup/pluginutils";
// Basic transformations
makeLegalIdentifier('foo-bar'); // 'fooBar'
makeLegalIdentifier('my-component'); // 'myComponent'
makeLegalIdentifier('foo_bar'); // 'foo_bar' (already valid)
// Handle special characters
makeLegalIdentifier('foo@bar'); // 'foo_bar'
makeLegalIdentifier('foo.bar'); // 'foo_bar'
makeLegalIdentifier('foo bar'); // 'foo_bar'
// Reserved words and edge cases
makeLegalIdentifier('typeof'); // '_typeof'
makeLegalIdentifier('class'); // '_class'
makeLegalIdentifier('123abc'); // '_123abc'
makeLegalIdentifier(''); // '_'
// Use in code generation
export default function myPlugin() {
return {
generateBundle(options, bundle) {
for (const [fileName, chunk] of Object.entries(bundle)) {
if (chunk.type === 'chunk') {
// Generate safe variable names from file names
const varName = makeLegalIdentifier(
fileName.replace(/\.[^.]+$/, '') // remove extension
);
// Use in generated code
const wrapper = `
const ${varName} = (function() {
${chunk.code}
return exports;
})();
`;
chunk.code = wrapper;
}
}
}
};
}
// Generate imports from module names
function generateImportName(moduleName) {
// Convert scoped packages: '@rollup/plugin-utils' → 'rollupPluginUtils'
const cleaned = moduleName.replace(/^@/, '').replace(/[^\w]/g, '-');
return makeLegalIdentifier(cleaned);
}
generateImportName('@rollup/plugin-utils'); // 'rollupPluginUtils'
generateImportName('lodash-es'); // 'lodashEs'
generateImportName('my-library/sub-module'); // 'myLibrarySubModule'Transforms JavaScript objects into tree-shakable ES module source code. Generates both named exports and default exports with comprehensive formatting options.
/**
* Transforms objects into tree-shakable ES Module imports
* Generates both named and default exports with formatting options
* @param data - An object to transform into an ES module
* @param options - Configuration options for code generation
* @returns Generated ES module source code
*/
function dataToEsm(data: unknown, options?: DataToEsmOptions): string;
interface DataToEsmOptions {
compact?: boolean;
includeArbitraryNames?: boolean;
indent?: string;
namedExports?: boolean;
objectShorthand?: boolean;
preferConst?: boolean;
}Parameters:
data (unknown): The data to convert to ES module formatoptions (DataToEsmOptions, optional): Configuration optionsDataToEsmOptions:
compact?: boolean - Minimize whitespace in generated code (default: false)includeArbitraryNames?: boolean - Support non-identifier keys as named exports using arbitrary module namespace identifier names (default: false)indent?: string - Indentation string for formatting (default: '\t')namedExports?: boolean - Generate named exports for object properties (default: true)objectShorthand?: boolean - Use ES6 object property shorthand syntax (default: true)preferConst?: boolean - Use const instead of var for declarations (default: false)Returns: Generated ES module source code as a string
Supported Data Types:
Usage Examples:
import { dataToEsm } from "@rollup/pluginutils";
// Basic object transformation
const config = {
apiUrl: 'https://api.example.com',
timeout: 5000,
debug: true
};
const moduleCode = dataToEsm(config, {
compact: false,
indent: ' ',
preferConst: true,
objectShorthand: true,
namedExports: true
});
console.log(moduleCode);
/*
export const apiUrl = 'https://api.example.com';
export const timeout = 5000;
export const debug = true;
export default { apiUrl, timeout, debug };
*/
// Complex data with formatting options
const complexData = {
users: ['alice', 'bob'],
settings: {
theme: 'dark',
notifications: true
},
created: new Date('2023-01-01'),
pattern: /^\w+$/,
bigNumber: BigInt('9007199254740991')
};
const compactCode = dataToEsm(complexData, {
compact: true,
namedExports: true,
includeArbitraryNames: false
});
// Use in plugin for configuration files
export default function configPlugin(options = {}) {
return {
resolveId(id) {
if (id === 'virtual:config') {
return id;
}
},
load(id) {
if (id === 'virtual:config') {
// Convert plugin options to ES module
return dataToEsm(options, {
preferConst: true,
objectShorthand: true,
namedExports: true
});
}
}
};
}
// Handle non-identifier keys
const dataWithSpecialKeys = {
'normal-key': 'value1',
'special@key': 'value2',
'123numeric': 'value3'
};
const codeWithArbitraryNames = dataToEsm(dataWithSpecialKeys, {
includeArbitraryNames: true,
namedExports: true
});
/*
export const normalKey = 'value1';
export { 'special@key' as specialKey };
export { '123numeric' as _123numeric };
export default { normalKey, 'special@key': specialKey, '123numeric': _123numeric };
*/
// Generate module from JSON file
export default function jsonPlugin() {
return {
transform(code, id) {
if (id.endsWith('.json')) {
const data = JSON.parse(code);
// Convert JSON to tree-shakable ES module
const esModule = dataToEsm(data, {
preferConst: true,
namedExports: true,
objectShorthand: true
});
return { code: esModule };
}
}
};
}import { dataToEsm, makeLegalIdentifier } from "@rollup/pluginutils";
export default function configPlugin(userConfig = {}) {
const defaultConfig = {
apiEndpoint: 'https://api.example.com',
timeout: 5000,
retries: 3,
debug: false
};
const finalConfig = { ...defaultConfig, ...userConfig };
return {
resolveId(id) {
if (id === 'virtual:app-config') return id;
},
load(id) {
if (id === 'virtual:app-config') {
// Generate tree-shakable config module
return dataToEsm(finalConfig, {
preferConst: true,
namedExports: true,
objectShorthand: true,
compact: false
});
}
}
};
}
// Usage in application code:
// import { apiEndpoint, timeout } from 'virtual:app-config';import { makeLegalIdentifier, dataToEsm } from "@rollup/pluginutils";
export default function dynamicImportPlugin(options = {}) {
const { modules = {} } = options;
return {
generateBundle() {
// Generate loader module with dynamic imports
const loaderCode = Object.entries(modules)
.map(([key, modulePath]) => {
const importName = makeLegalIdentifier(key);
return `
export const ${importName} = () => import('${modulePath}');
`.trim();
})
.join('\n');
// Also generate static config
const configModule = dataToEsm({
availableModules: Object.keys(modules),
moduleCount: Object.keys(modules).length
});
this.emitFile({
type: 'asset',
fileName: 'dynamic-loader.js',
source: loaderCode
});
this.emitFile({
type: 'asset',
fileName: 'loader-config.js',
source: configModule
});
}
};
}import { makeLegalIdentifier } from "@rollup/pluginutils";
export default function namespacePlugin(options = {}) {
const { namespace = 'MyLibrary' } = options;
return {
generateBundle(options, bundle) {
for (const [fileName, chunk] of Object.entries(bundle)) {
if (chunk.type === 'chunk') {
// Generate safe namespace from file name
const safeName = makeLegalIdentifier(
fileName.replace(/\.[^.]+$/, '') // remove extension
);
// Wrap exports in namespace
const namespacedCode = `
(function(global) {
'use strict';
// Original code
${chunk.code}
// Create namespace
global.${namespace} = global.${namespace} || {};
global.${namespace}.${safeName} = exports;
})(typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : this);
`;
chunk.code = namespacedCode;
}
}
}
};
}Install with Tessl CLI
npx tessl i tessl/npm-rollup--pluginutils