elpis前端工程化-webpack配置

97 阅读4分钟

注:全文理解源于:抖音“哲玄前端”《大前端全栈实践》

webpack是什么

webpack 是JavaScript 应用程序的静态模块打包工具。在前端开发中,我们的项目通常由众多的 JavaScript 模块、CSS 文件、图片等资源组成。webpack 能够智能地分析这些资源之间的依赖关系,并将它们打包成适合在浏览器中加载的静态文件。

webpack 的核心特性

1. 模块打包

Webpack 支持多种模块规范,包括 CommonJS、AMD 和 ES6 模块。无论你使用哪种模块化方式,Webpack 都能将其打包成一个或多个输出文件。通过配置 entry 属性,你可以指定项目的入口文件,Webpack 会从这里开始解析依赖。

2. 加载器(Loaders)

在前端开发中,我们不仅处理 JavaScript 文件,还有 CSS、图片、字体等各类资源。Webpack 的加载器(Loaders)允许你将这些非 JavaScript 文件转换为 JavaScript 模块,从而可以被 Webpack 打包。

3. 插件系统(Plugins)

Webpack 的插件系统是其强大的扩展机制。插件可以在打包过程的各个阶段执行任务,比如优化代码、管理资源、注入环境变量等。

4. 代码分割与懒加载

为了优化应用的加载性能,Webpack 提供了代码分割和懒加载的功能。代码分割可以将代码拆分成多个块(Chunks),然后按需加载。

5. 热模块替换(HMR)

热模块替换(Hot Module Replacement,HMR)是 Webpack 的一大亮点功能。它允许在应用运行时,替换修改过的模块,而无需刷新整个页面。这对于前端开发来说,极大地提高了调试效率。

webpack 在前端工程化中的实践

基础配置文件 webpack.config.js

  • entry:指定了项目的入口文件。
  • output:定义了打包后文件的输出路径和文件名。
  • module:可以为不同类型的文件设置对应的加载器。比如,处理 CSS 文件时使用 style-loadercss-loader,处理 JavaScript 文件时使用 babel-loader 进行语法转换。
  • plugins:这里可以配置各种插件实例,以增强 webpack 的功能。比如,HtmlWebpackPlugin 会根据模板生成 HTML 文件,MiniCssExtractPlugin 会提取 CSS 文件等。
  • optimization:这里配置代码分割,模块合并,缓存,TreeShaking,压缩等优化策略

用到的loader

  • vue-loader:用于处理 .vue 文件,这是 Vue.js 单文件组件的文件格式。它将模板(HTML)、脚本(JavaScript)和样式(CSS)三部分组合在一起的文件解析并打包。
  • babel-loader:用于将 ES6/ES7+ 转换为兼容浏览器的 JavaScript。
  • style-loader:将 CSS 代码注入到 HTML 页面中,通过创建 <style> 标签或将 CSS 代码作为字符串插入到页面中。
  • css-loader:解析 CSS 文件中的 @importurl() 等依赖关系,并将它们转换为模块化的形式,使 Webpack 能够处理这些依赖。
  • sass-loader:将 Sass 或 SCSS 文件编译为普通的 CSS 文件。
  • file-loader:处理文件资源,将文件输出到指定目录,并返回文件的相对路径。常用于处理图片、字体等静态资源。当你需要在代码中引入图片、字体等文件时,file-loader 会将这些文件复制到输出目录中,并返回可以在代码中使用的相对路径。
  • thread-loader:用于将 Loader 的工作分配到多个线程中运行,提高构建性能。它可以在支持多线程的环境中并行处理 Loader 的任务。
// 模块解析配置(决定了要加载解析哪些模块,以及用什么方式去解析)
  module: {
    rules: [
      {
        test: /\.vue$/,
        use: {
          loader: 'vue-loader'
        }
      },
      {
        test: /\.js$/,
        // 只对业务代码进行 babel,加快 webpack 打包速度
        include: [
          path.resolve(process.cwd(), './app/pages')
        ],
        use: {
          loader: 'babel-loader'
        }
      },
      {
        test: /\.(png|jpe?g|gif)(\?.+)?$/,
        use: {
          loader: 'url-loader',
          options: {
            limit: 300,
            esModule: false
          }
        }
      },
      {
        test: /\.css$/,
        use: ['style-loader', 'css-loader']
      },
      {
        test: /\.less$/,
        use: ['style-loader', 'css-loader', 'less-loader']
      },
      {
        test: /\.(eot|svg|ttf|woff|woff2)(\?\S*)?$/,
        use: 'file-loader'
      }
    ]
  },

plugins配置

  • VueLoaderPlugin

它的职能是将你定义过的其他规则复制并应用到 .vue 文件里;例如,如果有一条匹配规则 /.js$/ 的规则,那么它会应用到 .vue 文件中的

  • HtmlWebpackPlugin

它会根据指定的模板文件或默认模板生成一个 HTML 文件,并自动将 Webpack 打包后的 JavaScript 文件和 CSS 文件(如果使用了 CSS 提取插件)引入到 HTML 文件中。

  • CleanWebpackPlugin

在每次构建之前,自动清除输出目录中的旧文件,确保每次构建都是最新的,避免因旧文件残留而引发的问题。

  • webpack.ProvidePlugin

允许你为模块的依赖关系提供一个全局的变量,这样在代码中使用这些变量时就不需要每次都进行导入,简化了代码的编写。

  • webpack.DefinePlugin

允许你在编译时定义全局的常量,这些常量会在代码中被替换为指定的值,常用于配置不同的环境变量(如开发环境、生产环境等)。

  • mini-css-extract-plugin

将 CSS 代码从 JavaScript 文件中提取出来,生成独立的 .css 文件,这样可以更好地利用浏览器的缓存机制,提高应用的性能。

  • html-webpack-inject-attributes-plugin

主要作用是为 html-webpack-plugin 生成的 HTML 文件中的资源标签(如 <script> 和 <link>)注入自定义属性。

  • css-minimizer-webpack-plugin

用于压缩 CSS 代码,减少文件大小,提高应用的加载速度。

代码分割

代码分割的核心思想是将代码分成多个逻辑块,每个块可以独立加载。这样,用户在访问应用时,只需加载当前需要的代码,而不是整个应用的所有代码。这可以显著减少初始加载时间,提高应用的响应速度。

  • 分包策略配置的核心
  • 把 js 文件打包成3中类型
    1. vendor:第三方 lib 库,基本不会改动,除非依赖版本升级
    1. common:业务组件代码的公共部分抽取出来,改动较少
    1. entry.{page}:不同页面 entry 里的业务组件代码的差异部分,会经常改动
  • 目的:把改动和应用频率不一样的 js 区分出来,以达到更好利用浏览器缓存的效果
    // 配置打包输出优化(配置代码分割,模块合并,缓存,TreeShaking,压缩等优化策略)
  optimization: {
    splitChunks: {
      chunks: 'all', // 对同步和异步模块都进行分割
      maxAsyncRequests: 10, // 每次异步加载的最大并行请求数
      maxInitialRequests: 10, // 入口点的最大并行请求数
      cacheGroups: {
        vendor: { // 第三方依赖库
          test: /[\\/]node_modules[\\/]/, // 打包 node_modules 中的文件
          name: 'vendor', // 模块名称
          priority: 20, // 优先级,数字越大,优先级越高
          enforce: true, // 强制执行
          reuseExistingChunk: true, // 复用已有的公共 chunk
        },
        common: { // 公共模块
          name: 'common', // 模块名称
          minChunks: 2, // 被两处引用即被归为公共模块
          minSize: 1, // 最小分割文件大小(1 byte)
          priority: 10, // 优先级
          reuseExistingChunk: true, // 复用已有的公共 chunk
        }
      }
    },
    // 将 webpack 运行时生成的代码打包到 runtime.js
    runtimeChunk: true
  }

热更新(HMR)

它允许在不刷新整个页面的情况下,实时替换、添加或删除代码模块(如 JavaScript、CSS、组件),并保持当前应用状态(如输入框内容、UI 状态)不变。这一技术极大提升了开发效率和调试体验。

  • 技术实现
  • HotModuleReplacementPlugin:启用热模块替换功能,允许在运行时更新模块。
  • webpack-dev-middleware:提供实时编译和内存存储功能,避免每次修改文件后都需要重新编译。
  • webpack-Hot-middleware:与 webpack-dev-middleware 配合使用,实现浏览器的无刷新更新。
    // 生产环境 webpack 配置
const webpackConfig = merge.smart(baseConfig, {
  // 指定开发环境模式
    ...
  // 开发阶段 output 配置
    ...
  // 开发阶段插件
  plugins: [
    // HotModuleReplacementPlugin 用于实现热模块替换 (Hot Module Replacement 简称 HMR)
    // 模块热替换允许在应用程序运行时替换模块
    // 极大的提升开发效率,因为能让应用程序一直保持运行状态
    new webpack.HotModuleReplacementPlugin({
      multiple: false
    })
  ]
});
    // 引用 divMiddleware 中间件(监控文件改动)
app.use(devMiddleware(compiler, {
  // 落地文件
  writeToDisk: (filePath) => filePath.endsWith('.tpl'),

  // 资源路径
  publicPath: webpackConfig.output.publicPath,

  // header 配置
  headers: {
    'Access-Control-Allow-Origin': '*',
    'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, PATCH, OPTIONS',
    'Access-Control-Allow-Headers': 'X-Requested-Width, content-type, Authorization'
  },

  stats: {
    colors: true
  }
}));
// 引用 hotMiddleware 中间件(实现热更新通讯)
app.use(hotMiddleware(compiler, {
  path: `/${DEV_SERVER_CONFIG.HMR_PATH}`,
  log: () => { }
}));

总结

前端工程化的最终目标是让前端开发更加高效、可靠和可持续,以适应不断变化的需求和日益复杂的项目。随着技术的发展,前端工程化的方法和工具也在不断演进,需要开发者持续学习和实践。