成人无码视频,亚洲精品久久久久av无码,午夜精品久久久久久毛片,亚洲 中文字幕 日韩 无码

資訊專欄INFORMATION COLUMN

babel插件入門-AST

sanyang / 2073人閱讀

摘要:是一個對象,它表示兩個節(jié)點之間的連接。接著返回一個對象,其屬性是這個插件的主要節(jié)點訪問者。所以上面的執(zhí)行方式是運行引入了自定義插件的打包文件現(xiàn)在為明顯減小,自定義插件成功插件文件目錄覺得好玩就關(guān)注一下歡迎大家收藏寫評論

目錄

Babel簡介

Babel運行原理

AST解析

AST轉(zhuǎn)換

寫一個Babel插件

Babel簡介

Babel 是一個 JavaScript 編譯器,它能將es2015,react等低端瀏覽器無法識別的語言,進行編譯。

上圖的左邊代碼中有箭頭函數(shù),Babel將進行了源碼轉(zhuǎn)換,下面我們來看Babel的運行原理。

Babel運行原理

Babel 的三個主要處理步驟分別是:

解析(parse),轉(zhuǎn)換(transform),生成(generate)。.

其過程分解用語言描述的話,就是下面這樣:

解析

使用 babylon 解析器對輸入的源代碼字符串進行解析并生成初始 AST(File.prototype.parse)

利用 babel-traverse 這個獨立的包對 AST 進行遍歷,并解析出整個樹的 path,通過掛載的 metadataVisitor 讀取對應(yīng)的元信息,這一步叫 set AST 過程

轉(zhuǎn)換

transform 過程:遍歷 AST 樹并應(yīng)用各 transformers(plugin) 生成變換后的 AST 樹

babel 中最核心的是 babel-core,它向外暴露出 babel.transform 接口。

let result = babel.transform(code, {
    plugins: [
        arrayPlugin
    ]
})

生成

利用 babel-generatorAST 樹輸出為轉(zhuǎn)碼后的代碼字符串

AST解析

AST解析會把拿到的語法,進行樹形遍歷,對語法的每個節(jié)點進行響應(yīng)的變化和改造再生產(chǎn)新的代碼字符串

節(jié)點(node)

AST將開頭提到的箭頭函數(shù)轉(zhuǎn)根據(jù)節(jié)點換為節(jié)點樹

ES2015箭頭函數(shù)

codes.map(code=>{
    return code.toUpperCase()
})

AST樹形遍歷轉(zhuǎn)換后的結(jié)構(gòu)

{
    type:"ExpressionStatement",
    expression:{
        type:"CallExpression"
        callee:{
            type:"MemberExpression",
            computed:false
            object:{
                type:"Identifier",
                name:"codes"
            }
            property:{
                type:"Identifier",
                name:"map"
            }
            range:[]
        }
        arguments:{
            {
                type:"ArrowFunctionExpression",
                id:null,
                params:{
                    type:"Identifier",
                    name:"code",
                    range:[]
                }
                body:{
                    type:"BlockStatement"
                    body:{
                        type:"ReturnStatement",
                        argument:{
                            type:"CallExpression",
                            callee:{
                                type:"MemberExpression"
                                computed:false
                                object:{
                                    type:"Identifier"
                                    name:"code"
                                    range:[]
                                }
                                property:{
                                    type:"Identifier"
                                    name:"toUpperCase"
                                }
                                range:[]
                            }
                            range:[]
                        }
                    }
                    range:[]
                }
                generator:false
                expression:false
                async:false
                range:[]
            }
        }
    }
}

我們從 ExpressionStatement開始往樹形結(jié)構(gòu)里面走,看到它的內(nèi)部屬性有callee,type,arguments,所以我們再依次訪問每一個屬性及它們的子節(jié)點。

于是就有了如下的順序

進入  ExpressionStatement
進入  CallExpression
進入  MemberExpression
進入  Identifier
離開  Identifier
進入  Identifier
離開  Identifier
離開  MemberExpression
進入  ArrowFunctionExpression
進入  Identifier
離開  Identifier
進入  BlockStatement
進入  ReturnStatement
進入  CallExpression
進入  MemberExpression
進入  Identifier
離開  Identifier
進入  Identifier
離開  Identifier
離開  MemberExpression
離開  CallExpression
離開  ReturnStatement
離開  BlockStatement
離開  ArrowFunctionExpression
離開  CallExpression
離開  ExpressionStatement
離開  Program

Babel 的轉(zhuǎn)換步驟全都是這樣的遍歷過程。(有點像koa的洋蔥模型??)

AST轉(zhuǎn)換

解析好樹結(jié)構(gòu)后,我們手動對箭頭函數(shù)進行轉(zhuǎn)換。

對比兩張圖,發(fā)現(xiàn)不一樣的地方就是兩個函數(shù)的arguments.type

解析代碼
let babel = require("babel-core");//babel核心庫
let types = require("babel-types");
let code = `codes.map(code=>{return code.toUpperCase()})`;//轉(zhuǎn)換語句

let visitor = {
    ArrowFunctionExpression(path) {//定義需要轉(zhuǎn)換的節(jié)點
        let params = path.node.params
        let blockStatement = path.node.body
        let func = types.functionExpression(null, params, blockStatement, false, false)
        path.replaceWith(func) //
    }
}

let arrayPlugin = { visitor }
let result = babel.transform(code, {
    plugins: [
        arrayPlugin
    ]
})
console.log(result.code)
注意: ArrowFunctionExpression() { ... } 是 ArrowFunctionExpression: { enter() { ... } } 的簡寫形式。

Path 是一個對象,它表示兩個節(jié)點之間的連接。

解析步驟

定義需要轉(zhuǎn)換的節(jié)點

    ArrowFunctionExpression(path) {
        ......
    }

創(chuàng)建用來替換的節(jié)點

types.functionExpression(null, params, blockStatement, false, false)

babel-types文檔鏈接

在node節(jié)點上找到需要的參數(shù)

replaceWith(替換)

寫一個Babel插件

從一個接收了 babel 對象作為參數(shù)的 function 開始。

export default function(babel) {
  // plugin contents
}

接著返回一個對象,其 visitor 屬性是這個插件的主要節(jié)點訪問者。

export default function({ types: t }) {
  return {
    visitor: {
      // visitor contents
    }
  };
};

我們?nèi)粘R胍蕾嚨臅r候,會將整個包引入,導(dǎo)致打包后的代碼太冗余,加入了許多不需要的模塊,比如index.js三行代碼,打包后的文件大小就達到了483 KiB,

index.js

import { flatten, join } from "lodash";
let arr = [1, [2, 3], [4, [5]]];
let result = _.flatten(arr);

所以我們這次的目的是將

import { flatten, join } from "lodash";

轉(zhuǎn)換為從而只引入兩個lodash模塊,減少打包體積

import flatten from "lodash/flatten";
import join from "lodash/join";

實現(xiàn)步驟如下:

在項目下的node_module中新建文件夾 babel-plugin-extraxt

注意:babel插件文件夾的定義方式是 babel-plugin-插件名 
我們可以在.babelrc的plugin中引入自定義插件 或者在webpack.config.js的loader options中加入自定義插件

在babel-plugin-extraxt新建index.js

module.exports = function ({types:t}) {
    return {
        // 對import轉(zhuǎn)碼
        visitor:{
            ImportDeclaration(path, _ref = { opts: {} }) {
                const specifiers = path.node.specifiers;
                const source = path.node.source;
                // 只有l(wèi)ibraryName滿足才會轉(zhuǎn)碼
                if (_ref.opts.library == source.value && (!t.isImportDefaultSpecifier(specifiers[0]))) { //_ref.opts是傳進來的參數(shù)
                    var declarations = specifiers.map((specifier) => {      //遍歷  uniq extend flatten cloneDeep
                        return t.ImportDeclaration(                         //創(chuàng)建importImportDeclaration節(jié)點
                            [t.importDefaultSpecifier(specifier.local)],
                            t.StringLiteral(`${source.value}/${specifier.local.name}`)
                        )
                    })
                    path.replaceWithMultiple(declarations)
                }
            }
        }
    };
}

修改webpack.prod.config.js中babel-loader的配置項,在plugins中添加自定義的插件名

rules: [{
    test: /.js$/,
    loader: "babel-loader",
    options: {
        presets: ["env","stage-0"],
        plugins: [
            ["extract", { "library":"lodash"}],
            ["transform-runtime", {}]
        ]
    }
}]
注意:plugins 的插件使用順序是順序的,而 preset 則是逆序的。所以上面的執(zhí)行方式是extract>transform-runtime>env>stage-0

運行引入了自定義插件的webpack.config.js

打包文件現(xiàn)在為21.4KiB,明顯減小,自定義插件成功!~

插件文件目錄

YUAN-PLUGINS
|
| - node_modules
|   |
|   | - babel-plugins-extract
|           |
|           index.js
|   
| - src
|   | - index.js
|
| - webpack.config.js
覺得好玩就關(guān)注一下~歡迎大家收藏寫評論~~~

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://m.hztianpu.com/yun/93831.html

相關(guān)文章

  • Babel插件開發(fā)入門示例詳解

    摘要:的工作過程的處理主要過程解析轉(zhuǎn)換生成。代碼轉(zhuǎn)換處理,處理工具插件等就是在這個階段進行代碼轉(zhuǎn)換,返回新的。若感興趣了解更多內(nèi)容,插件中文開發(fā)文檔提供了很多詳細資料。 Babel簡介 Babel是Javascript編譯器,是種代碼到代碼的編譯器,通常也叫做『轉(zhuǎn)換編譯器』。 Babel的工作過程 Babel的處理主要過程:解析(parse)、轉(zhuǎn)換(transform)、生成(generat...

    Muninn 評論0 收藏0
  • Babel入門插件開發(fā)

    摘要:最近的技術(shù)項目里大量用到了需要修改源文件代碼的需求,也就理所當然的用到了及其插件開發(fā)。在這里我要推薦一款實現(xiàn)了這些標簽的插件,建議在你的項目中加入這個插件并用起來,不用再艱難的書寫三元運算符,會大大提升你的開發(fā)效率。具體可以參見插件手冊。 最近的技術(shù)項目里大量用到了需要修改源文件代碼的需求,也就理所當然的用到了Babel及其插件開發(fā)。這一系列專題我們介紹下Babel相關(guān)的知識及使用。 ...

    Jinkey 評論0 收藏0
  • 24 個實例入門并掌握「Webpack4」(三)

    摘要:繼個實例入門并掌握二后續(xù)配置配置配置使用加快打包速度多頁面打包配置編寫編寫編寫十七配置源碼地址本節(jié)使用的代碼為基礎(chǔ)我們來模擬平時開發(fā)中,將打包完的代碼防止到服務(wù)器上的操作,首先打包代碼然后安裝一個插件在中配置一個命令運 繼 24 個實例入門并掌握「Webpack4」(二) 后續(xù): PWA 配置 TypeScript 配置 Eslint 配置 使用 DLLPlugin 加快打包速度 多...

    mindwind 評論0 收藏0
  • babel的初步了解

    摘要:表示的是在嚴格模式下解析并且允許模塊定義即能識別和語法識別不了。 前段時間開始研究ast,然后慢慢的順便把babel都研究了,至于ast稍后的時間會寫一篇介紹性博客專門介紹ast,本博客先介紹一下babel的基本知識點。 背景: 由于現(xiàn)在前端出現(xiàn)了很多非es5的語法,如jsx,.vue,ts等等的格式和寫法,如果要在瀏覽器的設(shè)備上識別并執(zhí)行,需要額外將這些非傳統(tǒng)格式的語法轉(zhuǎn)成傳統(tǒng)的es...

    _Dreams 評論0 收藏0
  • babel+小程序】記“編寫babel插件”與“通過語法解析替換小程序路由表”的經(jīng)歷

    摘要:而掃描各個模塊并合并路由表的腳本非常簡單,讀寫文件就了。編寫插件之前先要理解抽象語法樹這個概念。的解析器,的配置。編寫腳本識別字段思路首先獲取到源代碼是類單文件的語法。獲取內(nèi)的字段,并替換成已生成的路由表。 話不多說先上圖,簡要說明一下干了些什么事。圖可能太模糊,可以點svg看看showImg(https://segmentfault.com/img/bV3fs4?w=771&h=63...

    李昌杰 評論0 收藏0

發(fā)表評論

0條評論

閱讀需要支付1元查看
<