国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

babel各單元簡介&如何寫一個babel插件

peixn / 2525人閱讀

摘要:是怎么工作的如何編譯應用場景語法糖的代碼統一相關概念介紹依賴,提供的方法,只轉化語法,不轉換類,的基礎配置利用對進行劫持,在中進行原理見同時對后的進行緩存,提高下次效率讀取緩存根據判斷是否需要重新中傳入配置入口函數提供

Babel babel是怎么工作的?

parse->AST->transform->gengerate

如何編譯js->AST

babel應用場景

語法糖的polyfill

代碼統一hack

相關概念介紹 babel-polyfill

依賴core-js,提供es*->es3的方法,只轉化語法,不轉換API(類Promise,WeakMap)

babel-helper babel-register(0.7.0-beta)

babel的基礎配置init

利用pirate對require進行劫持,在hook中進行babel 原理見

同時對babel后的code進行緩存,提高下次babel效率

function compile(code, filename) {
    ...

  let cacheKey = `${JSON.stringify(opts)}:${babel.version}`;

  const env = babel.getEnv(false);

  if (env) cacheKey += `:${env}`;

    //讀取緩存 根據mtime判斷是否需要重新babel
  if (cache) {
    const cached = cache[cacheKey];
    if (cached && cached.mtime === mtime(filename)) {
      return cached.code;
    }
  }

  const result = babel.transform(code, {
    ...opts,
    sourceMaps: opts.sourceMaps === undefined ? "both" : opts.sourceMaps,
    ast: false,
  });

  if (cache) {
    cache[cacheKey] = result;
    result.mtime = mtime(filename);
  }

  if (result.map) {
    if (Object.keys(maps).length === 0) {
      installSourceMapSupport();
    }
    maps[filename] = result.map;
  }

  return result.code;
}

//hook中傳入ext配置
function hookExtensions(exts) {
  if (piratesRevert) piratesRevert();
  piratesRevert = addHook(compile, { exts, ignoreNodeModules: false });
}

//入口函數
export default function register(opts?: Object = {}) {
  // Clone to avoid mutating the arguments object with the "delete"s below.
  opts = Object.assign({}, opts);
  if (opts.extensions) hookExtensions(opts.extensions);

  if (opts.cache === false && cache) {
    registerCache.clear();
    cache = null;
  } else if (opts.cache !== false && !cache) {
    registerCache.load();
    cache = registerCache.get();
  }
  
  ...
}
babel-core

提供基礎的transform方法

如何寫一個babel插件

babel-plugin其實是對code轉出的ast進行操作,

準備工具

ast轉換工具

ast轉換可視化工具

ast的解構可以類比成一個樹狀或者json嵌套結構,他的每一層結構都可以叫做一個節點,如下圖

babel提供一個visitor的方法,允許我們在里面指定我們想要訪問的節點,并且可以在命中該節點時做出自定義的的操作

實例分析

現在我們有一個需要移除整個業務bundle包里所有console.log的需求

1.那我們首先要知道console.log實際在ast是怎樣的一個節點結構

形如

console.log("a")

實際ast的展現如下

對于各個節點具體含義,這里不做細講,可以參考文末的babel手冊

2.這里直接貼上代碼講吧

module.exports = function (babel) {

    const { types: t, template } = babel;

    const visitor = {
            //需要訪問的節點名
            //訪問器默認會被注入兩個參數 path(類比成dom),state
        ExpressionStatement(path, state) {
            const node = path.node;
            //延當前節點向內部訪問,判斷是否符合console解析出的ast的特征
            const expressionNode = keyPathVisitor(node, ["expression"]);
            const isCallExpression = expressionNode.type === "CallExpression";
            if (isCallExpression) {
                const objectName = keyPathVisitor(expressionNode, ["callee", "object", "name"]);
                const prototypeName = keyPathVisitor(expressionNode, ["callee", "property", "name"]);
                if (objectName === "console" && prototypeName === "log" && !MAC) {
                        //如果符合上述條件,直接移除該節點
                    path.remove();
                }
            }
        }
    };

    return {
        visitor
    };
};

3.進階版:如果我們想在babel-plugin中新增代碼呢

差不多有三種方法

A:手動添加節點(很惡心~相信你不會想去了解)
B:先生成ast,直接path.insertBefore
C:使用babel-template
例子: 移除autobind裝飾器,并在constructor中自動bind this

注意點

1.因為babel判斷是否babel是根據modify time,所以babel插件寫完想實時生效,需要給當前的env加上 BABEL_DISABLE_CACHE

//babel-register/cache.js

function load() {
  if (process.env.BABEL_DISABLE_CACHE) return;
    
  process.on("exit", save);
  process.nextTick(save);
    
  if (!_fs2.default.existsSync(FILENAME)) return;
    
  try {
    data = JSON.parse(_fs2.default.readFileSync(FILENAME));
  } catch (err) {
    return;
  }
}

2.babel插件寫完后發布npm時,記得一定要加上babel-plugin-前綴,因為配置在babelrc中的插件名都會被babel在加載時統一加上babel-plugin前綴,然后在模塊系統中去查找

題外話 如何實現給require加上hook

傳送門

參考文獻

Babel插件手冊

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/93618.html

相關文章

  • Babel 插件原理的理解與深入

    摘要:抽象語法樹是怎么生成的談到這點,就要說到計算機是怎么讀懂我們的代碼的。需要注意什么狀態狀態是抽象語法樹轉換的敵人,狀態管理會不斷牽扯我們的精力,而且幾乎所有你對狀態的假設,總是會有一些未考慮到的語法最終證明你的假設是錯誤的。 現在談到 babel 肯定大家都不會感覺到陌生,雖然日常開發中很少會直接接觸到它,但它已然成為了前端開發中不可或缺的工具,不僅可以讓開發者可以立即使用 ES 規范...

    draveness 評論0 收藏0
  • babel插件入門-AST

    摘要:是一個對象,它表示兩個節點之間的連接。接著返回一個對象,其屬性是這個插件的主要節點訪問者。所以上面的執行方式是運行引入了自定義插件的打包文件現在為明顯減小,自定義插件成功插件文件目錄覺得好玩就關注一下歡迎大家收藏寫評論 目錄 Babel簡介 Babel運行原理 AST解析 AST轉換 寫一個Babel插件 Babel簡介 Babel 是一個 JavaScript 編譯器,它能將es...

    sanyang 評論0 收藏0
  • 2020年如何一個現代的JavaScript庫

    摘要:我寫過一些開源項目,在開源方面有一些經驗,最近開到了阮老師的微博,深有感觸,現在一個開源項目涉及的東西確實挺多的,特別是對于新手來說非常不友好最近我寫了一個,旨在從多方面快速幫大家搭建一個標準的庫,本文將已為例,介紹寫一個開源庫的知識 我寫過一些開源項目,在開源方面有一些經驗,最近開到了阮老師的微博,深有感觸,現在一個開源項目涉及的東西確實挺多的,特別是對于新手來說非常不友好 show...

    joyqi 評論0 收藏0
  • 基于 Gulp + Browserify 構建 ES6 環境下的自動化前端項目

    摘要:本文特此給大家介紹下如何使用配合來構建基于的前端項目。最后,在目錄下會生成最終的項目文件。執行單元測試本例中使用進行單元測試。 隨著React、Angular2、Redux等前沿的前端框架越來越流行,使用webpack、gulp等工具構建前端自動化項目也隨之變得越來越重要。鑒于目前業界普遍更流行使用webpack來構建es6(ECMAScript 2015)前端項目,網上的相關教程也比...

    yuanxin 評論0 收藏0
  • Next.js踩坑入門系列(二)— 添加Antd && CSS

    摘要:踩坑入門系列一二添加三目錄重構再談路由陸續更新個人對于腳手架的有一種執念,如果搭建出來就是一個首頁標簽跳轉,實在不是我這個處女座的風格,因此第二步我就想引用框架,相信很多使用的開發者用的也都是這個框架吧。 Next.js踩坑入門系列 (一) Hello Next.js (二) 添加Antd && CSS (三) 目錄重構&&再談路由 陸續更新... 個人對于腳手架的UI有一種執...

    lifesimple 評論0 收藏0

發表評論

0條評論

最新活動
閱讀需要支付1元查看
<