A Babel plugin that compiles ES2015 template literals to ES5-compatible string concatenation. The plugin transforms both tagged and untagged template literals, handling embedded expressions and providing configurable options for different compilation modes.
npm install --save-dev babel-plugin-transform-es2015-template-literals// Default CommonJS import (plugin exports default function)
const plugin = require("babel-plugin-transform-es2015-template-literals");ES6 import:
import plugin from "babel-plugin-transform-es2015-template-literals";{
"plugins": ["transform-es2015-template-literals"]
}With options:
{
"plugins": [
["transform-es2015-template-literals", {
"loose": true,
"spec": true
}]
]
}require("babel-core").transform("code", {
plugins: ["transform-es2015-template-literals"]
});babel --plugins transform-es2015-template-literals script.jsInput:
const message = `Hello ${name}!`;
const count = `You have ${items.length} items`;
const multiline = `Line 1
Line 2 with ${value}`;
const escaped = `Use \`backticks\` in "${context}"`;Output:
const message = "Hello " + name + "!";
const count = "You have " + items.length + " items";
const multiline = "Line 1\nLine 2 with " + value;
const escaped = "Use `backticks` in \"" + context + "\"";The main export is a function that creates a Babel plugin instance.
/**
* Creates a Babel plugin for transforming ES2015 template literals
* @param {Object} api - Babel API object containing types utility
* @param {Object} api.types - Babel types utility for AST manipulation
* @returns {Object} Babel plugin object with visitor methods
*/
function pluginFactory({ types: t }) {
return {
visitor: {
TaggedTemplateExpression: Function,
TemplateLiteral: Function
}
};
}Transforms untagged template literals into string concatenation expressions.
/**
* Visitor method for transforming untagged template literals
* @param {Object} path - Babel AST path object
* @param {Object} state - Plugin state object containing options
* @param {Object} state.opts - Plugin configuration options
* @param {boolean} state.opts.spec - Whether to wrap expressions with String()
*/
TemplateLiteral(path, state) {
// Converts `foo${bar}` to "foo" + bar (or "foo" + String(bar) with spec option)
}Examples:
Basic transformation:
// Input: `Hello ${name}`
// Output: "Hello " + nameWith spec option:
// Input: `Hello ${name}`
// Output: "Hello " + String(name)Empty expressions filtered:
// Input: `${greeting}${name}`
// Output: greeting + nameComplex expressions:
// Input: `Result: ${calculateValue()} (${status})`
// Output: "Result: " + calculateValue() + " (" + status + ")"Edge case handling:
// Input: `${a}${b}${c}` (no static strings)
// Output: "" + a + b + c // Empty string prepended for proper coercionTransforms tagged template literals into function calls with template object arrays.
/**
* Visitor method for transforming tagged template literals
* @param {Object} path - Babel AST path object
* @param {Object} state - Plugin state object containing options
* @param {Object} state.opts - Plugin configuration options
* @param {boolean} state.opts.loose - Whether to use loose mode for template objects
*/
TaggedTemplateExpression(path, state) {
// Converts tag`foo${bar}` to tag(templateObject, bar)
}Examples:
Basic tagged template:
// Input: styled`color: ${color}`
// Output: styled(_templateObject(), color)With loose option:
// Uses taggedTemplateLiteralLoose helper instead of taggedTemplateLiteral
// Template objects are not frozen in loose modeTemplate Object Caching:
The plugin automatically caches template objects to avoid recreating identical template literal metadata. Each unique template literal gets a generated template object (e.g., _templateObject, _templateObject2) that contains both the processed and raw string arrays.
/**
* Loose mode configuration option
* @type {boolean}
* @default false
* @description In loose mode, tagged template literal objects aren't frozen
*/
loose: booleanEffect: Uses taggedTemplateLiteralLoose helper instead of taggedTemplateLiteral, which doesn't freeze template objects for better performance.
/**
* Spec compliance configuration option
* @type {boolean}
* @default false
* @description Wraps template literal expressions with String() (except strings and numbers)
*/
spec: booleanEffect: Ensures all expressions are converted to strings by wrapping them with String(), except for string and number literals which are already primitive strings/numbers.
Examples:
// Without spec: `foo${bar}` → "foo" + bar
// With spec: `foo${bar}` → "foo" + String(bar)
// Numbers and strings are not wrapped:
// `count: ${42}` → "count: " + 42
// `name: ${"John"}` → "name: " + "John"
// Objects/functions are wrapped:
// `user: ${user}` → "user: " + String(user)interface PluginObject {
visitor: {
TaggedTemplateExpression(path: Path, state: State): void;
TemplateLiteral(path: Path, state: State): void;
}
}
interface State {
opts: {
loose?: boolean;
spec?: boolean;
};
file: {
addTemplateObject(templateName: string, strings: any, raw: any): any;
};
}
interface Path {
node: Node;
get(key: string): Path;
replaceWith(node: Node): void;
}The plugin operates on AST nodes and relies on Babel's error handling. Invalid template literal syntax will be caught by Babel's parser before reaching this plugin.
loose: true for better performance when template object freezing is not required