vite-plugin-formatjs
v1.1.3
Published
A Vite plugin that integrates FormatJS for message extraction, compilation, and build-time code transformation with hot reload support
Maintainers
Readme
vite-plugin-formatjs
A powerful Vite plugin that integrates FormatJS for automatic message extraction, compilation, and build-time optimization with hot reload support.
✨ Features
- 🔄 Automatic Message Extraction - Extract i18n messages from source code automatically
- ⚡ Hot Reload Support - Real-time message updates during development
- 🎯 Multi-Framework Support - Works with React, Vue, TypeScript, JavaScript, and more
- 🚀 Performance Optimized - Debounced processing and intelligent caching
- 📦 Build Integration - Seamless integration with Vite build process
- 🛠️ Flexible Configuration - Extensive customization options
- 📊 Rich Logging - Detailed debug information and performance metrics
- 🔧 TypeScript Support - Full TypeScript support with detailed type definitions
🚀 Quick Start
Installation
# npm
npm install -D vite-plugin-formatjs
# yarn
yarn add -D vite-plugin-formatjs
# pnpm
pnpm add -D vite-plugin-formatjsBasic Setup
1. Configure the Plugin
Add the plugin to your vite.config.ts:
// vite.config.ts
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import { formatjs } from 'vite-plugin-formatjs';
export default defineConfig({
plugins: [
// Configure React with babel-plugin-formatjs for runtime optimization
react({
babel: {
plugins: [
[
'formatjs',
{
idInterpolationPattern: '[sha512:contenthash:base64:6]',
ast: true,
removeDefaultMessage: process.env.NODE_ENV === 'production',
},
],
],
},
}),
// Configure vite-plugin-formatjs for build-time processing
formatjs({
extract: {
include: ['src/**/*.{ts,tsx,js,jsx}'],
outFile: 'src/i18n/lang/en.json',
idInterpolationPattern: '[sha512:contenthash:base64:6]',
},
compile: {
inputDir: 'src/i18n/lang',
outputDir: 'src/i18n/compiled-lang',
},
debug: process.env.NODE_ENV === 'development',
}),
],
});2. Create Your i18n Setup
// src/i18n/index.ts
export const supportedLocales = ['en', 'zh', 'fr'] as const;
export type SupportedLocale = (typeof supportedLocales)[number];
export async function loadMessages(locale: string) {
const normalizedLocale = supportedLocales.includes(locale as SupportedLocale)
? locale
: 'en';
try {
const messages = await import(`./compiled-lang/${normalizedLocale}.json`);
return messages.default || messages;
} catch (error) {
console.warn(`Failed to load messages for ${normalizedLocale}`, error);
return {};
}
}3. Use in Your Components
// src/components/Welcome.tsx
import { FormattedMessage } from 'react-intl';
export function Welcome() {
return (
<div>
<h1>
<FormattedMessage
id="welcome.title"
defaultMessage="Welcome to our app!"
/>
</h1>
<p>
<FormattedMessage
id="welcome.description"
defaultMessage="This message will be automatically extracted and compiled."
/>
</p>
</div>
);
}🔧 Configuration
Complete Configuration Example
import { formatjs } from 'vite-plugin-formatjs';
formatjs({
// Message extraction configuration
extract: {
// Files to scan for messages
include: [
'src/**/*.{ts,tsx,js,jsx}',
'components/**/*.vue',
'pages/**/*.html',
],
// Files to ignore
ignore: ['node_modules/**', '**/*.test.*', '**/*.spec.*', 'dist/**'],
// Output file for extracted messages
outFile: 'src/i18n/lang/en.json',
// Message ID generation pattern
idInterpolationPattern: '[sha512:contenthash:base64:6]',
// FormatJS extraction options
additionalComponentNames: ['CustomFormattedMessage'],
preserveWhitespace: true,
},
// Message compilation configuration
compile: {
inputDir: 'src/i18n/lang', // Source translation files
outputDir: 'src/i18n/compiled-lang', // Compiled output directory
},
// Development options
debug: process.env.NODE_ENV === 'development',
autoExtract: true,
debounceTime: 300,
extractOnBuild: true,
});Configuration Options
Extract Options
| Option | Type | Default | Description |
| --------- | ---------- | --------------------------------------------------- | ---------------------------------- |
| include | string[] | ['src/**/*.{ts,tsx,js,jsx,vue,hbs,gjs,gts}'] | File patterns to scan for messages |
| ignore | string[] | ['node_modules/**', '**/*.test.*', '**/*.spec.*'] | File patterns to ignore |
| outFile | string | 'src/i18n/lang/en.json' | Output file for extracted messages |
All options from @formatjs/cli-lib are also supported.
Compile Options
| Option | Type | Default | Description |
| ----------- | -------- | -------------------------- | -------------------------------------- |
| inputDir | string | 'src/i18n/lang' | Directory containing translation files |
| outputDir | string | 'src/i18n/compiled-lang' | Output directory for compiled files |
All options from @formatjs/cli-lib are also supported.
Plugin Options
| Option | Type | Default | Description |
| ---------------- | --------- | ------- | ------------------------------------------------------ |
| debug | boolean | false | Enable detailed debug logging |
| autoExtract | boolean | true | Automatically extract messages on file changes |
| debounceTime | number | 300 | Debounce time in milliseconds for file change handling |
| extractOnBuild | boolean | false | Extract messages at build start |
🔥 Hot Reload
The plugin provides seamless hot reload functionality during development:
Source File Changes: When you modify source files containing messages, the plugin automatically:
- Extracts new/modified messages
- Updates the message files
- Recompiles affected translations
- Triggers Vite's HMR
Translation File Changes: When you update translation files, the plugin:
- Recompiles the specific file
- Updates the compiled output
- Triggers HMR for immediate preview
Smart Debouncing: Multiple file changes are batched together to avoid excessive processing.
🏗️ Build Process
Development Mode (vite dev)
- Initial Setup: Extract and compile all messages on startup
- File Watching: Monitor source files for message changes
- Hot Updates: Real-time message extraction and compilation
- Debug Logging: Detailed information about processing (when
debug: true)
Production Build (vite build)
- Final Extraction: Ensure all messages are extracted (if
extractOnBuild: true) - Compilation: Compile all translation files for optimal runtime performance
- Optimization: Remove debug information and optimize output
🧩 Framework Integration
React + React-Intl
// Complete setup with React
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import { formatjs } from 'vite-plugin-formatjs';
export default defineConfig({
plugins: [
react({
babel: {
plugins: [
[
'formatjs',
{
idInterpolationPattern: '[sha512:contenthash:base64:6]',
ast: true,
removeDefaultMessage: process.env.NODE_ENV === 'production',
},
],
],
},
}),
formatjs({
extract: {
include: ['src/**/*.{ts,tsx}'],
outFile: 'src/locales/en.json',
idInterpolationPattern: '[sha512:contenthash:base64:6]',
},
compile: {
inputDir: 'src/locales',
outputDir: 'src/compiled-locales',
},
}),
],
});Vue + Vue-i18n
import { formatjs } from 'vite-plugin-formatjs';
export default defineConfig({
plugins: [
vue(),
formatjs({
extract: {
include: ['src/**/*.{vue,ts,js}'],
outFile: 'src/locales/messages.json',
},
compile: {
inputDir: 'src/locales',
outputDir: 'src/compiled-locales',
},
}),
],
});📊 Performance & Optimization
- Debounced Processing: Batches multiple file changes to reduce unnecessary work
- Incremental Updates: Only processes changed files during development
- Parallel Compilation: Compiles multiple translation files concurrently
- Smart Caching: Avoids reprocessing unchanged content
- Memory Efficient: Optimized for large codebases
📁 Project Structure
src/
├── components/
│ └── *.tsx # Components with messages
├── i18n/
│ ├── index.ts # i18n setup and utilities
│ ├── lang/ # Source translation files
│ │ ├── en.json # Extracted messages (auto-generated)
│ │ ├── zh.json # Chinese translations
│ │ └── fr.json # French translations
│ └── compiled-lang/ # Compiled translation files (auto-generated)
│ ├── en.json
│ ├── zh.json
│ └── fr.json
└── ...🔧 API Reference
formatjs(options?: UserFormatJSConfig)
Creates the Vite plugin with the specified configuration.
Parameters
options(optional): Configuration object of typeUserFormatJSConfig
Returns
A Vite plugin object.
Configuration Types
UserFormatJSConfig
type UserFormatJSConfig = Partial<
VitePluginFormatJSOptions & Partial<ExtractOptions> & Partial<CompileOptions>
>;The main configuration type that users provide when using the plugin. All fields are optional, and the plugin will use sensible defaults for missing options.
VitePluginFormatJSOptions
interface VitePluginFormatJSOptions {
extract: ExtractOptions; // Message extraction configuration
compile: CompileOptions; // Message compilation configuration
debug: boolean; // Enable debug logging (default: false)
autoExtract: boolean; // Auto-extract on file changes (default: true)
debounceTime: number; // Debounce time in ms (default: 300)
extractOnBuild: boolean; // Extract on build start (default: false)
}ExtractOptions
Extends ExtractCLIOptions from @formatjs/cli-lib with additional file matching configuration.
interface ExtractOptions extends ExtractCLIOptions {
include: string[]; // File patterns to scan (required)
}Key Properties:
include: Array of file matching patterns using minimatch syntaxoutFile: Output file for extracted messagesidInterpolationPattern: Pattern for generating message IDs- All other options from
@formatjs/cli-lib
CompileOptions
Extends CompileOpts from @formatjs/cli-lib with directory configuration.
interface CompileOptions extends CompileOpts {
inputDir: string; // Input directory for translation files
outputDir: string; // Output directory for compiled files
}🤝 Integration with Babel Plugin
This plugin works seamlessly with babel-plugin-formatjs:
- vite-plugin-formatjs: Handles build-time extraction and compilation
- babel-plugin-formatjs: Handles runtime code optimization and transformation
Both plugins can use the same idInterpolationPattern to ensure consistency.
🐛 Debugging
Enable debug mode to get detailed information about the plugin's operation:
formatjs({
debug: true, // or process.env.NODE_ENV === 'development'
// ... other options
});Debug output includes:
- File processing information and timing
- Message extraction results and statistics
- Compilation status and performance metrics
- Error details and stack traces
🔧 Advanced Configuration
Custom Message ID Generation
formatjs({
extract: {
// Generate short, stable IDs based on content
idInterpolationPattern: '[sha512:contenthash:base64:6]',
// Or use custom patterns
idInterpolationPattern: '[contenthash:5]',
},
});Environment-Based Configuration
const isProduction = process.env.NODE_ENV === 'production';
formatjs({
debug: !isProduction,
extractOnBuild: isProduction,
debounceTime: isProduction ? 100 : 300,
extract: {
// Production builds might want more aggressive extraction
include: isProduction
? ['src/**/*.{ts,tsx,js,jsx,vue}']
: ['src/**/*.{ts,tsx,js,jsx}'],
},
});📝 Contributing
We welcome contributions! Please see our Contributing Guide for details.
📄 License
MIT © asfamilybank
