Babel plugin that compiles ES2015 template literals to ES5-compatible code
—
Babel plugin that compiles ES2015 template literals to ES5-compatible code. Transforms both regular template literals (`hello ${name}`) and tagged template expressions (html`<div>${content}</div>`) into equivalent ES5 syntax while preserving JavaScript specification compliance for expression evaluation order.
npm install --save-dev @babel/plugin-transform-template-literalsimport templateLiterals from "@babel/plugin-transform-template-literals";For CommonJS:
const templateLiterals = require("@babel/plugin-transform-template-literals");Plugin Development Imports (for extending or understanding the plugin):
import { declare } from "@babel/helper-plugin-utils";
import { template, types as t, type NodePath } from "@babel/core";// Babel configuration (.babelrc or babel.config.js)
{
"plugins": [
"@babel/plugin-transform-template-literals"
]
}
// With options
{
"plugins": [
["@babel/plugin-transform-template-literals", { "loose": true }]
]
}Input (ES2015):
`Hello ${name}!`;
html`<div>${content}</div>`;Output (ES5):
"Hello " + name + "!";
html(_templateObject || (_templateObject = _taggedTemplateLiteral(["<div>", "</div>"])), content);The plugin operates through Babel's AST transformation pipeline:
declare() from @babel/helper-plugin-utils with Babel version 7+ requirementTemplateLiteral and TaggedTemplateExpression nodes.concat() calls; tagged templates become function calls with template objectstaggedTemplateLiteral, taggedTemplateLiteralLoose) for tagged template object creationignoreToPrimitiveHint, mutableTemplateObject) for optimizationMain plugin function that creates the Babel plugin configuration.
/**
* Default export function that creates the Babel plugin
* Requires Babel version 7 or higher
* @param api - Babel API object with version assertion and assumptions
* @param options - Plugin configuration options
* @returns Babel plugin object with name and visitor configuration
*/
export default function(api: BabelAPI, options: Options): BabelPlugin;
interface BabelPlugin {
name: "transform-template-literals";
visitor: {
TaggedTemplateExpression(path: NodePath<TaggedTemplateExpression>): void;
TemplateLiteral(path: NodePath<TemplateLiteral>): void;
};
}Configuration interface for customizing plugin behavior.
/**
* Plugin configuration options
*/
export interface Options {
/** Enable loose mode for more aggressive optimizations (default: false) */
loose?: boolean;
}Converts regular template literals to ES5-compatible string operations.
Transformation Logic:
\hello ${name}`→"hello " + name`.concat() method calls to preserve evaluation orderOptions Impact:
ignoreToPrimitiveHint: true: Uses binary + operators for concatenationignoreToPrimitiveHint: false: Uses .concat() method calls to preserve primitive conversion orderConverts tagged template expressions to function calls with template objects.
Transformation Logic:
html`<div>${content}</div>` → html(templateObject, content)taggedTemplateLiteral or taggedTemplateLiteralLoose based on mutableTemplateObject assumptionOptions Impact:
mutableTemplateObject: true: Uses taggedTemplateLiteralLoose helper for mutable template objectsmutableTemplateObject: false: Uses taggedTemplateLiteral helper for immutable template objects/**
* Babel API object provided to plugin functions
*/
interface BabelAPI {
/** Assert that the Babel version meets requirements */
assertVersion(version: number | string): void;
/** Get assumption value with optional fallback */
assumption(name: "ignoreToPrimitiveHint" | "mutableTemplateObject"): boolean | undefined;
}
/**
* Generic AST node type
*/
interface Node {
type: string;
}
/**
* Generic expression node
*/
interface Expression extends Node {
type: string;
}
/**
* Babel scope for variable management
*/
interface Scope {
generateUidIdentifier(name: string): Identifier;
buildUndefinedNode(): Node;
getProgramParent(): Scope;
push(node: { id: Node }): void;
}
/**
* Identifier AST node
*/
interface Identifier extends Expression {
type: "Identifier";
name: string;
}
/**
* AST node path for template literals
*/
interface NodePath<T> {
node: T;
parent: Node;
scope: Scope;
get(key: string): NodePath | NodePath[];
replaceWith(node: Node): void;
}
/**
* Template literal AST node
*/
interface TemplateLiteral {
type: "TemplateLiteral";
quasis: TemplateElement[];
expressions: Expression[];
}
/**
* Tagged template expression AST node
*/
interface TaggedTemplateExpression {
type: "TaggedTemplateExpression";
tag: Expression;
quasi: TemplateLiteral;
}
/**
* Template element (string part) of template literal
*/
interface TemplateElement {
value: {
raw: string;
cooked: string | null;
};
}The plugin respects two Babel assumptions that can be configured globally:
ignoreToPrimitiveHint: When true, uses binary + operators instead of .concat() calls for better performance but less spec compliancemutableTemplateObject: When true, uses loose mode helpers that allow template object mutation for better performanceThese assumptions can be set in Babel configuration or overridden by the plugin's loose option.
Install with Tessl CLI
npx tessl i tessl/npm-babel--plugin-transform-template-literals