基础配置详解

深入学习 Webpack 的基础配置选项,包括 Entry、Output、Resolve 等配置的详细说明和最佳实践。


📋 学习目标

  • ✅ 理解完整的配置结构
  • ✅ 掌握 Entry 的各种配置方式
  • ✅ 掌握 Output 的详细配置
  • ✅ 理解 Resolve 配置(路径解析)
  • ✅ 学会环境变量配置

完整配置结构

基础配置模板

const path = require('path')
 
module.exports = {
  // 入口配置
  entry: './src/index.js',
  
  // 输出配置
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'bundle.js'
  },
  
  // 模式
  mode: 'development',
  
  // 模块处理
  module: {
    rules: []
  },
  
  // 插件
  plugins: [],
  
  // 解析配置
  resolve: {
    extensions: ['.js', '.json'],
    alias: {}
  },
  
  // 开发服务器
  devServer: {},
  
  // 优化配置
  optimization: {}
}

Entry 配置详解

1. 单入口(字符串)

module.exports = {
  entry: './src/index.js'
}

适用场景:单页面应用(SPA)

2. 多入口(对象)

module.exports = {
  entry: {
    main: './src/index.js',
    vendor: './src/vendor.js',
    admin: './src/admin.js'
  }
}

适用场景

  • 需要分离第三方库代码
  • 多页面应用
  • 需要独立的入口点

3. 动态入口(函数)

module.exports = {
  entry: () => {
    return './src/index.js'
  }
}

高级用法:根据条件动态决定入口

module.exports = {
  entry: () => {
    return new Promise((resolve) => {
      // 动态决定入口
      const entry = process.env.NODE_ENV === 'production'
        ? './src/index.prod.js'
        : './src/index.dev.js'
      resolve(entry)
    })
  }
}

4. 数组入口

module.exports = {
  entry: ['./src/index.js', './src/polyfills.js']
}

说明:多个文件会打包到一个 chunk 中


Output 配置详解

基础配置

const path = require('path')
 
module.exports = {
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'bundle.js'
  }
}

完整配置选项

const path = require('path')
 
module.exports = {
  output: {
    // 输出目录(必须是绝对路径)
    path: path.resolve(__dirname, 'dist'),
    
    // 输出文件名(单入口)
    filename: 'bundle.js',
    
    // 输出文件名(多入口,使用占位符)
    filename: '[name].bundle.js',
    
    // 非入口 chunk 的文件名
    chunkFilename: '[name].chunk.js',
    
    // 公共路径(CDN 路径)
    publicPath: '/',
    
    // 清理输出目录
    clean: true,
    
    // 资源模块的文件名
    assetModuleFilename: 'assets/[hash][ext]',
    
    // 输出库的配置(用于库开发)
    library: {
      name: 'MyLibrary',
      type: 'umd'
    }
  }
}

文件名占位符

module.exports = {
  output: {
    filename: '[name].[contenthash:8].js'
  }
}

可用占位符

  • [name] - chunk 名称
  • [id] - chunk ID
  • [hash] - 整个项目的 hash
  • [chunkhash] - chunk 的 hash
  • [contenthash] - 内容的 hash(推荐)
  • [fullhash] - 完整 hash

Hash 长度[contenthash:8] 表示只取前 8 位

多入口输出配置

module.exports = {
  entry: {
    main: './src/index.js',
    vendor: './src/vendor.js'
  },
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'js/[name].[contenthash].js',
    chunkFilename: 'js/[name].[contenthash].chunk.js'
  }
}

输出结果

  • dist/js/main.abc123.js
  • dist/js/vendor.def456.js

Resolve 配置(路径解析)

Resolve 配置告诉 Webpack 如何解析模块路径。

基础配置

module.exports = {
  resolve: {
    // 自动解析的扩展名
    extensions: ['.js', '.json', '.jsx', '.ts', '.tsx'],
    
    // 路径别名
    alias: {
      '@': path.resolve(__dirname, 'src'),
      '@components': path.resolve(__dirname, 'src/components'),
      '@utils': path.resolve(__dirname, 'src/utils')
    },
    
    // 模块查找目录
    modules: [
      path.resolve(__dirname, 'src'),
      'node_modules'
    ]
  }
}

extensions 配置

module.exports = {
  resolve: {
    extensions: ['.js', '.jsx', '.ts', '.tsx']
  }
}

说明:配置后可以省略文件扩展名

// 可以这样导入
import App from './App'  // 自动查找 App.js, App.jsx, App.ts, App.tsx

alias 配置(路径别名)

module.exports = {
  resolve: {
    alias: {
      '@': path.resolve(__dirname, 'src'),
      '@components': path.resolve(__dirname, 'src/components'),
      '@utils': path.resolve(__dirname, 'src/utils'),
      '@assets': path.resolve(__dirname, 'src/assets')
    }
  }
}

使用示例

// 使用别名
import Button from '@components/Button'
import { formatDate } from '@utils/date'
import logo from '@assets/logo.png'
 
// 而不是
import Button from '../../../components/Button'

modules 配置

module.exports = {
  resolve: {
    modules: [
      path.resolve(__dirname, 'src'),  // 优先查找 src 目录
      'node_modules'                    // 然后查找 node_modules
    ]
  }
}

说明:配置后可以直接从 src 目录导入

// 可以直接这样导入
import utils from 'utils'  // 自动从 src/utils 查找

完整 Resolve 配置示例

const path = require('path')
 
module.exports = {
  resolve: {
    extensions: ['.tsx', '.ts', '.js', '.jsx', '.json'],
    alias: {
      '@': path.resolve(__dirname, 'src'),
      '@components': path.resolve(__dirname, 'src/components'),
      '@utils': path.resolve(__dirname, 'src/utils'),
      '@styles': path.resolve(__dirname, 'src/styles'),
      '@assets': path.resolve(__dirname, 'src/assets')
    },
    modules: [
      path.resolve(__dirname, 'src'),
      'node_modules'
    ],
    // 解析包的主入口
    mainFields: ['browser', 'module', 'main'],
    // 解析包的主文件
    mainFiles: ['index']
  }
}

环境变量配置

使用 DefinePlugin

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')
    })
  ]
}

使用 dotenv

npm install --save-dev dotenv-webpack

创建 .env 文件

# .env
NODE_ENV=development
API_URL=http://localhost:8080

配置 webpack

const Dotenv = require('dotenv-webpack')
 
module.exports = {
  plugins: [
    new Dotenv({
      path: '.env',  // 默认是 .env
      safe: false,   // 如果 .env.example 存在,使用它作为模板
      systemvars: true  // 加载系统变量
    })
  ]
}

多环境配置

创建不同环境的 .env 文件

  • .env.development
  • .env.production
  • .env.test

webpack.config.js

const Dotenv = require('dotenv-webpack')
const path = require('path')
 
module.exports = (env) => {
  const envFile = `.env.${env.NODE_ENV || 'development'}`
  
  return {
    plugins: [
      new Dotenv({
        path: path.resolve(__dirname, envFile)
      })
    ]
  }
}

其他重要配置

Context 配置

module.exports = {
  context: path.resolve(__dirname, 'src'),
  entry: './index.js'  // 相对于 context
}

Target 配置

module.exports = {
  target: 'web',  // 默认值,用于浏览器
  // target: 'node',  // 用于 Node.js
  // target: 'electron-main',  // 用于 Electron 主进程
}

Externals 配置

module.exports = {
  externals: {
    jquery: 'jQuery',  // 从 CDN 引入,不打包
    react: 'React',
    'react-dom': 'ReactDOM'
  }
}

配置最佳实践

1. 使用函数式配置

module.exports = (env, argv) => {
  const isProduction = argv.mode === 'production'
  
  return {
    mode: isProduction ? 'production' : 'development',
    output: {
      filename: isProduction
        ? '[name].[contenthash].js'
        : '[name].js'
    }
  }
}

2. 分离配置文件

webpack.common.js

const path = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')
 
module.exports = {
  entry: './src/index.js',
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: '[name].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'
})

webpack.prod.js

const { merge } = require('webpack-merge')
const common = require('./webpack.common.js')
 
module.exports = merge(common, {
  mode: 'production',
  devtool: 'source-map'
})

3. 使用环境变量

module.exports = (env) => {
  return {
    output: {
      publicPath: env.production
        ? 'https://cdn.example.com/'
        : '/'
    }
  }
}

完整配置示例

const path = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const webpack = require('webpack')
 
module.exports = (env, argv) => {
  const isProduction = argv.mode === 'production'
  
  return {
    entry: './src/index.js',
    
    output: {
      path: path.resolve(__dirname, 'dist'),
      filename: isProduction
        ? 'js/[name].[contenthash:8].js'
        : 'js/[name].js',
      chunkFilename: isProduction
        ? 'js/[name].[contenthash:8].chunk.js'
        : 'js/[name].chunk.js',
      publicPath: '/',
      clean: true
    },
    
    mode: isProduction ? 'production' : 'development',
    
    resolve: {
      extensions: ['.js', '.jsx', '.json'],
      alias: {
        '@': path.resolve(__dirname, 'src')
      },
      modules: [
        path.resolve(__dirname, 'src'),
        'node_modules'
      ]
    },
    
    plugins: [
      new HtmlWebpackPlugin({
        template: './src/index.html'
      }),
      new webpack.DefinePlugin({
        'process.env.NODE_ENV': JSON.stringify(argv.mode)
      })
    ]
  }
}

总结

  • Entry:支持字符串、对象、函数等多种配置方式
  • Output:使用占位符实现灵活的文件命名
  • Resolve:配置路径别名和扩展名,简化导入
  • 环境变量:使用 DefinePlugin 或 dotenv 管理环境变量
  • 最佳实践:分离配置、使用函数式配置

下一步


Webpack 基础配置 Entry Output Resolve 环境变量