An esbuild plugin that compiles .coffee and .litcoffee files with CoffeeScript 2, so you can import and bundle them like any other module.
pnpm add --dev esbuild-coffeescript esbuild
# or
npm install --save-dev esbuild-coffeescript esbuildRequires Node.js 20+ and esbuild 0.25.9 or later.
# main.coffee
answer = 42
console.log("the answer is #{answer}")// build.js
import esbuild from "esbuild";
import coffeeScriptPlugin from "esbuild-coffeescript";
await esbuild.build({
entryPoints: ["main.coffee"],
bundle: true,
outfile: "out.js",
plugins: [coffeeScriptPlugin()],
});CoffeeScript compiles main.coffee to this before esbuild bundles it:
(function () {
var answer;
answer = 42;
console.log(`the answer is ${answer}`);
}).call(this);Pass options to the plugin: coffeeScriptPlugin({ bare: true }).
| Option | Type | Default | Description |
|---|---|---|---|
bare |
boolean |
false |
Omit the top-level function safety wrapper. |
header |
boolean |
false |
Add a "Generated by CoffeeScript" header. |
inlineMap |
boolean |
false |
Append a base64-encoded source map comment. |
literate |
boolean |
true for .litcoffee |
Parse every file as Literate CoffeeScript. Leave unset to detect it from the file extension. |
transpile |
object |
undefined |
Babel options for transpilation. |
// Development: source maps and a header
coffeeScriptPlugin({ bare: true, header: true, inlineMap: true });
// Production: bare output, no header
coffeeScriptPlugin({ bare: true });
// Transpile with Babel
coffeeScriptPlugin({
bare: true,
transpile: { presets: ["@babel/preset-env"], targets: { node: "18" } },
});.litcoffee files work without configuration. Indented blocks are code; everything else is Markdown.
<!-- docs.litcoffee -->
# My Application
This is documentation written in Markdown with embedded CoffeeScript:
class Calculator
add: (a, b) -> a + b
multiply: (a, b) -> a * b
calc = new Calculator()
console.log calc.add(5, 3)esbuild.build({
entryPoints: ["docs.litcoffee"],
bundle: true,
outfile: "calculator.js",
plugins: [coffeeScriptPlugin()],
});# models/User.coffee
class User
constructor: (@name, @email) ->
greet: -> "Hello, I'm #{@name}"
module.exports = { User }# main.coffee
{User} = require('./models/User.coffee')
user = new User('John', 'john@example.com')
console.log user.greet()esbuild.build({
entryPoints: ["main.coffee"],
bundle: true,
format: "esm",
outfile: "app.js",
plugins: [coffeeScriptPlugin({ bare: true })],
});esbuild.build({
entryPoints: ["src/app.coffee"],
bundle: true,
format: "esm",
minify: true,
outdir: "dist",
sourcemap: true,
target: "es2020",
plugins: [coffeeScriptPlugin()],
});esbuild handles .ts itself; the plugin only touches CoffeeScript files.
esbuild.build({
entryPoints: ["src/main.ts", "src/utils.coffee"],
bundle: true,
format: "esm",
outdir: "dist",
plugins: [coffeeScriptPlugin({ bare: true })],
});const context = await esbuild.context({
entryPoints: ["src/app.coffee"],
bundle: true,
outdir: "dist",
plugins: [coffeeScriptPlugin()],
});
await context.watch();Each plugin instance caches compiled output per file for the lifetime of the build context, so rebuilds only recompile files whose source changed.
CoffeeScript syntax errors are reported as esbuild errors with the file, line and column:
# invalid.coffee
hello . 8✘ [ERROR] unexpected number [plugin coffeescript]
invalid.coffee:1:8:
1 │ hello . 8
╵ ^
-
Could not resolve "./utils.coffee": esbuild resolves imports relative to the importing file. Check that the path and extension are correct. -
Source maps missing: enable esbuild's
sourcemapoption, andinlineMap: trueon the plugin to map back to the CoffeeScript source:esbuild.build({ sourcemap: true, // or "inline" plugins: [coffeeScriptPlugin({ inlineMap: true })], });
Still stuck? Search the GitHub issues.
v3 → v4: the ast and filename options are removed. ast returned an AST object that esbuild rejects; the plugin now always passes each file's path to CoffeeScript, so error locations and source maps point at the right file.
v2 → v3: requires Node.js 20+ and esbuild 0.25.9+, uses CoffeeScript 2.7, and is ESM-first:
// v2
const coffeeScriptPlugin = require("esbuild-coffeescript");
// v3+
import coffeeScriptPlugin from "esbuild-coffeescript";See the Contributing Guide.
git clone https://github.com/johnie/esbuild-coffeescript.git
cd esbuild-coffeescript
pnpm install
pnpm test # or test:watch, test:coverage
pnpm buildMIT © Johnie Hjelm