Plugin for using esbuild in @web/dev-server to transform TypeScript, JSX, TSX, and JavaScript files during development
npx @tessl/cli install tessl/npm-web--dev-server-esbuild@1.0.0@web/dev-server-esbuild is a plugin for @web/dev-server that integrates esbuild to transform TypeScript, JSX, TSX, and JavaScript files during development. It provides fast, efficient code transformation with automatic browser target detection and supports configurable compilation options.
npm install @web/dev-server-esbuild@web/dev-server or @web/dev-server-core for plugin integrationThe package exports a single function esbuildPlugin:
import { esbuildPlugin } from "@web/dev-server-esbuild";For CommonJS:
const { esbuildPlugin } = require("@web/dev-server-esbuild");Note: The package only exports the esbuildPlugin function. All types (EsBuildPluginArgs, Plugin, Context, etc.) are available for TypeScript users through the type definitions, but are not runtime exports.
import { createConfig } from '@web/dev-server';
import { esbuildPlugin } from '@web/dev-server-esbuild';
export default createConfig({
plugins: [
// Basic TypeScript support
esbuildPlugin({ ts: true }),
// JSX support with custom factory
esbuildPlugin({
jsx: true,
jsxFactory: 'h',
jsxFragment: 'Fragment'
}),
// Multiple file types with auto targeting
esbuildPlugin({
ts: true,
tsx: true,
jsx: true,
target: 'auto'
})
]
});Creates and configures an esbuild plugin instance for @web/dev-server.
/**
* Creates an esbuild plugin instance for @web/dev-server
* @param args - Configuration options for the plugin
* @returns Plugin instance compatible with @web/dev-server
*/
function esbuildPlugin(args?: EsBuildPluginArgs): Plugin;
interface EsBuildPluginArgs {
/** Compilation target (e.g., 'es2020', 'auto', 'auto-always') or array of targets */
target?: string | string[];
/** Enable JavaScript compilation */
js?: boolean;
/** Enable TypeScript compilation */
ts?: boolean;
/** Enable JSON loading */
json?: boolean;
/** Enable JSX compilation */
jsx?: boolean;
/** Enable TSX compilation */
tsx?: boolean;
/** JSX factory function (e.g., 'React.createElement', 'h') */
jsxFactory?: string;
/** JSX fragment (e.g., 'React.Fragment', 'Fragment') */
jsxFragment?: string;
/** Custom file extension loaders */
loaders?: Record<string, Loader>;
/** Global constants replacement for define transforms */
define?: { [key: string]: string };
/** Path to TypeScript config file */
tsconfig?: string;
/** Code to prepend to all transformed files */
banner?: string;
/** Code to append to all transformed files */
footer?: string;
}The target option controls compilation output:
'auto' - Automatically detects browser capabilities from user agent. Skips compilation for modern browsers, falls back to ES module compatible code for older browsers'auto-always' - Similar to 'auto' but always compiles, using modern targets for recent browsers'es2020', 'es2019' - Compile to specific ECMAScript versions['chrome80', 'firefox75', 'safari13']Enable transformation for different file types:
// TypeScript files (.ts)
esbuildPlugin({ ts: true })
// JSX files (.jsx)
esbuildPlugin({ jsx: true })
// TSX files (.tsx)
esbuildPlugin({ tsx: true })
// JSON files (.json)
esbuildPlugin({ json: true })
// JavaScript files (.js) - useful with custom targets
esbuildPlugin({ js: true, target: 'es2015' })
// Multiple types
esbuildPlugin({ ts: true, tsx: true, jsx: true, json: true })Configure how specific file extensions are processed:
esbuildPlugin({
loaders: {
'.foo': 'text', // Load .foo files as text
'.bar': 'json', // Load .bar files as JSON
'scss': 'css' // Load .scss files as CSS (extension dot is optional)
}
})Customize JSX transformation:
// React
esbuildPlugin({
jsx: true,
jsxFactory: 'React.createElement',
jsxFragment: 'React.Fragment'
})
// Preact
esbuildPlugin({
jsx: true,
jsxFactory: 'h',
jsxFragment: 'Fragment'
})
// Custom JSX
esbuildPlugin({
jsx: true,
jsxFactory: 'myCreateElement',
jsxFragment: 'myFragment'
})Use with TypeScript configuration:
esbuildPlugin({
ts: true,
tsconfig: './tsconfig.json' // Path to TypeScript config
})Add code banners and footers:
esbuildPlugin({
ts: true,
banner: '/* Generated code - do not edit */',
footer: '/* End of generated code */'
})Replace global constants during compilation:
esbuildPlugin({
ts: true,
define: {
'process.env.NODE_ENV': '"development"',
'__VERSION__': '"1.0.0"',
'DEBUG': 'true'
}
})The following types are available when using TypeScript. Import them from their respective packages:
// Main function and its configuration
import { esbuildPlugin } from '@web/dev-server-esbuild';
import type { EsBuildPluginArgs } from '@web/dev-server-esbuild';
// Plugin-related types from @web/dev-server-core
import type { Plugin, Context, PluginSyntaxError } from '@web/dev-server-core';
// esbuild types
import type { Loader } from 'esbuild';/** esbuild loader type for different file extensions (from 'esbuild') */
type Loader = 'js' | 'jsx' | 'ts' | 'tsx' | 'css' | 'json' | 'text' | 'base64' | 'dataurl' | 'file' | 'binary';
/** @web/dev-server plugin interface (imported from '@web/dev-server-core') */
interface Plugin {
name: string;
injectWebSocket?: boolean;
serverStart?(args: ServerStartParams): void | Promise<void>;
serverStop?(): void | Promise<void>;
serve?(context: Context): ServeResult | Promise<ServeResult>;
transform?(context: Context): TransformResult | Promise<TransformResult>;
transformCacheKey?(context: Context): string | undefined | Promise<string> | Promise<undefined>;
resolveImport?(args: {
source: string;
context: Context;
code?: string;
column?: number;
line?: number;
resolveOptions?: ResolveOptions;
}): ResolveResult | Promise<ResolveResult>;
resolveImportSkip?(context: Context, source: string, importer: string): void;
transformImport?(args: {
source: string;
context: Context;
code?: string;
column?: number;
line?: number;
}): ResolveResult | Promise<ResolveResult>;
resolveMimeType?(context: Context): ResolveMimeTypeResult | Promise<ResolveMimeTypeResult>;
fileParsed?(context: Context): void;
}
/** Server start parameters for plugin initialization */
interface ServerStartParams {
config: DevServerCoreConfig;
app: Koa;
server?: Server;
fileWatcher: FSWatcher;
logger: Logger;
webSockets?: WebSocketsManager;
}
/** Plugin method return types */
type ServeResult = void | string | { body: string; type?: string; headers?: Record<string, string> };
type TransformResult = void | string | { body?: string; headers?: Record<string, string>; transformCache?: boolean };
type ResolveResult = void | string | { id?: string };
type ResolveMimeTypeResult = void | string | { type?: string };
/** Resolve options for import resolution */
interface ResolveOptions {
isEntry?: boolean;
skipSelf?: boolean;
[key: string]: unknown;
}
/** Koa Context interface (imported from 'koa' package) */
interface Context {
/** Request URL path */
path: string;
/** Parsed URL object */
url: URL;
/** Request headers */
headers: Record<string, string>;
/** Request/Response body */
body: string | Buffer;
/** Response helpers */
response: {
/** Check if response matches a MIME type */
is(type: string): boolean;
};
/** Additional Koa context properties available but not commonly used by plugins */
}
/** Error thrown when plugin encounters syntax errors during transformation */
class PluginSyntaxError extends Error {
constructor(
public message: string,
public filePath: string,
public code: string,
public line: number,
public column: number,
);
}The plugin automatically detects browser capabilities and adjusts compilation accordingly:
// Automatic browser detection
esbuildPlugin({ target: 'auto', ts: true })
// - Modern Chrome/Firefox/Edge: compiles to 'esnext' (minimal transformation)
// - Latest Safari: compiles to Safari-specific target
// - Older browsers: compiles to ES module compatible codeThe plugin automatically transforms inline scripts in HTML files:
<script type="module">
// This TypeScript code will be transformed
const message: string = 'Hello, world!';
console.log(message);
</script>For TypeScript files, the plugin handles .js import resolution by checking for corresponding .ts files:
// In a .ts file, this import:
import { helper } from './utils.js';
// Will resolve to ./utils.ts if it existsThe plugin provides detailed error information for compilation failures through the PluginSyntaxError class:
// Example of syntax error thrown by the plugin
throw new PluginSyntaxError(
'Unexpected token', // Error message
'/path/to/file.ts', // File path where error occurred
'const x: invalid syntax;', // Code that caused the error
5, // Line number (1-based)
12 // Column number (1-based)
);Error Types:
PluginSyntaxErrortsconfig is specified)Common Error Scenarios:
tsconfig option is specifiedError Handling Behavior:
The plugin filters certain warnings (like "Unsupported source map comment") to reduce noise, but reports all compilation errors. Errors include detailed location information when available from esbuild.