如何使用 JS compiler/parser/transformer 进行积极的内联?

How to do aggressive inlining with JS compiler/parser/transformer?

我正在尝试弄清楚如何对 JS 代码进行积极的内联。这是一个例子:

// Source code
var fruits = {
  'a': { name: 'apple' },
  'b': { name: 'banana' }
};


function getFruit(n) {
  return fruits[n];
}

console.log(getFruit('a'));
console.log(getFruit('b'));

如果我在此代码上使用 Google Closure Compiler 并将 optimization 设置为 advanced,我将得到以下结果:

// Closure output
var a = {a:{name:"apple"}, b:{name:"banana"}};
console.log(a.a);
console.log(a.b);

这很好,因为函数 getFruit 是内联的,但对象 a 仍然存在,我想要这个:

console.log({a:{name:"apple"}, b:{name:"banana"}}.a);
console.log({a:{name:"apple"}, b:{name:"banana"}}.b);

当然 Closure 的目的也是缩小,所以如果对象 a 被多次使用,它不会被内联。如果我删除 console.log(getFruit('b')); 然后我得到我想要的。

Prepack 也没什么用:

// Prepack output
var getFruit, fruits;
(function () {
  var _[=14=] = this;

  var _9 = function (n) {
    return fruits[n];
  };

  _[=14=].getFruit = _9;
  var _2 = {
    name: "apple"
  };
  var _4 = {
    name: "banana"
  };
  _[=14=].fruits = {
    a: _2,
    b: _4
  };
  console.log(_2);
  console.log(_4);
}).call(this);

所以我的问题是,有没有什么方法可以将 compiler/parser 与临时规则一起使用,该规则可以积极地内联任何其计算结果在编译时可知的表达式?换句话说,它应该尽可能地去除所有的间接寻址。

为什么:

因为我想知道 console.log 函数是否在 compile 时使用特定参数值调用。编译时我的意思是只静态地查看代码而不必 运行 因为我已经有了这些信息。 fruits 对象在我 运行 这段代码后没有改变。

恐怕任务范围太窄,找不到现成的工具。如您所见,Google Closure Compiler 优化了代码大小(好吧,它可以更好地优化这个特定示例,比如

console.log({name:"apple"});
console.log({name:"banana"});

您或许可以与作者讨论)而不是变量的数量(非常不常见的指标)。此外,对象初始化甚至可以改变脚本的行为({a:1} != {a:1},对吗?而 var o = {a:1} 是这样:o == o),这使得理想的结果更加奇特。

但是,您可以通过实际分析 JS 语法和操作描述它的结构来创建这样的工具。这种结构称为 abstract syntax trees and probably the most well-known tool(*) to manipulate those (creating so called codemods) is https://github.com/facebook/jscodeshift .

注意:创建 codemod 并非易事,所以我认为要创建其中一个,您应该有一个 非常 充分的理由,或者有兴趣学习和做一些复杂的事情好玩的东西。关于该主题的文档或文章也不多,但也许已经足够了。 This may be helpful as an introduction to ASTs and this 包含许多不错的 codemod 示例以及指向 "how to write your own codemod" 事物的链接。

(*) 我的意思是你自定义的操作; JS 世界中最著名的基于 AST 的工具可能是 Babel(或者可能是 TypeScript 或其他 parses/produces JS 的工具)