Skip to content
On this page

Webpack 入口与输出

Webpack 的入口(Entry)和输出(Output)配置决定了构建过程的起点和结果的存放位置。理解这些配置对于控制打包行为至关重要。

入口配置(Entry)

入口配置告诉 Webpack 从哪个模块开始构建依赖图。

单入口配置

javascript
// 单个入口文件
module.exports = {
  entry: './src/index.js'
  // 等价于
  // entry: {
  //   main: './src/index.js'
  // }
};

多入口配置

javascript
// 多个入口文件
module.exports = {
  entry: {
    home: './src/home.js',
    about: './src/about.js',
    contact: './src/contact.js'
  },
  output: {
    filename: '[name].bundle.js',              // [name] 对应入口键名
    path: path.resolve(__dirname, 'dist')
  }
};

高级入口配置

javascript
module.exports = {
  entry: {
    // 数组形式 - 多个文件作为一个入口
    app: [
      './src/polyfills.js',                   // 垫片文件
      './src/index.js'                        // 主文件
    ],
    // 对象形式 - 详细的入口配置
    admin: {
      import: './src/admin.js',               // 入口文件
      dependOn: 'shared',                     // 依赖于 shared chunk
      filename: 'admin.bundle.js'             // 自定义输出文件名
    },
    shared: {
      import: ['./src/common.js', './src/utils.js'],  // 多个入口文件
      filename: 'shared.js'
    }
  },
  output: {
    filename: '[name].bundle.js',
    path: path.resolve(__dirname, 'dist')
  }
};

输出配置(Output)

输出配置告诉 Webpack 如何输出编译后的文件。

基础输出配置

javascript
const path = require('path');

module.exports = {
  entry: './src/index.js',
  output: {
    filename: 'bundle.js',                    // 输出文件名
    path: path.resolve(__dirname, 'dist'),    // 输出目录的绝对路径
    publicPath: '/'                          // 公共路径
  }
};

多入口输出配置

javascript
module.exports = {
  entry: {
    home: './src/home.js',
    about: './src/about.js'
  },
  output: {
    filename: '[name].[contenthash].js',      // 使用内容哈希
    path: path.resolve(__dirname, 'dist'),
    publicPath: '/assets/'                    // 所有资源的基础路径
  }
};

高级输出配置

javascript
module.exports = {
  entry: {
    app: './src/app.js',
    vendor: './src/vendor.js'
  },
  output: {
    filename: (pathData) => {
      // 根据入口点动态生成文件名
      return pathData.chunk.name === 'vendor' 
        ? 'vendors.[contenthash].js' 
        : '[name].[contenthash].js';
    },
    chunkFilename: '[name].[contenthash].chunk.js',  // 非入口 chunk 文件名
    path: path.resolve(__dirname, 'dist'),
    publicPath: process.env.NODE_ENV === 'production' 
      ? 'https://cdn.example.com/' 
      : '/',
    clean: true,                             // Webpack 5 - 构建前清理输出目录
    assetModuleFilename: 'images/[hash][ext][query]'  // 资源模块输出路径
  }
};

公共路径配置(Public Path)

公共路径决定了构建后资源的引用路径。

静态公共路径

javascript
module.exports = {
  entry: './src/index.js',
  output: {
    filename: 'bundle.js',
    path: path.resolve(__dirname, 'dist'),
    publicPath: '/assets/'                   // 静态资源引用前缀
  }
};

动态公共路径

javascript
module.exports = {
  entry: './src/index.js',
  output: {
    filename: 'bundle.js',
    path: path.resolve(__dirname, 'dist'),
    publicPath: (env) => {
      // 根据环境变量动态设置公共路径
      return env === 'production' 
        ? 'https://cdn.example.com/' 
        : '/';
    }
  }
};

运行时公共路径

javascript
// 在应用代码中动态设置
__webpack_public_path__ = window.location.protocol + '//' + window.location.host + '/assets/';

module.exports = {
  entry: './src/index.js',
  output: {
    filename: 'bundle.js',
    path: path.resolve(__dirname, 'dist'),
    publicPath: ''                           // 在代码中动态设置
  }
};

代码分割与输出

使用 SplitChunksPlugin

javascript
module.exports = {
  entry: {
    home: './src/home.js',
    about: './src/about.js'
  },
  output: {
    filename: '[name].[contenthash].js',
    chunkFilename: '[name].[contenthash].chunk.js',  // 分割后的 chunk 文件名
    path: path.resolve(__dirname, 'dist')
  },
  optimization: {
    splitChunks: {
      chunks: 'all',
      cacheGroups: {
        vendor: {
          test: /[\\/]node_modules[\\/]/,
          name: 'vendors',
          priority: 10,
          chunks: 'all'
        },
        common: {
          name: 'common',
          minChunks: 2,
          priority: 5,
          chunks: 'all',
          enforce: true
        }
      }
    }
  }
};

动态导入输出

javascript
// 在代码中使用动态导入
// src/index.js
import('./components/lazy-component')
  .then(module => {
    // 使用加载的模块
    module.render();
  });

module.exports = {
  entry: './src/index.js',
  output: {
    filename: '[name].[contenthash].js',
    chunkFilename: 'chunks/[name].[contenthash].js',  // 动态导入的 chunk 输出路径
    path: path.resolve(__dirname, 'dist'),
    publicPath: '/'
  }
};

环境特定配置

开发环境配置

javascript
// webpack.dev.js
module.exports = {
  entry: './src/index.js',
  output: {
    filename: '[name].js',                    // 不使用哈希,便于调试
    path: path.resolve(__dirname, 'dist'),
    publicPath: '/',                          // 开发服务器路径
    clean: false                              // 不清理,保留缓存
  }
};

生产环境配置

javascript
// webpack.prod.js
module.exports = {
  entry: './src/index.js',
  output: {
    filename: '[name].[contenthash].js',      // 使用内容哈希,更好的缓存
    chunkFilename: '[name].[contenthash].chunk.js',
    path: path.resolve(__dirname, 'dist'),
    publicPath: 'https://cdn.example.com/',   // CDN 路径
    clean: true                               // 构建前清理输出目录
  }
};

高级输出选项

非常数表达式

javascript
module.exports = {
  entry: './src/index.js',
  output: {
    filename: ({ chunk }) => {
      // 根据 chunk 名称生成不同的文件名
      if (chunk.name === 'main') {
        return 'main.[contenthash].js';
      } else if (chunk.name.startsWith('page-')) {
        return 'pages/[name].[contenthash].js';
      }
      return '[name].[contenthash].js';
    },
    path: path.resolve(__dirname, 'dist'),
    publicPath: '/'
  }
};

跨平台路径处理

javascript
const path = require('path');

module.exports = {
  entry: './src/index.js',
  output: {
    filename: 'bundle.js',
    path: path.resolve(__dirname, 'dist'),
    // 确保路径分隔符在不同操作系统上一致
    pathinfo: true                            // 开发模式下保留路径信息
  }
};

输出优化策略

缓存优化

javascript
module.exports = {
  entry: {
    app: './src/index.js'
  },
  output: {
    filename: '[name].[contenthash].js',      // 使用内容哈希实现长期缓存
    path: path.resolve(__dirname, 'dist'),
    publicPath: '/',
    clean: true
  },
  optimization: {
    moduleIds: 'deterministic',              // 确定性模块 ID
    runtimeChunk: 'single',                   // 单独的运行时 chunk
    splitChunks: {
      cacheGroups: {
        vendor: {
          test: /[\\/]node_modules[\\/]/,
          name: 'vendors',
          chunks: 'all'
        }
      }
    }
  }
};

文件名优化

javascript
module.exports = {
  entry: {
    home: './src/home.js',
    about: './src/about.js'
  },
  output: {
    filename: (pathData) => {
      // 根据路径数据生成有意义的文件名
      const name = pathData.chunk.name;
      if (name === 'runtime') {
        return 'runtime.[contenthash].js';
      } else if (name === 'vendors') {
        return 'vendors.[contenthash].js';
      } else {
        return '[name].[contenthash].js';
      }
    },
    chunkFilename: 'chunks/[name].[contenthash].chunk.js',
    path: path.resolve(__dirname, 'dist'),
    publicPath: '/'
  }
};

小结

入口和输出配置是 Webpack 构建过程的基础,它们决定了构建的起点和结果的组织方式。通过合理的配置,我们可以实现代码分割、缓存优化、环境适配等功能。理解这些配置选项的含义和用法,对于构建高效的 Webpack 配置至关重要。