elpis里程碑二总结——webpack工程化模块

6 阅读4分钟

elpis里程碑二总结——webpack工程化模块

Webpack 多页面应用高级配置:从基础到开发/生产环境拆分

一、整体架构概览

三个配置文件通过 webpack-merge 有机组合,形成  “公共 + 环境专属”  的经典模式:

文件职责
webpack.base.js定义入口生成逻辑、通用 loader、resolve 别名、基础插件及代码分割策略
webpack.dev.js注入 HMR 客户端、设置开发模式、Source Map、开发环境 output
webpack.prod.js启用生产优化(多线程、压缩、CSS 提取、清理目录等)

这种分层既避免了重复配置,又保证了各环境的独立调优。


二、webpack.base.js:构建的基石

2.1 动态多入口与 HtmlWebpackPlugin

  • 使用 glob 扫描 app/pages/**/entry.*.js,自动提取入口名称(如 entry.page1)。
  • 同步生成 HtmlWebpackPlugin 列表,每个插件将模板 entry.tpl 渲染为对应的 .tpl 文件(供后端模板使用),并通过 chunks 只注入当前入口的 JS。

代码要点:

javascript

const entryList = path.resolve(process.cwd(), "./app/pages/**/entry.*.js");
glob.sync(entryList).forEach((file) => {
  const entryName = path.basename(file, ".js");
  pageEntries[entryName] = file;
  HtmlWebpackPluginList.push(
    new HtmlWebpackPlugin({
      template: path.resolve(process.cwd(), 'app/view/entry.tpl'),
      filename: path.resolve(process.cwd(), 'app/public/dist', `${entryName}.tpl`),
      chunks: [entryName],
    })
  );
});

2.2 Loader 配置一览

文件类型Loader 链关键参数
.vuevue-loader需配合 VueLoaderPlugin
.jsbabel-loaderinclude: path.resolve('app/pages')
.scssstyle-loader + css-loader + sass-loader开发环境内嵌 style
.lessstyle-loader + css-loader + less-loader-
.cssstyle-loader + css-loader-
图片(png等)url-loaderlimit: 300,小于 300B 转 base64
字体(eot等)file-loader-

2.3 Resolve 别名与 extensions

javascript

resolve: {
  extensions: ['.js', '.vue', 'less', 'css'],//尝试按顺序解析这些后缀名。如果有多个文件有相同的名字,但后缀名不同,webpack 会解析列在数组首位的后缀的文件 并跳过其余的后缀。
  alias: {
    '$pages': path.resolve(process.cwd(), 'app/pages'),
    '$common': path.resolve(process.cwd(), 'app/pages/common'),
    '$widgets': path.resolve(process.cwd(), 'app/pages/widgets'),
    '$store': path.resolve(process.cwd(), 'app/pages/store'),
  }
}

2.4 通用插件

  • VueLoaderPlugin:处理 .vue 文件的必须插件。
  • webpack.ProvidePlugin:自动加载 Vueaxios_ 到全局。
  • webpack.DefinePlugin:定义 Vue 运行时常量(如 __VUE_OPTIONS_API__)。
  • 动态生成的 HtmlWebpackPluginList(需展开至 plugins 数组)。

2.5 代码分割策略(optimization.splitChunks)

javascript

splitChunks: {
  chunks: 'all',
  cacheGroups: {
    vendors: { test: /[\/]node_modules[\/]/, priority: 20, name: 'vendors' },
    common: { minChunks: 2, priority: 10, name: 'common', minSize: 1 }
  }
},
runtimeChunk: true
  • vendors:第三方依赖(变化极少) → 强缓存。
  • common:被 2 个以上入口引用的业务公共模块 → 中等缓存。
  • runtimeChunk:单独抽离 Webpack 运行时 → 避免因业务变更导致 vendor hash 变化。

⚠️ 注意:minSize: 1 会导致极小的模块也被分割,生产环境建议调至 20KB 左右(可通过环境变量区分)。


三、webpack.dev.js:开发体验至上

3.1 动态注入 HMR 客户端

javascript

Object.keys(baseConfig.entry).forEach(v => {
  if (v !== 'vendor') {
    baseConfig.entry[v] = [
      baseConfig.entry[v],
      `webpack-hot-middleware/client?path=http://${HOST}:${PORT}/${HMR_PATH}&timeout=${TIMEOUT}&reload=true`
    ];
  }
});
  • 仅对业务入口注入(排除 vendor),避免第三方库被热替换影响。
  • 通过 webpack-hot-middleware 实现与开发服务器的 WebSocket 通信。

3.2 开发专属配置项

配置项作用
mode'development'启用开发优化(如 process.env.NODE_ENV 注入)
devtool'eval-cheap-module-source-map'快速重建,源码定位到行(不包含列),仅用于开发
output.filenamejs/[name]_[chunkhash:8].bundle.js使用 chunkhash 便于缓存(开发环境虽不强制,但保持一致性)
output.pathapp/public/dist/dev/输出到 dev 子目录,与生产环境隔离
output.publicPathhttp://127.0.0.1:9002/public/dist/dev/绝对路径,确保通过 dev server 访问静态资源
pluginsnew webpack.HotModuleReplacementPlugin()启用模块热替换(HMR)

3.3 配合 Dev Server 的注意事项

  • 实际开发中,需要启动一个 Express/Koa 服务器,挂载 webpack-dev-middleware 和 webpack-hot-middleware
  • publicPath 必须与中间件提供的资源路径严格一致,否则会出现 404。

四、webpack.prod.js:性能与缓存为王

4.1 输出配置(生产专用)

javascript

output: {
  path: path.join(process.cwd(), "./app/public/dist/prod"),
  filename: "js/[name]_[chunkhash:8].bundle.js",
  publicPath: "/dist/prod",
  crossOriginLoading: "anonymous",
}
  • 输出至 prod 子目录,避免与开发文件混淆。
  • crossOriginLoading: "anonymous" 为动态加载的 chunk 添加 crossorigin 属性,便于 CDN 错误监控。

4.2 多线程编译:HappyPack

javascript

new HappyPack({
  id: 'js',
  loaders: [`babel-loader?${JSON.stringify({ presets: ["@babel/preset-env"], plugins: ['@babel/plugin-transform-runtime'] })}`]
}),
new HappyPack({
  id: 'css',
  loaders: [{ path: 'css-loader', options: { importLoaders: 1 } }]
})
  • 利用 os.cpus().length 开启多线程,加速 JS/CSS 的转译过程。
  • 在 module.rules 中通过 'happypack/loader?id=js' 引用对应的 HappyPack 实例。

⚠️ 演进建议:新时代项目可改用 thread-loader,HappyPack 已停止维护,但逻辑依然值得学习。

4.3 CSS 处理链路

  • MiniCssExtractPlugin.loader 替代 style-loader,将 CSS 抽离为独立文件。
  • CssMinimizerPlugin 在 optimization 阶段压缩 CSS,与 JS 压缩并行。
  • 最终产物:.css 文件带有 [contenthash:8] 指纹,便于长期缓存。

4.4 清理与压缩

  • CleanWebpackPlugin:每次打包前删除 app/public/dist 整个目录,避免旧文件残留。

  • TerserWebpackPlugin

    • parallel: true 启用多进程压缩。
    • cache: true 缓存压缩中间结果。
    • drop_console: true 移除所有 console.* 语句,保证生产环境日志清洁。

4.5 安全与跨域

HtmlWebpackInjectAttributesPlugin 为所有注入的 <script> 和 <link> 标签统一添加 crossorigin="anonymous",提升 CDN 资源错误捕获能力。

4.6 关闭性能警告

javascript

performance: { hints: false }

生产包体积可能较大(尤其包含大图片时),避免无意义的警告干扰 CI 日志。


五、开发 vs 生产:关键差异速查表

对比维度开发环境 (dev)生产环境 (prod)
modedevelopmentproduction
source mapeval-cheap-module-source-map通常关闭(或 hidden-source-map
代码压缩不压缩TerserWebpackPlugin + CssMinimizerPlugin
console 语句保留drop_console: true 删除
CSS 处理style-loader 内联MiniCssExtractPlugin 提取为独立文件
多线程编译未使用(节省启动时间)HappyPack 加速(或 thread-loader
HMR注入 webpack-hot-middleware/client
输出路径app/public/dist/devapp/public/dist/prod
publicPath绝对路径(含协议+端口)相对路径 /dist/prod
清理输出目录否(通常手动或依赖 dev server)CleanWebpackPlugin 自动清理
性能提示默认hints: false

六、最佳实践与常见问题

6.1 构建脚本示例(package.json)

json

"scripts": {
  "build:dev":"node --max_old_space_size=4096 ./app/webpack/dev.js",
   "build:prod":"node ./app/webpack/prod.js"
}
命令内存参数原因
build:dev--max_old_space_size=4096开发构建需要生成 Source Map、保留未压缩代码、支持 HMR,内存开销极大
build:prod无(默认约 1.5GB)生产构建通过代码压缩、多进程拆分、缓存等策略,内存需求相对较低

6.2 路径与端口配置化

建议将 HOST、PORT 等环境相关参数提取到 .env 文件或 config/index.js,避免硬编码。

6.3 HappyPack 的现代替代

javascript

// 使用 thread-loader 替代 HappyPack
module: {
  rules: [{
    test: /.js$/,
    use: ['thread-loader', 'babel-loader'],
    include: [path.resolve('app/pages')]
  }]
}

6.4 开发环境为何不开启多线程?

因为开发阶段强调快速启动增量重建,多线程的线程池创建和通信反而会降低速度。仅在生产构建时启用。

6.5 缓存策略进阶

  • 配合 WebpackManifestPlugin 生成资源映射表,供后端模板动态注入带有 hash 的资源 URL。
  • 对 vendors 和 common chunk 设置 optimization.moduleIds: 'deterministic',避免添加新依赖时影响其他 chunk 的 hash。

七、总结

通过 webpack.base.jswebpack.dev.jswebpack.prod.js 三个文件的精细化拆分,我们实现了一套可维护、高性能、环境友好的 Webpack 多页面构建方案。

  • 基础层:统一入口扫描、Loader 链、别名、公共插件、代码分割策略。
  • 开发层:热更新、可读的 Source Map、绝对路径 publicPath,提升编码效率。
  • 生产层:多线程编译、CSS/JS 极致压缩、内容哈希缓存、安全策略,保障线上性能。