3、构建工具选型:Webpack vs Vite vs Turbopack、构建配置基础、开发服务器配置

说到模板工程的搭建,构建工具选型永远是第一道坎。

我见过太多团队,一上来就选 Webpack,结果项目跑起来要等 30 秒热更新。也见过有人跟风上 Vite,结果遇到老项目兼容性问题,折腾了两天。

说白了,没有银弹。每种工具都有自己的脾气。

3.1 三大构建工具横向对比

我们先看一张对比表,心里有个底:

特性 Webpack 5 Vite 4/5 Turbopack (Alpha)
启动速度 慢(需全量打包) 极快(基于 ESM) 极快(Rust 编写)
热更新速度 中等(模块多时变慢) 极快(按需编译) 极快(增量编译)
生态成熟度 ★★★★★ ★★★★☆ ★★☆☆☆
配置复杂度 高 低 低
插件丰富度 极丰富 较丰富 有限
生产构建速度 中等 快(Rollup) 快(Rust)
适用场景 大型复杂项目、老项目 新项目、中小型项目 Next.js 生态

3.2 我为什么还在用 Webpack?

说实话,现在让我选新项目,我大概率会选 Vite。但现实是,很多公司有大量存量项目,Webpack 依然是主力。

我在上一家公司接手过一个 5 年历史的后台系统,Webpack 配置写了 400 多行。你想想看,这种项目谁敢轻易换构建工具?

核心结论:

  • 新项目、纯前端项目 → 优先 Vite
  • 老项目、需要深度定制 → 继续 Webpack
  • Next.js 项目 → 等 Turbopack 稳定后再考虑

3.3 构建配置基础(以 Webpack 为例)

不管用哪个工具,核心配置思路是相通的。我习惯把配置拆成三块:

  1. 入口与出口 — 告诉工具从哪里开始,打包到哪里去
  2. Loader 与规则 — 处理不同类型的文件
  3. 插件 — 做 Loader 做不了的事

一个最基础的 Webpack 配置长这样:

// webpack.config.js
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
  // 入口
  entry: './src/index.js',

  // 出口
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'bundle.[contenthash].js',
    clean: true
  },

  // 模块规则
  module: {
    rules: [
      {
        test: /\.jsx?$/,
        exclude: /node_modules/,
        use: {
          loader: 'babel-loader',
          options: {
            presets: ['@babel/preset-env', '@babel/preset-react']
          }
        }
      },
      {
        test: /\.css$/,
        use: ['style-loader', 'css-loader']
      },
      {
        test: /\.(png|svg|jpg)$/,
        type: 'asset/resource'
      }
    ]
  },

  // 插件
  plugins: [
    new HtmlWebpackPlugin({
      template: './public/index.html'
    })
  ],

  // 模式
  mode: 'development'
};

小技巧:contenthash 是缓存利器。文件内容变了,hash 才会变,浏览器就知道该重新下载了。我曾经见过有人没用 hash,每次发版用户都要清缓存,那叫一个痛苦。

3.4 Vite 配置 — 真香警告

Vite 的配置就清爽多了。它基于 ESM,开发时不用打包,按需编译。我第一次用的时候,项目启动速度从 15 秒降到了 2 秒,当时就愣住了。

// vite.config.js
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import path from 'path';

export default defineConfig({
  plugins: [react()],

  resolve: {
    alias: {
      '@': path.resolve(__dirname, 'src')
    }
  },

  server: {
    port: 3000,
    open: true,
    proxy: {
      '/api': {
        target: 'http://localhost:8080',
        changeOrigin: true
      }
    }
  },

  build: {
    outDir: 'dist',
    sourcemap: false,
    rollupOptions: {
      output: {
        manualChunks: {
          vendor: ['react', 'react-dom']
        }
      }
    }
  }
});

看到了吗?Vite 内置了 React 插件支持,不用自己配 Babel。路径别名也直接写在 resolve 里,比 Webpack 的 resolve.alias 直观多了。

3.5 开发服务器配置 — 避坑指南

开发服务器是每天都要打交道的东西。配置不好,一天的心情都毁了。

3.5.1 代理配置

前后端分离开发时,跨域问题是躲不开的。我曾经犯过一个低级错误:把代理路径写成了 /api/(带斜杠),结果请求一直 404。后来才发现,Vite 和 Webpack 的代理路径匹配规则不一样。

// Webpack devServer 代理
devServer: {
  proxy: {
    '/api': {
      target: 'http://localhost:8080',
      pathRewrite: { '^/api': '' },
      changeOrigin: true
    }
  }
}

// Vite 代理(注意!路径匹配规则不同)
server: {
  proxy: {
    '/api': {
      target: 'http://localhost:8080',
      rewrite: (path) => path.replace(/^\/api/, ''),
      changeOrigin: true
    }
  }
}

注意:Webpack 用 pathRewrite,Vite 用 rewrite 函数。别搞混了,不然调试半天找不到原因。

3.5.2 HMR 配置

热模块替换(HMR)是开发体验的核心。Vite 默认就支持,Webpack 需要额外配置:

// Webpack 启用 HMR
const webpack = require('webpack');

module.exports = {
  devServer: {
    hot: true,
    liveReload: false  // 关闭自动刷新,只做热更新
  },
  plugins: [
    new webpack.HotModuleReplacementPlugin()
  ]
};

嗯,这里要注意:如果 HMR 不生效,先检查 entry 文件里有没有加 module.hot.accept()。我刚开始用 Webpack 时,折腾了一下午才发现是这个问题。

3.6 如何选择?我的建议

最后给个实在的建议:

  • 如果你在搭新项目模板 — 无脑选 Vite。开发体验好,配置简单,社区资源也够用。
  • 如果你在维护老项目 — 别急着换工具。先把 Webpack 配置优化好,比如用 cache: { type: 'filesystem' } 开启持久化缓存,能快不少。
  • 如果你在用 Next.js — 可以关注 Turbopack,但目前还是 alpha 阶段,生产环境慎用。

说白了,工具是为人服务的。别为了炫技而选工具,也别因为怕麻烦而拒绝新工具。找到适合团队和项目的,就是最好的。

一句话总结:Vite 是现在,Webpack 是过去,Turbopack 是未来。但「现在」和「过去」之间,还有很长一段路要走。