Feuille de chaleur Webpack¶
Webpack - Module statique Bundler
Webpack est un groupeur de modules statiques pour les applications JavaScript modernes. Lorsque webpack traite votre application, il construit en interne un graphique de dépendance à partir d'un ou de plusieurs points d'entrée et combine ensuite chaque module dont votre projet a besoin en un ou plusieurs paquets.
Sommaire¶
- [Installation] (#installation)
- [Configuration de base] (#basic-configuration)
- [Points d'entrée] (#entry-points)
- [Extrait] (#output)
- [Loaders] (#loaders)
- [Plugins] (#plugins)
- [Mode] (#mode)
- [Serveur de développement] (#development-server)
- [Doublure du code] (#code-splitting)
- [Optimisation] (#optimization)
- [Résolution sur les modules] (#module-resolution)
- [Remplacement du module hôte] (#hot-module-replacement)
- [variables environnementales] (#environment-variables)
- [Construire la production] (#production-build)
- [Configuration avancée] (#advanced-configuration)
- [Performance] (#performance)
- [Dépannage] (#troubleshooting)
- [Meilleures pratiques] (#best-practices)
Installation¶
Installation mondiale¶
Installation locale (recommandée)¶
# Initialize npm project
npm init -y
# Install webpack locally
npm install --save-dev webpack webpack-cli
# Install webpack dev server
npm install --save-dev webpack-dev-server
# Install common loaders and plugins
npm install --save-dev html-webpack-plugin css-loader style-loader file-loader url-loader
```_
### Paquet.json Scripts
```json
{
"scripts": {
"build": "webpack --mode production",
"dev": "webpack --mode development",
"start": "webpack serve --mode development",
"watch": "webpack --mode development --watch"
}
}
```_
## Configuration de base
### Minimal webpack.config.js
```javascript
const path = require('path');
module.exports = {
entry: './src/index.js',
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist')
}
};
Configuration de base complète¶
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: './src/index.js',
output: {
filename: 'bundle.[contenthash].js',
path: path.resolve(__dirname, 'dist'),
clean: true
},
module: {
rules: [
{
test: /\.css$/i,
use: ['style-loader', 'css-loader']
},
{
test: /\.(png|svg|jpg|jpeg|gif)$/i,
type: 'asset/resource'
}
]
},
plugins: [
new HtmlWebpackPlugin({
template: './src/index.html'
})
]
};
Configuration du script de type¶
const path = require('path');
module.exports = {
entry: './src/index.ts',
module: {
rules: [
{
test: /\.tsx?$/,
use: 'ts-loader',
exclude: /node_modules/
}
]
},
resolve: {
extensions: ['.tsx', '.ts', '.js']
},
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist')
}
};
Points d'entrée¶
Point d'entrée unique¶
Points d'entrée multiples¶
Points d'entrée dynamiques¶
Entrée avec dépendances¶
module.exports = {
entry: {
main: {
import: './src/index.js',
dependOn: 'shared'
},
admin: {
import: './src/admin.js',
dependOn: 'shared'
},
shared: 'lodash'
}
};
Produit¶
Configuration de sortie de base¶
const path = require('path');
module.exports = {
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist')
}
};
Sortie à entrées multiples¶
module.exports = {
entry: {
main: './src/index.js',
admin: './src/admin.js'
},
output: {
filename: '[name].bundle.js',
path: path.resolve(__dirname, 'dist')
}
};
Sortie avec Hashing¶
module.exports = {
output: {
filename: '[name].[contenthash].js',
path: path.resolve(__dirname, 'dist'),
clean: true
}
};
Configuration de la voie publique¶
module.exports = {
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist'),
publicPath: '/assets/'
}
};
Produit de la bibliothèque¶
module.exports = {
output: {
filename: 'my-library.js',
path: path.resolve(__dirname, 'dist'),
library: {
name: 'MyLibrary',
type: 'umd'
}
}
};
Chargeurs¶
CSS Chargeurs¶
module.exports = {
module: {
rules: [
{
test: /\.css$/i,
use: ['style-loader', 'css-loader']
},
{
test: /\.s[ac]ss$/i,
use: ['style-loader', 'css-loader', 'sass-loader']
},
{
test: /\.less$/i,
use: ['style-loader', 'css-loader', 'less-loader']
}
]
}
};
Chargeurs JavaScript¶
module.exports = {
module: {
rules: [
{
test: /\.m?js$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env']
}
}
},
{
test: /\.tsx?$/,
use: 'ts-loader',
exclude: /node_modules/
}
]
}
};
Chargeurs de fichiers¶
module.exports = {
module: {
rules: [
{
test: /\.(png|svg|jpg|jpeg|gif)$/i,
type: 'asset/resource'
},
{
test: /\.(woff|woff2|eot|ttf|otf)$/i,
type: 'asset/resource'
},
{
test: /\.(csv|tsv)$/i,
use: ['csv-loader']
},
{
test: /\.xml$/i,
use: ['xml-loader']
}
]
}
};
Modules d'actifs¶
module.exports = {
module: {
rules: [
{
test: /\.png/,
type: 'asset/resource'
},
{
test: /\.html/,
type: 'asset/resource'
},
{
test: /\.txt/,
type: 'asset/source'
},
{
test: /\.jpg/,
type: 'asset',
parser: {
dataUrlCondition: {
maxSize: 4 * 1024 // 4kb
}
}
}
]
}
};
Options du chargeur¶
module.exports = {
module: {
rules: [
{
test: /\.css$/i,
use: [
'style-loader',
{
loader: 'css-loader',
options: {
modules: true,
sourceMap: true
}
}
]
}
]
}
};
Greffons¶
Plugin HTML Webpack¶
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
plugins: [
new HtmlWebpackPlugin({
template: './src/index.html',
filename: 'index.html',
inject: 'body'
})
]
};
Extrait CSS Greffon¶
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
module.exports = {
module: {
rules: [
{
test: /\.css$/i,
use: [MiniCssExtractPlugin.loader, 'css-loader']
}
]
},
plugins: [
new MiniCssExtractPlugin({
filename: '[name].[contenthash].css'
})
]
};
Définir le greffon¶
const webpack = require('webpack');
module.exports = {
plugins: [
new webpack.DefinePlugin({
'process.env.NODE_ENV': JSON.stringify('production'),
'process.env.API_URL': JSON.stringify('https://api.example.com')
})
]
};
Copier le plugin Webpack¶
const CopyWebpackPlugin = require('copy-webpack-plugin');
module.exports = {
plugins: [
new CopyWebpackPlugin({
patterns: [
{ from: 'public', to: 'public' },
{ from: 'assets/images', to: 'images' }
]
})
]
};
Analyseur de groupe Greffon¶
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
module.exports = {
plugins: [
new BundleAnalyzerPlugin({
analyzerMode: 'static',
openAnalyzer: false
})
]
};
Nettoyer le plugin Webpack¶
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
module.exports = {
plugins: [
new CleanWebpackPlugin()
]
};
Mode¶
Mode de développement¶
Mode de production¶
Mode spécifique Configuration¶
module.exports = (env, argv) => {
const isProduction = argv.mode === 'production';
return {
mode: argv.mode,
devtool: isProduction ? 'source-map' : 'eval-source-map',
optimization: {
minimize: isProduction
}
};
};
Serveur de développement¶
Serveur Dev de base¶
Configuration avancée du serveur Dev¶
module.exports = {
devServer: {
static: {
directory: path.join(__dirname, 'dist')
},
compress: true,
port: 3000,
hot: true,
open: true,
historyApiFallback: true,
proxy: {
'/api': {
target: 'http://localhost:8080',
changeOrigin: true,
pathRewrite: {
'^/api': ''
}
}
}
}
};
Serveur HTTPS Dev¶
module.exports = {
devServer: {
https: true,
// or with custom certificates
https: {
key: fs.readFileSync('/path/to/server.key'),
cert: fs.readFileSync('/path/to/server.crt'),
ca: fs.readFileSync('/path/to/ca.pem')
}
}
};
Fractionnement du code¶
Découpe des points d'entrée¶
Importations dynamiques¶
// In your JavaScript code
import('./math.js').then(math => {
console.log(math.add(16, 26));
});
// Or with async/await
async function loadMath() {
const math = await import('./math.js');
return math.add(16, 26);
}
Plugin SplitChunks¶
module.exports = {
optimization: {
splitChunks: {
chunks: 'all',
cacheGroups: {
vendor: {
test: /[\\/]node_modules[\\/]/,
name: 'vendors',
chunks: 'all'
},
common: {
name: 'common',
minChunks: 2,
chunks: 'all',
enforce: true
}
}
}
}
};
fractionnement avancé du code¶
module.exports = {
optimization: {
splitChunks: {
chunks: 'all',
minSize: 20000,
maxSize: 244000,
cacheGroups: {
default: {
minChunks: 2,
priority: -20,
reuseExistingChunk: true
},
vendor: {
test: /[\\/]node_modules[\\/]/,
priority: -10,
reuseExistingChunk: true
},
react: {
test: /[\\/]node_modules[\\/](react|react-dom)[\\/]/,
name: 'react',
chunks: 'all'
}
}
}
}
};
Optimisation¶
Minification¶
const TerserPlugin = require('terser-webpack-plugin');
module.exports = {
optimization: {
minimize: true,
minimizer: [
new TerserPlugin({
terserOptions: {
compress: {
drop_console: true
}
}
})
]
}
};
CSS Optimisation¶
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');
module.exports = {
optimization: {
minimizer: [
new CssMinimizerPlugin()
]
}
};
Shaking d'arbre¶
Runtime Chunk¶
Concaténation du module¶
Résolution du module¶
Résoudre la configuration¶
const path = require('path');
module.exports = {
resolve: {
extensions: ['.js', '.jsx', '.ts', '.tsx', '.json'],
alias: {
'@': path.resolve(__dirname, 'src'),
'components': path.resolve(__dirname, 'src/components'),
'utils': path.resolve(__dirname, 'src/utils')
},
modules: [
'node_modules',
path.resolve(__dirname, 'src')
]
}
};
Résoudre l'automne¶
module.exports = {
resolve: {
fallback: {
"fs": false,
"path": require.resolve("path-browserify"),
"crypto": require.resolve("crypto-browserify")
}
}
};
Remplacement du module à chaud¶
Activer HMR¶
const webpack = require('webpack');
module.exports = {
devServer: {
hot: true
},
plugins: [
new webpack.HotModuleReplacementPlugin()
]
};
RSM dans le code¶
// In your JavaScript modules
if (module.hot) {
module.hot.accept('./library.js', function() {
console.log('Accepting the updated library module!');
// Re-render or update your app
});
}
Réagir à la recharge chaude¶
const ReactRefreshWebpackPlugin = require('@pmmmwh/react-refresh-webpack-plugin');
module.exports = {
module: {
rules: [
{
test: /\.[jt]sx?$/,
exclude: /node_modules/,
use: [
{
loader: 'babel-loader',
options: {
plugins: ['react-refresh/babel']
}
}
]
}
]
},
plugins: [
new ReactRefreshWebpackPlugin()
]
};
Variables d'environnement¶
Définir Plugin pour les variables d'environnement¶
const webpack = require('webpack');
module.exports = {
plugins: [
new webpack.DefinePlugin({
'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV),
'process.env.API_URL': JSON.stringify(process.env.API_URL || 'http://localhost:3000')
})
]
};
Environnement Configuration¶
module.exports = (env, argv) => {
const isProduction = argv.mode === 'production';
return {
mode: argv.mode,
plugins: [
new webpack.DefinePlugin({
'process.env.NODE_ENV': JSON.stringify(argv.mode),
'process.env.API_URL': JSON.stringify(
isProduction ? 'https://api.production.com' : 'http://localhost:3000'
)
})
]
};
};
Plugin DotEnv¶
const Dotenv = require('dotenv-webpack');
module.exports = {
plugins: [
new Dotenv({
path: './.env',
safe: true,
systemvars: true
})
]
};
Construction de production¶
Configuration de production¶
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');
const TerserPlugin = require('terser-webpack-plugin');
module.exports = {
mode: 'production',
entry: './src/index.js',
output: {
filename: '[name].[contenthash].js',
path: path.resolve(__dirname, 'dist'),
clean: true
},
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env']
}
}
},
{
test: /\.css$/,
use: [MiniCssExtractPlugin.loader, 'css-loader']
}
]
},
plugins: [
new HtmlWebpackPlugin({
template: './src/index.html',
minify: {
removeComments: true,
collapseWhitespace: true,
removeRedundantAttributes: true,
useShortDoctype: true,
removeEmptyAttributes: true,
removeStyleLinkTypeAttributes: true,
keepClosingSlash: true,
minifyJS: true,
minifyCSS: true,
minifyURLs: true
}
}),
new MiniCssExtractPlugin({
filename: '[name].[contenthash].css'
})
],
optimization: {
minimize: true,
minimizer: [
new TerserPlugin({
terserOptions: {
compress: {
drop_console: true
}
}
}),
new CssMinimizerPlugin()
],
splitChunks: {
chunks: 'all',
cacheGroups: {
vendor: {
test: /[\\/]node_modules[\\/]/,
name: 'vendors',
chunks: 'all'
}
}
},
runtimeChunk: 'single'
}
};
Construire des scripts¶
{
"scripts": {
"build": "webpack --mode production",
"build:analyze": "webpack --mode production --env analyze",
"build:stats": "webpack --mode production --json > stats.json"
}
}
Configuration avancée¶
Demande multipages¶
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: {
home: './src/home.js',
about: './src/about.js',
contact: './src/contact.js'
},
plugins: [
new HtmlWebpackPlugin({
filename: 'home.html',
template: './src/home.html',
chunks: ['home']
}),
new HtmlWebpackPlugin({
filename: 'about.html',
template: './src/about.html',
chunks: ['about']
}),
new HtmlWebpackPlugin({
filename: 'contact.html',
template: './src/contact.html',
chunks: ['contact']
})
]
};
Microfenêtres Configuration¶
const ModuleFederationPlugin = require('@module-federation/webpack');
module.exports = {
plugins: [
new ModuleFederationPlugin({
name: 'shell',
remotes: {
mfe1: 'mfe1@http://localhost:3001/remoteEntry.js',
mfe2: 'mfe2@http://localhost:3002/remoteEntry.js'
}
})
]
};
Application Web progressive¶
const WorkboxPlugin = require('workbox-webpack-plugin');
module.exports = {
plugins: [
new WorkboxPlugin.GenerateSW({
clientsClaim: true,
skipWaiting: true
})
]
};
Chargeurs personnalisés¶
// custom-loader.js
module.exports = function(source) {
// Transform the source
return `export default ${JSON.stringify(source)}`;
};
// webpack.config.js
module.exports = {
module: {
rules: [
{
test: /\.custom$/,
use: path.resolve(__dirname, 'custom-loader.js')
}
]
}
};
Plugins personnalisés¶
class MyCustomPlugin {
apply(compiler) {
compiler.hooks.emit.tapAsync('MyCustomPlugin', (compilation, callback) => {
console.log('This is an example plugin!');
callback();
});
}
}
module.exports = {
plugins: [
new MyCustomPlugin()
]
};
Rendement¶
Budgets d'exécution¶
module.exports = {
performance: {
maxAssetSize: 250000,
maxEntrypointSize: 250000,
hints: 'warning'
}
};
Chargement paresseux¶
// Dynamic imports for lazy loading
const LazyComponent = React.lazy(() => import('./LazyComponent'));
// Webpack magic comments
import(
/* webpackChunkName: "my-chunk-name" */
/* webpackMode: "lazy" */
'./modules/my-module.js'
);
Préconditionnement et préchargement¶
// Prefetch
import(
/* webpackPrefetch: true */
'./modules/LoginModal.js'
);
// Preload
import(
/* webpackPreload: true */
'./modules/ChartingLibrary.js'
);
Analyse de l'ensemble¶
# Generate stats file
webpack --profile --json > stats.json
# Analyze with webpack-bundle-analyzer
npx webpack-bundle-analyzer stats.json
# Use webpack-bundle-analyzer plugin
npm install --save-dev webpack-bundle-analyzer
Dépannage¶
Questions et solutions communes¶
Module non trouvé¶
// Check resolve configuration
module.exports = {
resolve: {
extensions: ['.js', '.jsx', '.ts', '.tsx'],
alias: {
'@': path.resolve(__dirname, 'src')
}
}
};
Problèmes de mémoire¶
# Increase Node.js memory limit
node --max-old-space-size=4096 node_modules/.bin/webpack
# Or in package.json
{
"scripts": {
"build": "node --max-old-space-size=4096 node_modules/.bin/webpack"
}
}
Temps de construction lents¶
module.exports = {
// Use cache
cache: {
type: 'filesystem'
},
// Exclude node_modules from babel-loader
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: 'babel-loader'
}
]
},
// Use thread-loader for expensive loaders
module: {
rules: [
{
test: /\.js$/,
use: [
'thread-loader',
'babel-loader'
]
}
]
}
};
Questions relatives aux cartes sources¶
module.exports = {
// Different source map options
devtool: 'eval-source-map', // Development
devtool: 'source-map', // Production
devtool: 'cheap-module-source-map', // Faster builds
devtool: false // No source maps
};
Configuration de débogage¶
module.exports = {
stats: {
colors: true,
modules: false,
children: false,
chunks: false,
chunkModules: false
}
};
Meilleures pratiques¶
Organisation de configuration¶
// webpack.common.js
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: './src/index.js',
plugins: [
new HtmlWebpackPlugin({
template: './src/index.html'
})
]
};
// webpack.dev.js
const { merge } = require('webpack-merge');
const common = require('./webpack.common.js');
module.exports = merge(common, {
mode: 'development',
devtool: 'eval-source-map',
devServer: {
static: './dist'
}
});
// webpack.prod.js
const { merge } = require('webpack-merge');
const common = require('./webpack.common.js');
module.exports = merge(common, {
mode: 'production',
devtool: 'source-map'
});
Optimisation des performances¶
- Utiliser le mode de production pour les optimisations
- Activer les tremblements d'arbre pour supprimer le code mort
- Split chunks pour améliorer la mise en cache
- Utiliser le hachage du contenu pour la mise en cache à long terme
- ** Minimiser la taille du paquet** avec les chargeurs et les plugins appropriés
Expérience en matière de développement¶
- Utiliser HMR pour un développement plus rapide
- Configurer les cartes sources pour le débogage
- Set up dev server avec proxy pour les appels API
- Utilisez webpack-bundle-analyzer pour comprendre la composition du faisceau
Code Organisation¶
- Séparer la configuration pour différents environnements
- Alias utilisés pour les importations plus propres
- Organiser les chargeurs par type de fichier
- Les plugins liés au groupe ensemble
Résumé¶
Webpack est un groupeur de modules puissant et flexible qui peut gérer les exigences de construction complexes pour les applications Web modernes. Les principales caractéristiques sont les suivantes :
- Module Bundling: Combine des modules en paquets optimisés
- Loaders: Transformer les fichiers pendant le processus de construction
- Plugins: Extension de la fonctionnalité webpack
- Doublure du code: Diviser le code en petits morceaux pour une meilleure performance
- Remplacement du module hôte: Mettre à jour les modules sans recharger la page complète
- Tree Shaking: Supprimer le code inutilisé des paquets
- Gestion des actifs: Gérer divers types de fichiers et actifs
En maîtrisant la configuration du webpack et en suivant les meilleures pratiques, vous pouvez créer des processus de construction efficaces qui améliorent l'expérience de développement et la performance de l'application.