webpack 是一个现代 JavaScript 应用程序的静态模块打包器(module bundler)。当 webpack 处理应用程序时,它会递归地构建一个依赖关系图(dependency graph),其中包含应用程序需要的每个模块,然后将所有这些模块打包成一个或多个 bundle

四个概念

  • entry:入口起点,可以配置多页面。
  • output:出口,项目编译完成后之后文件输出路径。
  • loader:webpack 自身只理解 JavaScript,loader 能够去处理非 JavaScript 文件并转化 JavaScript,处理源文件,一次处理一个。
  • plugins:用来扩展 webpack 功能,插件能够执行很多任务。如:打包优化、压缩等。

核心对象

  • Tapable:控制钩子的发布与订阅。
  • Compiler:webpack 的编译器,继承 Tapable 对象,可以广播和监听 webpack 事件,webpack 生命周期值存在一个 Compiler 对象。Compiler 在 webpack 启动时创建实例,compiler 实例中包含 webpack 的完整配置,包括 loaders, plugins 信息。
  • Compilation:编译器编译之后的资源信息对象,继承 Tapable 对象,可以广播和监听 webpack 事件,Compilation 实例仅代表一次 webpack 构建和生成编译资源的的过程。

webpack 开发模式开启 watch 选项,每次检测到入口文件模块变化时,会创建一次新的编译: 生成一次新的编译资源和新的 compilation 对象,这个 compilation 对象包含了当前编译的模块资源 module,编译生成的资源,变化的文件,依赖的的状态。

module、chunk、bundle

  • module:js 模块,就是被 require 或 export 的模块,如:ES 模块、commonjs 模块、 AMD 模块。
  • chunk:代码块,是进行依赖分析的时候,代码分割出来的代码块,包括一个或多个 module,是被分组了的 module 集合,code spliting 之后的就是chunk。
  • bundle:文件,最终打包出来的文件,通常一个 bundle 对应一个 chunk。

打包原理

根据文件间的依赖关系对其进行静态分析,然后将这些模块按指定规则生成静态资源。当 webpack 处理应用程序时,它会递归地构建一个依赖关系图,其中包含应用程序需要的每个模块,然后将所有这些模块打包成一个或多个 bundle。webpack 有两种组织模块的依赖方式,同步、异步。异步依赖将作为分割点,形成一个新的块;在优化了依赖树之后,每一个异步区块都将作为一个文件被打包。

构建流程

  • 生成 options(将 webpack.config.js 和 shell 中的参数合并到 options 对象)。
  • 实例化 compiler 对象 (webpack 全局对象,包含 entry、output、loader、plugins等所有配置对象)。
  • 实例化 compilation 对象(compiler.run 方法执行,开始编译过程,生成 compilation 对象)。
  • 分析入口 js 文件,调用 AST 引擎处理入口文件,生成抽象语法树 AST,根据 AST 构建模块的所有依赖。
  • 通过 loader 处理入口文件的所有依赖,转换为 js 模块,生成 AST,然后继续递归遍历,直至所有依赖被分析完毕。
  • 对生成的所有 module 进行处理,调用 plugins,合并,拆分,生成 chunk。
  • 将 chunk 生成为对应 bundle 文件,输出到目录。

HMR(热更新)

模块热替换功能会在应用程序应用过程中进行替换、添加或者删除模块,无需加载整个页面。主要通过以下几种方式:

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

webpack 的热更新,只是提供一套接口和基础的模块替换的实现。开发者需要在代码中通过热更新的接口(module.hot.xxx)向 webpack 声明依赖模块和当前模块是否能够更新,以及更新的前后进行的处理。如果接受更新,那么需要开发者自己来在模块替换前清理或者保留必要的数据、状态,并在模块被替换后恢复之前的数据、状态。在 vue-cli 等脚手架中,热更新的开发者这边的工作是由 vue-loader、css-loader 等加载器已经完成了,再配合 webpack 的 module.hot 等 API 来完成了热更新。

大致热更新流程:webpack 进行文件变化监听,服务端和客户端使用 websocket 进行通信,服务端传递模块变化信息给客户端,客户端根据文件变化消息获取变更模块代码,进行模块的替换。

  • 运行时开启热更新配置,在打包的 bundle 里面包含 HMR runtime 及 websocket 功能。
  • 服务端与客户端建立 websocket 长连接。
  • webpack 监听文件变化,文件保存时触发 webpack 重新编译,编译后代码保存在内存中。
  • 编译时会生成 hot-update.json (已改动模块的 json)、hot-update.js (已改动模块的 js)。
  • 通过 websocket 向客户端发送 hash 值。
  • 客户端对比 hash 值,一致走缓存,不一致再通过 Ajax 获取 hot-update.json,json 包含模块 hash 值,再通过 jsonp 请求获取 hot-update.js。
  • 热更新 js 模块,若失败,则 live reload 刷新浏览器代替热更新(若模块未配置热更新,则同样 live reload)。

webpack如何管理模块

当编译器开始运行、解析和映射应用程序时,manifest 数据集合会保留所有模块的详细要点。当完成打包并发送到浏览器时,会在运行通过 manifest 来解析和加载模块。无论选择哪种模块语法,import 或者 require 都已转换为 __webpack_require__ 方法,此方法指向模块标识符。通过使用 manifest 中的数据,runtime 能够查询模块标识符,检索出背后对应的模块。

style-loader 与 css-loader

css-loader 用来识别 css 文件,转为 js 对象。

style-loader 将 css-loader 编译之后的 js 对象转为 css 并插入 DOM 中。

tree shaking

移除 JavaScript 上下文中的未引用代码(dead-code)。

// 用法  package.json
{
sideEffects: false
}

这个有一定的副作用:如果一个文件执行一些特殊功能,而不是仅仅暴露一个或多个 export,比如 polyfill,影响全局作用域,通常又不提供 export,那么它将会被移除。

如果所有代码都不含副作用,则可以标记为 false,如果有,那么就提供一个数组:

{
"name": "your-project",
"sideEffects": [
"./src/some-side-effectful-file.js"
]
}

在项目中,任何导入的文件都受 tree shaking 影响,比如导入的 css 文件,我们则需要将它们添加进去:

{
"name": "your-project",
"sideEffects": [
"./src/some-side-effectful-file.js",
"*.css"
]
}

shimming全局变量

webpack 中如果需要用到的不规范的第三方库,有可能会引起全局依赖,如 jQuery 的 $。但是如果我们需要用到一个全局变量,可以使用 ProvidePlugin 后,能够在通过 webpack 编译的每个模块中,通过访问一个变量来获取到 package 包。如果 webpack 知道这个变量在某个模块中被使用了,那么 webpack 将在最终 bundle 中引入我们给定的 package。

const path = require('path');
const webpack = require('webpack'); module.exports = {
entry: './src/index.js',
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist')
}
},
plugins: [
new webpack.ProvidePlugin({
_: 'lodash'
})
]
}

polyfills 加载优化

// 传统引入方式
npm install --save babel-polyfill // src/main.js
import 'babel-polyfill'; ......

polyfills 虽然是一种模块引入方式,但是并不推荐在主 bundle 中引入 polyfills,因为这不利于具备这些模块功能的现代浏览器用户,会使他们下载体积很大、但却不需要的脚本文件。

让我们把 import 放入一个新文件,并加入 whatwg-fetch polyfill:

npm install --save whatwg-fetch

// 新建 src/polyfills.js
import 'babel-polyfill';
import 'whatwg-fetch'; // webpack.config.js
const path = require('path');
const webpack = require('webpack'); module.exports = {
entry: './src/index.js',
entry: {
polyfills: './src/polyfills.js',
index: './src/index.js'
},
output: {
filename: '[name].bundle.js',
path: path.resolve(__dirname, 'dist')
}
};
// index.html 然后根据条件引入
<!doctype html>
<html>
<head>
<title>Getting Started</title>
<script>
var modernBrowser = (
'fetch' in window &&
'assign' in Object
); if ( !modernBrowser ) {
var scriptElement = document.createElement('script'); scriptElement.async = false;
scriptElement.src = '/polyfills.bundle.js';
document.head.appendChild(scriptElement);
}
</script>
</head>
<body>
<script src="index.bundle.js"></script>
</body>
</html>

webpack 优化

  • 保持 node.js 最新版本:较新的版本能够建立更高效的模块树以及提高解析速度。
  • loaders 应用于最少数的必要模块:
    // no
    {
    test: /\.js$/,
    loader: "babel-loader"
    } // yes
    {
    test: /\.js$/,
    include: path.resolve(__dirname, "src"),
    loader: "babel-loader"
    }
  • 尽量少使用不同的 loader/plugin 工具:每个额外的 loader/plugin 都有启动时间。
  • 使用 Dlls:使用 DllPlugin 将更改不频繁的代码进行单独编译。这将改善引用程序的编译速度,即使它增加了构建过程的复杂性。
  • 尽量保持 chunks 小巧:减少编译的整体大小,以提高构建性能。
  • Worker Poll:thread-loader 可以将非常消耗资源的 loaders 转存到 worker pool 中。
  • 持久化缓存:使用 cache-loader 启用持久化缓存。使用 package.json 中的 "postinstall" 清除缓存目录。
  • 关闭 Source Maps:Source Maps很耗性能。
  • 开发环境中避免用到只有在生产环境中才能用到的工具:
    UglifyJsPlugin
    ExtractTextPlugin
    [hash]/[chunkhash]
    AggressiveSplittingPlugin
    AggressiveMergingPlugin
    ModuleConcatenationPlugin

未完待续......

web前端知识点(webpack篇)的更多相关文章

  1. 25、前端知识点--webpack篇之面试考点

    前端面试之webpack篇 https://blog.csdn.net/sinat_17775997/article/details/78122999 关于webpack的面试题 随着现代前端开发的复 ...

  2. web前端知识点(JavaScript篇)

    call,apply,bind call,apply,bind这三者的区别,及内部实现原理,点这里 promise promise函数的内部实现原理,点这里 闭包 闭包就是能够读取其他函数内部变量的函 ...

  3. web前端知识点

    一.CSS问题 1.flex布局 display:flex; 在父元素设置,子元素受弹性盒影响,默认排成一行,如果超出一行,按比例压缩 flex:1; 子元素设置,设置子元素如何分配父元素的空间,fl ...

  4. 27、前端知识点--webpack面试题(二)

    webpack面试题总结 本文主要是对webpack面试会常被问到的问题做一些总结,且文章会不断持续更新 1.webpack打包原理 把所有依赖打包成一个 bundle.js 文件,通过代码分割成单元 ...

  5. 23、前端知识点--webpack的使用详解

    Webpack 是当下最热门的前端资源模块化管理和打包工具. https://www.cnblogs.com/zhangruiqi/p/7656206.html

  6. Web前端知识点记录

    一.HTML的加载顺序 浏览器边下载HTML,边解析HTML代码,二者是从上往下同步进行的 先解析<head>中的代码,在<head>中遇到了<script>标签, ...

  7. web前端知识点1

    1. input属于窗体元素,层级显示比flash.其它元素都高.请判断这句话的正确与否. 错误 层级显示优先级: frameset > 表单元素 > 非表单元素 在html中,帧元素(f ...

  8. web前端知识点反思总结

    当别人问你之前的知识,我们便会勾起之前的回忆,然后进行一番痛苦的挣扎后,发现我依然记得你 什么是 DTD ? 文档类型定义 (DTD) 可定义合法的 xml 文档的构建模块 ,他是使用一系列合法的元素 ...

  9. Web 前端知识点

随机推荐

  1. Spark GraphX从入门到实战

      第1章 Spark GraphX 概述 1.1 什么是 Spark GraphX   Spark GraphX 是一个分布式图处理框架,它是基于 Spark 平台提供对图计算和图挖掘简洁易用的而丰 ...

  2. Pycharm下安装Numpy包

    Numpy--Numerical Python,是一个基于Python的可以存储和处理大型矩阵的库.几乎是Python 生态系统的数值计算的基石,例如Scipy,Pandas,Scikit-learn ...

  3. Android开发Fragment的使用学习

    基本概念 Fragment是Android3.0(API11)提出的概念,support-v4库中也开发了一套Fragment API,最低兼容Android 1.6.所以在开发中要注意不要导错包 导 ...

  4. fatal error C1083: Cannot open include file: '_defs.h': No such file or directory

    b-PAC SDK: https://www.baidu.com/link?url=p6FcG0fvFl6XJf9QdSFLBP16eaS03jOQsdr0zd8cYprHWwqVy5t53bzMrA ...

  5. thinkphp3.2 where 条件查询

    thinkphp3.2 where 条件查询 在连贯操作中条件where的操作有时候自己很晕,所以整理下,有助于使用 查询条件 支持的表达式查询,tp不区分大小写 含义 TP运算符 SQL运算符 例子 ...

  6. 自由切换 网页上的 ico 图标

    自由切换 网页上的   ico   图标: 第一步:      进入这个网站 :https://www.uupoop.com/ico/?action=make 第二步:      进入网站后,然后选择 ...

  7. 详述@Responsebody和HTTP异步请求的关系

    Map.ModelAndView.User.List等对象都可以作为返回值.上述这两种对象都可以使用此注解.使用此注解即表示是在同一次请求的响应体里返回.浏览器以异步http的方式来接收.比如后端的M ...

  8. (二)、JAVA运行时数据区域

    根据<Java 虚拟机规范(Java SE 7版)>规定,Java虚拟机所管理的内存,将会包括以下几个运行时数据区域: 注: 1.由所有线程共享的数据区: 对应 java内存模型的主内存, ...

  9. linux网络编程-一个简单的线程池(41)

    有时我们会需要大量线程来处理一些相互独立的任务,为了避免频繁的申请释放线程所带来的开销,我们可以使用线程池 1.线程池拥有若干个线程,是线程的集合,线程池中的线程数目有严格的要求,用于执行大量的相对短 ...

  10. 利用xampp集成环境搭建pikachu靶场及部分问题解决

    xampp的环境部署 1.本地服务器的搭建 首先要到官网下载xampp https://www.apachefriends.org/zh_cn/index.html 有各个不同的系统版本,这里我们选择 ...