【总结】2267- 聊聊前端构建工具该怎么选?

科技   2024-12-10 23:22   福建  


前端 Bundler,即前端打包工具,用于处理和优化前端资源(JavaScript、CSS、HTML、图片、字体等)的工具。它将这些资源组合并捆绑成一个或多个文件,以减少加载时间和提高应用性能

为什么需要 bundler

随着现代前端开发的复杂度不断增加,Bundler 作为构建过程的重要组成部分,帮助开发者管理复杂的依赖关系、进行代码拆分、实现模块化开发,并优化构建输出,已经成为开发流程中不可或缺的一部分

  1. 模块化开发:支持现代 JavaScript 模块系统,提高代码可维护性。
  2. 减少 HTTP 请求:将多个文件合并打包,减少请求数量,提高加载速度。
  3. 代码转译与兼容性:将现代 JavaScript 转译成兼容的旧版本。
  4. 优化与压缩:自动优化和压缩代码,减小文件体积。
  5. 静态资源处理:处理和优化 CSS、图片、字体等静态资源。
  6. 提升开发体验:提供热模块替换等功能,提高开发效率。
  7. 代码分割与懒加载:按需加载代码,提高执行性能。
  8. 自动化与任务管理:简化和自动化构建任务,提升开发过程效率。

Webpack

Webpack 是目前最流行的前端打包工具,功能强大,插件生态丰富,适合处理复杂的前端项目。

  • 功能全面、生态丰富、高度可定制,几乎可以满足所有需求
  • 配置繁琐复杂,学习成本高
  • 性能相对于 Go、Rust 编写的 bundler 较慢
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
  entry'./src/index.js'// 入口文件
  output: {
    path: path.resolve(__dirname, 'dist'), // 输出目录
    filename'bundle.js'// 输出文件名
    cleantrue // 清理输出目录
  },
  module: {
    rules: [
      {
        test/.js$/// 匹配.js文件(使用正则表达式)
        exclude/node_modules/// 排除node_modules目录
        use: {
          loader'babel-loader'// 使用babel-loader
        }
      },
      {
        test/.css$/// 匹配.css文件
        use: ['style-loader''css-loader'// 依次使用style-loader和css-loader
      }
    ]
  },
  plugins: [
    new HtmlWebpackPlugin({
      template'./public/index.html'// 指定模板文件
      filename'index.html'// 输出文件名
    })
  ],
  devServer: {
    contentBase: path.join(__dirname, 'public'), // 指定静态文件目录
    compresstrue// 启用gzip压缩
    port9000// 端口号
    opentrue// 自动打开浏览器
    hottrue // 启用热模块替换
  },
  resolve: {
    extensions: ['.js''.jsx'// 自动解析文件扩展名
  },
  mode'development' // 设置模式为开发模式
};

如果应用规模不大,或者暂时对构建性能的要求并不高,Webpack 是最保险的选择

Vite

严格来讲 Vite 并不能仅仅是 bundler,Vite 既是一个前端开发服务器和任务运行器,也是一个 bundler,只不过在不同阶段,它的功能侧重点有所不同

  • 开发阶段:主要对模块进行即时编译和 HMR,而不进行传统的打包,因此这个阶段可以认为它不是传统的 bundler。
  • 生产构建阶段:使用 Rollup 进行完整的打包和优化工作,因此在这个阶段,它确实可以被认为是一个 bundler。

这种双重策略使得 Vite 能够在提供极快开发体验的同时,也能生成高效的生产代码,从而更好地适应现代前端开发的需求。

mport { defineConfig } from 'vite';
import vue from '@vitejs/plugin-vue';

export default defineConfig({
  plugins: [vue()],
  build: {
    rollupOptions: {
      input'src/main.js',
      output: {
        entryFileNames`assets/[name].js`,
        chunkFileNames`assets/[name].js`,
        assetFileNames`assets/[name].[ext]`
      },
    }
  }
});

如果使用 Vue 那可以直接应用 Vite,使用 React 等如果没有历史包袱,Vite 也是一个不错的选择,如果是老项目建议沿用 Webpack 或替换为 Rspack 等和 Webpack 生态兼容的选择

ESBuild

ESBuild 是一个新的打包工具,因其极高的编译速度而迅速受到关注和青睐,使用 Go 语言编写。

  • 高速构建:编译速度非常快,是 Webpack 的数倍。适合开发环境和快速构建。
  • 简单易用:配置简洁,适合快速上手。
  • 生态系统较小:插件和加载器数量不如 Webpack 丰富,某些复杂需求可能无法实现。
  • 功能覆盖不完全:目前不支持所有 Webpack 的高级特性,如复杂的代码分割策略。

ESBuild 取代 Webpack 独立使用的话生态和代码风格=功能的缺失可能会使大问题,但可以作为 Webpack 的一个插件使用,以获得 Webpack 的生态系统和配置灵活性的同时,利用 ESBuild 的高效编译能力来加速构建过程

module.exports = {
  entry'./src/index.tsx',  // 入口文件
  output: {
    filename'bundle.js',  // 打包后的文件名
    path: path.resolve(__dirname, 'dist')  // 输出路径
  },
  module: {
    rules: [
      {
        test/.tsx?$/,  // 匹配 TypeScript 和 TSX 文件
        loader'esbuild-loader',
        options: {
          loader'tsx',  // 适配 TypeScript 和 React 的 JSX
          target'es2015'  // 指定编译目标为 ES2015
        }
      },
      {
        test/.css$/,  // 匹配 CSS 文件
        use: ['style-loader''css-loader']  // 使用 style-loader 和 css-loader 加载 CSS
      }
    ]
  },
  resolve: {
    extensions: ['.ts''.tsx''.js']  // 解析文件扩展名
  },
  devtool'source-map'  // 启用 source map 以便调试
};

Rspack

www.rspack.dev/zh/guide/st…[1]

我们创建 Rspack 的原因,是为了解决在字节跳动维护构建工具时遇到的各种性能问题。由于字节跳动内部存在许多巨石应用,它们都具有复杂的构建配置,生产环境的构建需要耗费十几分钟,甚至超过半小时;开发环境的耗时也超过十几分钟。

我们在 webpack 上尝试了多种方法来优化这些巨石应用,但是效果甚微。我们意识到在 webpack 上的优化已经难以为继,必须要从底层改造,才能适应我们的需求。

Rspack 是字节跳动技术团队为了解决构建性能使用 Rust 开发的 bundler

  • 使用 Rust 编写,并且将大量的 loader 内置,带来了显著的性能提升和配置简化
  • 配置基于 webpack 设计实现,开发者可以非常轻松地将项目从 webpack 迁移至 rspack
  • 虽然 Rspack 内置了一些常见的加载器,但其生态系统的插件和加载器数量不如 Webpack 丰富
  • 作为一个新兴的构建工具,社区支持和文档资源相对较少
  • 与现有工具链和流行框架的集成度不如 Webpack

Rspack 相对 Turbopack 还是很有潜力,但目前在成长期,尤其是作为国人发布的产品,海外的参与度在前期可能有限,考虑到社区支持和文档资源,建议观望

Respack 2024.08.28 发布了 v1.0[2],新项目可以尝试一下了

const path = require('path');

module.exports = {
  entry'./src/index.tsx',
  output: {
    filename'bundle.js',
    path: path.resolve(__dirname, 'dist')
  },
  resolve: {
    extensions: ['.ts''.tsx''.js']
  },
  module: {
    rules: [
      {
        test/.(ts|tsx|js)$/,
        loader'rspack-loader',
        options: {
          loader'tsx',
          target'es2015'
        }
      },
      {
        test/.css$/,
        use: ['style-loader''css-loader']
      }
    ]
  },
  devtool'source-map'
};

Turbopack

Turbopack 是 Webpack 的作者使用 Rust 语言开发一个前端模块化的工具,目标是取代 Webpack,目前 Turbopack 仍然处于 AIpha 阶段,离正式运用到生产环境还有不少时间。

  • 快确实是快,但主要 提升来自于 SWC
  • Turbopack 提供了一些基础插件和扩展,能够支持常见的文件处理和优化任务,但仍然与 Webpack 和其他成熟工具的插件生态系统有差距
  • 作为新兴工具,Turbopack 的社区相对来说还在发展初期,社区规模和活跃度与 Webpack 等工具相比还不大
const path = require('path');

module.exports = {
  entry'./src/index.tsx'// 入口文件
  output: {
    path: path.resolve(__dirname, 'dist'), // 输出目录
    filename'bundle.js'// 输出文件名
  },
  resolve: {
    extensions: ['.ts''.tsx''.js'], // 自动解析扩展名
    alias: {
      '@': path.resolve(__dirname, 'src'), // 别名配置
    },
  },
  module: {
    rules: [
      {
        test/.tsx?$/// 匹配 .ts 或 .tsx 文件
        use'ts-loader'// 使用 ts-loader 处理
        exclude/node_modules/// 排除 node_modules 目录
      },
      {
        test/.css$/// 匹配 .css 文件
        use: ['style-loader''css-loader'], // 依次使用 style-loader 和 css-loader
      }
    ],
  },
  devServer: {
    contentBase: path.join(__dirname, 'public'), // 指定内容目录
    compresstrue// 启用 gzip 压缩
    port3000// 端口号
    hottrue// 启用 HMR(热模块替换)
    opentrue// 自动打开浏览器
  },
  mode'development'// 设置开发模式
};

Turbopack 被设计为 Next.js 的一个未来核心构建工具,以替代 Webpack 和其他构建工具。这种紧密集成在 Next.js 项目中有一定的优势,其它项目不建议使用

Rollup

Rollup 从一开始就设计为打包 JavaScript 库,因此在构建库文件时有很多优化措施。例如,输出更干净的代码结构、更少的开销(boilerplate)等,顺便说一句 Rollup 是第一个广泛应用和推广 Tree Shaking 的 JavaScript 模块打包工具

Rollup 原生支持多种模块格式(如 ES6、CommonJS、UMD、AMD 等),这使得它在发布兼容性库时非常方便。图表四兄弟 D3.js、Three.js、Chart.js、Highcharts 都使用 rollup 进行打包,Echarts、LodashES、Preact、Svelte、dayjs、date-fns 等也在使用 rollup,当然 vite 目前底层还在使用 Rollup 在生产阶段构建(使用 Rust 写的 rolldown[3] 已经开源了,未来可能替换掉 Rollup)

import resolve from '@rollup/plugin-node-resolve';
import commonjs from '@rollup/plugin-commonjs';
import babel from '@rollup/plugin-babel';
import postcss from 'rollup-plugin-postcss';
import { terser } from 'rollup-plugin-terser';

export default {
  input'src/index.js',  // 入口文件
  output: {
    file'dist/bundle.js',  // 输出文件
    format'iife',  // 立即调用函数表达式(IIFE)格式适合浏览器环境
    sourcemaptrue  // 生成sourcemap文件以便调试
  },
  plugins: [
    resolve(),  // 处理模块路径
    commonjs(),  // 转换CommonJS模块为ES6
    babel({
      exclude'node_modules/**',  // 排除node_modules目录
      babelHelpers'bundled'
    }),
    postcss({
      extracttrue  // 将CSS提取到单独的文件
    }),
    terser()  // 压缩输出文件
  ]
};

Rollup 其实没有太多和 Webpack 对比的必要,插件的生态的丰富度和配置灵活性肯定不及 Webpack,但 Rollup 更适合于开发和打包 JavaScript 库,尤其是希望生成干净、体积小的可重用模块时

SWC

虽然我们对 SWC 的理解主要是作为代码转译工具使用,但 SWC/swcpack 也有 bundler 的能力

SWC can be used for both compilation and bundling. For compilation, it takes JavaScript / TypeScript files using modern JavaScript features and outputs valid code that is supported by all major browsers.

但不幸的是 SWC 作者主要精力在 Turbopack 上

This feature is still under construction. Also, the main author of SWC works for Turbopack(opens in a new tab)[4] by Vercel, so this feature is not something that will be actively developed.

建议目前不要使用,反而希望 SWC 在代码转译生态上发发力

本文转载于稀土掘金技术社区,作者:谦行

原文链接:https://juejin.cn/post/7390815289993216054

前端自习课
每日清晨,享受一篇前端优秀文章。
 最新文章