五、webpack的基本使用,防止重复,入口文件,懒加载,预获取/预加载(Mhua)

入口文件

webpack 打包文件时,可以拆分多个入口文件。
首先安装 lodash 插件

npm install lodash

在这里插入图片描述

在入口文件 index.js 配置如下内容:

import imgSrc from "./assets/2.png";
import "./style.css";
import "./style.less";

const img = document.createElement("img");
img.src = imgSrc;

document.body.appendChild(img);

const div = document.createElement("div");
div.style.cssText = "width: 100px; height: 100px; background-color: skyblue;";

div.classList.add("bg");

document.body.appendChild(div);

index2.js 文件内容:

import _ from "lodash"

console.log(_.join([1, 2, 3], " "))

webpack.config.js文件 配置:

entry: {
  # 配置生成两个入口文件
  index: "./src/index.js",
  another: "./src/index2.js"
},
# 文件输出位置
output: {
  # 配置打包后,设置入口文件名字。[name] 默认拿到  entry对象的key值,也就是打包后的文件 分别为 index.build.js/index2.build.js
  filename: "[name].build.js",
  path: path.resolve(__dirname, './dist'),
  clean: true,  // 每次打包前先删除 dist 目录

  // contenthash 表示哈希值
  // ext 表示扩展名
  assetModuleFilename: "images/[contenthash][ext]"
},

开始打包

npx webpack

# 生成两个入口文件
asset another.build.js 1.38 MiB [emitted] (name: another) // index2.js 引用第三方的包,所以 another.build.js 打包后为 1.38 M
asset index.build.js 10 KiB [emitted] (name: index)

打开 dist 下的 app.html文件

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
<link href="styles/42827711e5e6d5ca309f.css" rel="stylesheet"></head>
<body>
  <script defer src="index.build.js"></script>
  <script defer src="another.build.js"></script>
</body>
</html>

然后我们开始在 index.js 文件中使用 lodash 。

import imgSrc from "./assets/2.png";
import "./style.css";
import "./style.less";
import _ from "lodash"

console.log(_.join([1, 2, 3], " "))

const img = document.createElement("img");
img.src = imgSrc;

document.body.appendChild(img);

const div = document.createElement("div");
div.style.cssText = "width: 100px; height: 100px; background-color: skyblue;";

div.classList.add("bg");

document.body.appendChild(div);

重新打包,两份入口文件大小都变大了。原因是两份入口文件都打包了 lodash 库。

npx webpack

# 打包结果
# index.build.js 从 10 k 变成了 1.38 M, 造成重复打包了。
asset index.build.js 1.38 MiB [emitted] (name: index)
asset another.build.js 1.38 MiB [compared for emit] (name: another)

防止重复

两份入口文件,防止重复打包相同的 库 文件代码。
在webpack.config.js 文件,配置 entry。

entry: {
  index: {
    import: "./src/index.js",
    dependOn: 'shared'
  },

  another: {
    import: "./src/index2.js",
    dependOn: 'shared'
  },

  # 当两个入口文件有 lodash 模块时就会抽离出来,并且取名 为 shared.build.js
  shared: 'lodash'
},

执行打包命令:

npx webpack

# 这里把 loadash 抽离 到 shared.build.js,其它两份入口文件都变小了。
asset shared.build.js 1.39 MiB [emitted] (name: shared)
asset index.build.js 4.39 KiB [emitted] (name: index)
asset another.build.js 1.45 KiB [emitted] (name: another)

打开 dist 下的 app.html 文件, 三份 js 文件都引入到 app.html里面了。

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
<link href="styles/42827711e5e6d5ca309f.css" rel="stylesheet"></head>
<body>
  <script defer src="index.build.js"></script>
  <script defer src="another.build.js"></script>
  <script defer src="shared.build.js"></script>
  </body>
</html>

防止重复(第二种方法)

使用webpack自带的插件 split-chunks-plugin,对公共代码进行抽离。
首先:webpack.config.js entry 恢复原来配置

entry: {
  index: "./src/index.js",
  another: "./src/index2.js"
}

# 优化配置
optimization: {
  # 这里的配置项是实现代码分割,并且保存到单独的一个文件里。
  splitChunks: {
    chunks: 'all'
  }
}

开始打包:

npx webpack

结果:生成了三份 js 文件。lodash 库文件单独抽离出来了。
在这里插入图片描述

懒加载

使用 ECMAScript 的 import() 来实现代码分离。

首先创建 math.js 文件。并且添加两个函数

export const add = (x, y) => {
  return x + y;
};

export const sub = (x, y) => {
  return x - y;
};

在 index.js 入口文件中使用 math.js

const btn = document.createElement("button");

btn.textContent = "按钮";

btn.addEventListener("click", () => {
  // /* webpackChunkName: 'math' */ 指定打包后文件名为 math
  // 最终文件名为 math.build.js ,这是因为 在 webpack.config.js 配置 output 下的 filename 
  import(/* webpackChunkName: 'math' */ "./math.js").then(({ add }) => {
    console.log(add(1, 2))
  });
});

document.body.appendChild(btn);

执行 npx webpack 打包 src 目录下文件。结果如下:生成了 新的 math.build.js
在这里插入图片描述

执行 npx webpack-dev-server 启动 web 服务器。页面展示一个按钮,并且点击按钮后,才会加载 math.build.js 文件。
在这里插入图片描述

预获取/预加载模块

webpack v4.6.0 版本对预获取和预加载的支持。
在声明 import 时,使用下面这些内置指令,可以让webpack 输出 “resource hint(资源提示)”,来告知浏览器:

  • prefetch(预获取):将来某些导航下可能需要的资源。
  • preload(预加载):当前导航下可能需要的资源。

prefetch 预加载演示

const btn = document.createElement("button");

btn.textContent = "按钮";

btn.addEventListener("click", () => {
  // webpackPrefetch 设置 为 true
  import(/* webpackChunkName: 'math', webpackPrefetch: true */ "./math.js").then(({ add }) => {
    console.log(add(1, 2))
  });
});

document.body.appendChild(btn);

启动 webpack 服务器。

npx webpack-dev-server

默认地址是:127.0.0.1:8080。
刷新浏览器,查看 network,可以发现 math.build.js 已经加载下来。
并且 index.html 文件,增加了 link 标签,链接到 math.build.js 文件。
rel=“prefetch” 这里使用 prefetch 预加载,当我们首页内容加载完毕,在网络空闲的时候,才会加载 link 对应的文件。

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <link rel="prefetch" as="script" href="http://127.0.0.1:8080/math.build.js">
</head>

preload 预加载演示
打开 index.js 文件, 在 import() 函数中,加入参数 webpackPreload: true

const btn = document.createElement("button");

btn.textContent = "按钮";

btn.addEventListener("click", () => {
  // webpackPreload: true
  import(/* webpackChunkName: 'math', webpackPreload: true */ "./math.js").then(({ add }) => {
    console.log(add(1, 2))
  });
});

document.body.appendChild(btn);

效果和懒加载一样,也是点击按钮后才会加载 math.js 文件。

完整的 webpack.config.js 文件

let path = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin")
const MinCssExtractPlugin = require("mini-css-extract-plugin")
const CssMinmizerPlugin = require("css-minimizer-webpack-plugin")

module.exports = {
  // 入口文件
  entry: {
    // index: {
    //   import: "./src/index.js",
    //   dependOn: 'shared'
    // },

    // another: {
    //   import: "./src/index2.js",
    //   dependOn: 'shared'
    // },

    // // 当两个入口文件有 lodash 模块时就会抽离出来,并且取名 为 shared.js
    // shared: 'lodash'

    index: "./src/index.js",
    another: "./src/index2.js"
  },
  // 打包后文件
  output: {
    // 配置打包后,入口文件名字
    filename: "[name].build.js",
    path: path.resolve(__dirname, './dist'),
    clean: true,  // 每次打包前先删除 dist 目录

    // contenthash 表示哈希值
    // ext 表示扩展名
    assetModuleFilename: "images/[contenthash][ext]"
  },

  // 模式 development/production
  mode: 'development',
  // 打包后,可以方便的调试代码。代码的位置和源文件一致。
  devtool: "inline-source-map",

  // 插件使用。
  // HtmlWebpackPlugin 用于自动生成 dist 目录下 index.html 魔板文件
  plugins: [
    new HtmlWebpackPlugin({
      // 根据魔板文件生成
      template: "./index.html",
      // 生成 dist 目录中 html 的文件名
      filename: "app.html",
      // 生成的 js 文件 引入到body标签中
      inject: "body"
    }),

    // 把 css 合并成一个文件
    new MinCssExtractPlugin({
      // 打包文件,放到 dist 下的 styles 目录下
      // contenthash 哈希字符串
      filename: "styles/[contenthash].css"
    })
  ],

  // 指定 dist 作为根路径
  devServer: {
    static: "./dist"
  },

  // 配置打包 其它资源文件 规则
  module: {
    rules: [
      {
        test: /\.png$/,
        type: "asset/resource",

        // 打包后文件命名 
        // 优先级高于 output 下 assetModuleFilename
        generator: {
          filename: "images/[contenthash][ext]"
        }
      },
      {
        test: /\.svg$/,
        // 导出资源类型的 dataurl (base64格式)
        type: "asset/inline"
      },
      {
        test: /\.txt$/,
        // 导出资源的源代码
        type: "asset/source"
      },
      {
        test: /\.jpg$/,
        // 会根据 resource / inline 两种方式进行选择
        // 默认情况下,当资源文件大于 8k 选择 resource 模式生成资源
        // 当资源文件小于8k 选择 inline 生成 base64 数据。
        type: "asset",
        parser: {
          dataUrlCondition: {
            // 设置临界值,超过 maxSize 就会 使用  asset/resource 模式,否则使用  asset/inline 生成 base64 代码
            maxSize: 4 * 1024 * 1024   // 4 M
          }
        }
      },
      {
        test: /\.(css|less)$/,
        // loader 执行顺序是从右到左(三个loader位置不能颠倒)
        use: [MinCssExtractPlugin.loader, 'css-loader', 'less-loader']
      },
      {
        test: /\.(woff|woff2|eot|ttf|otf)$/,
        // asset/resource 可以帮助我们载入任何类型的资源
        type: "asset/resource"
      },
      {
        test: /\.(csv|tsv)$/,
        use: "csv-loader"
      },
      {
        test: /\.xml$/,
        use: "xml-loader"
      },
      {
        test: /\.js$/,
        // 排除 node_modules 目录下的 js 文件
        exclude: /node_modules/,
        use: {
          loader: "babel-loader",
          options: {
            presets: ["@babel/preset-env"]
          }
        }
      }
    ]
  },

  // 优化配置
  optimization: {
    minimizer: [
      new CssMinmizerPlugin()
    ],

    // 实现代码分割,并且保存到单独的一个文件里。
    splitChunks: {
      chunks: 'all'
    }
  }
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值