资讯专栏INFORMATION COLUMN

babel原理分析-babel-register addHook

sugarmo / 1641人阅读

摘要:动态编译编译到这行的时候进行编译原理分析注本文参考代码为版本代码。于是简单写了一个运行去看这个的执行时机以及。当然虽然是废弃的,但是这个模块已经锁死,所以大佬还在肆无忌惮的用,当然已经做了修正

babel原理分析-babel-register addHook 前言

阅读本文时希望您对babel-register有一定了解,如果还有不了解的可以阅读之前的文章传送门

在之前的文章中已经简单介绍了babel-register的功能

那么babel如何给require加上钩子,使得在node环境下实现动态编译的呢(静态编译:统一babel。动态编译:js编译到这行的时候进行编译)

原理分析

注:本文参考代码为babel-0.7.0-beta版本代码。

其实在上文babel-register中可以看到,node环境下babel的编译,是通过一个require上addHook的解决方法,那么这个hook是怎么挂载到require上的呢

首先想到的是node官版有没有提供原生的方法处理,官版确实提供了一个require.extensions的方法,可惜已经废弃了,moudle模块也没有所谓addhook的办法。那就只能安静点看pirate的实现了

深入pirate的源码时,我们却发现实际pirate这个npm包并没有做什么功能

核心代码不超过100行,如下

const Module = module.constructor.length > 1
  ? module.constructor
  : BuiltinModule;

export function addHook(hook, opts = {}) { // eslint-disable-line import/prefer-default-export
  let reverted = false;
  const loaders = [];
  const oldLoaders = [];
  let exts;

  const originalJSLoader = Module._extensions[".js"];

  const matcher = opts.matcher || null;
  const ignoreNodeModules = opts.ignoreNodeModules !== false;
  exts = opts.extensions || opts.exts || opts.extension || opts.ext || [".js"];
  if (!Array.isArray(exts)) exts = [exts];

  exts.forEach((ext) => {
    if (typeof ext !== "string") throw new TypeError(`Invalid Extension: ${ext}`);
    const oldLoader = Module._extensions[ext] || originalJSLoader;
    oldLoaders[ext] = oldLoader;

    loaders[ext] = Module._extensions[ext] = function newLoader(mod, filename) {
      let compile;
      if (!reverted) {
        if (shouldCompile(filename, exts, matcher, ignoreNodeModules)) {
          compile = mod._compile;
          mod._compile = function _compile(code) {
            mod._compile = compile;
            const newCode = hook(code, filename);
            if (typeof newCode !== "string") {
              throw new Error(HOOK_RETURNED_NOTHING_ERROR_MESSAGE);
            }

            return mod._compile(newCode, filename);
          };
        }
      }

      oldLoader(mod, filename);
    };
  });
  return function revert() {
    if (reverted) return;
    reverted = true;

    exts.forEach((ext) => {
      if (Module._extensions[ext] === loaders[ext]) {
        Module._extensions[ext] = oldLoaders[ext];
      }
    });
  };
}

看起来这个代码做的事很简单就是在给原生moudle方法上不断地挂载moudle._extension[".js/.es6/.jsx"]之类的处理func,始终没有看到执行时机。

于是简单写了一个demo

console.log("naturelessTT")

debugger;

require("require.js")

babel-node index.js --inspect-brk运行去看这个hook的执行时机以及call stack。

实际是require文件时,io读取文件后会通过moudle.load的方法加载文件,然后依次执行_extension里挂载的方法

真相大白,但是令人惊讶的是0.7之前的版本并没有引入pirate这个包,看了0.6.26版本后,emmmm,babel大佬使用了官版已经标记为废弃的require.extensions。

当然虽然是废弃的,但是node这个模块已经锁死,所以babel大佬还在肆无忌惮的用,当然0.7已经做了修正

Deprecated 

In the past, this list has been used to load non-JavaScript modules into Node.js by compiling them on-demand. However, in practice, there are much better ways to do this, such as loading modules via some other Node.js program, or compiling them to JavaScript ahead of time.

Since the module system is locked, this feature will probably never go away. However, it may have subtle bugs and complexities that are best left untouched.

Note that the number of file system operations that the module system has to perform in order to resolve a require(...) statement to a filename scales linearly with the number of registered extensions.

In other words, adding extensions slows down the module loader and should be discouraged.

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/93617.html

相关文章

  • babel各单元简介&如何写一个babel插件

    摘要:是怎么工作的如何编译应用场景语法糖的代码统一相关概念介绍依赖,提供的方法,只转化语法,不转换类,的基础配置利用对进行劫持,在中进行原理见同时对后的进行缓存,提高下次效率读取缓存根据判断是否需要重新中传入配置入口函数提供 Babel babel是怎么工作的? parse->AST->transform->gengerate 如何编译js->AST babel应用场景 语法糖的polyfi...

    peixn 评论0 收藏0
  • 你真的会用 Babel 吗?

    摘要:安装然后在的配置文件加入入口文件引入这样就可以啦,还是可以减少很多代码量的。是参数,等同于执行正常。这个包很简单,就是引用了和,然后生产环境把它们编译到目录下,做了映射,供使用。 引入 这个问题是对自己的发问,但我相信会有很多跟我一样的同学。对于 babel 的使用,近半年来一直停留在与 webpack 结合使用,以及在浏览器开发环境下。导致很多 babel 的包,我都不清楚他们是干嘛...

    mochixuan 评论0 收藏0
  • 干货实例:什么是React服务端渲染?

    摘要:今天分享一篇公司大佬的文章,非常厉害的大神崇拜脸,讲讲服务端渲染。服务端渲染,它到底用了什么原理呢服务端渲染原理服务端渲染的方式有很多,主流的服务端语言为使用渲染。 富婆来报道,今天想问题想不出来,随手抓了一下头发,没想到啊没想到,我那浓(mei)密(sheng)茂(ji)盛(gen)的秀发又少了好几根,一定要改掉这个想不出来问题就揪头发的坏习惯。今天分享一篇公司大佬的文章,非常厉害的...

    Jason_Geng 评论0 收藏0
  • 如何让 node 运行 es6 模块文件,及其原理

    摘要:如何让运行模块文件,及其原理最新版的支持最新版几乎所有特性,但有一个特性却一直到现在都还没有支持,那就是从开始定义的模块化机制。便是使用这种方式达到运行模块文件的目的的。 如何让 node 运行 es6 模块文件,及其原理 最新版的 node 支持最新版 ECMAScript 几乎所有特性,但有一个特性却一直到现在都还没有支持,那就是从 ES2015 开始定义的模块化机制。而现在我们很...

    ytwman 评论0 收藏0
  • ES6+mocha+istanbul,针对ES6语法的带覆盖率检查的mocha测试

    摘要:安装注意版本为为支持语法安装依赖包注意为了使支持语法,在加入注意为了使支持语法,在加入小猫快跳最终运行或都可以参考 安装 mocha, chai,mochawesome,istanbul npm install mocha chai mochawesome istanbul@1.0.0-alpha.2 --save-dev 注意1: istanbul 版本为 ^1.0.0-alpha....

    wuyangnju 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<