這是山月關於高級前端進階暨前端工程系列文章的第 M 篇文章 (M 隨便打的,畢竟也不知道能寫多少篇),關於前 M-1 篇文章,能夠從個人 github repo shfshanyue/blog 中找到,若是點進去的話能夠捎帶~點個贊~,若是沒有點進去的話,那就給這篇文章點個贊。。今天的文章開始了javascript
本篇文章地址在 前端工程化系列,歡迎訂閱。前端
隨着前端的發展,特別是 React
,Vue
等構造單頁應用的興起,前端的能力得以很大提高,隨之而來的是項目的複雜度愈來愈大。此時的前端的靜態資源也愈來愈龐大,而毫無疑問 javascript
資源已經是前端的主體資源,對於壓縮它的體積至爲重要。vue
爲何說更小的體積很重要呢:更小的體積對於用戶體驗來講意味着更快的加載速度以及更好的用戶體驗,這也能早就企業更大的利潤。另外,更小的體積對於服務器來講也意味更小的帶寬以及更少的服務器費用。java
前端構建編譯代碼時,可使用 webpack
中的 optimization.minimizer
來對代碼進行壓縮優化。可是咱們也須要了解如何它是壓縮代碼的,這樣當在生產環境的控制檯調試代碼時對它也有更深入的理解。node
對於咱們所編寫的代碼,它在操做系統中是一個文件,根據文件系統中的 stat
信息咱們能夠查看該文件的大小。webpack
stat
命令用來打印文件系統的信息:git
$ 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
github
$ wc -c config.js 3663 config.js
// 對兩個數求和 function sum (a, b) { return a + b; }
先把一個抽象的問題給具體化,若是是以上一段代碼,那如何壓縮它的體積呢:web
此時文件大小是 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
,抽象語法樹,js 代碼解析後的最小詞法單元,而這個過程就是經過 Parser 來完成的。
那麼 AST 能夠作什麼呢?
咱們在平常工做中常常會不經意間與它打交道,如 eslint
與 babel
,都會涉及到 js
與代碼中游走。不一樣的解析器會生成不一樣的 AST,司空見慣的是 babel 使用的解析器 babylon
,而 uglify
在代碼壓縮中使用到的解析器是 UglifyJS
。
你能夠在 AST Explorer 中直觀感覺到,以下圖:
那壓縮代碼的過程:code -> AST -> (transform)一顆更小的AST -> code,這與 babel
和 eslint
的流程如出一轍。
不要重複造輪子!
因而我找了一個久負盛名的關於代碼壓縮的庫: UglifyJS3,一個用以代碼壓縮混淆的庫。那它是如何完成一些壓縮功能的,好比替換空白符,答案是 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 官方文檔
{ { ecma: 8, }, compress: { ecma: 5, warnings: false, comparisons: false, inline: 2, }, output: { ecma: 5, comments: false, ascii_only: true, } }
在知道代碼壓縮是怎麼完成的以後,咱們終於能夠把它搬到生產環境中去壓縮代碼。終於到了實踐的時候了,雖然它只是簡單的調用 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 }) ] }
掃碼添加個人機器人微信,將會自動(自動拉人程序正在研發中)把你拉入前端高級進階學習羣
我是山月,能夠加我微信
shanyue94
與我交流,備註交流。另外能夠關注個人公衆號【全棧成長之路】