摘要:今天研究的對(duì)象是抽象語(yǔ)法樹(shù)它以樹(shù)狀的形式表現(xiàn)編程語(yǔ)言的語(yǔ)法結(jié)構(gòu),樹(shù)上的每個(gè)節(jié)點(diǎn)都表示源代碼中的一種結(jié)構(gòu)??偨Y(jié)發(fā)現(xiàn)水很深平時(shí)接觸的也比較少今天算是個(gè)入門(mén)了解下作為理解源碼前的鋪墊。參考源碼參考文檔
什么是AST
樹(shù)是一種重要的數(shù)據(jù)結(jié)構(gòu),由根結(jié)點(diǎn)和若干顆子樹(shù)構(gòu)成的。 根據(jù)結(jié)構(gòu)的不同又可以劃分為二叉樹(shù),trie樹(shù),紅黑樹(shù)等等。
今天研究的對(duì)象是AST,抽象語(yǔ)法樹(shù),它以樹(shù)狀的形式表現(xiàn)編程語(yǔ)言的語(yǔ)法結(jié)構(gòu),樹(shù)上的每個(gè)節(jié)點(diǎn)都表示源代碼中的一種結(jié)構(gòu)。
通過(guò)操作這棵樹(shù),可以精準(zhǔn)的定位到聲明、賦值、運(yùn)算語(yǔ)句,從而實(shí)現(xiàn)對(duì)代碼的分析、優(yōu)化、變更等操作。
AST處理步驟代碼風(fēng)格,語(yǔ)法的檢查,IDE中的錯(cuò)誤提示,格式化,自動(dòng)補(bǔ)全等等
優(yōu)化變更代碼,代碼壓縮等等
es6轉(zhuǎn)es5,以及TypeScript、JSX等轉(zhuǎn)化為原生Javascript等等
js中借助于一些庫(kù)可以把js源碼解析為語(yǔ)法樹(shù),比如 Babylon, esprima、acorn、UglifyJS、AST explorer等等,如下所示是一個(gè)簡(jiǎn)單的示例。
var a = 42; var b = 5; ar c = a + b;
說(shuō)明 一個(gè)簡(jiǎn)單的ast樹(shù)示例,對(duì)應(yīng)的json格式如下所示
{ "type": "Program", "start": 0, "end": 37, "body": [ { "type": "VariableDeclaration", "start": 0, "end": 11, "declarations": [ { "type": "VariableDeclarator", "start": 4, "end": 10, "id": { "type": "Identifier", "start": 4, "end": 5, "name": "a" }, "init": { "type": "Literal", "start": 8, "end": 10, "value": 42, "raw": "42" } } ], "kind": "var" }, { "type": "VariableDeclaration", "start": 12, "end": 22, "declarations": [ { "type": "VariableDeclarator", "start": 16, "end": 21, "id": { "type": "Identifier", "start": 16, "end": 17, "name": "b" }, "init": { "type": "Literal", "start": 20, "end": 21, "value": 5, "raw": "5" } } ], "kind": "var" }, { "type": "VariableDeclaration", "start": 23, "end": 37, "declarations": [ { "type": "VariableDeclarator", "start": 27, "end": 36, "id": { "type": "Identifier", "start": 27, "end": 28, "name": "c" }, "init": { "type": "BinaryExpression", "start": 31, "end": 36, "left": { "type": "Identifier", "start": 31, "end": 32, "name": "a" }, "operator": "+", "right": { "type": "Identifier", "start": 35, "end": 36, "name": "b" } } } ], "kind": "var" } ], }
通過(guò)操縱解析出來(lái)的ast,可以實(shí)現(xiàn)我們AST應(yīng)用場(chǎng)景中列出的一些應(yīng)用。
下面針對(duì)上面列出的ast樹(shù)做一些簡(jiǎn)單說(shuō)明:
任何一顆ast樹(shù)根節(jié)點(diǎn)的類型都是Program,start和end記錄了字符的位置,body表示程序體,其內(nèi)部是三個(gè)簡(jiǎn)單的變量聲明,每個(gè)變量聲明中記錄了標(biāo)示符以及字面量的值。最后一個(gè)變量c中init是一個(gè)BinaryExpression(二元運(yùn)算表達(dá)),記錄的不是字面值,而是引用到的標(biāo)示符和操作符。想要實(shí)現(xiàn)應(yīng)用場(chǎng)景中舉的示例,大致就是遍歷,修改,刪除,移動(dòng)這棵樹(shù)上的節(jié)點(diǎn),最后遍歷處理后ast生成最終代碼。
//compile.js this.hooks.make.callAsync(compilation, err => {}); ---- //NormalModules.js runLoaders( { resource: this.resource, loaders: this.loaders, context: loaderContext, readResource: fs.readFile.bind(fs) }, (err, result) => { this._source = this.createSource( this.binary ? asBuffer(source) : asString(source), resourceBuffer, sourceMap ); return callback(); } ); ---------------------------------- //Parse.js const acorn = require("acorn-dynamic-import").default; ast = acorn.parse(code, parserOptions); if (this.hooks.program.call(ast, comments) === undefined) { this.detectStrictMode(ast.body); this.prewalkStatements(ast.body); this.walkStatements(ast.body); }
說(shuō)明 上面是webpack源碼中摘取的和ast處理有關(guān)的上下文關(guān)鍵片段
在webpack執(zhí)行流程中,make是一個(gè)重要的階段,在一個(gè)新的 Compilation 創(chuàng)建完畢后,即將從 Entry 開(kāi)始讀取文件,根據(jù)文件類型和配置的 Loader 對(duì)文件進(jìn)行編譯,將loader處理后的文件通過(guò)acorn抽象成抽象語(yǔ)法樹(shù)AST,然后遍歷AST,遞歸分析構(gòu)建該模塊的所有依賴。
發(fā)現(xiàn)ast水很深,平時(shí)接觸的也比較少, 今天算是個(gè)入門(mén)了解下,作為理解webpack源碼前的鋪墊。
參考源碼
webpack: "4.4.1"
webpack-cli: "2.0.13"
參考文檔
https://github.com/acornjs/acorn
https://zh.wikipedia.org/wiki...
https://www.sitepoint.com/und...
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://hztianpu.com/yun/93966.html
摘要:引言通過(guò)前面幾張的鋪墊下面開(kāi)始分析源碼核心流程大體上可以分為初始化編譯輸出三個(gè)階段下面開(kāi)始分析初始化這個(gè)階段整體流程做了什么啟動(dòng)構(gòu)建,讀取與合并配置參數(shù),加載,實(shí)例化。推薦源碼之源碼之機(jī)制源碼之簡(jiǎn)介源碼之機(jī)制參考源碼 引言 通過(guò)前面幾張的鋪墊,下面開(kāi)始分析webpack源碼核心流程,大體上可以分為初始化,編譯,輸出三個(gè)階段,下面開(kāi)始分析 初始化 這個(gè)階段整體流程做了什么? 啟動(dòng)構(gòu)建,讀...
摘要:是一個(gè)對(duì)象,它表示兩個(gè)節(jié)點(diǎn)之間的連接。接著返回一個(gè)對(duì)象,其屬性是這個(gè)插件的主要節(jié)點(diǎn)訪問(wèn)者。所以上面的執(zhí)行方式是運(yùn)行引入了自定義插件的打包文件現(xiàn)在為明顯減小,自定義插件成功插件文件目錄覺(jué)得好玩就關(guān)注一下歡迎大家收藏寫(xiě)評(píng)論 目錄 Babel簡(jiǎn)介 Babel運(yùn)行原理 AST解析 AST轉(zhuǎn)換 寫(xiě)一個(gè)Babel插件 Babel簡(jiǎn)介 Babel 是一個(gè) JavaScript 編譯器,它能將es...
前言 本文所有內(nèi)容全部發(fā)布再個(gè)人博客主頁(yè) https://github.com/muwoo/blogs歡迎訂閱。不過(guò)最近因?yàn)槭虑楸容^多,有一段時(shí)間沒(méi)有更新了,后面打算繼續(xù)不斷學(xué)習(xí)更新,歡迎小伙伴一起溝通交流~ 最近更新 前端單測(cè)的那些事 基于virtual dom 的canvas渲染 js Event loop 機(jī)制簡(jiǎn)介 axios 核心源碼實(shí)現(xiàn)原理 JS 數(shù)據(jù)類型、賦值、深拷貝和淺拷貝 j...
前言 本文所有內(nèi)容全部發(fā)布再個(gè)人博客主頁(yè) https://github.com/muwoo/blogs歡迎訂閱。不過(guò)最近因?yàn)槭虑楸容^多,有一段時(shí)間沒(méi)有更新了,后面打算繼續(xù)不斷學(xué)習(xí)更新,歡迎小伙伴一起溝通交流~ 最近更新 前端單測(cè)的那些事 基于virtual dom 的canvas渲染 js Event loop 機(jī)制簡(jiǎn)介 axios 核心源碼實(shí)現(xiàn)原理 JS 數(shù)據(jù)類型、賦值、深拷貝和淺拷貝 j...
前言 本文所有內(nèi)容全部發(fā)布再個(gè)人博客主頁(yè) https://github.com/muwoo/blogs歡迎訂閱。不過(guò)最近因?yàn)槭虑楸容^多,有一段時(shí)間沒(méi)有更新了,后面打算繼續(xù)不斷學(xué)習(xí)更新,歡迎小伙伴一起溝通交流~ 最近更新 前端單測(cè)的那些事 基于virtual dom 的canvas渲染 js Event loop 機(jī)制簡(jiǎn)介 axios 核心源碼實(shí)現(xiàn)原理 JS 數(shù)據(jù)類型、賦值、深拷貝和淺拷貝 j...
閱讀 3795·2023-04-26 02:55
閱讀 3005·2021-11-02 14:38
閱讀 4321·2021-10-21 09:39
閱讀 3004·2021-09-27 13:36
閱讀 4161·2021-09-22 15:08
閱讀 2829·2021-09-08 10:42
閱讀 2945·2019-08-29 12:21
閱讀 831·2019-08-29 11:22