Advanced Webpack Modular Configuration
Code Splitting (SplitChunksPlugin, Dynamic Imports)
In-Depth SplitChunksPlugin Configuration:
// webpack.config.js
module.exports = {
optimization: {
splitChunks: {
chunks: 'all', // Split all types of chunks (all/async/initial)
minSize: 20000, // Minimum size for generated chunks (20KB)
minRemainingSize: 0, // Minimum size for remaining chunks after splitting
minChunks: 1, // Minimum number of references for a module to be split
maxAsyncRequests: 30, // Maximum parallel requests for on-demand loading
maxInitialRequests: 30, // Maximum parallel requests for entry points
enforceSizeThreshold: 50000, // Size threshold to enforce splitting
cacheGroups: {
defaultVendors: {
test: /[\\/]node_modules[\\/]/,
priority: -10, // Priority
reuseExistingChunk: true // Reuse existing chunk if module is already split
},
default: {
minChunks: 2,
priority: -20,
reuseExistingChunk: true
},
// Custom cache group
reactVendor: {
test: /[\\/]node_modules[\\/](react|react-dom)[\\/]/,
name: 'react-vendor',
chunks: 'all',
priority: 20 // Higher priority
},
utilityVendor: {
test: /[\\/]node_modules[\\/](lodash|moment)[\\/]/,
name: 'utility-vendor',
chunks: 'all'
}
}
}
}
};Dynamic Import Best Practices:
// Basic dynamic import
const loadModule = () => import('./module.js');
// Dynamic import with Webpack magic comments
const loadModuleWithComments = () => import(
/* webpackChunkName: "my-chunk" */
/* webpackPrefetch: true */
'./module.js'
);
// Dynamic import with React.lazy
const LazyComponent = React.lazy(() => import(
/* webpackChunkName: "lazy-component" */
'./LazyComponent'
));
// Dynamic import with error boundary
class ErrorBoundary extends React.Component {
state = { hasError: false };
static getDerivedStateFromError() {
return { hasError: true };
}
render() {
if (this.state.hasError) {
return <div>Component loading failed</div>;
}
return this.props.children;
}
}
const SafeLazyComponent = () => (
<ErrorBoundary>
<React.Suspense fallback={<div>Loading...</div>}>
<LazyComponent />
</React.Suspense>
</ErrorBoundary>
);Tree Shaking Principles and Configuration
Tree Shaking Core Principles:
- ESM Static Analysis: Webpack identifies unused exports by analyzing the static structure of ES modules.
- Side Effect Marking: Declares whether a module has side effects via the
sideEffectsfield inpackage.json. - Compression Optimization: The Terser plugin removes unreferenced code.
Configuration Example:
// webpack.config.js
module.exports = {
optimization: {
usedExports: true, // Mark unused exports
minimize: true, // Enable code minification
concatenateModules: true // Scope hoisting
}
};package.json Configuration:
{
"name": "my-library",
"sideEffects": [
"*.css",
"*.global.js"
],
"exports": {
".": {
"import": "./dist/esm/index.js",
"require": "./dist/cjs/index.js"
},
"./styles": "./dist/styles.css"
}
}Pure Modules Marking:
// Mark pure functions in modules
/*#__PURE__*/
const result = expensiveCalculation();
// Or automatically add markings with Babel plugin
// babel-plugin-transform-remove-pure-annotationsModule Resolution Rules
resolve.alias Configuration:
// webpack.config.js
module.exports = {
resolve: {
alias: {
'@components': path.resolve(__dirname, 'src/components'),
'@utils': path.resolve(__dirname, 'src/utils'),
'react': path.resolve(__dirname, 'node_modules/react') // Force specific React version
}
}
};resolve.extensions Configuration:
// webpack.config.js
module.exports = {
resolve: {
extensions: ['.js', '.jsx', '.ts', '.tsx', '.json'],
// List of extensions that can be omitted
// Webpack tries these extensions in order
}
};Advanced Resolution Configuration:
// webpack.config.js
module.exports = {
resolve: {
modules: [
path.resolve(__dirname, 'src'),
'node_modules' // Default value
],
mainFields: ['browser', 'module', 'main'], // Fields to look up in order
mainFiles: ['index'], // Default file names to look for
symlinks: true, // Follow symbolic links
cacheWithContext: false // Cache with context
}
};Caching and Persistence
Webpack Cache API:
// webpack.config.js
module.exports = {
cache: {
type: 'filesystem', // Use filesystem cache
buildDependencies: {
config: [__filename] // Invalidate cache when webpack config changes
},
cacheDirectory: path.resolve(__dirname, '.webpack_cache'), // Cache directory
compression: 'gzip' // Compress cache
}
};HardSourceWebpackPlugin Configuration:
// webpack.config.js
const HardSourceWebpackPlugin = require('hard-source-webpack-plugin');
module.exports = {
plugins: [
new HardSourceWebpackPlugin({
// Cache directory
cacheDirectory: 'node_modules/.cache/hard-source/[confighash]',
// Config hash calculation
configHash: function(webpackConfig) {
return require('node-object-hash')({sort: false}).hash(webpackConfig);
},
// Environment hash calculation
environmentHash: {
root: process.cwd(),
directories: [],
files: ['package-lock.json', 'yarn.lock']
},
// Cache version
version: '1.0.0'
})
]
};Cache Strategy Comparison:
| Feature | Webpack Cache API | HardSourceWebpackPlugin |
|---|---|---|
| Official Support | Yes | Third-Party Plugin |
| Persistence | Yes | Yes |
| Cache Granularity | Fine-Grained | Medium-Grained |
| Configuration Complexity | Medium | High |
| Use Case | Production Builds | Development Builds |
| Cache Invalidation Control | Precise | Moderate |
Webpack Module Federation and Micro-Frontend Support
Complete Module Federation Configuration:
// Host application webpack.config.js
const ModuleFederationPlugin = require('webpack/lib/container/ModuleFederationPlugin');
module.exports = {
plugins: [
new ModuleFederationPlugin({
name: 'host_app',
remotes: {
app1: 'app1@http://localhost:3001/remoteEntry.js',
app2: 'app2@http://localhost:3002/remoteEntry.js'
},
shared: {
react: {
singleton: true,
requiredVersion: '^17.0.2'
},
'react-dom': {
singleton: true,
requiredVersion: '^17.0.2'
},
lodash: {
eager: true // Load immediately instead of on-demand
}
}
})
]
};
// Remote application webpack.config.js
new ModuleFederationPlugin({
name: 'app1',
filename: 'remoteEntry.js',
exposes: {
'./Button': './src/components/Button',
'./utils': './src/utils'
},
shared: {
react: {
singleton: true,
requiredVersion: '^17.0.2'
},
'react-dom': {
singleton: true,
requiredVersion: '^17.0.2'
}
}
});Dynamic Remote Configuration:
// Dynamically load remote modules
async function loadRemoteModule(remoteName, modulePath) {
if (!window[remoteName]) {
await loadRemoteEntry(remoteName);
}
const container = window[remoteName];
await container.init(__webpack_share_scopes__.default);
const factory = await container.get(modulePath);
return factory();
}
async function loadRemoteEntry(remoteName) {
return new Promise((resolve, reject) => {
const script = document.createElement('script');
script.src = `http://localhost:300${remoteName === 'app1' ? 1 : 2}/remoteEntry.js`;
script.onload = () => resolve();
script.onerror = reject;
document.head.appendChild(script);
});
}
// Usage example
loadRemoteModule('app1', './Button')
.then(Button => {
ReactDOM.render(<Button />, document.getElementById('root'));
})
.catch(err => console.error('Module loading failed', err));Advanced Rollup Modular Configuration
Deep Optimization for Tree Shaking
Side Effect Analysis Configuration:
// rollup.config.js
export default {
treeshake: {
annotations: true, // Respect /*#__PURE__*/ annotations
correctVarValueBeforeDeclaration: true, // Correct variable values before declaration
propertyReadSideEffects: false, // Assume property access has no side effects
tryCatchDeoptimization: false, // Do not optimize try-catch blocks
unknownGlobalSideEffects: false // Assume unknown globals have no side effects
}
};Pure Module Marking:
// package.json
{
"sideEffects": [
"*.css",
"*.global.js",
"**/*.scss"
]
}
// Or more precise control
{
"sideEffects": false // Entire package has no side effects
}Manual Pure Function Marking:
// Mark pure functions in code
/*#__PURE__*/
const result = expensiveCalculation();
// Rollup recognizes these markings and optimizes unused callsPlugin System
Custom Plugin Development:
// my-rollup-plugin.js
export default function myPlugin(options = {}) {
return {
name: 'my-plugin', // Plugin name (required)
// Called at build start
buildStart() {
console.log('Build started');
},
// Called when loading individual files
load(id) {
if (id.endsWith('.custom')) {
return `export default "Processed custom file content";`;
}
return null; // Return null to skip processing
},
// Called during code transformation
transform(code, id) {
if (id.endsWith('.js')) {
// Simple transformation example
return code.replace(/console\.log/g, 'console.debug');
}
return null;
},
// Called during chunk generation
generateBundle(options, bundle) {
// Modify generated bundle
for (const chunk of Object.values(bundle)) {
if (chunk.type === 'chunk') {
chunk.code += '\n// Added trailing code';
}
}
}
};
}Plugin Usage Example:
// rollup.config.js
import myPlugin from './my-rollup-plugin';
import babel from '@rollup/plugin-babel';
import resolve from '@rollup/plugin-node-resolve';
export default {
input: 'src/index.js',
output: {
file: 'dist/bundle.js',
format: 'esm'
},
plugins: [
myPlugin(),
resolve(),
babel({ exclude: 'node_modules/**' })
]
};Multiple Entries and Code Splitting
Multiple Entry Configuration:
// rollup.config.js
export default [
{
input: 'src/main.js',
output: {
file: 'dist/main.js',
format: 'cjs'
}
},
{
input: 'src/admin.js',
output: {
file: 'dist/admin.js',
format: 'cjs'
}
}
];Code Splitting (Using @rollup/plugin-multi-entry):
// rollup.config.js
import multi from '@rollup/plugin-multi-entry';
export default {
input: ['src/entry1.js', 'src/entry2.js'],
output: {
dir: 'dist',
format: 'esm',
manualChunks(id) {
if (id.includes('node_modules')) {
return 'vendor';
}
}
},
plugins: [multi()]
};Dynamic Import Support:
// rollup.config.js
export default {
input: 'src/index.js',
output: {
dir: 'dist',
format: 'esm',
chunkFileNames: '[name]-[hash].js' // Naming for dynamically imported chunks
}
};Deep Integration of Rollup with ES Modules
ESM Output Configuration:
// rollup.config.js
export default {
input: 'src/index.js',
output: {
file: 'dist/bundle.esm.js',
format: 'esm', // ES module format
exports: 'named' // Named exports
}
};Integration with TypeScript:
// rollup.config.js
import typescript from '@rollup/plugin-typescript';
export default {
input: 'src/index.ts',
output: {
file: 'dist/bundle.js',
format: 'esm'
},
plugins: [
typescript({
tsconfig: './tsconfig.json',
declaration: true, // Generate declaration files
declarationDir: 'dist/types'
})
]
};Integration with Babel:
// rollup.config.js
import babel from '@rollup/plugin-babel';
export default {
input: 'src/index.js',
output: {
file: 'dist/bundle.js',
format: 'esm'
},
plugins: [
babel({
babelHelpers: 'bundled',
exclude: 'node_modules/**',
presets: ['@babel/preset-env']
})
]
};Rollup in Library Development
Library Development Configuration Example:
// rollup.config.js
import resolve from '@rollup/plugin-node-resolve';
import commonjs from '@rollup/plugin-commonjs';
import typescript from '@rollup/plugin-typescript';
import { terser } from 'rollup-plugin-terser';
export default {
input: 'src/index.ts',
output: [
{
file: 'dist/library.cjs.js',
format: 'cjs' // CommonJS format
},
{
file: 'dist/library.esm.js',
format: 'esm' // ES module format
},
{
file: 'dist/library.umd.js',
format: 'umd', // UMD format
name: 'MyLibrary' // UMD global variable name
}
],
plugins: [
resolve(),
commonjs(),
typescript({
tsconfig: './tsconfig.json'
}),
process.env.NODE_ENV === 'production' && terser() // Minify in production
]
};package.json Configuration:
{
"name": "my-library",
"version": "1.0.0",
"main": "dist/library.cjs.js", // CommonJS entry
"module": "dist/library.esm.js", // ES module entry
"browser": "dist/library.umd.js", // Browser UMD entry
"types": "dist/types/index.d.ts", // Type declaration file
"files": [
"dist"
],
"scripts": {
"build": "rollup -c",
"build:watch": "rollup -c -w"
},
"devDependencies": {
"@rollup/plugin-commonjs": "^22.0.0",
"@rollup/plugin-node-resolve": "^13.0.0",
"@rollup/plugin-typescript": "^8.0.0",
"rollup": "^2.60.0",
"rollup-plugin-terser": "^7.0.0",
"typescript": "^4.0.0"
}
}Vite Modularization Principles
ESM-Based Development Server
Vite Development Server Working Principles:
- Native ESM Imports: Directly leverages browser-native ES module support.
- File System Routing: Automatic routing based on the file system.
- Instant Server Startup: No bundling required, fast startup.
- On-Demand Compilation: Compiles files only when requested by the browser.
Vite Configuration Example:
// vite.config.js
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
export default defineConfig({
plugins: [react()],
server: {
port: 3000,
open: true,
fs: {
strict: true, // Restrict access to files outside project root
allow: ['..'] // Allow access to parent directory (use with caution)
}
},
esbuild: {
jsxFactory: 'h', // Custom JSX factory function
jsxFragment: 'Fragment'
}
});Vite Development Server Features:
- HMR (Hot Module Replacement): Extremely fast module updates.
- Dependency Pre-Bundling: Pre-compiles node_modules dependencies into ESM.
- CSS Handling: Native CSS imports and hot updates.
- Static Asset Handling: Directly serves static files.
On-Demand Compilation and Hot Updates
On-Demand Compilation Mechanism:
- Browser Request: Browser requests an ESM module.
- Vite Interception: Vite server intercepts the request.
- On-Demand Transformation: Transforms files based on their type.
- Return Result: Returns transformed code.
HMR Implementation Principles:
// Example: Using Vite’s HMR API
if (import.meta.hot) {
import.meta.hot.accept('./module.js', (newModule) => {
// Callback when module updates
console.log('Module updated', newModule);
});
import.meta.hot.dispose(() => {
// Cleanup before module replacement
console.log('Module about to be replaced');
});
}HMR Configuration Options:
// vite.config.js
export default defineConfig({
server: {
hmr: {
protocol: 'ws', // Use WebSocket protocol
host: 'localhost',
port: 3000,
path: '/hmr' // HMR WebSocket path
}
}
});Rollup Bundling and Production Optimization
Production Build Configuration:
// vite.config.js
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import { visualizer } from 'rollup-plugin-visualizer';
export default defineConfig(({ mode }) => ({
plugins: [
react(),
mode === 'analyze' && visualizer() // Production analysis plugin
],
build: {
minify: 'terser', // Use Terser for minification
sourcemap: true, // Generate sourcemap
rollupOptions: {
output: {
manualChunks(id) {
if (id.includes('node_modules')) {
return 'vendor';
}
},
entryFileNames: '[name].[hash].js',
chunkFileNames: '[name].[hash].js',
assetFileNames: '[name].[hash][extname]'
}
}
}
}));Build Optimization Strategies:
- Code Splitting: Properly configure
manualChunks. - Preload Hints: Use
<link rel="modulepreload">. - Resource Compression: Terser for JS, CSS minification.
- Caching Strategy: Content-hashed file names.
Vite’s Module Caching Mechanism
Development Environment Caching:
- Dependency Pre-Build Cache:
node_modules/.vitedirectory. - File System Cache: In-memory file states.
- HMR Cache: Module update states.
Production Environment Caching:
- Content-Hashed File Names: Generate hashes based on file content.
- Long-Term Caching Strategy: Configure correct HTTP cache headers.
- Service Worker Caching: Optional integration.
Cache Control Configuration:
// vite.config.js
export default defineConfig({
build: {
rollupOptions: {
output: {
assetFileNames: 'assets/[name]-[hash][extname]',
chunkFileNames: 'js/[name]-[hash].js',
entryFileNames: 'js/[name]-[hash].js'
}
}
},
server: {
fs: {
strict: true,
cachedChecks: true // Enable cache checks
}
}
});Vite Integration with Vue and React Modularization
Vite + React Integration:
// vite.config.js
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
export default defineConfig({
plugins: [
react({
babel: {
plugins: ['@babel/plugin-transform-runtime']
},
fastRefresh: true // Fast refresh
})
]
});React Component Modularization Example:
// src/components/Button.jsx
import React from 'react';
import PropTypes from 'prop-types';
const Button = ({ text, onClick, variant }) => {
return (
<button
className={`btn ${variant}`}
onClick={onClick}
>
{text}
</button>
);
};
Button.propTypes = {
text: PropTypes.string.isRequired,
onClick: PropTypes.func,
variant: PropTypes.oneOf(['primary', 'secondary'])
};
Button.defaultProps = {
variant: 'primary'
};
export default Button;
// src/App.jsx
import React, { lazy, Suspense } from 'react';
import Button from './components/Button';
const LazyComponent = lazy(() => import('./components/LazyComponent'));
function App() {
return (
<div>
<Button text="Click me" onClick={() => console.log('Clicked')} />
<Suspense fallback={<div>Loading...</div>}>
<LazyComponent />
</Suspense>
</div>
);
}
export default App;Vite + Vue Integration:
// vite.config.js
import { defineConfig } from 'vite';
import vue from '@vitejs/plugin-vue';
export default defineConfig({
plugins: [vue()],
resolve: {
alias: {
'@': '/src'
}
}
});Vue Single File Component Modularization Example:
<!-- src/components/Button.vue -->
<template>
<button :class="['btn', variant]" @click="onClick">
<slot></slot>
</button>
</template>
<script>
export default {
Hydrology: 'AppButton',
props: {
variant: {
type: String,
default: 'primary',
validator: value => ['primary', 'secondary'].includes(value)
}
},
methods: {
onClick() {
this.$emit('click');
}
}
}
</script>
<style scoped>
.btn {
padding: 8px 16px;
border-radius: 4px;
cursor: pointer;
}
.primary {
background-color: #1890ff;
color: white;
}
.secondary {
background-color: #f5f5f5;
color: #333;
}
</style>
<!-- src/App.vue -->
<template>
<div>
<Button text="Click me" @click="handleClick" />
<Suspense>
<template #default>
<div LazyComponent />
</div>
<template #fallback>
return div>Loading...</div>
</template>
</Suspense>
</div>
</template>
<script>
import { defineAsyncComponent } from 'vue';
import Button from './components/Button.vue';
const LazyComponent = defineAsyncComponent(() =>
import('./components/LazyComponent.vue')
);
export default {
components: {
Button,
LazyComponent
},
methods: {
handleClick() {
console.log('Button clicked');
}
}
}
</script>



