webpack学习[一]:基本概念

webpack 是一个用于现代 JavaScript 应用程序的 静态模块打包工具。当 webpack 处理应用程序时,它会在内部从一个或多个入口点构建一个依赖图,然后将你项目中所需的每一个模块组合成一个或多个 bundles*,它们均为静态资源,用于展示你的内容。

本文将从如下最基础的项目入手,介绍 webpack 的一些基本概念。

webpack学习[一]:基本概念

一、入口(entry)

官方解释: 入口起点(entry point)  指示 webpack 应该使用哪个模块,来作为构建其内部依赖图的开始。进入入口起点后,webpack 会找出有哪些模块和库是入口起点(直接和间接)依赖的。

默认值是 ./src/index.js,可以通过在webpack.config.js文件中配置 entry 属性,来指定一个(或多个)不同的入口起点

1.1 基本语法:entry: string | [string]

  • 单入口:当只有单个入口时,可以按如下方式简写:
module.exports = {
  entry: './path/to/my/entry/file.js',
};
  • 多入口:可以将一个文件路径数组传递给 entry 属性,这将创建一个所谓的  “multi-main entry”
module.exports = {
  entry: ['./src/file_1.js', './src/file_2.js'],
  output: {
    filename: 'bundle.js',
  },
};

1.2 对象语法:entry: { <entryChunkName> string | [string] } | {}

module.exports = {
  entry: {
    main: './path/to/my/entry/file.js',
  },
};

其实上述第一种写法就是这种写法的一种简写形式。

对于每个入口我们可以使用如下属性进行描述:

  • filename: 指定要输出的文件名称。即入口文件。
  • dependOn: 当前入口所依赖的入口。它们必须在该入口被加载前被加载。
  • import: 启动时需加载的模块。
  • library: 指定 library 选项,为当前 entry 构建一个 library。
  • runtime: 运行时 chunk 的名字。如果设置了,就会创建一个新的运行时 chunk。
  • publicPath: 当该入口的输出文件在浏览器中被引用时,为它们指定一个公共 URL 地址。
module.exports = {
  entry: {
    a2: 'dependingfile.js',
    b2: {
      dependOn: 'a2',
      import: './src/app.js',
    },
  },
};

二、输出(output)

output 属性告诉 webpack 在哪里输出它所创建的 bundle,以及如何命名这些文件。主要输出文件的默认值是 ./dist/main.js,其他生成文件默认放置在 ./dist 文件夹中。

output的基础配置如下:

const path = require('path');

module.exports = {
  entry: './path/to/my/entry/file.js',
  output: {
    // 输出文件夹
    path: path.resolve(__dirname, 'dist'),
    // 输出文件名
    filename: 'bundle.js',
  },
};

其中需要引入node.jspath模块对路径进行处理,其中path.resolve是将一系列路径或路径段解析为绝对路径。所以说 path 的属性值一定要是绝对路径。

当通过多个入口起点(entry point)、代码拆分(code splitting)或各种插件(plugin)创建多个 bundle,应该使用以下一种替换方式,来赋予每个 bundle 一个唯一的名称。

  • 使用入口名称
module.exports = {
  //...
  output: {
    filename: '[name].bundle.js',
  },
};
  • 使用内部chunk id
module.exports = {
  //...
  output: {
    filename: '[id].bundle.js',
  },
};
  • 使用内容产生的hash
module.exports = {
  //...
  output: {
    filename: '[contenthash].bundle.js',
  },
};

当然output中还有很多配置属性,这里就不一一介绍了。

三、loader

webpack 只能理解 JavaScriptJSON 文件,这是 webpack 开箱可用的自带能力。

loader 让 webpack 能够去处理其他类型的文件,并将它们转换为有效模块,以供应用程序使用,以及被添加到依赖图中。

在 webpack 的配置中,loader 有两个属性:

  1. test 属性,识别出哪些文件会被转换。
  2. use 属性,定义出在进行转换时,应该使用哪个 loader

如下:

module.exports = {
  ...
  module: {
    rules: [
        { 
            test: /.txt$/, 
            use: 'raw-loader' 
        }
   ],
  },
  ...
};

该配置告诉 webpack 在打包时,如果遇到 import/require() 语句中存在解析为.txt的路径时,在打包之前,先用 raw-loader 进行转换。

我们也可以针对不同的类型的资源,配置不同的loader:

module.exports = {
  module: {
    rules: [
      { test: /.css$/, use: 'css-loader' },
      { test: /.ts$/, use: 'ts-loader' },
    ],
  },
};

module.rules允许你在 webpack 配置中为某个类型资源指定多个 loader,以加载 CSS 文件为例:

module.exports = {
  module: {
    rules: [
      {
        test: /.css$/,
        use: [
          { loader: 'style-loader' },
          {
            loader: 'css-loader',
            options: {
              modules: true
            }
          },
        ]
      }
    ]
  }
};
  • loader 支持链式调用从右往左从下往上)。链中的每个 loader 会将转换应用在已处理过的资源上。一组链式的 loader 将按照相反的顺序执行。链中的第一个 loader 将其结果(也就是应用过转换后的资源)传递给下一个 loader,依此类推。最后,链中的最后一个 loader,返回 webpack 所期望的 JavaScript。例如:上例中 CSS 文件会先被 css-loader 处理,处理后的资源紧接着传给 style-loader 处理。
  • loader 可以是同步的,也可以是异步的。
  • loader 运行在 Node.js 中,并且能够执行任何操作。
  • loader 可以通过 options 对象配置。
  • loader 能够产生额外的任意文件。

四、插件(plugin)

插件可以用于执行范围更广的任务。包括:打包优化,资源管理,注入环境变量。

webpack 插件是一个具有 apply 方法的 JavaScript 对象。apply 方法会被 webpack compiler 调用,并且在 整个 编译生命周期都可以访问 compiler 对象。

想要使用一个插件,你只需要 require() 它,然后把它添加到 plugins 数组中。多数插件可以通过选项(option)自定义。你也可以在一个配置文件中因为不同目的而多次使用同一个插件,这时需要通过使用 new 操作符来创建一个插件实例

const HtmlWebpackPlugin = require('html-webpack-plugin');
const webpack = require('webpack'); // 用于访问内置插件

module.exports = {
  module: {
    rules: [{ test: /.txt$/, use: 'raw-loader' }],
  },
  plugins: [new HtmlWebpackPlugin({ template: './src/index.html' })],
};

在上面的示例中,html-webpack-plugin 为应用程序生成一个 HTML 文件,并自动将生成的所有 bundle 注入到此文件中。

五、模式(mode)

设置 mode 参数,你可以启用 webpack 内置在相应环境下的优化。可以设置为 developmentproduction 或 none其中一个,默认值为production

选项 描述
development 会将 DefinePlugin 中 process.env.NODE_ENV 的值设置为 development. 为模块和 chunk 启用有效的名。
production 会将 DefinePlugin 中 process.env.NODE_ENV 的值设置为 production。为模块和 chunk 启用确定性的混淆名称,FlagDependencyUsagePluginFlagIncludedChunksPluginModuleConcatenationPluginNoEmitOnErrorsPlugin 和 TerserPlugin 。
none 不使用任何默认优化选项

简单来说,在production模式下,webpack会进行更加细致的打包优化,例如代码压缩等。不同模式下会有不同的配置。

上述入口(entry)、输出(output)、loader、插件(plugin)、模式(mode)是webpack的核心概念。了解了这些,我们在配置文件中进行如下简单的配置:

const path = require('path');

module.exports = {
    entry: './src/index.js',
    output: {
        path: path.resolve(__dirname, 'dist'),
        filename: 'main.js',
    },
    mode: 'development'
}

然后在入口文件 ./src/index.js 中写入如下代码:

function f(a, b) {
    return a + b;
}

然后再命令行运行 webpack 进行打包,可以看到 dist 目录下会生成 main.js,内容如下图:

webpack学习[一]:基本概念

六、模块(Modules)

在模块化编程中,开发者将程序分解为功能离散的 chunk,并称之为 模块。对于 webpack 而言,天生支持以下模块类型:

  • ECMAScript 模块
  • CommonJS 模块
  • AMD 模块
  • Assets
  • WebAssembly 模块

通过 loader 可以使 webpack 支持多种语言和预处理器语法编写的模块。loader 向 webpack 描述了如何处理非原生模块,并将相关依赖引入到你的 bundles中。

webpack 能够解析三种文件路径:

  • 绝对路径
import 'C:\Users\me\file';

此种情况下不需要进行进一步解析。

  • 相对路径
import './file2';

在这种情况下,使用 import 或 require 的资源文件所处的目录,被认为是上下文目录。在 import/require 中给定的相对路径,会拼接此上下文路径,来生成模块的绝对路径。

  • 模块路径
import 'module';

该种路径与配置项 resolve 相关,这里暂不详细描述。

七、依赖图

当 webpack 处理应用程序时,它会根据命令行参数中或配置文件中定义的模块列表开始处理。 从入口开始,webpack 会递归的构建一个 依赖关系图,这个依赖图包含着应用程序中所需的每个模块,然后将所有模块打包为少量的 bundle —— 通常只有一个 —— 可由浏览器加载

八、runtime 和 manifest

runtime

runtime,以及伴随的 manifest 数据,主要是指:在浏览器运行过程中,webpack 用来连接模块化应用程序所需的所有代码。它包含:在模块交互时,连接模块所需的加载和解析逻辑。包括:已经加载到浏览器中的连接模块逻辑,以及尚未加载模块的延迟加载逻辑。

manifest

一旦你的应用在浏览器中以 index.html 文件的形式被打开,一些 bundle 和应用需要的各种资源都需要用某种方式被加载与链接起来。在经过打包、压缩、为延迟加载而拆分为细小的 chunk 这些 webpack 优化之后,你精心安排的 /src 目录的文件结构都已经不再存在。所以 webpack 如何管理所有所需模块之间的交互呢?这就是 manifest 数据用途的由来……

当 compiler 开始执行、解析和映射应用程序时,它会保留所有模块的详细要点。这个数据集合称为 “manifest”,当完成打包并发送到浏览器时,runtime 会通过 manifest 来解析和加载模块。无论你选择哪种 模块语法,那些 import 或 require 语句现在都已经转换为 __webpack_require__ 方法,此方法指向模块标识符(module identifier)。通过使用 manifest 中的数据,runtime 将能够检索这些标识符,找出每个标识符背后对应的模块。

以上内容均参考 webpack 官方文档,详细内容可见官方文档。

参考:
webpack文档

原文链接:https://juejin.cn/post/7261059812238983229 作者:大力yy

(0)
上一篇 2023年7月30日 上午10:20
下一篇 2023年7月30日 上午10:31

相关推荐

发表回复

登录后才能评论