Webpack 学习笔记(一 - 管理资源、管理输出、开发环境、代码分离、模块热替换、懒加载)

管理资源

包括加载CSS、加载图片、加载字体、加载数据。按需选择。

const path = require('path');

 module.exports = {
   entry: './src/index.js',
   output: {
     filename: 'bundle.js',
     path: path.resolve(__dirname, 'dist'),
   },
  module: {
    rules: [
      {
        test: /\.css$/i,
        use: ['style-loader', 'css-loader'],
      },
      {
        test: /\.(png|svg|jpg|jpeg|gif)$/i,
        type: 'asset/resource',
      },
      {
        test: /\.(woff|woff2|eot|ttf|otf)$/i,
        type: 'asset/resource',
      },
      {
        test: /\.(csv|tsv)$/i,
        use: ['csv-loader'],
      },
      {
        test: /\.xml$/i,
        use: ['xml-loader'],
      },
    ],
  },
 };

 管理输出

清理 ./dist 文件夹

webpack.config.js

clean: true

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

manifest

webpack 通过 manifest 追踪所有模块到输出的 bundle 之间的映射。了解 manifest 将会帮助了解如何以其他方式控制 webpack 输出

WebpackManifestPlugin 插件可以将 manifest 数据提取为 json 文件。

参阅 manifest 概念页面以深入了解如何在项目中使用此插件,同时 缓存 指南介绍了其与长效缓存之间的关系。


 开发环境

使用source map

目的:在代码报错时,不会定位到打包后的 bundle.js 中,而是定位到打包前的具体某一 js 代码。

webpack.config.js

devtool: 'inline-source-map',

选择一个开发工具

目的:当代码发生改变时,自动编译。

安装依赖:

npm install --save-dev webpack-dev-server

webpack.config.js 添加 

  devServer: {
    static: './dist',
  },

代码分离

代码分离是 webpack 中最引人注目的特性之一。此特性能够把代码分离到不同的 bundle 中,然后便能按需加载或并行加载这些文件。代码分离可以用于获取更小的 bundle、控制资源加载优先级,如果使用合理,会极大减小加载时间。

常用的代码分离方法有三种:

  • 入口起点:使用 entry 配置手动地分离代码。
  • 防止重复:使用 入口依赖 或者 SplitChunksPlugin 去重和分离 chunk。
  • 动态导入:通过模块的内联函数调用分离代码。

主要介绍第二种方法:防止重复

入口依赖

在配置文件中配置 dependOn 选项,以在多个 chunk 之间共享模块:

webpack.config.js

entry: {
    index: {
      import: './src/index.js',
      dependOn: 'shared',
    },
    another: {
      import: './src/another-module.js',
      dependOn: 'shared',
    },
    shared: 'lodash',
   },

如果想要在一个 HTML 页面上使用多个入口起点,还需设置 optimization.runtimeChunk: 'single'

webpack.config.js

optimization: {
    runtimeChunk: 'single',
  },

构建结果如下:

...
[webpack-cli] Compilation finished
asset shared.bundle.js 549 KiB [compared for emit] (name: shared)
asset runtime.bundle.js 7.79 KiB [compared for emit] (name: runtime)
asset index.bundle.js 1.77 KiB [compared for emit] (name: index)
asset another.bundle.js 1.65 KiB [compared for emit] (name: another)
Entrypoint index 1.77 KiB = index.bundle.js
Entrypoint another 1.65 KiB = another.bundle.js
Entrypoint shared 557 KiB = runtime.bundle.js 7.79 KiB shared.bundle.js 549 KiB
runtime modules 3.76 KiB 7 modules
cacheable modules 530 KiB
  ./node_modules/lodash/lodash.js 530 KiB [built] [code generated]
  ./src/another-module.js 84 bytes [built] [code generated]
  ./src/index.js 257 bytes [built] [code generated]
webpack 5.4.0 compiled successfully in 249 ms

可以看到,除了 shared.bundle.jsindex.bundle.js 和 another.bundle.js 之外,还生成了一个 runtime.bundle.js 文件。

尽管 webpack 允许每个页面使用多个入口起点,但在可能的情况下,应该避免使用多个入口起点,而使用具有多个导入的单个入口起点:entry: { page: ['./analytics', './app'] }。这样可以获得更好的优化效果,并在使用异步脚本标签时保证执行顺序一致。

SplitChunksPlugin

SplitChunksPlugin 插件可以将公共的依赖模块提取到已有的入口 chunk 中,或者提取到一个新生成的 chunk。让我们使用这个插件去除之前示例中重复的 lodash 模块:

webpack.config.js

    optimization: {
     splitChunks: {
       chunks: 'all',
     },
   },

使用 optimization.splitChunks 配置选项后构建,将会发现 index.bundle.js 和 another.bundle.js 已经移除了重复的依赖模块。从插件将 lodash 分离到单独的 chunk,并且将其从 main bundle 中移除,减轻了 bundle 大小。执行 npm run build 查看效果:

...
[webpack-cli] Compilation finished
asset vendors-node_modules_lodash_lodash_js.bundle.js 549 KiB [compared for emit] (id hint: vendors)
asset index.bundle.js 8.92 KiB [compared for emit] (name: index)
asset another.bundle.js 8.8 KiB [compared for emit] (name: another)
Entrypoint index 558 KiB = vendors-node_modules_lodash_lodash_js.bundle.js 549 KiB index.bundle.js 8.92 KiB
Entrypoint another 558 KiB = vendors-node_modules_lodash_lodash_js.bundle.js 549 KiB another.bundle.js 8.8 KiB
runtime modules 7.64 KiB 14 modules
cacheable modules 530 KiB
  ./src/index.js 257 bytes [built] [code generated]
  ./src/another-module.js 84 bytes [built] [code generated]
  ./node_modules/lodash/lodash.js 530 KiB [built] [code generated]
webpack 5.4.0 compiled successfully in 241 ms

以下是由社区提供,对代码分离很有帮助的 plugin 和 loader:


模块热替换

模块热替换(HMR)是 webpack 提供的最有用的功能之一。它能帮助在运行时不完全刷新页面的情况下更新所有类型的模块。 

警告

HMR 不适用于生产环境,而应当用于开发环境。

启用HMR

从 webpack-dev-server v4.0.0 开始,模块热替换是默认开启的。

webpack.config.js

    devServer: {
      static: './dist',
      hot: true,
    },

提示:可以通过以下命令修改  webpack-dev-server 配置。

webpack serve --hot-only

 通过 Node.js API 启用 HMR

在 Node.js API 中使用 webpack dev server 时,不要将 dev server 选项放在 webpack 配置对象中。而是在创建时, 将其作为第二个参数传递。例如:

new WebpackDevServer(options, compiler)

想要启用 HMR,还需要修改 webpack 配置对象,使其包含 HMR 入口起点。这是关于如何使用的一个基本示例:

dev-server.js

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

const webpack = require('webpack');
const webpackDevServer = require('webpack-dev-server');

const config = {
  mode: 'development',
  entry: [
    // 模块热替换的运行时代码
    'webpack/hot/dev-server.js',
    // 用于 web 套接字传输、热重载逻辑的 web server 客户端
    'webpack-dev-server/client/index.js?hot=true&live-reload=true',
    // 你的入口起点
    './src/index.js',
  ],
  devtool: 'inline-source-map',
  plugins: [
    // 模块热替换的插件
    new webpack.HotModuleReplacementPlugin(),
    new HtmlWebpackPlugin({
      title: 'Hot Module Replacement',
    }),
  ],
  output: {
    filename: '[name].bundle.js',
    path: path.resolve(__dirname, 'dist'),
    clean: true,
  },
};
const compiler = webpack(config);

// 由于手动添加了 `hot` 与 `client` 参数,其将被禁用
const server = new webpackDevServer({ hot: false, client: false }, compiler);

(async () => {
  await server.start();
  console.log('dev server 正在运行');
})();

参阅 webpack-dev-server 的 Node.js API 的完整文档 以了解更多。

HMR 加载样式

借助 style-loader 后,使用模块热替换加载 CSS 实际上极其简单。此 loader 在幕后使用了 module.hot.accept,在 CSS 依赖模块更新之后,会将其修补到 <style> 标签中。

首先安装两个 loader:

npm install --save-dev style-loader css-loader

 然后更新配置文件,使用这两个 loader

webpack.config.js

     rules: [
       {
         test: /\.css$/,
         use: ['style-loader', 'css-loader'],
       },
     ],
   },

懒加载

懒加载或者按需加载,是一种很好的优化网页或应用的方式。这种方式实际上是先把你的代码在一些逻辑断点处分离开,然后在一些代码块中完成某些操作后,立即引用或即将引用另外一些新的代码块。这样加快了应用的初始加载速度,减轻了它的总体体积,因为某些代码块可能永远不会被加载。

举例

我们在代码分离中的例子基础上,进一步做些调整来说明这个概念。那里的代码确实会在脚本运行的时候产生一个分离的代码块 lodash.bundle.js ,在技术概念上“懒加载”它。问题是加载这个包并不需要用户的交互 - 意思是每次加载页面的时候都会请求它。这样做并没有对我们有很多帮助,还会对性能产生负面影响。

警告:注意当调用 ES6 模块的 import() 方法(引入模块)时,必须指向模块的 .default 值,因为它才是 promise 被处理后返回的实际的 module 对象。

框架

许多框架和类库对于如何用它们自己的方式来实现(懒加载)都有自己的建议。这里有一些例子:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值