Webpack —— tree-starking 解析
原文出自:https://www.pandashen.com
tree-sharking 简介
tree-sharking
是 Webpack 2
后续版本的优化功能,顾名思义,就是将多余的代码给 “摇晃” 掉,在开发中我们经常使用一些第三方库,而这些第三方库只使用了这个库的一部门功能或代码,未使用的代码也要被打包进来,这样出口文件会非常大,tree-sharking
帮我们解决了这个问题,它可以将各个模块中没有使用的方法过滤掉,只对有效代码进行打包。
AST 语法树分析
假设我们现在使用了 ElementUI 库的两个组件,通常会使用解构赋值来引入。
// 优化前
import { Button, Alert } from "element-ui";
这样引用资源, Webpack 在打包的时候会找到 element-ui
并把里面所有的代码全部打包到出口文件,我们只使用了两个组件,全部打包不是我们所希望的,tree-sharking
是通过在 Webpack 中配置 babel-plugin-import
插件来实现的,它可以将解构的代码转换成下面的形式。
// 优化后
import Button from "element-ui/lib/button";
import Alert from "element-ui/lib/Alert";
转化后会去 node_modules
中的 element-ui
模块找到 Button
和 Alert
两个组件对应的文件,并打包到出口文件中。
通过上面的转换可以看出,其实 tree-sharking
的实现原理是通过改变 AST 语法树的结构来实现的,如果不了解抽象语法树可以参考 AST 抽象语法树,我们可以通过在线转换网站 http://esprima.org/demo/parse... 将 JS 代码装换成 AST 语法树。
{"type": "Program","body": [{"type": "ImportDeclaration","specifiers": [{"type": "ImportSpecifier","local": {"type": "Identifier","name": "Button"},"imported": {"type": "Identifier","name": "Button"}},{"type": "ImportSpecifier","local": {"type": "Identifier","name": "Alert"},"imported": {"type": "Identifier","name": "Alert"}}],"source": {"type": "Literal","value": "element-ui","raw": "\"element-ui\""}}],"sourceType": "module"
}
{"type": "Program","body": [{"type": "ImportDeclaration","specifiers": [{"type": "ImportDefaultSpecifier","local": {"type": "Identifier","name": "Button"}}],"source": {"type": "Literal","value": "element-ui/lib/button","raw": "\"element-ui/lib/button\""}},{"type": "ImportDeclaration","specifiers": [{"type": "ImportDefaultSpecifier","local": {"type": "Identifier","name": "Alert"}}],"source": {"type": "Literal","value": "element-ui/lib/Alert","raw": "\"element-ui/lib/Alert\""}}],"sourceType": "module"
}
模拟 tree-starking
// 文件:babel-plugin-my-import.js
const babel = require("babel-core");
const types = require("babel-types");let code = `import { Button, Alert } from "element-ui"`;let importPlugin = {visitor: {ImportDeclaration(path) {let node = path.node;let source = node.source.value;let specifiers = node.specifiers;// 判断是否是默认导出,其中一个不是默认导出,则都不是默认导出if (!types.isImportDefaultSpecifier(specifiers[0])) {// 如果不是默认导出,则需要转换specifiers = specifiers.map(specifier => {// 数组内容:当前默认导出的标识、从哪里导入return types.importDeclaration([types.importDefaultSpecifier(specifier.local)],types.stringLiteral(`${source}/lib/${specifier.local.name.toLowerCase()}`));});// 替换树结构path.replaceWithMultiple(specifiers);}}}
};let result = babel.transform(code, {plugins: [importPlugin]
});console.log(result.code);// import Button from "element-ui/lib/button";
// import Alert from "element-ui/lib/alert";
通过上面的代码可以发现我们使用 babel-core
和 babel-types
两个模块的核心方法对语法书进行了遍历、修改和替换,更详细的 API 可以查看 https://github.com/babel/babe...。
结合 Webpack 使用插件
前面只是验证了 tree-sharking
中 JS 语法的转换过程,接下来将上面的代码转换成插件配合 Webpack 使用,来彻底感受 tree-sharking
的工作过程。
// 文件:~node_modules/babel-plugin-my-import.js
const babel = require("babel-core");
const types = require("babel-types");let importPlugin = {visitor: {ImportDeclaration(path) {let node = path.node;let source = node.source.value;let specifiers = node.specifiers;// 判断是否是默认导出,其中一个不是默认导出,则都不是默认导出if (!types.isImportDefaultSpecifier(specifiers[0])) {// 如果不是默认导出,则需要转换specifiers = specifiers.map(specifier => {// 数组内容:当前默认导出的标识、从哪里导入return types.importDeclaration([types.importDefaultSpecifier(specifier.local)],types.stringLiteral(`${source}/lib/${specifier.local.name.toLowerCase()}`));});// 替换树解构path.replaceWithMultiple(specifiers);}}}
};module.exports = importPlugin;
上面删掉了多余的测试代码,将模块中的 importPlugin
插件导出,并把 babel-plugin-my-import.js
移入了 node_modules
当中。
npm install webpack webpack-cli babel-loader babel-presets-env
npm install vue element-ui --save
安装完依赖,写一个要编译的文件,使用 Webpack 进行打包,查看使用插件前和使用插件后出口文件的大小。
// 文件:import.js
import Vue from "vue";
import { Button, Alert } from "element-ui";
下面来写一个简单的 Webpack 配置文件。
// 文件:webpcak.config.js
module.exports = {mode: "development",entry: "import.js",output: {filename: "bundle.js",path: __dirname},module: {rules: [{test: /\.js$/,use: {loader: "babel-loader",options: {presets: ["env",],plugins: [// 插件:不使用插件打包注释掉该行即可["my-import", { libararyName: "element-ui" }]]}},exclude: /node_modules/}]}
};
为了防止 babel
相关的依赖升级 7.0
后出现一些问题导致 Webpack 无法启动,再此贴出 package.json
文件,按照对应版本下载依赖保证上面 Webpack 配置生效。
文件:package.json
{"name": "ast-lesson","version": "1.0.0","description": "tree-starking","main": "index.js","scripts": {"test": "echo \"Error: no test specified\" && exit 1"},"keywords": [],"author": "","license": "ISC","dependencies": {"babel-core": "^6.26.3","babel-loader": "^7.1.5","babel-preset-env": "^1.7.0","babel-types": "^6.26.0","escodegen": "^1.10.0","esprima": "^4.0.0","estraverse": "^4.2.0","webpack": "^4.16.0","webpack-cli": "^3.0.8"},"devDependencies": {"vue": "^2.5.17","element-ui": "^2.4.6"}
}
对比使用插件前后的出口文件
接下来分别在使用插件和不使用插件时执行打包命令,查看出口文件 bondle.js
的大小。
npx webpack
使用 babel-plugin-my-import
前:
使用 babel-plugin-my-import
后:
通过对比,可以看到使用 tree-sharking
即我们自己实现的 babel-plugin-my-import
插件后,打包的出口文件大大减小,其原因是将引入第三方库没有使用的代码全都过滤掉了,只打包了有效代码。
总结
上面对 Webpack 的 tree-sharking
进行了分析,并模拟 babel-plugin-import
简易的实现了一版 tree-sharking
的优化插件,这个过程中相信大家已经了解了 tree-sharking
的原理以及实现类似插件的思路,并已经具备了开发类似插件的基本条件,最后还有一点需要补充,tree-sharking
优化的方式是根据 ES6 语法 import
“静态” 引入的特性实现的,如果要说 tree-sharking
很强大,还不如说 ES6 模块化规范 “静态” 引入的特性强大,正由于是基于 “静态” 引入,所以目前 tree-sharking
只支持遍历一层 import
关键字。
Webpack —— tree-starking 解析相关推荐
- 实战 webpack 4 配置解析四
接上篇: 实战 webpack 4 配置解析三 WEBPACK.PROD.JS 解析 现在让我们看看我们的 webpack.prod.js 配置文件,它包含了我们正在处理项目时用于生产构建的所有设置. ...
- Webpack核心概念解析
原文链接:banggan.github.io/2019/05/09/- Webpack核心概念解析 终于忙完了论文,可以愉快的开始学习了,重拾起重学前端.webpack以及Vue的源码解读作为入职前的 ...
- webpack源码解析七(optimization)
前言 前面我们写了几篇文章用来介绍webpack源码,跟着官网结合demo把整个webpack配置撸了一遍: webpack源码解析一 webpack源码解析二(html-webpack-plugin ...
- Webpack Tree Shaking
Tree Shaking tree shaking 是一个术语,通常用于描述移除 JavaScript 上下文中的未引用代码(dead-code).它依赖于 ES2015 模块语法的 静态结构 特性, ...
- 拆分js文件_2021入门Webpack,看这篇就够了:Webpack.config.js 解析
这是优妈成长记的第63篇原创 这是一个webpack配置说明 本文是发布在github上webpack-demo的README文件内容.主要对webpack.config.js每一条的注释说明. gi ...
- Webpack配置全解析(基础篇)
Webpack凭借强大的功能,成为最流行和最活跃的打包工具,也是面试时高级程序员必须掌握的"软技能":笔者结合在项目中的使用经验,介绍webpack的使用:本文是入门篇,主要介 ...
- 实战 webpack 4 配置解析一
配置 github 仓库:https://github.com/nystudio107/annotated-webpack-4-config 随着Web开发变得越来越复杂,我们需要工具来帮助我们构建现 ...
- Gin 框架 核心 httprouter tree树结构解析
gin web 是一个 go 的开源框架 他在保持简洁小巧的设计 的同时又保持了不错的性能 着其中也得益于 他在解析路由的时候用到了 httprouter 这个开源的路由解析框架 gin框架将get ...
- webpack入门与解析(一)
每次学新东西总感觉自己是不是变笨了,看了几个博客,试着试着就跑不下去,无奈只有去看官方文档. webpack是基于node的.先安装最新的node. 1.初始化 安装node后,新建一个目录,比如ht ...
- Webpack HMR 原理解析
Hot Module Replacement(以下简称 HMR)是 webpack 发展至今引入的最令人兴奋的特性之一 ,当你对代码进行修改并保存后,webpack 将对代码重新打包,并将新的模块发送 ...
最新文章
- 兼容iOS Android,React Native兼容iOS Android的TabBar
- 使用PerfView监测.NET程序性能(三):分组
- swift 拖动按钮_Swift 简单控件示例:滑块(UISlider)
- 第七章 consul docker集群
- 如何一键查看你的QQ/绑定了多少应用?
- TextView属性设置
- java生成xps文件_Java 将 Excel 转为PDF、图片、html、XPS、XML、CSV
- 在Word2019中不能插入公式的解决办法
- matlab 警告:警告: 更新 Legend 时出错。Not enough input arguments.
- [52PJ] Java面向对象笔记(转自52 1510988116)
- PowerDesigner16.5 生成MySQL 数据库模型
- T-Pot安装教程(保证能运行,附安装需要的所有东西清单)
- 如何在idea中使用Mysql
- 离散数学:常用的数学符号
- LPspice 电路仿真软件
- Windows查看网络连接并清理缓存
- 浅谈数据标注平台运营模式
- day007-列表和字典
- 燕山大学教务系统官网计算机学院,燕山大学教务系统登录入口:https://jwc.ysu.edu.cn/...
- 视频播放网站CDN内容分发网络简单代码实现
热门文章
- 生产环境部署python代码(django+uwsgi+nginx)
- 【PHP】PHPExcel类 excel常用操作小结
- python分析nginx日志的ip(中篇一)
- 【Oracle Database 12c新特性】ASM Scrubbing Disk Groups
- TortoiseSVN无法查看日志和SVN LOG无法查看日志的解决办法。
- 一个层动态放大的例子的一些知识点
- Java Abstract class and Interface
- python 基础 -- python 模块
- 写一个工具生成数据库实体类
- 第25月第2天 Django-By-Example项目记录01