webpack4.x 性能优化

栏目: JavaScript · 发布时间: 6年前

内容简介:webpack可以说是当下最流行的打包库,当webpack处理应用程序时,它会递归地构建一个依赖关系图,其中包含应用程序需要的每一个模块,然后将所有这些模块打包成一个或多个bundle。这篇文章将介绍webpack非常重要的一部分——性能优化。文章的代码的在此:本文将从以下几部分进行总结:启用noParse:

webpack可以说是当下最流行的打包库,当webpack处理应用程序时,它会递归地构建一个依赖关系图,其中包含应用程序需要的每一个模块,然后将所有这些模块打包成一个或多个bundle。这篇文章将介绍webpack非常重要的一部分——性能优化。文章的代码的在此: github.com/USTB-musion…

本文将从以下几部分进行总结:

  1. noParse
  2. ignorePlugin
  3. dllPlugin
  4. happypack
  5. Tree-Shaking
  6. 抽离公共代码
  7. 懒加载
  8. 热更新

noParse

  • noParse 配置项可以让 Webpack 忽略对部分没采用模块化的文件的递归解析和处理,这样做的好处是能提高构建性能。 原因是一些库例如 jQuery 、ChartJS 它们庞大又没有采用模块化标准,让 Webpack 去解析这些文件耗时又没有意义。

启用noParse:

module: {
    // 不去解析jquery的依赖关系
    noParse: /jquery/
  },
复制代码

ignorePlugin

  • moment 2.18 会将所有本地化内容和核心功能一起打包)。可以使用 IgnorePlugin 在打包时忽略本地化内容,经过实验,使用 ignorePlugin 之后 :package: 之后的体积由 1.2M 降低至 800K

ignorePlugin启用方法:

// 用法:
new webpack.IgnorePlugin(requestRegExp, [contextRegExp]);

//eg.
plugins: [new webpack.IgnorePlugin(/\.\/local/, /moment/)];
复制代码

DllPlugin

  • DllPlugin 是基于 Windows 动态链接库(dll)的思想被创作出来的。这个插件会把第三方库单独打包到一个文件中,这个文件就是一个单纯的依赖库。这个依赖库不会跟着你的业务代码一起被重新打包,只有当依赖自身发生版本变化时才会重新打包。

用 DllPlugin 处理文件,要分两步走:

  • 基于 dll 专属的配置文件,打包 dll 库
let path = require("path");
let webpack = require("webpack");

module.exports = {
  mode: "development",
  entry: {
    react: ["react", "react-dom"]
  },
  output: {
    filename: "_dll_[name].js", // 产生的文件名
    path: path.resolve(__dirname, "dist"),
    library: "_dll_[name]"
  },
  plugins: [
    // name要等于library里的name
    new webpack.DllPlugin({
      name: "_dll_[name]",
      path: path.resolve(__dirname, "dist", "manifest.json")
    })
  ]
};
复制代码
  • 基于 webpack.config.js 文件,打包业务代码
let path = require("path");
let HtmlWebpackPlugin = require("html-webpack-plugin");
let webpack = require("webpack");

module.exports = {
  mode: "development",
  // 多入口
  entry: {
    home: "./src/index.js"
  },
  devServer: {
    port: 3000,
    open: true,
    contentBase: "./dist"
  },
  module: {
    // 不去解析jquery的依赖关系
    noParse: /jquery/,
    rules: [
      {
        test: /\.css$/,
        use: ["style-loader", "css-loader"]
      },
      {
        test: /\.js$/,
        exclude: /node_modules/,
        include: path.resolve("src"),
        use: {
          loader: "babel-loader",
          options: {
            presets: ["@babel/preset-env", "@babel/preset-react"]
          }
        }
      }
    ]
  },
  output: {
    // name -> home a
    filename: "[name].js",
    path: path.resolve(__dirname, "dist")
  },
  plugins: [
    new webpack.DllReferencePlugin({
      manifest: path.resolve(__dirname, "dist", "manifest.json")
    }),
    new webpack.IgnorePlugin(/\.\/local/, /moment/),
    new HtmlWebpackPlugin({
      template: "./src/index.html",
      filename: "index.html"
    }),
    new webpack.DefinePlugin({
      DEV: JSON.stringify("production")
    })
  ]
};
复制代码

Happypack——将 loader 由单进程转为多进程

  • 大家知道,webpack 是单线程的,就算此刻存在多个任务,你也只能排队一个接一个地等待处理。这是 webpack 的缺点,好在我们的 CPU 是多核的,Happypack 会充分释放 CPU 在多核并发方面的优势,帮我们把任务分解给多个子进程去并发执行,大大提升打包效率。

happypack的使用方法:

将loader中的配置转移到happypack中就好:

let path = require("path");
let HtmlWebpackPlugin = require("html-webpack-plugin");
let webpack = require("webpack");
// 模块 happypack 可以实现多线程:package:
let Happypack = require("happypack");

module.exports = {
  mode: "development",
  // 多入口
  entry: {
    home: "./src/index.js"
  },
  devServer: {
    port: 3000,
    open: true,
    contentBase: "./dist"
  },
  module: {
    // 不去解析jquery的依赖关系
    noParse: /jquery/,
    rules: [
      {
        test: /\.css$/,
        use: "Happypack/loader?id=css"
      },
      {
        test: /\.js$/,
        exclude: /node_modules/,
        include: path.resolve("src"),
        use: "Happypack/loader?id=js"
      }
    ]
  },
  output: {
    // name -> home a
    filename: "[name].js",
    path: path.resolve(__dirname, "dist")
  },
  plugins: [
    new Happypack({
      id: "css",
      use: ["style-loader", "css-loader"]
    }),
    new Happypack({
      id: "js",
      use: [
        {
          loader: "babel-loader",
          options: {
            presets: ["@babel/preset-env", "@babel/preset-react"]
          }
        }
      ]
    }),
    new webpack.DllReferencePlugin({
      manifest: path.resolve(__dirname, "dist", "manifest.json")
    }),
    new webpack.IgnorePlugin(/\.\/local/, /moment/),
    new HtmlWebpackPlugin({
      template: "./src/index.html",
      filename: "index.html"
    }),
    new webpack.DefinePlugin({
      DEV: JSON.stringify("production")
    })
  ]
};
复制代码

Tree-Shaking

  • 基于 import/export 语法,Tree-Shaking 可以在编译的过程中获悉哪些模块并没有真正被使用,这些没用的代码,在最后打包的时候会被去除。适合于处理模块级别的代码,所以尽量使用es6的import/export语法。

抽离公共代码

把公共代码抽离出来的好处:

  • 减少网络传输流量,降低服务器成本;
  • 虽然用户第一次打开网站的速度得不到优化,但之后访问其它页面的速度将大大提升。

启用抽离代码:

// webpack 4.x版本之前的commonChunkPlugins
  optimization: {
    // 分割代码块
    splitChunks: {
      // 缓存组
      cacheGroups: {
        // 公共模块
        common: {
          chunks: "initial",
          minSize: 0,
          // 最小公用模块次数
          minChunks: 2
        },
        vendor: {
          priority: 1,
          // 抽离出来
          test: /node_modules/,
          chunks: "initial",
          minSize: 0,
          minChunks: 2
        }
      }
    }
  }
复制代码

按需加载

按需加载的思想

  • 一次不加载完所有的文件内容,只加载此刻需要用到的那部分(会提前做拆分)
  • 当需要更多内容时,再对用到的内容进行即时加载

通过 es6 的 import 实现按需加载,在使用 import() 分割代码后,你的浏览器并且要支持 Promise API 才能让代码正常运行, 因为 import() 返回一个 Promise,它依赖 Promise。对于不原生支持 Promise 的浏览器,你可以注入 Promise polyfill。

let button = document.createElement("button");

button.innerHTML = "musion";

// vue,react的懒加载原理也是如此
button.addEventListener("click", function() {
  // es6草案中的语法, jsonp实现动态加载文件
  import("./source.js").then(data => {
    console.log(data.default);
  });
  console.log("click");
});

document.body.appendChild(button);
复制代码

热更新

模块热替换(HMR - Hot Module Replacement)是 webpack 提供的最有用的功能之一。它允许在运行时替换,添加,删除各种模块,而无需进行完全刷新重新加载整个页面,其思路主要有以下几个方面:

  • 保留在完全重新加载页面时丢失的应用程序的状态
  • 只更新改变的内容,以节省开发时间
  • 调整样式更加快速,几乎等同于就在浏览器调试器中更改样式

启用HRM

  1. 引入了webpack库
  2. 使用了new webpack.HotModuleReplacementPlugin()
  3. 设置devServer选项中的hot字段为true
let path = require("path");
let HtmlWebpackPlugin = require("html-webpack-plugin");
let webpack = require("webpack");

module.exports = {
  mode: "production",
  // 多入口
  entry: {
    index: "./src/index.js",
    other: "./src/other.js"
  },
  devServer: {
    // 启用热更新
    hot: true,
    port: 3000,
    open: true,
    contentBase: "./dist"
  },
  module: {
    rules: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        include: path.resolve("src"),
        use: {
          loader: "babel-loader",
          options: {
            presets: ["@babel/preset-env", "@babel/preset-react"],
            plugins: ["@babel/plugin-syntax-dynamic-import"]
          }
        }
      }
    ]
  },
  output: {
    // name -> home a
    filename: "[name].js",
    path: path.resolve(__dirname, "dist")
  },
  plugins: [
    new webpack.NamedModulesPlugin(), // 打印更新的模块路径
    new webpack.HotModuleReplacementPlugin() // 热更新插件
  ]
};
复制代码

以上所述就是小编给大家介绍的《webpack4.x 性能优化》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Ajax for Web Application Developers

Ajax for Web Application Developers

Kris Hadlock / Sams / 2006-10-30 / GBP 32.99

Book Description Reusable components and patterns for Ajax-driven applications Ajax is one of the latest and greatest ways to improve users’ online experience and create new and innovative web f......一起来看看 《Ajax for Web Application Developers》 这本书的介绍吧!

在线进制转换器
在线进制转换器

各进制数互转换器

UNIX 时间戳转换
UNIX 时间戳转换

UNIX 时间戳转换

RGB CMYK 转换工具
RGB CMYK 转换工具

RGB CMYK 互转工具