@expozr/webpack-adapter
v2.2.0
Published
Webpack adapter for the Expozr ecosystem
Readme
@expozr/webpack-adapter
Webpack integration for the Expozr module federation ecosystem
The Webpack adapter provides seamless integration between Webpack and the Expozr module federation system. It enables you to build and consume federated modules with Webpack's mature ecosystem, robust optimization features, and extensive plugin architecture.
Features
- 🎯 UMD-First Architecture: Optimized UMD builds for maximum Navigator compatibility
- 🔧 Automatic Configuration: Zero-config setup with intelligent defaults
- 🌐 Development Server Integration: Hot reloading with CORS support
- 📦 Inventory Management: Automatic generation and serving of module inventories
- 🔗 Expozr & Host Support: Both module producers and consumers
- ⚡ Production Optimized: Tree-shaking and code-splitting ready
- 🛡️ Type Safety: Full TypeScript support with optimized configurations
- 🎨 Developer Experience: Warning suppression and clear error messages
- 🌍 Cross-Origin Ready: Built-in CORS configuration for distributed deployments
Installation
npm install @expozr/webpack-adapter
# or
yarn add @expozr/webpack-adapter
# or
pnpm add @expozr/webpack-adapterQuick Start
Expozr (Module Producer)
Create an expozr that exposes modules to be consumed by other applications:
// webpack.config.js
const { createExpozrPlugin } = require("@expozr/webpack-adapter");
module.exports = {
entry: "./src/index.ts",
mode: "development",
plugins: [
createExpozrPlugin(), // Auto-discovers expozr.config.ts
],
devServer: {
port: 3001,
},
};// expozr.config.ts
import { defineConfig } from "@expozr/core";
export default defineConfig({
name: "my-expozr",
expose: {
"./Button": "./src/components/Button.tsx",
"./utils": "./src/utils/index.ts",
},
build: {
format: ["umd"], // UMD for optimal Navigator compatibility
outDir: "dist",
},
});Host (Module Consumer)
Create a host application that consumes remote modules:
// webpack.config.js
const {
createHostPlugin,
createHostWebpackConfig,
} = require("@expozr/webpack-adapter");
module.exports = createHostWebpackConfig({
entry: "./src/index.ts",
plugins: [
createHostPlugin({
config: {
expozrs: {
"design-system": {
url: "http://localhost:3001",
},
"shared-utils": {
url: "https://cdn.example.com/utils",
},
},
},
}),
],
});API Reference
Plugins
createExpozrPlugin(options)
Creates a webpack plugin for expozr applications that expose federated modules.
Options:
configFile?: string- Path to Expozr config file (default: auto-discovery)config?: ExpozrConfig- Direct config object (overrides configFile)outputPath?: string- Custom output path (overrides config)publicPath?: string- Custom public path (overrides config)
Example:
const { createExpozrPlugin } = require("@expozr/webpack-adapter");
// Basic usage - auto-discovers expozr.config.ts
createExpozrPlugin();
// Custom config file
createExpozrPlugin({
configFile: "./my-expozr.config.js",
});
// Direct configuration
createExpozrPlugin({
config: {
name: "my-expozr",
expose: {
"./Component": "./src/Component.tsx",
},
},
});createHostPlugin(options)
Creates a webpack plugin for host applications that consume remote federated modules.
Options:
configFile?: string- Path to host config fileconfig?: HostConfig- Direct config object (overrides configFile)
Example:
const { createHostPlugin } = require("@expozr/webpack-adapter");
createHostPlugin({
config: {
expozrs: {
"ui-components": {
url: "http://localhost:4000",
},
"business-logic": {
url: "https://api.example.com/modules",
},
},
},
});Adapter Class
WebpackAdapter
The main adapter class implementing the Expozr bundler adapter interface.
const { WebpackAdapter } = require("@expozr/webpack-adapter");
const adapter = new WebpackAdapter();
// Configure for expozr build
const expozrWebpackConfig = adapter.configureExpozr(
expozrConfig,
baseWebpackConfig
);
// Configure for host build
const hostWebpackConfig = adapter.configureHost(hostConfig, baseWebpackConfig);
// Check if webpack is available
console.log("Webpack available:", adapter.isAvailable());Methods:
configureExpozr(config, bundlerConfig)- Configure webpack for expozr buildsconfigureHost(config, bundlerConfig)- Configure webpack for host buildsgetDefaultConfig()- Get default webpack configurationisAvailable()- Check if webpack is availablecreateExpozrPlugin(config)- Create ExpozrPlugin instancecreateHostPlugin(config)- Create ExpozrHostPlugin instancegetIgnoreWarnings()- Get warning suppressions for better DX
Utility Functions
createHostWebpackConfig(customConfig)
Creates a webpack configuration optimized for Expozr host applications with sensible defaults.
const { createHostWebpackConfig } = require("@expozr/webpack-adapter");
module.exports = createHostWebpackConfig({
entry: "./src/app.tsx",
plugins: [
// your plugins
],
devServer: {
port: 3000,
},
});Features:
- Pre-configured TypeScript support
- CORS headers for development
- Dynamic import support
- Warning suppression
- Optimized resolve configuration
suppressExpozrWarnings()
Returns ignoreWarnings configuration to suppress common Expozr-related webpack warnings.
const { suppressExpozrWarnings } = require("@expozr/webpack-adapter");
module.exports = {
// ... your webpack config
ignoreWarnings: [
...suppressExpozrWarnings(),
// your custom warning filters
],
};Configuration
Expozr Configuration
Your expozr.config.ts file defines what modules to expose and how to build them:
import { defineConfig } from "@expozr/core";
export default defineConfig({
name: "my-design-system",
// Modules to expose
expose: {
"./Button": "./src/components/Button/index.tsx",
"./Input": "./src/components/Input/index.tsx",
"./Theme": "./src/theme/index.ts",
"./utils/validators": "./src/utils/validators.ts",
},
// Build configuration
build: {
format: ["umd"], // UMD recommended for webpack + Navigator
target: "web", // Target environment
outDir: "dist", // Output directory
publicPath: "/", // Public path for assets
sourcemap: true, // Generate sourcemaps
minify: false, // Minification (use webpack optimization instead)
},
// Module system configuration
moduleSystem: {
primary: "umd",
fallbacks: ["esm"],
strategy: "dynamic",
},
// Dependencies configuration
dependencies: {
react: "^18.0.0",
"react-dom": "^18.0.0",
},
});Host Configuration
Configure which expozrs your host application consumes:
interface HostConfig {
expozrs: {
[expozrName: string]: {
url: string; // Expozr URL
scope?: string; // Optional scope for name resolution
timeout?: number; // Request timeout in ms
retries?: number; // Number of retry attempts
version?: string; // Version constraint (semver)
fallback?: string; // Fallback URL
};
};
// Optional catalog configuration
catalog?: {
url: string;
refreshInterval?: number;
};
// Cache configuration
cache?: {
strategy: "memory" | "localStorage" | "indexedDB";
ttl?: number;
};
}Webpack Configuration
The adapter integrates seamlessly with your existing webpack configuration:
// webpack.config.js
const path = require("path");
const {
createExpozrPlugin,
suppressExpozrWarnings,
} = require("@expozr/webpack-adapter");
module.exports = {
entry: "./src/index.ts",
mode: "development",
module: {
rules: [
{
test: /\.tsx?$/,
use: "ts-loader",
exclude: /node_modules/,
},
{
test: /\.css$/,
use: ["style-loader", "css-loader"],
},
],
},
resolve: {
extensions: [".tsx", ".ts", ".js"],
alias: {
"@": path.resolve(__dirname, "src"),
},
},
plugins: [
createExpozrPlugin({
configFile: "./expozr.config.ts",
}),
],
// Suppress Expozr-related warnings for cleaner output
ignoreWarnings: suppressExpozrWarnings(),
// UMD-optimized output
output: {
path: path.resolve(__dirname, "dist"),
filename: "[name].js",
library: {
name: "[name]",
type: "umd",
},
globalObject: "typeof self !== 'undefined' ? self : this",
clean: true,
},
// Development server with CORS
devServer: {
port: 3001,
headers: {
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Methods": "*",
"Access-Control-Allow-Headers": "*",
},
static: {
directory: path.join(__dirname, "dist"),
},
},
// Production optimizations
optimization: {
// Disable optimizations that break UMD
concatenateModules: false,
usedExports: false,
sideEffects: false,
splitChunks: false,
runtimeChunk: false,
},
};Advanced Configuration
Multiple Output Formats
While UMD is recommended for maximum compatibility, you can configure multiple formats:
// expozr.config.ts
export default defineConfig({
name: "multi-format-expozr",
expose: {
"./utils": "./src/utils.ts",
},
build: {
format: ["umd", "esm"], // Multiple formats
outDir: "dist",
},
});The webpack adapter will generate:
dist/utils.js(UMD format)dist/utils.mjs(ESM format)
TypeScript Integration
The adapter automatically configures TypeScript for optimal expozr builds:
// webpack.config.js
module.exports = {
module: {
rules: [
{
test: /\.tsx?$/,
use: [
{
loader: "ts-loader",
options: {
// The adapter optimizes these settings
compilerOptions: {
target: "es2018",
module: "esnext",
moduleResolution: "node",
declaration: true,
declarationMap: true,
},
},
},
],
},
],
},
};External Dependencies
Configure external dependencies to avoid bundling common libraries:
// webpack.config.js
module.exports = {
externals: {
react: {
commonjs: "react",
commonjs2: "react",
amd: "react",
root: "React", // Global variable name
},
"react-dom": {
commonjs: "react-dom",
commonjs2: "react-dom",
amd: "react-dom",
root: "ReactDOM",
},
},
};Production Optimization
For production builds, enable webpack's optimization features:
// webpack.config.js
const TerserPlugin = require("terser-webpack-plugin");
module.exports = {
mode: "production",
optimization: {
minimize: true,
minimizer: [
new TerserPlugin({
terserOptions: {
compress: {
drop_console: true, // Remove console.log
},
format: {
comments: false, // Remove comments
},
},
extractComments: false,
}),
],
// Enable these optimizations carefully with UMD
usedExports: true,
sideEffects: false,
},
};Development Workflow
Local Development
Start the expozr development server:
cd packages/my-expozr npm run dev # webpack serveStart the host application:
cd apps/host-app npm run devAccess inventory endpoint:
http://localhost:3001/inventory.json
Production Deployment
Build the expozr:
npm run build # webpack --mode=productionDeploy static files:
# Deploy dist/ folder to CDN or static hosting aws s3 sync dist/ s3://my-expozr-bucket/Update host configuration:
const config = { expozrs: { "my-expozr": { url: "https://cdn.example.com/my-expozr", }, }, };
Troubleshooting
Common Issues
1. Module Not Found Errors
Problem: Module not found: Error: Can't resolve 'my-expozr/Button'
Solution: Ensure the expozr is running and the inventory is accessible:
# Check if inventory is available
curl http://localhost:3001/inventory.json
# Verify the expose configuration
cat expozr.config.ts2. CORS Errors
Problem: Access to fetch at 'http://localhost:3001' from origin 'http://localhost:3000' has been blocked by CORS policy
Solution: The adapter automatically configures CORS headers, but verify your setup:
// webpack.config.js
module.exports = {
devServer: {
headers: {
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Methods": "GET, POST, PUT, DELETE, PATCH, OPTIONS",
"Access-Control-Allow-Headers":
"X-Requested-With, content-type, Authorization",
},
},
};3. UMD Global Issues
Problem: Cannot read property 'Button' of undefined when accessing UMD exports
Solution: Verify your library configuration:
// webpack.config.js
module.exports = {
output: {
library: {
name: "MyExpozr", // Must match what host expects
type: "umd",
},
globalObject: "typeof self !== 'undefined' ? self : this",
},
};4. TypeScript Declaration Issues
Problem: Missing or incorrect TypeScript declarations
Solution: Enable declaration generation:
// webpack.config.js
module.exports = {
module: {
rules: [
{
test: /\.tsx?$/,
use: {
loader: "ts-loader",
options: {
compilerOptions: {
declaration: true,
declarationMap: true,
outDir: "dist/types",
},
},
},
},
],
},
};Performance Tips
Use webpack-bundle-analyzer to understand bundle size:
npm install --save-dev webpack-bundle-analyzerEnable tree-shaking for smaller bundles:
module.exports = { optimization: { usedExports: true, sideEffects: false, // or array of files with side effects }, };Use dynamic imports for code splitting:
// Instead of static imports import { heavyUtility } from "./heavy-utils"; // Use dynamic imports const loadHeavyUtility = () => import("./heavy-utils");
Comparison with Other Bundlers
| Feature | Webpack | Vite | Rollup | | ---------------------------- | ------------ | ------------ | ------------ | | UMD Support | ✅ Excellent | ⚠️ Limited | ✅ Good | | Development Speed | ⚠️ Moderate | ✅ Very Fast | ⚠️ Moderate | | Production Optimization | ✅ Excellent | ✅ Good | ✅ Excellent | | Plugin Ecosystem | ✅ Massive | ✅ Growing | ✅ Good | | Configuration Complexity | ⚠️ High | ✅ Low | ⚠️ Moderate | | Navigator Compatibility | ✅ Perfect | ✅ Good | ✅ Good |
When to Choose Webpack
Choose webpack when you:
- Need maximum UMD compatibility
- Have complex build requirements
- Use advanced webpack features (federation, workers, etc.)
- Require extensive plugin ecosystem
- Need mature production optimizations
- Have existing webpack expertise in your team
Consider alternatives when you:
- Want the fastest development experience (→ Vite)
- Need the smallest bundle sizes (→ Rollup)
- Prefer minimal configuration (→ Vite)
Examples
Check out the examples directory for complete working examples:
- Get Started - Basic setup
- React Components - React component federation
- UMD Library - UMD library federation
- Vanilla JS - Pure JavaScript modules
- ESM Support - Modern ESM builds
Migration Guide
From Webpack Module Federation
If you're migrating from webpack's native Module Federation:
// Before: webpack.config.js with ModuleFederationPlugin
module.exports = {
plugins: [
new ModuleFederationPlugin({
name: "myExpozr",
filename: "remoteEntry.js",
exposes: {
"./Button": "./src/Button.tsx",
},
}),
],
};
// After: webpack.config.js with Expozr
module.exports = {
plugins: [
createExpozrPlugin(), // Uses expozr.config.ts
],
};// Create: expozr.config.ts
export default defineConfig({
name: "myExpozr",
expose: {
"./Button": "./src/Button.tsx",
},
});From Other Bundlers
See the migration guide for detailed instructions on migrating from other bundlers.
Contributing
We welcome contributions! Please see our Contributing Guide for details.
Development Setup
Clone the repository:
git clone https://github.com/brunos3d/expozr.git cd expozrInstall dependencies:
npm installBuild the webpack adapter:
cd packages/adapters/webpack npm run buildRun tests:
npm test
License
MIT © Bruno Silva
Related
- @expozr/core - Core Expozr functionality
- @expozr/navigator - Module loading and navigation
- @expozr/vite-adapter - Vite integration
- @expozr/adapter-sdk - Shared adapter utilities
