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.