【前端学习笔记】Webpack

news2025/3/13 19:06:20

1.介绍

在这里插入图片描述
Webpack 是一个现代 JavaScript 应用程序的静态模块打包工具,它将 JavaScript、CSS、图片、字体等资源文件打包成一个或多个静态文件,以供浏览器使用。当 webpack 处理应用程序时,它会在内部从一个或多个入口点构建一个 依赖图(dependency graph),然后将项目中所需的每一个模块组合成一个或多个 bundles,它们均为静态资源。

基本概念

1.入口(Entry)
入口起点(entry point) 指示 webpack 应该使用哪个模块,来作为构建其内部 依赖图(dependency graph) 的开始。进入入口起点后,webpack 会找出有哪些模块和库是入口起点(直接和间接)依赖的。
默认值是 ./src/index.js,但你可以通过在 webpack configuration 中配置 entry 属性,来指定一个(或多个)不同的入口起点。
入口是 Webpack 处理项目的起点。它指定了 Webpack 应该从哪个文件开始分析和构建模块依赖图。一般来说,入口文件是项目的主要 JavaScript 文件。

2.输出(output)
output 属性告诉 webpack 在哪里输出它所创建的 bundle,以及如何命名这些文件。主要输出文件的默认值是 ./dist/main.js,其他生成文件默认放置在 ./dist 文件夹中。输出配置指定了 Webpack 打包后文件的存放位置和文件名称。通常,输出目录会存放在 dist 目录中,文件名称可以通过配置来定制。
output.filename 和 output.path 属性 告诉 webpack bundle 的名称,以及想要 bundle 生成(emit)到哪里。

3.加载器(loader)
webpack 默认只能理解 JavaScript 和 JSON 文件,loader 让 webpack 能够去处理其他类型的文件,并将它们转换为有效 模块,以供应用程序使用,以及被添加到依赖图中。Loaders 是 Webpack 的一个强大功能,它让你能够转换和处理各种类型的文件(如 CSS、图片、TypeScript、SASS 等),让它们可以作为模块导入到 JavaScript 文件中。

4.插件(Plugins)
Plugins 用来执行各种各样的任务,比如优化输出文件、注入环境变量、生成 HTML 文件等。它们在 Webpack 构建过程中执行各种操作。插件允许你在构建过程中做一些额外的操作(例如:代码压缩、生成 HTML 文件、环境变量注入等)。Webpack 插件通过 webpack 对象的 plugins 属性进行配置。

5.模块(Modules)
Webpack 的核心理念是“一切皆模块”。无论是 JavaScript、CSS、图片,还是字体文件等,都可以被视作模块。在 Webpack 中,模块是应用的基本单位,Webpack 通过模块化来处理所有资源。Webpack 会通过依赖图找到所有模块,进行打包。

6.模式(mode)
通过选择 development, production 或 none 之中的一个,来设置 mode 参数,可以启用 webpack 内置在相应环境下的优化。其默认值为 production。

  • development 模式 主要关注开发过程中的效率和可调试性,提供详细的错误信息和调试支持,构建速度较快,但输出的代码未经过压缩,体积较大。
  • production 模式 主要关注优化性能和代码体积,启用代码压缩、树摇、分离代码等优化手段,构建速度较慢,但输出的代码小且高效,更适合用于生产环境。

7.开发服务器(Development Server)
Webpack 提供了一个内置的开发服务器 webpack-dev-server,用于在开发过程中提供热更新、自动刷新等功能。可以通过配置 devServer 来启用这个功能。

const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
  mode: 'development',  // 设置模式
  entry: './src/index.js',  // 入口文件
  output: {
    filename: 'bundle.js',  // 输出文件名
    path: path.resolve(__dirname, 'dist'),  // 输出目录
  },
  module: {
    rules: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        use: 'babel-loader',
      },
    ],
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: './src/index.html',
    }),
  ],
  devServer: {
    contentBase: './dist',  // 开发服务器提供的静态文件目录
    hot: true,  // 启用热更新
  },
};

2.入口Entry

它指定了打包过程的入口文件。entry 配置项的主要作用是告诉 Webpack 从哪个文件开始打包。Webpack 会从这个文件开始,递归地分析所有依赖,最终将这些依赖和文件打包成最终的输出。默认情况下,entry 可以是一个字符串,表示单一的入口文件;也可以是一个对象,表示多个入口文件。entry: string | [string]

用于描述入口的对象。可以使用如下属性:

  • dependOn: 当前入口所依赖的入口。它们必须在该入口被加载前被加载。
  • filename: 指定要输出的文件名称。可以是字符串、模板或函数。
    • [name]:入口文件的名称
    • [contenthash]:基于文件内容生成的哈希值,用于缓存优化
    • [id]:模块的 ID
    • [chunkhash]:模块内容生成的哈希值,用于缓存优化
  • import: 指定启动时需要加载的模块。
  • library: 指定 library 选项,为当前 entry 构建一个 library。用于将打包的代码暴露为一个库,允许其他 JavaScript 环境(比如浏览器、Node.js 或其他框架)使用。libraryTarget:指定库的输出目标,这里使用了 umd(通用模块定义)格式,兼容多种模块化系统。
  • runtime: 处理 Webpack 生成的运行时代码,并将其提取到单独的文件中。如果设置了,就会创建一个新的运行时 chunk。在 webpack 5.43.0 之后可将其设为 false 以避免一个新的运行时 chunk。
  • publicPath: 当该入口的输出文件在浏览器中被引用时,为它们指定一个公共 URL 地址。指定资源的公共 URL 地址,即所有通过 Webpack 打包的资源(如 JavaScript、CSS、图片等)在浏览器中引用时的基础 URL。它允许你在不同的环境下(开发、生产等)动态地配置资源的加载路径。

1.单入口配置
最简单的形式是通过指定一个文件路径,告诉 Webpack 从哪个文件开始构建。

module.exports = {
  entry: './src/index.js',  // 单一入口文件
  output: {
    filename: 'bundle.js',  // 输出的文件
    path: path.resolve(__dirname, 'dist'),  // 输出目录
  },
};

2.多入口配置
如果一个项目有多个入口文件,例如一个多页面应用(MPA),你可以使用一个对象来指定多个入口点。每个入口文件会生成一个独立的输出文件。

module.exports = {
  entry: {
    app: './src/app.js',
    admin: './src/admin.js',
  },
  output: {
    filename: '[name].js',  // 使用入口文件名作为输出文件名
    path: path.resolve(__dirname, 'dist'),
  },
};

3.动态入口
你也可以使用一个函数来动态返回入口配置。这在根据不同的环境或条件来设置入口文件时非常有用。

module.exports = (env) => {
  return {
    entry: env.production ? './src/index.prod.js' : './src/index.dev.js',
    output: {
      filename: 'bundle.js',
      path: path.resolve(__dirname, 'dist'),
    },
  };
};

4.数组形式
也可以为同一个入口点配置多个模块。通过将多个文件放入一个数组中,你可以告诉 Webpack 从多个文件开始打包。Webpack 会将这些文件合并为一个入口文件。

module.exports = {
  entry: ['./src/file_1.js', './src/file_2.js'],
  output: {
    filename: 'bundle.js',
  },
};

3.输出(output)

在 Webpack 中,output 配置项用于指定打包后的文件如何输出。它控制了 Webpack 构建的输出路径、文件名称、以及其他相关的配置,决定了如何组织和存储打包后的文件。

output 配置项的主要属性

  1. path:指定了输出文件的目标目录。它必须是一个绝对路径(相对路径会引发错误)。 这个路径定义了 Webpack 打包后的文件存放位置。

    const path = require('path');
    module.exports = {
      output: {
        path: path.resolve(__dirname, 'dist'), // 输出文件存放目录
      },
    };
    
  2. filename
    filename 属性用于设置输出文件的名称。它可以使用模板变量(例如:[name][hash][chunkhash] 等)来根据文件的特征动态命名。 通常,filename 会用于定义 JavaScript 文件的名称。

    module.exports = {
      output: {
        filename: 'bundle.js', // 输出文件名
      },
    };
    

    你也可以使用模板字符串来生成文件名,以便支持缓存和版本控制:

    module.exports = {
      output: {
        filename: '[name].[contenthash].js', // 输出文件名包含哈希值,便于缓存
      },
    };
    
    • [name]:表示入口的名称。
    • [hash]:表示整个构建的哈希值,常用于生成唯一文件名。
    • [chunkhash]:表示特定 chunk(代码块)的哈希值,适用于按需加载的模块,能更精确地控制缓存。
    • [contenthash]:表示文件内容的哈希值,适用于文件内容变化时修改文件名,通常用在生产环境中。
  3. publicPath:用于指定加载资源(如 JS、CSS、图片等)时的 URL 路径。它可以是一个相对路径或绝对路径,指示浏览器从哪里加载资源。如果你在服务器上部署文件时需要设置路径,这个配置很有用。可以确保在服务器上资源文件能够正确加载,特别是在有 CDN 或特定路径需求时。

    module.exports = {
      output: {
        publicPath: '/assets/', // 所有资源都会通过 /assets/ 路径加载
      },
    };
    
    • 例如,假设你的文件结构是:

      /assets/js/bundle.js
      /assets/css/style.css
      

      那么在 HTML 中引入这些资源时,会自动加上 /assets/ 前缀。

    • 对于 CDN 资源,可以配置为:

      output: {
        publicPath: 'https://cdn.example.com/', // CDN 地址
      },
      
  4. librarylibraryTarget:Webpack 可以将构建结果暴露为可复用的库,适用于开发 JavaScript 库和工具。

    • library 配置项用于指定输出的代码如何暴露给全局作用域,通常在构建库时使用。你可以选择将代码暴露为一个变量、一个对象,或者其他目标。
    • libraryTarget 用于指定输出文件的模块格式。它的值可以是 varumdcommonjs 等。
    module.exports = {
      output: {
        library: 'MyLibrary', // 使得打包后的文件可以通过 MyLibrary 变量访问
        libraryTarget: 'umd', // 输出的文件兼容多种模块格式
      },
    };
    
    • libraryTarget 可以设置为:
      • var:将库暴露为全局变量(适用于浏览器)。
      • umd:通用模块定义,支持浏览器、CommonJS 和 AMD 模块。
      • commonjs:以 CommonJS 模式输出(适用于 Node.js 环境)。
  5. chunkFilename:指定了异步加载的代码块(chunk)生成的文件名。它通常和代码拆分(Code Splitting)一起使用,将代码分割成多个文件,按需加载。

    module.exports = {
      output: {
        chunkFilename: '[name].[chunkhash].js', // 非入口文件(按需加载的文件)命名
      },
    };
    

    chunkFilename 主要用于动态加载的模块文件。它会生成类似于 main.chunk.jsvendor.chunk.js 这样的文件。

  6. pathinfo:是一个布尔值,决定是否在输出的文件中包含模块的信息(如文件的路径信息)。这对于调试很有帮助,但会增加文件体积,因此在生产环境中一般会禁用。

    module.exports = {
      output: {
        pathinfo: true, // 输出文件中包含模块的路径信息
      },
    };
    

    在开发模式下,pathinfo 默认为 true,会在控制台或源代码中显示有关模块的信息。生产环境中,通常会禁用该选项以减小文件体积。

4.加载器(loader)

Webpack 默认只处理 JavaScript 文件,但在现代前端开发中,我们往往需要处理各种不同类型的文件,比如:CSS 文件、图片(如 PNG、JPG、SVG 等)、字体(如 TTF、WOFF 等)、TypeScript 文件、SASS/LESS 文件、JSON 文件以及其他自定义文件格式。加载器通过将这些资源转换为 Webpack 能够处理的模块,使得 Webpack 能够打包、优化这些资源。

Webpack 通过加载器将不同格式的文件转换成模块,整个过程可以理解为:

  1. 解析文件:当 Webpack 遇到某个文件时,它根据配置的规则判断该文件应该使用哪个加载器进行处理。
  2. 执行加载器:加载器会对文件内容进行转换。例如,使用 babel-loader 转换 ES6+ 代码为 ES5,或者用 css-loader 将 CSS 文件转换为 JavaScript 模块。
  3. 返回处理后的内容:加载器会返回处理后的内容,Webpack 会将其继续处理,直到所有依赖的模块都被解析完毕。
  • loader 支持链式调用。链中的每个 loader 会将转换应用在已处理过的资源上。一组链式的 loader 将按照相反的顺序执行。链中的第一个 loader 将其结果(也就是应用过转换后的资源)传递给下一个 loader,依此类推。最后,链中的最后一个 loader,返回 webpack 所期望的 JavaScript。
  • loader 可以是同步的,也可以是异步的。
  • loader 运行在 Node.js 中,并且能够执行任何操作。
  • loader 可以通过 options 对象配置(仍然支持使用 query 参数来设置选项,但是这种方式已被废弃)。
module.exports = {
  module: {
    rules: [
      {
        test: /\.css$/, // 处理 .css 文件
        use: ['style-loader', 'css-loader'], // 使用 css-loader 和 style-loader
      },
      {
        test: /\.js$/, // 处理 .js 文件
        exclude: /node_modules/, // 排除 node_modules 文件夹中的文件
        use: 'babel-loader', // 使用 babel-loader 进行转换
      },
    ],
  },
};

常见的加载器

  1. babel-loader(用于 JavaScript 转译)

    • babel-loader 用于将 ES6+ 代码转译为浏览器兼容的 ES5 代码。
    • 配合 Babel 使用,通常需要配合 .babelrc 配置文件或 babel.config.js 文件来指定使用的转译规则。

    示例配置:

    {
      test: /\.js$/,
      exclude: /node_modules/,
      use: {
        loader: 'babel-loader',
        options: {
          presets: ['@babel/preset-env'], // 使用 @babel/preset-env 转译 ES6+ 语法
        },
      },
    }
    
  2. css-loader(用于处理 CSS)

    • css-loader 用于解析和转换 CSS 文件。它会将 CSS 转换成一个 JavaScript 模块,允许你通过 import 语句导入 CSS 文件。

    示例配置:

    {
      test: /\.css$/,
      use: ['style-loader', 'css-loader'], // 先用 css-loader 解析,再用 style-loader 将其注入到 HTML 文件中
    }
    
  3. style-loader(用于将 CSS 注入到 HTML 中)

    • style-loader 用于将 JavaScript 中的 CSS 插入到 HTML 文件的 <style> 标签中。它通常和 css-loader 一起使用。

    示例配置:

    {
      test: /\.css$/,
      use: ['style-loader', 'css-loader'],
    }
    
  4. sass-loaderless-loader(用于处理 SASS/LESS)

    • sass-loaderless-loader 分别用于处理 SASS 和 LESS 文件,并将它们转换为 CSS。使用时通常还需要配合 css-loaderstyle-loader

    示例配置(处理 SASS 文件):

    {
      test: /\.scss$/,
      use: ['style-loader', 'css-loader', 'sass-loader'], // 顺序很重要
    }
    
  5. file-loaderurl-loader(用于处理文件)

    • file-loader 用于将文件复制到输出目录,并返回文件的 URL。它常用于图片、字体等资源的处理。
    • url-loader 类似于 file-loader,但它可以将小于指定大小的文件转为 base64 编码,减少网络请求。

    示例配置(处理图片):

    {
      test: /\.(png|jpg|gif)$/,
      use: 'file-loader', // 使用 file-loader 处理图片文件
    }
    

    示例配置(使用 url-loader,将图片小于 8kb 的转换为 base64):

    {
      test: /\.(png|jpg|gif)$/,
      use: 'url-loader?limit=8192', // 小于 8KB 的图片将转为 base64
    }
    
  6. html-loader(用于处理 HTML 文件中的资源)

    • html-loader 用于将 HTML 文件中的资源(如图片、字体)转换为合适的路径。它会将 HTML 文件中的静态资源引入到打包结果中。

    示例配置:

    {
      test: /\.html$/,
      use: 'html-loader', // 处理 HTML 文件中的资源
    }
    
  7. json-loader(用于加载 JSON 文件)

    • json-loader 用于加载 JSON 文件。自 Webpack 2 版本起,JSON 文件已经被 Webpack 内置支持,因此不需要额外的 loader,除非使用特殊的配置或版本。

    示例配置:

    {
      test: /\.json$/,
      use: 'json-loader', // 不常用,Webpack 2 以上版本已内建支持
    }
    
  8. ts-loaderawesome-typescript-loader(用于 TypeScript 文件)

    • ts-loaderawesome-typescript-loader 用于将 TypeScript 文件(.ts/.tsx)转译为 JavaScript 文件。

    示例配置:

    {
      test: /\.tsx?$/,
      use: 'ts-loader', // 使用 ts-loader 处理 TypeScript 文件
    }
    

加载器的执行顺序

当 Webpack 处理一个文件时,它会o从右到左(或从下到上)地取值(evaluate)/执行(execute)配置的加载器。Webpack 会从 use 数组的 右向左 执行加载器(如果有多个加载器时)。这意味着,首先应用数组中的最后一个加载器,然后向前应用加载器。需要注意的是,加载器的顺序非常重要,先执行的加载器处理内容较为原始,后执行的加载器处理的是更高层次的内容。

例如,处理 scss 文件时:

  1. sass-loader:将 SASS 编译为 CSS。
  2. css-loader:将 CSS 转换为 JavaScript 模块。
  3. style-loader:将最终的 CSS 插入到 HTML 文件中。

自定义 loader
自定义 loader是一个 Node.js 模块,它导出一个函数来处理文件内容。

module.exports = function (source) {
  // 对文件内容进行处理
  return `export default ${JSON.stringify(source)}`;
};

然后在 Webpack 配置中使用自定义 loader:

module: {
  rules: [
    {
      test: /\.txt$/,
      use: path.resolve(__dirname, 'my-loader.js') // 使用自定义 loader
    }
  ]
}

5.插件(Plugins)

插件目的在于解决 loader 无法实现的其他事。Webpack 插件是一个具有 apply 方法的 JavaScript 对象。apply 方法会被 webpack compiler 调用,并且在 整个 编译生命周期都可以访问 compiler 对象。
插件不同于加载器(Loader),加载器主要负责转换资源文件,而插件则可以在构建过程中执行更复杂的任务,比如优化、打包管理、环境配置、文件生成等。通过插件,开发者可以干预 Webpack 的构建过程,实现从构建流程的各个环节对项目进行深入的定制和优化。

插件通过 Webpack 提供的 生命周期钩子(Hooks) 与构建过程进行交互。在构建过程中,Webpack 会触发一系列的事件,插件通过监听这些事件并执行相应的操作来完成工作。

插件通常是在 Webpack 配置文件中通过 plugins 数组进行配置,插件的调用是同步或异步的,具体取决于插件的设计。

插件通常是通过 new PluginName() 的方式来初始化,并传入必要的配置参数。WebPack 配置文件中的 plugins 是一个数组,所有的插件实例都在这个数组中。

const HtmlWebpackPlugin = require('html-webpack-plugin');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');

module.exports = {
  // ...其他配置
  plugins: [
    new CleanWebpackPlugin(), // 在每次构建之前清理输出目录
    new HtmlWebpackPlugin({
      template: './src/index.html', // 使用自定义的 HTML 模板
      inject: 'body', // 将脚本标签插入到 <body> 中
    }),
  ],
};

常见插件

  1. HtmlWebpackPlugin

    • HtmlWebpackPlugin 用于简化 HTML 文件的创建,特别是在 Webpack 打包时自动插入所有生成的资源文件(如 JS、CSS)。
    • 它能够自动生成一个 index.html 文件,并将输出的 JS 和 CSS 文件插入到该文件中。

    示例配置:

    const HtmlWebpackPlugin = require('html-webpack-plugin');
    
    module.exports = {
      plugins: [
        new HtmlWebpackPlugin({
          template: './src/index.html', // 自定义模板
          filename: 'index.html', // 输出文件名
          inject: 'body', // 将所有 JS 脚本标签插入到 <body> 中
        }),
      ],
    };
    
  2. CleanWebpackPlugin

    • CleanWebpackPlugin 插件用于在每次构建前清空输出目录。这样可以确保不会留下旧的文件,避免生成无用文件。
    • 它通常与 output.path 配合使用。

    示例配置:

    const { CleanWebpackPlugin } = require('clean-webpack-plugin');
    
    module.exports = {
      plugins: [
        new CleanWebpackPlugin(), // 清理 dist 目录
      ],
    };
    
  3. MiniCssExtractPlugin

    • MiniCssExtractPlugin 用于将 CSS 从 JavaScript 文件中提取出来,生成独立的 CSS 文件。这对于生产环境中的性能优化非常有用,特别是当你有大量的 CSS 时。

    示例配置:

    const MiniCssExtractPlugin = require('mini-css-extract-plugin');
    
    module.exports = {
      module: {
        rules: [
          {
            test: /\.css$/,
            use: [MiniCssExtractPlugin.loader, 'css-loader'],
          },
        ],
      },
      plugins: [
        new MiniCssExtractPlugin({
          filename: '[name].[contenthash].css', // 输出文件名包含哈希值
        }),
      ],
    };
    
  4. TerserWebpackPlugin

    • TerserWebpackPlugin 是 Webpack 默认用于压缩 JavaScript 代码的插件。它可以删除无用的代码,减小输出文件的体积。
    • 默认情况下,在 production 模式下启用此插件。

    示例配置:

    const TerserWebpackPlugin = require('terser-webpack-plugin');
    
    module.exports = {
      optimization: {
        minimize: true, // 开启代码压缩
        minimizer: [new TerserWebpackPlugin()],
      },
    };
    
  5. CopyWebpackPlugin

    • CopyWebpackPlugin 用于将静态资源从源目录复制到输出目录(比如复制图片、字体等文件)。

    示例配置:

    const CopyWebpackPlugin = require('copy-webpack-plugin');
    
    module.exports = {
      plugins: [
        new CopyWebpackPlugin({
          patterns: [
            { from: 'src/assets', to: 'assets' }, // 将 src/assets 目录复制到 dist/assets
          ],
        }),
      ],
    };
    
  6. BundleAnalyzerPlugin

    • BundleAnalyzerPlugin 用于可视化 Webpack 打包生成的文件大小,有助于发现哪些模块占用了较多的空间,从而进行性能优化。

    示例配置:

    const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer');
    
    module.exports = {
      plugins: [
        new BundleAnalyzerPlugin(), // 启动 Bundle 分析工具
      ],
    };
    
  7. DefinePlugin

    • DefinePlugin 用于在代码中创建全局常量,通常用于区分不同的环境(如开发环境和生产环境)。
    • 比如,我们可以通过这个插件在代码中注入 process.env.NODE_ENV,以便进行条件渲染。

    示例配置:

    const webpack = require('webpack');
    
    module.exports = {
      plugins: [
        new webpack.DefinePlugin({
          'process.env.NODE_ENV': JSON.stringify('production'), 
        }),
      ],
    };
    

Webpack 插件通过监听 Webpack 提供的 钩子(hooks) 来与构建流程进行交互。Webpack 的构建过程是由多个阶段组成的,插件可以在这些阶段中执行不同的任务。插件通常使用 Webpack Compiler APIWebpack Compilation API 来访问构建过程中的各个阶段。

  • apply():插件的核心方法。所有插件都需要实现 apply 方法,这个方法会在插件实例化时被调用。在 apply 方法中,插件可以通过 Webpack 提供的钩子和事件与构建过程进行交互。
  • 钩子:Webpack 提供了多个钩子供插件使用,如 emitafterCompiledone 等。插件可以在这些钩子中添加自定义逻辑。

6.模块(Modules)

在 Webpack 中,模块是构成应用程序的基本单元。任何在 Webpack 配置中需要被打包的资源,都被视为模块。

  1. 模块解析: Webpack 会从项目的入口文件开始,递归地分析文件中的依赖关系。它会逐步识别所有 import 或 require 引入的模块,并解析这些模块的内容。
  2. 使用加载器(Loader): Webpack 处理每个模块时,使用加载器来转换非 JavaScript 模块(如 CSS、图片、SASS 等)。加载器会根据配置的规则,逐步将不同类型的文件转换为 Webpack 可以理解的模块。
  3. 模块打包: Webpack 会收集所有模块,建立模块之间的依赖图,然后将这些模块和依赖关系打包成最终的输出文件。Webpack 会通过 代码分割(Code Splitting) 来决定将哪些模块打包成单独的文件。

Webpack 会从入口文件开始,递归地解析每个模块的依赖关系。所有模块通过 import 或 require 引入其他模块时,Webpack 会追踪这些依赖,并将它们组织成一个 依赖图(Dependency Graph)。
Webpack 不仅会解析和打包这些模块,还会根据配置的优化策略进行代码分割(Code Splitting)。这样可以将代码分成多个独立的文件,按需加载,优化页面的加载性能。
入口代码分割: Webpack 会根据入口文件,将不同的模块打包成独立的文件。比如,在多个页面之间共享一些代码时,Webpack 会将共享的代码提取成单独的文件。
动态导入(Dynamic Imports): 通过动态导入,Webpack 可以在代码运行时按需加载模块,减少初始加载的包体积。动态导入使用 import() 函数来实现。

在 Webpack 中,每个模块的内容都会被缓存,以便在后续的构建过程中加速构建速度。Webpack 会基于模块的 内容哈希(content hash) 来判断是否需要重新构建模块,这样能够避免不必要的重复构建,提升构建效率。
持久化缓存(Persistent Caching):从 Webpack 5 开始,Webpack 支持持久化缓存(通过硬盘缓存),这样即使是开发环境中的模块,也能在下一次构建时快速加载。

为什么要使用代码分割?

  1. 减少初次加载时间:如果所有代码都打包成一个文件,用户访问时必须等待整个文件加载完才能使用应用。通过代码分割,只有用户当前需要的部分才会被加载,从而加速页面的首次加载。
  2. 按需加载:通过动态导入,WebPack 可以根据用户操作或需求,加载页面所需的特定模块。这对于大型应用非常重要,可以避免加载不必要的资源。
  3. 缓存优化:当代码发生变化时,整个打包文件都会更新并重新下载。通过将不常变化的公共代码(如第三方库)提取为单独的文件,浏览器可以缓存这些文件,避免不必要的重新加载。
  4. 提高模块复用:通过将公共代码提取成独立的文件,多个页面或入口点可以复用这些模块,避免重复加载相同的内容。

7.模式(mode)

在 Webpack 中,mode 是一个非常重要的配置项,它用于告诉 Webpack 你希望构建过程的目标环境,以便 Webpack 根据该模式优化输出内容。mode 主要有三个可选值:development、production 和 none。每个模式都有不同的优化策略和行为,目的是根据不同的构建需求(开发还是生产环境)来调整 Webpack 的行为,从而提高构建性能和优化输出结果。

  1. development(开发模式)
    在开发模式下,Webpack 主要关注的是构建速度和开发过程中的调试体验,因此它会做以下优化:

    • Source Maps:Webpack 会生成源映射(source maps),这样你可以在浏览器中查看原始的源代码,而不仅仅是打包后的代码。源映射使得调试过程更加简便。
    • 不压缩代码:为了便于调试,Webpack 默认不会压缩 JavaScript 文件,以保留代码的可读性。
    • 更快的构建速度:Webpack 会做一些优化,使得构建过程更加快速,但牺牲了一些代码体积的优化。
    • 更详细的错误和警告信息:开发模式下,Webpack 会提供更详细的错误提示和警告信息,帮助开发者快速定位问题。
  2. production(生产模式)
    在生产模式下,Webpack 的主要目标是优化代码体积和性能,因此它会做以下优化:

    • 代码压缩:Webpack 会使用 TerserPlugin 来压缩 JavaScript 代码,从而减小文件体积。
      优化打包体积:Webpack 会启用一些优化策略来删除无用的代码(比如死代码、未使用的模块等),以减少最终打包文件的大小。
    • 去除开发相关的代码:在生产环境下,Webpack 会去除一些只对开发有用的功能,比如调试信息、警告和源映射等。
    • 自动启用 ModuleConcatenationPlugin:这个插件会将多个模块合并成一个函数调用,减少运行时的开销,提高执行效率。
    • 使用更精简的错误和警告输出:在生产环境下,Webpack 会将错误和警告信息压缩和精简,以提高构建效率和减少输出日志的冗余。
  3. none(无模式)
    none 模式基本上禁用 Webpack 的所有默认优化配置。在这种模式下,Webpack 不会自动启用任何优化,它会执行最基础的打包工作,适合一些特殊的需求或当你希望完全控制优化策略时使用。
    通常,如果你不希望 Webpack 根据模式自动进行优化,或者你想要在自己的配置中完全控制构建过程,那么你可以使用 none 模式。

8.开发服务器(Development Server)

Webpack 的开发服务器(webpack-dev-server)通过搭建一个本地服务器,提供热更新(Hot Module Replacement, HMR)、自动刷新(Auto Refresh)等功能,从而大大提升开发效率。

开发服务器的作用

  1. 实时预览和自动刷新:开发服务器可以实时查看文件变动,当源代码文件(如 JS、CSS)发生更改时,浏览器会自动刷新或更新页面,避免手动刷新,提升开发体验。

  2. 热模块替换(Hot Module Replacement, HMR):Webpack Dev Server 可以在不重新加载整个页面的情况下,仅替换更改的模块。这样,开发者在修改代码时,不仅可以看到修改结果,还能保留页面状态,比如表单数据或滚动位置等。

  3. 简化本地开发:它提供了一个本地开发环境,使得开发者能够像在生产环境中一样运行应用,只是它的构建速度更快,且具备开发过程中所需要的热更新、自动刷新等功能。

  4. 代理和跨域支持:在开发过程中,很多时候需要与后端 API 进行交互。Webpack Dev Server 支持代理功能,可以将开发服务器的请求转发到后台 API,解决跨域问题。

要在 Webpack 项目中使用开发服务器,需要先安装 webpack-dev-server,然后在 Webpack 配置文件中进行相关配置。在 webpack.config.js 文件中,添加 devServer 配置项,来启用开发服务器功能。

module.exports = {
  mode: 'development',
  entry: './src/index.js',
  output: {
    filename: 'bundle.js',
    path: path.resolve(__dirname, 'dist'),
  },
  devServer: {
    contentBase: path.join(__dirname, 'dist'),  // 指定静态文件的根目录
    port: 9000,  // 指定开发服务器的端口号
    open: true,  // 启动后自动打开浏览器
    hot: true,   // 启用热模块替换
  },
};

在这个基本配置中,最重要的部分是 devServer 配置项。以下是常用的配置项和含义:

  • contentBase:指定开发服务器的静态文件目录,默认是 ./public。它告诉服务器从哪里提供静态资源。通常设置为 dist,即构建后的输出目录。

  • port:设置开发服务器的端口号,默认为 8080,你可以根据需要修改为其他端口。

  • open:设置为 true 时,开发服务器启动后会自动在浏览器中打开应用。默认是 false

  • hot:启用热模块替换(HMR)。当代码修改时,Webpack 只会替换修改的模块,而不会重新加载整个页面,从而保持应用的状态。

  • historyApiFallback:对于使用 HTML5 History API 的单页面应用(SPA),如果在浏览器中直接访问某个路径时返回 404 错误,可以通过此配置让开发服务器始终返回 index.html。例如,应用路由是基于 Hash 的时候,刷新页面可能会导致找不到资源。

    devServer: {
      historyApiFallback: true,
    }
    
  • proxy:设置代理,解决跨域问题。在开发时,可能需要与后端 API 进行交互。此时,可以通过配置代理将某些请求转发到指定的后端服务器。

    devServer: {
      proxy: {
        '/api': 'http://localhost:3000', // 将 /api 请求代理到后端的 3000 端口
      },
    }
    
  • inline:启用内联模式。在内联模式下,Webpack 会将脚本注入到页面中,通常用于调试。现在大多数情况下不再需要此配置,因为 devServer 默认启用内联模式。

  • watchContentBase:启用该选项后,Webpack 会监控静态资源文件(如 HTML、CSS 等)的变化,自动重新加载页面。

  • compress:启用 gzip 压缩,压缩服务器响应的文件。在开发环境中,可以减少网络传输的大小,提升性能。

    devServer: {
      compress: true,  // 启用 gzip 压缩
    }
    

热模块替换(HMR)

热模块替换(HMR)是 Webpack 的一个重要特性,能在应用运行时只替换已更改的模块,而不是重新加载整个页面。它不仅能加速开发过程,还能保持应用的状态(如用户输入的数据、滚动条位置等)。Webpack Dev Server 默认启用了 HMR。

要使用 HMR,除了启用 hot: true 配置外,还需要在应用中引入 HMR 相关的 API。例如,在 JavaScript 中使用 module.hot.accept() 处理模块的更新:

if (module.hot) {
  module.hot.accept('./module.js', function() {
    console.log('Module updated!');
  });
}

production 模式下,HMR 不会默认启用,因为生产环境下,代码通常经过压缩和优化,不需要实时更新。HMR 主要用于开发环境。

启动开发服务器

webpack.config.js 配置好 devServer 后,可以通过命令启动开发服务器:

npx webpack serve

或者,如果你在 package.json 中配置了 scripts,可以直接使用 npm 或 yarn 启动开发服务器:

{
  "scripts": {
    "start": "webpack serve --config webpack.config.js"
  }
}

然后,在浏览器中访问 http://localhost:9000 即可看到运行中的应用。

Webpack Dev Server 并不完全模拟生产环境,它主要是为开发环境提供快速的构建、实时预览和调试功能。它并不会自动进行生产环境的优化(如代码压缩、去除死代码等)。虽然它有一些功能可以模拟生产环境的行为(如代理、热更新等),但其主要目标是提高开发效率。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2300376.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

数据结构(陈越,何钦铭)第三讲 树(上)

3.1 树与数的表示 3.1.1 顺序查找 int SequentialSearch(List Tbl,ElementType K){int i;Tbl->Element[0]K;for(iTbl->Length;Tbl->Element[i]!K;i--);return i; } typedef struct LNode *List; struct LNode{ElementType Element[MAXSIZE];int Length; };3.1.2 二分…

【深度解析】图解Deepseek-V3模型架构-混合专家模型(MoE)

一、引言 最近非常火爆的DeepSeek-V3模型&#xff0c;是一个包含6710亿总参数的强大混合专家模型&#xff08;MoE&#xff09;&#xff0c;其中每个token激活370亿参数。该模型在DeepSeek-V2验证有效的核心架构基础上&#xff0c;采用多头潜在注意力&#xff08;MLA&#xff0…

c#判断exe文件是不是7z或者rar的自解压文件

亲测可以实现检测7z的自解压&#xff0c;但是对于rar的自解压格式&#xff0c;最新版不支持&#xff0c;尝试修改回发现几乎检测成了exe文件&#xff0c;这显然是不正确的&#xff0c;其他版本未测试。 如下图所示&#xff0c;可以检测出自解压格式的7z文件&#xff0c;黑色显…

富士SC2022,C325,C328打印机扫描到网络详细教程

前言&#xff1a; 在开始教程之前,我先声明目前该教程适用于FujiXerox apeos C325Z和FujiXerox DocuCentre SC2022打印机。这次教程以FujiXerox DocuCentre SC2022为例&#xff0c;该打印机IP地址为10.40.11.240。 前提条件 &#xff1a; 1. 安装打印机所需打印机和扫…

人工智能3d点云之Pointnet++项目实战源码解读(点云分类与分割)

一.项目文件概述 二.数据读取模块配置 实际代码运行时是先定义与加载好模型&#xff0c;然后再去读取数据进来传入到模型网络中去训练。但现在反过来先读取数据开始。 进入ModelNetDataLoader类的_getitem方法, 做标准化的目的是处理异常大的数值 上面返回的cls是类别,相当于…

IP 路由基础 | 路由条目生成 / 路由表内信息获取

注&#xff1a;本文为 “IP 路由” 相关文章合辑。 未整理去重。 IP 路由基础 秦同学学学已于 2022-04-09 18:44:20 修改 一. IP 路由产生背景 我们都知道 IP 地址可以标识网络中的一个节点&#xff0c;并且每个 IP 地址都有自己的网段&#xff0c;各个网段并不相同&#xf…

java后端开发day16--字符串(二)

&#xff08;以下内容全部来自上述课程&#xff09; 1.StringBuilder 因为StringBuilder是Java已经写好的类。 java在底层对他进行了一些特殊处理。 打印对象不是地址值而是属性值。 1.概述 StringBuilder可以看成是一个容器&#xff0c;创建之后里面的内容是可变的。 作用…

LabVIEW危化品仓库的安全监测系统

本案例展示了基于LabVIEW平台设计的危化品仓库安全监测系统&#xff0c;结合ZigBee无线通信技术、485串口通讯技术和传感器技术&#xff0c;实现了对危化品仓库的实时无线监测。该系统不仅能提高安全性&#xff0c;还能大幅提升工作效率&#xff0c;确保危化品仓库的安全运营。…

深度学习框架探秘|Keras 应用案例解析以及 Keras vs TensorFlow vs PyTorch

引言 上一篇文章《深度学习框架探秘&#xff5c;Keras&#xff1a;深度学习的魔法钥匙》 我们初步学习了 Keras&#xff0c;包括它是什么、具备哪些优势&#xff08;简洁易用的 API、强大的兼容性、广泛的应用领域&#xff09;&#xff0c;以及基本使用方法。本文&#xff0c;…

NAT(网络地址转换)技术详解:网络安全渗透测试中的关键应用与防御策略

目录 NAT的作用 NAT类型 NAT工作流程示例 NAT 转换技术的原理 源地址转换&#xff08;SNAT&#xff0c;Source NAT&#xff09;&#xff1a; 目标地址转换&#xff08;DNAT&#xff0c;Destination NAT&#xff09;&#xff1a; 端口地址转换&#xff08;PAT&#xff0c…

容器化部署Kafka的最佳实践:基于KRaft模式的无ZooKeeper方案

一、docker 部署kafka单节点 1.1安装docker 可以参考这篇CentOS 7安装docker并配置镜像加速 1.3 运行kafka&#xff08;注意修改zookeeper&#xff0c;kafka地址&#xff09; docker run -d --name kafka -e KAFKA_ADVERTISED_LISTENERSPLAINTEXT://172.16.10.180:9092 -p …

【PHP】php+mysql 活动信息管理系统(源码+论文+数据库+数据库文件)【独一无二】

&#x1f449;博__主&#x1f448;&#xff1a;米码收割机 &#x1f449;技__能&#x1f448;&#xff1a;C/Python语言 &#x1f449;专__注&#x1f448;&#xff1a;专注主流机器人、人工智能等相关领域的开发、测试技术。 【PHP】php 活动信息管理系统&#xff08;源码论文…

thingboard告警信息格式美化

原始报警json内容&#xff1a; { "severity": "CRITICAL","acknowledged": false,"cleared": false,"assigneeId": null,"startTs": 1739801102349,"endTs": 1739801102349,"ackTs": 0,&quo…

OpenHarmonry 5.0.1源码下载与编译

预置环境&#xff1a;硬盘500G、内存32G、Ubuntu 20.04.6 LTS Ubuntu系统下载路径&#xff1a;ubuntu-releases安装包下载_开源镜像站-阿里云 一、必需环境 sudo apt-get update && sudo apt-get install binutils binutils-dev git git-lfs gnupg flex bison gperf…

STM32 外部中断和NVIC嵌套中断向量控制器

目录 背景 外部中断/事件控制器(EXTI) 主要特性 功能说明 外部中断线 嵌套向量中断控制器 特性 ‌中断线&#xff08;Interrupt Line&#xff09; 中断线的定义和作用 STM32中断线的分类和数量 优先级分组 抢占优先级&#xff08;Preemption Priority&#xff09; …

string类详解(上)

文章目录 目录1. STL简介1.1 什么是STL1.2 STL的版本1.3 STL的六大组件 2. 为什么学习string类3. 标准库中的string类3.1 string类3.2 string类的常用接口说明 目录 STL简介为什么学习string类标准库中的string类string类的模拟实现现代版写法的String类写时拷贝 1. STL简介 …

【Go并发编程】Goroutine 调度器揭秘:从 GMP 模型到 Work Stealing 算法

每天一篇Go语言干货&#xff0c;从核心到百万并发实战&#xff0c;快来关注魔法小匠&#xff0c;一起探索Go语言的无限可能&#xff01; 在 Go 语言中&#xff0c;Goroutine 是一种轻量级的并发执行单元&#xff0c;它使得并发编程变得简单高效。而 Goroutine 的高效调度机制是…

【前端】Vue组件库之Element: 一个现代化的 UI 组件库

文章目录 前言一、官网1、官网主页2、设计原则3、导航4、组件 二、核心功能&#xff1a;开箱即用的组件生态1、丰富的组件体系2、特色功能亮点 三、快速上手&#xff1a;三步开启组件化开发1、安装&#xff08;使用Vue 3&#xff09;2、全局引入3、按需导入&#xff08;推荐&am…

坐井说天阔---DeepSeek-R1

前言 DeepSeek-R1这么火&#xff0c;虽然网上很多介绍和解读&#xff0c;但听人家的总不如自己去看看原论文。于是花了大概一周的时间&#xff0c;下班后有进入了研究生的状态---读论文。 DeepSeek这次的目标是探索在没有任何监督数据的情况下训练具有推理能力的大模型&#…

UART(一)——UART基础

一、定义 UART(Universal Asynchronous Receiver/Transmitter)是一种广泛使用的串行通信协议,用于在设备间通过异步方式传输数据。它无需共享时钟信号,而是依赖双方预先约定的参数(如波特率)完成通信。 功能和特点 基本的 UART 系统只需三个信号即可提供稳健的中速全双工…