We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
前言
现代前端开发已经变得十分的复杂,所以我们开发过程中会遇到如下的问题:
ES6+
TypeScript
sass
less
css
JavaScript
HTML
CSS
而webpack恰巧可以解决以上问题
webpack
原理简述
JavaScript 的 模块打包工具 (module bundler)。通过分析模块之间的依赖,最终将所有模块打包成一份或者多份代码包 (bundler),供 HTML 直接引用。实质上,Webpack 仅仅提供了 打包功能 和一套 文件处理机制,然后通过生态中的各种 Loader 和 Plugin 对代码进行预编译和打包。因此 Webpack 具有高度的可拓展性,能更好的发挥社区生态的力量。
1、读取配置文件,按命令 初始化 配置参数,创建 Compiler 对象; 2、调用插件的 apply 方法 挂载插件 监听,然后从入口文件开始执行编译; 3、按文件类型,调用相应的 Loader 对模块进行 编译,并在合适的时机点触发对应的事件,调用 Plugin 执行,最后再根据模块 依赖查找 到所依赖的模块,递归执行第三步; 4、将编译后的所有代码包装成一个个代码块 (Chuck), 并按依赖和配置确定 输出内容。这个步骤,仍然可以通过 Plugin 进行文件的修改; 5、最后,根据 Output 把文件内容一一写入到指定的文件夹中,完成整个过程;
模块机制: webpack 自己实现了一套模拟模块的机制,将其包裹于业务代码的外部,从而提供了一套模块机制; 文件编译: webpack 规定了一套编译规则,通过 Loader 和 Plugin,以管道的形式对文件字符串进行处理;
Loader
由于 Webpack 是基于 Node,因此 Webpack 其实是只能识别 js 模块,比如 css / html / 图片等类型的文件并无法加载,因此就需要一个对 不同格式文件转换器。其实 Loader 做的事,也并不难理解: 对 Webpack 传入的字符串进行按需修改。例如一个最简单的 Loader:
// html-loader/index.js module.exports = function(htmlSource) { // 返回处理后的代码字符串 // 删除 html 文件中的所有注释 return htmlSource.replace(/<!--[\w\W]*?-->/g, '') }
当然,实际的 Loader 不会这么简单,通常是需要将代码进行分析,构建 AST (抽象语法树), 遍历进行定向的修改后,再重新生成新的代码字符串。如我们常用的 Babel-loader 会执行以下步骤:
Loader 特性:
常用 Loader:
<style>
@import
url()
Plugin
Plugin 就是插件,基于事件流框架 Tapable ,插件可以扩展 Webpack 的功能。在编译的整个生命周期中,Webpack 会触发许多事件钩子,Plugin 可以监听这些事件,根据需求在相应的时间点对打包内容进行定向的修改。
class MyPlugin{ // 注册插件时,会调用 apply 方法 // apply 方法接收 compiler 对象 // 通过 compiler 上提供的 Api,可以对事件进行监听,执行相应的操作 apply(compiler){ // compilation 是监听每次编译循环 // 每次文件变化,都会生成新的 compilation 对象并触发该事件 compiler.plugin('compilation',function(compilation) {}) } }
// webpack.config.js module.export = { plugins:[ new MyPlugin(options), ] }
Webpack 就像工厂中的一条产品流水线。原材料经过 Loader 与 Plugin 的一道道处理,最后输出结果。
Webpack 事件流编程范式的核心是基础类 Tapable,是一种 观察者模式 的实现事件的订阅与广播:
const { SyncHook } = require("tapable") const hook = new SyncHook(['arg']) // 订阅 hook.tap('event', (arg) => { // 'event-hook' console.log(arg) }) // 广播 hook.call('event-hook')
Webpack 中两个最重要的类 Compiler 与 Compilation 便是继承于 Tapable,也拥有这样的事件流机制。
区别:
常用 Plugin:
编译优化
无用代码消除,是许多编程语言都具有的优化手段,这个过程称为 DCE (dead code elimination),即 删除不可能执行的代码; 例如我们的UglifyJs,它就会帮我们在生产环境中删除不可能被执行的代码,例如:
UglifyJs
var fn = function() { return 1; // 下面代码便属于 不可能执行的代码; // 通过 UglifyJs (Webpack4+ 已内置) 便会进行 DCE; var a = 1; return a; }
摇树优化 (Tree-shaking),这是一种形象比喻。我们把打包后的代码比喻成一棵树,这里其实表示的就是,通过工具 "摇" 我们打包后的 js 代码,将没有使用到的无用代码 "摇" 下来 (删除)。即 消除那些被 引用了但未被使用 的模块代码。
原理: 由于是在编译时优化,因此最基本的前提就是语法的静态分析,ES6的模块机制 提供了这种可能性。不需要运行时,便可进行代码字面上的静态分析,确定相应的依赖关系。
问题: 具有 副作用 的函数无法被 tree-shaking。
code-spliting: 代码分割 技术,将代码分割成多份进行 懒加载 或 异步加载,避免打包成一份后导致体积过大,影响页面的首屏加载;
scope hoisting: 作用域提升,将分散的模块划分到同一个作用域中,避免了代码的重复引入,有效减少打包后的代码体积和运行时的内存损耗;
node_moudles
cacheDirectory
profile:true
cheap-module-eval-source-map
hidden-source-map
The text was updated successfully, but these errors were encountered:
No branches or pull requests
现代前端开发已经变得十分的复杂,所以我们开发过程中会遇到如下的问题:
ES6+
、TypeScript
开发脚本逻辑,通过sass
、less
等方式来编写css
样式代码JavaScript
代码需要模块化,HTML
和CSS
这些资源文件也会面临需要被模块化的问题而
webpack
恰巧可以解决以上问题核心概念
JavaScript 的 模块打包工具 (module bundler)。通过分析模块之间的依赖,最终将所有模块打包成一份或者多份代码包 (bundler),供 HTML 直接引用。实质上,Webpack 仅仅提供了 打包功能 和一套 文件处理机制,然后通过生态中的各种 Loader 和 Plugin 对代码进行预编译和打包。因此 Webpack 具有高度的可拓展性,能更好的发挥社区生态的力量。
工作流程 (加载 - 编译 - 输出)
1、读取配置文件,按命令 初始化 配置参数,创建 Compiler 对象;
2、调用插件的 apply 方法 挂载插件 监听,然后从入口文件开始执行编译;
3、按文件类型,调用相应的 Loader 对模块进行 编译,并在合适的时机点触发对应的事件,调用 Plugin 执行,最后再根据模块 依赖查找 到所依赖的模块,递归执行第三步;
4、将编译后的所有代码包装成一个个代码块 (Chuck), 并按依赖和配置确定 输出内容。这个步骤,仍然可以通过 Plugin 进行文件的修改;
5、最后,根据 Output 把文件内容一一写入到指定的文件夹中,完成整个过程;
总结:
模块机制: webpack 自己实现了一套模拟模块的机制,将其包裹于业务代码的外部,从而提供了一套模块机制;
文件编译: webpack 规定了一套编译规则,通过 Loader 和 Plugin,以管道的形式对文件字符串进行处理;
由于 Webpack 是基于 Node,因此 Webpack 其实是只能识别 js 模块,比如 css / html / 图片等类型的文件并无法加载,因此就需要一个对 不同格式文件转换器。其实 Loader 做的事,也并不难理解: 对 Webpack 传入的字符串进行按需修改。例如一个最简单的 Loader:
当然,实际的 Loader 不会这么简单,通常是需要将代码进行分析,构建 AST (抽象语法树), 遍历进行定向的修改后,再重新生成新的代码字符串。如我们常用的 Babel-loader 会执行以下步骤:
Loader 特性:
常用 Loader:
<style>
标签的形式插入到 html 中;@import
和url()
,引用 css 文件与对应的资源;Plugin 就是插件,基于事件流框架 Tapable ,插件可以扩展 Webpack 的功能。在编译的整个生命周期中,Webpack 会触发许多事件钩子,Plugin 可以监听这些事件,根据需求在相应的时间点对打包内容进行定向的修改。
Webpack 就像工厂中的一条产品流水线。原材料经过 Loader 与 Plugin 的一道道处理,最后输出结果。
Webpack 事件流编程范式的核心是基础类 Tapable,是一种 观察者模式 的实现事件的订阅与广播:
Webpack 中两个最重要的类 Compiler 与 Compilation 便是继承于 Tapable,也拥有这样的事件流机制。
区别:
常用 Plugin:
代码优化:
无用代码消除,是许多编程语言都具有的优化手段,这个过程称为 DCE (dead code elimination),即 删除不可能执行的代码;
例如我们的
UglifyJs
,它就会帮我们在生产环境中删除不可能被执行的代码,例如:摇树优化 (Tree-shaking),这是一种形象比喻。我们把打包后的代码比喻成一棵树,这里其实表示的就是,通过工具 "摇" 我们打包后的 js 代码,将没有使用到的无用代码 "摇" 下来 (删除)。即 消除那些被 引用了但未被使用 的模块代码。
原理: 由于是在编译时优化,因此最基本的前提就是语法的静态分析,ES6的模块机制 提供了这种可能性。不需要运行时,便可进行代码字面上的静态分析,确定相应的依赖关系。
问题: 具有 副作用 的函数无法被 tree-shaking。
code-spliting: 代码分割
code-spliting: 代码分割 技术,将代码分割成多份进行 懒加载 或 异步加载,避免打包成一份后导致体积过大,影响页面的首屏加载;
scope hoisting: 作用域提升
scope hoisting: 作用域提升,将分散的模块划分到同一个作用域中,避免了代码的重复引入,有效减少打包后的代码体积和运行时的内存损耗;
编译性能优化
node_moudles
,避免编译第三方库中已经被编译过的代码;cacheDirectory
,可以缓存编译结果,避免多次重复编译;profile:true
,对各个编译阶段耗时进行监控,寻找耗时最多的地方;cheap-module-eval-source-map
;hidden-source-map
;引用文献
The text was updated successfully, but these errors were encountered: