javascript 代码是如何被压缩的示例代码


Posted in Javascript onMay 06, 2020

随着前端的发展,特别是 ReactVue 等构造单页应用的兴起,前端的能力得以很大提升,随之而来的是项目的复杂度越来越大。 此时的前端的静态资源也越来越庞大,而毫无疑问 javascript 资源已是前端的主体资源,对于压缩它的体积至为重要。

为什么说更小的体积很重要呢:更小的体积对于用户体验来说意味着更快的加载速度以及更好的用户体验,这也能早就企业更大的利润。另外,更小的体积对于服务器来说也意味更小的带宽以及更少的服务器费用。

前端构建编译代码时,可以使用 webpack 中的 optimization.minimizer 来对代码进行压缩优化。但是我们也需要了解如何它是压缩代码的,这样当在生产环境的控制台调试代码时对它也有更深刻的理解。

如何查看资源的体积

对于我们所编写的代码,它在操作系统中是一个文件,根据文件系统中的 stat 信息我们可以查看该文件的大小。

stat 命令用来打印文件系统的信息:

$ stat config.js
 File: ‘config.js'
 Size: 3663      Blocks: 8     IO Block: 4096  regular file
Device: fd01h/64769d  Inode: 806060   Links: 1
Access: (0644/-rw-r--r--) Uid: (  0/  root)  Gid: (  0/  root)
Access: 2020-02-13 13:43:54.851381702 +0800
Modify: 2020-02-13 13:43:52.668417641 +0800
Change: 2020-02-13 13:43:52.691417262 +0800
 Birth: -

stat 打印的信息过大,如果只用来衡量体积,可以使用 wc -c

$ wc -c config.js
3663 config.js

如何压缩代码体积?

去除多余字符: 空格,换行及注释

// 对两个数求和
function sum (a, b) {
 return a + b;
}

先把一个抽象的问题给具体化,如果是以上一段代码,那如何压缩它的体积呢:

此时文件大小是 62 Byte , 一般来说中文会占用更大的空间。

多余的空白字符会占用大量的体积,如空格,换行符,另外注释也会占用文件体积。当我们把所有的空白符合注释都去掉之后,代码体积会得到减少。

去掉多余字符之后,文件大小已经变为 30 Byte 。 压缩后代码如下:

function sum(a,b){return a+b}

替换掉多余字符后会有什么问题产生呢?

有,比如多行代码压缩到一行时要注意行尾分号。这就需要通过以下介绍的 AST 来解决。

压缩变量名:变量名,函数名及属性名

function sum (first, second) {
 return first + second;
}

如以上 first 与 second 在函数的作用域中,在作用域外不会引用它,此时可以让它们的变量名称更短。但是如果这是一个 module 中, sum 这个函数也不会被导出呢?那可以把这个函数名也缩短。

// 压缩: 缩短变量名
function sum (x, y) {
 return x + y;
}

// 再压缩: 去除空余字符
function s(x,y){return a+b}

在这个示例中,当完成代码压缩 ( compress ) 时,代码的混淆 ( mangle ) 也捎带完成。 但此时缩短变量的命名也需要 AST 支持,不至于在作用域中造成命名冲突。

更简单的表达:合并声明以及布尔值简化

合并声明的示例如下:

// 压缩前
const a = 3;
const b = 4;

// 压缩后
const a = 3, b = 4;

布尔值简化的示例如下:

// 压缩前
!b && !c && !d && !e

// 压缩后
b||c||d||e

这个示例更是需要解析 AST 了

AST

AST ,抽象语法树,js 代码解析后的最小词法单元,而这个过程就是通过 Parser 来完成的。

那么 AST 可以做什么呢?

  • eslint: 校验你的代码风格
  • babel: 编译代码到 ES 低版本
  • taro/mpvue: 各种可以多端运行的小程序框架
  • GraphQL: 解析客户端查询

我们在日常工作中经常会不经意间与它打交道,如 eslint 与 babel ,都会涉及到 js 与代码中游走。不同的解析器会生成不同的 AST,司空见惯的是 babel 使用的解析器 babylon ,而 uglify 在代码压缩中使用到的解析器是 UglifyJS 。

你可以在 AST Explorer [3] 中直观感受到,如下图:

javascript 代码是如何被压缩的示例代码

那压缩代码的过程:code -> AST -> (transform)一颗更小的 AST -> code,这与 babel 和 eslint 的流程一模一样。

javascript 代码是如何被压缩的示例代码 

UglifyJS

不要重复造轮子!

于是我找了一个久负盛名的关于代码压缩的库: UglifyJS3 [4] ,一个用以代码压缩混淆的库。那它是如何完成一些压缩功能的,比如替换空白符,答案是 AST。

webpack 中内置的代码压缩插件就是使用了它,它的工作流程大致如下:

// 原始代码
const code = `const a = 3;`

// 通过 UglifyJS 把代码解析为 AST
const ast = UglifyJS.parse(code);
ast.figure_out_scope();


// 转化为一颗更小的 AST 树
compressor = UglifyJS.Compressor();
ast = ast.transform(compressor);

// 再把 AST 转化为代码
code = ast.print_to_string();

而当你真正使用它来压缩代码时,你只需要面向配置编程即可,文档参考 uglify 官方文档 [5]

{
 {
  ecma: 8,
 },
 compress: {
  ecma: 5,
  warnings: false,
  comparisons: false,
  inline: 2,
 },
 output: {
  ecma: 5,
  comments: false,
  ascii_only: true,
 }
}

在 webpack 中压缩代码

在知道代码压缩是怎么完成的之后,我们终于可以把它搬到生产环境中去压缩代码。终于到了实践的时候了,虽然它只是简单的调用 API 并且调调参数。

一切与性能优化相关的都可以在 optimization 中找到, TerserPlugin 是一个底层基于 uglifyjs 的用来压缩 JS 的插件。

optimization: {
 minimize: isEnvProduction,
 minimizer: [
  new TerserPlugin({
   terserOptions: {
    parse: {
     ecma: 8,
    },
    compress: {
     ecma: 5,
     warnings: false,
     comparisons: false,
     inline: 2,
    },
    output: {
     ecma: 5,
     comments: false,
     ascii_only: true,
    },
   },
   sourceMap: true
  })
 ]
}

参考资料 [1]

shfshanyue/blog: https://github.com/shfshanyue/blog

[2]

前端工程化系列: https://github.com/shfshanyue/blog/tree/master/frontend-engineering

[3]

AST Explorer: https://astexplorer.net/

[4]

UglifyJS3: https://github.com/mishoo/UglifyJS2

[5]

uglify 官方文档: https://github.com/mishoo/UglifyJS2#parse-options

到此这篇关于javascript 代码是如何被压缩的的文章就介绍到这了,更多相关js代码压缩内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

Javascript 相关文章推荐
JavaScript 基础篇之对象、数组使用介绍(三)
Apr 07 Javascript
AJAX跨域请求json数据的实现方法
Nov 11 Javascript
解决window.opener=null;window.close(),只支持IE6不支持IE7,IE8的问题
Jan 14 Javascript
jQuery中$.get、$.post、$.getJSON和$.ajax的用法详解
Nov 19 Javascript
javascript先序遍历DOM树的方法
Feb 27 Javascript
js传值后台中文出现乱码的解决方法
Jun 30 Javascript
JavaScript实现Fly Bird小游戏
Dec 15 Javascript
EasyUI折叠表格层次显示detailview详解及实例
Dec 28 Javascript
Javascript DOM事件操作小结(监听鼠标点击、释放,悬停、离开等)
Jan 20 Javascript
基于原生JS封装的Modal对话框插件的示例代码
Sep 09 Javascript
jQuery实现二级导航菜单的示例
Sep 30 jQuery
关于JavaScript轮播图的实现
Nov 20 Javascript
Layui弹框中数据表格中可双击选择一条数据的实现
May 06 #Javascript
Vue SSR 即时编译技术的实现
May 06 #Javascript
深入webpack打包原理及loader和plugin的实现
May 06 #Javascript
将Vue组件库更换为按需加载的方法步骤
May 06 #Javascript
让IDE识别webpack的别名alias的实现方法
May 06 #Javascript
JS 设计模式之:工厂模式定义与实现方法浅析
May 06 #Javascript
JS 设计模式之:单例模式定义与实现方法浅析
May 06 #Javascript
You might like
PHP使用内置函数生成图片的方法详解
2016/05/09 PHP
示例详解Laravel的注册重构
2016/08/14 PHP
laravel 5.3中自定义加密服务的方案详解
2017/05/09 PHP
ThinkPHP3.2框架自定义配置和加载用法示例
2018/06/14 PHP
JQuery浮动DIV提示信息并自动隐藏的代码
2010/08/29 Javascript
HTML复选框和单选框 checkbox和radio事件介绍
2012/12/12 Javascript
jQuery中prevAll()方法用法实例
2015/01/08 Javascript
详解JavaScript的AngularJS框架中的表达式与指令
2016/03/05 Javascript
Bootstrap模态对话框的简单使用
2016/04/29 Javascript
Bootstrap 附加导航(Affix)插件实例详解
2016/06/01 Javascript
解决Angular.Js与Django标签冲突的方案
2016/12/20 Javascript
微信端开发--登录小程序步骤
2017/01/11 Javascript
详解微信小程序开发之——wx.showToast(OBJECT)的使用
2017/01/18 Javascript
jQuery+Ajax请求本地数据加载商品列表页并跳转详情页的实现方法
2017/07/12 jQuery
nginx部署访问vue-cli搭建的项目的方法
2018/02/12 Javascript
vue中简单弹框dialog的实现方法
2018/02/26 Javascript
JavaScript实现的DOM绘制柱状图效果示例
2018/08/08 Javascript
vue 属性拦截实现双向绑定的实例代码
2018/10/24 Javascript
基于Vue实现电商SKU组合算法问题
2019/05/29 Javascript
JavaScript中EventBus实现对象之间通信
2020/10/18 Javascript
JS相册图片抖动放大展示效果的示例代码
2021/01/29 Javascript
[01:20]DOTA2 齐天大圣至宝动态展示
2016/12/13 DOTA
python解析html开发库pyquery使用方法
2014/02/07 Python
全面解析Python的While循环语句的使用方法
2015/10/13 Python
利用pyinstaller将py文件打包为exe的方法
2018/05/14 Python
更改Python的pip install 默认安装依赖路径方法详解
2018/10/27 Python
windows7 32、64位下python爬虫框架scrapy环境的搭建方法
2018/11/29 Python
基于python实现复制文件并重命名
2020/09/16 Python
css3截图_动力节点Java学院整理
2017/07/11 HTML / CSS
希尔顿酒店官方网站:Hilton Hotels
2017/06/01 全球购物
Booking.com西班牙:全球酒店预订
2018/03/30 全球购物
大二学生职业生涯规划书
2014/02/05 职场文书
学习雷锋演讲稿
2014/05/10 职场文书
英文演讲稿开场白
2014/08/25 职场文书
2014年资料员工作总结
2014/11/18 职场文书
2015年房产销售工作总结范文
2015/05/22 职场文书