A Vite plugin that integrates FormatJS for message extraction, compilation, and build-time code transformation with hot reload support
npm install vite-plugin-formatjsA powerful Vite plugin that integrates FormatJS for automatic message extraction, compilation, and build-time optimization with hot reload support.


- š 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
``bashnpm
npm install -D vite-plugin-formatjs
$3
#### 1. Configure the Plugin
Add the plugin to your
vite.config.ts:`typescript
// 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
`typescript
// 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
`tsx
// src/components/Welcome.tsx
import { FormattedMessage } from 'react-intl';export function Welcome() {
return (
id="welcome.title"
defaultMessage="Welcome to our app!"
/>
id="welcome.description"
defaultMessage="This message will be automatically extracted and compiled."
/>
);
}
`š§ Configuration
$3
`typescript
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,
});
`$3
#### 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 |@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 |@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:
1. 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
2. Translation File Changes: When you update translation files, the plugin:
- Recompiles the specific file
- Updates the compiled output
- Triggers HMR for immediate preview
3. Smart Debouncing: Multiple file changes are batched together to avoid excessive processing.
šļø Build Process
$3
1. Initial Setup: Extract and compile all messages on startup
2. File Watching: Monitor source files for message changes
3. Hot Updates: Real-time message extraction and compilation
4. Debug Logging: Detailed information about processing (when
debug: true)$3
1. Final Extraction: Ensure all messages are extracted (if
extractOnBuild: true)
2. Compilation: Compile all translation files for optimal runtime performance
3. Optimization: Remove debug information and optimize outputš§© Framework Integration
$3
`typescript
// 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',
},
}),
],
});
`$3
`typescript
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
$3
Creates the Vite plugin with the specified configuration.
#### Parameters
-
options (optional): Configuration object of type UserFormatJSConfig#### Returns
A Vite plugin object.
$3
####
UserFormatJSConfig`typescript
type UserFormatJSConfig = Partial<
VitePluginFormatJSOptions & Partial & Partial
>;
`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`typescript
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)
}
`####
ExtractOptionsExtends
ExtractCLIOptions from @formatjs/cli-lib with additional file matching configuration.`typescript
interface ExtractOptions extends ExtractCLIOptions {
include: string[]; // File patterns to scan (required)
}
`Key Properties:
-
include: Array of file matching patterns using minimatch syntax
- outFile: Output file for extracted messages
- idInterpolationPattern: Pattern for generating message IDs
- All other options from @formatjs/cli-lib####
CompileOptionsExtends
CompileOpts from @formatjs/cli-lib with directory configuration.`typescript
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:
`typescript
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
$3
`typescript
formatjs({
extract: {
// Generate short, stable IDs based on content
idInterpolationPattern: '[sha512:contenthash:base64:6]', // Or use custom patterns
idInterpolationPattern: '[contenthash:5]',
},
});
`$3
`typescript
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}'],
},
});
``We welcome contributions! Please see our Contributing Guide for details.
MIT Ā© asfamilybank
- FormatJS Documentation
- Vite Plugin API
- React-Intl
- Vue-i18n