@kpsoftec/vite-external-remotes-plugin
v1.1.0
Published
Vite plugin for dynamic external remotes with window variable resolution
Maintainers
Readme
vite-external-remotes-plugin
A Vite plugin for dynamic external remotes with window variable resolution in microfrontend applications. Enables runtime configuration of remote URLs for Module Federation.
Features
- ✅ Dynamic remote URL resolution using window variables
- ✅ Support for multiple pattern formats
- ✅ Runtime window variable replacement
- ✅ Plugin options (debug, variablePrefix, patterns)
- ✅ TypeScript support
- ✅ Debug logging
Installation
npm install @kpsoftec/vite-external-remotes-pluginBasic Usage
// vite.config.js
import { defineConfig } from 'vite'
import ExternalRemotesPlugin from '@kpsoftec/vite-external-remotes-plugin'
import federation from '@originjs/vite-plugin-federation'
export default defineConfig({
plugins: [
ExternalRemotesPlugin(),
federation({
name: 'host-app',
remotes: {
remote_app: '@[window.remote_app_url]/assets/remoteEntry.js',
remote_two: 'remote@[window.remote_two_url]/remoteEntry.js'
},
shared: ['react', 'react-dom']
})
]
})Supported Patterns
| Pattern | Description | Example |
|---------|-------------|---------|
| @[window.variable]/path | Direct window variable URL | @[window.remote_url]/remoteEntry.js |
| remote@[window.variable]/path | Federation remote with window variable | myRemote@[window.base_url]/remoteEntry.js |
| [window.variable] | Standalone window variable | [window.full_remote_url] |
| @[window.variable] | Standalone @ syntax | @[window.remote_entry_url] |
Examples
Basic Remote Configuration
federation({
name: 'host-app',
remotes: {
// Simple pattern
remote_app: '@[window.remote_app_url]/remoteEntry.js',
// With remote name
user_service: 'userService@[window.user_service_url]/remoteEntry.js',
// Multiple variables in path
api_service: '@[window.api_base_url]/services/[window.service_name]/remoteEntry.js'
}
})With Query Parameters
remotes: {
// Cache busting with build hash
remote_app: '@[window.remote_url]/remoteEntry.js?v=[window.BUILD_HASH]',
// Multiple parameters
remote_two: '@[window.api_url]/remoteEntry.js?env=[window.ENV]&v=[window.VERSION]'
}Runtime Configuration
Method 1: JSON Configuration File
// main.jsx
async function loadRemoteConfig() {
try {
const response = await fetch('/config/remotes.json')
const config = await response.json()
// Set window variables
Object.assign(window, config)
// Import app after config is loaded
await import('./bootstrap')
} catch (error) {
console.error('Failed to load remote config:', error)
}
}
loadRemoteConfig()// public/config/remotes.json
{
"remote_app_url": "http://localhost:4173",
"user_service_url": "https://user-service.example.com",
"BUILD_HASH": "abc123def456"
}Method 2: Environment-based Configuration
// config/remotes.js
const configs = {
development: {
remote_app_url: 'http://localhost:4001',
user_service_url: 'http://localhost:4002',
BUILD_HASH: 'dev'
},
production: {
remote_app_url: 'https://remote1.example.com',
user_service_url: 'https://user-service.example.com',
BUILD_HASH: process.env.VITE_BUILD_HASH
}
}
const env = import.meta.env.MODE || 'development'
Object.assign(window, configs[env])Method 3: Direct Assignment
// Set before app initialization
window.remote_app_url = 'https://my-remote.example.com'
window.BUILD_HASH = '12345'
// Then import your app
import('./App')Plugin Options
// vite.config.js
ExternalRemotesPlugin({
// Custom variable prefix (default: 'window.')
variablePrefix: 'globalThis.',
// Enable debug logging
debug: true,
// Custom pattern matching
patterns: [
/\[window\.[\w_]+\]/g,
/\[globalThis\.[\w_]+\]/g
]
})TypeScript Support
// types/window.d.ts
declare global {
interface Window {
remote_app_url: string;
user_service_url: string;
BUILD_HASH: string;
ENV: 'development' | 'staging' | 'production';
}
}
export {};// config.ts
import type { ExternalRemotesPluginOptions } from '@kpsoftec/vite-external-remotes-plugin';
interface RemoteConfig {
remote_app_url: string;
user_service_url: string;
BUILD_HASH: string;
}
export async function loadTypedConfig(): Promise<RemoteConfig> {
const response = await fetch('/config/remotes.json');
const config: RemoteConfig = await response.json();
// Type-safe assignment
Object.assign(window, config);
return config;
}Debug Mode
Enable debug logging to see pattern replacements:
ExternalRemotesPlugin({ debug: true })This will log:
- Which files are being processed
- What patterns are being replaced
- Available window variables
How It Works
The plugin transforms federation configuration at build time by replacing window variable patterns with actual window property access:
Before transformation:
remotes: {
remote_app: '@[window.remote_url]/remoteEntry.js?v=[window.BUILD_HASH]'
}After transformation:
remotes: {
remote_app: window.remote_url + "/remoteEntry.js?v=" + window.BUILD_HASH
}Best Practices
Load configuration before app initialization
// ✅ Correct await loadConfig() await import('./App') // ❌ Wrong - app loads before config import('./App') loadConfig()Provide fallback values
window.remote_url = window.remote_url || 'https://fallback.example.com'Validate required variables
const required = ['remote_app_url', 'BUILD_HASH'] const missing = required.filter(key => !window[key]) if (missing.length > 0) { throw new Error(`Missing config: ${missing.join(', ')}`) }
Troubleshooting
Remote not loading
- Ensure window variables are set before app initialization
- Check browser console for variable values:
console.log(window.remote_app_url)
404 errors
- Verify remote URLs are accessible
- Check if BUILD_HASH or other variables are correctly set
Pattern not replaced
- Ensure the plugin is loaded before the federation plugin
- Check that patterns match exactly:
[window.variable_name]
API Reference
ExternalRemotesPlugin(options?)
Parameters:
options.variablePrefix:string- Variable prefix (default: 'window.')options.debug:boolean- Enable debug logging (default: false)options.patterns:RegExp[]- Custom pattern matching
Returns: Vite plugin that transforms federation remote configurations
Supported Patterns:
@[window.variable]/path→window.variable + "/path"remote@[window.variable]/path→window.variable + "/path"[window.variable]→window.variable
License
MIT
