未加星标

Reify: Meteor’s evolving JavaScript module compiler

字体大小 | |
[前端(javascript) 所属分类 前端(javascript) | 发布者 店小二04 | 时间 2017 | 作者 红领巾 ] 0人收藏点击收藏

Reify: Meteor’s evolving JavaScript module compiler
Reify working its magic in Node4.8.4

On the surface, Meteor supports the same ECMAScript import and export syntax as many other web frameworks, bundlers, and build tools. Like most of those projects, we too use Babel to configure and run a set of syntax transformations that turn modern javascript into code that works in all browsers. Babel is a fantastic tool, and Meteor relies heavily on it.

However, the code Meteor generates for import and export declarations differs radically from what other tools produce, thanks to a special compiler called Reify that we developed and first shipped in Meteor 1.3.3, back in June 2016. This unique approach has been tested and proven in tens of thousands of Meteor apps over those thirteen months, and we believe the benefits are worth understanding. Even if the code you end up writing looks the same as anyone else’s ECMAScript, it will compile faster, behave more like natively-supported modules, and be easier to debug.

This post begins by explaining some subtle details of how import and export declarations are supposed to behave, then explains how Babel works within difficult constraints to achieve those requirements with its popular babel-plugin-transform-es2015-modules-commonjs plugin, then shows how Reify improves on that developer experience, and concludes with some exciting news about the future of the Reify compiler.

What’s so tricky about import andexport?

If you’re not already an expert on the differences between ECMAScript modules and the module systems that came before, such as the CommonJS system used by Node, I would recommend watching this detailed talk that I gave at EmpireNode 2015 , in which I explain how import and export build on the successes of CommonJS require and exports , while also solving some of CommonJS’s thorniest problems.

The subtlety that I want to highlight in this post is the concept of immutable live bindings , a subtle yet critical feature that enables imported symbols to remain up-to-date with export declarations in other modules. In particular, live bindings allow ECMAScript modules to cope gracefully with circular dependencies. However, as you will see later in this post, simulating live bindings faithfully is one of the most challenging parts of implementing a compiler for import and export declarations.

If live bindings are already familiar to you, feel free to skim or skip the rest of this section. If not, keep reading!

When you write an import declaration such as

import increment, { value } from "./some/module";

it’s important to realize that the imported symbols, value and increment , are not ordinary variables. Instead, you should think of them as reflections of variables that were declared in ./some/module , made visible to the current module. That’s what we mean when we say the import declaration creates bindings for value and increment , as opposed to declaring new variables that happen to hold the same values.

This sharing of declarations between files is a concept that did not exist in JavaScript before the specification of modules, so you’re not alone if it seems strange the first time you hear about it.

Here’s how ./some/module might declare and export value and increment :

// Export `value` by name, hence the curly braces to import it. export let value = 1234; // Export `increment` as the default export, hence no braces. export default function increment(by) { value += by; }

We say the imported bindings are live because the exporting module has the ability to change their values at any time, and those changes will be reflected immediately by bindings in other modules.

Suppose we add the following code after the import declaration:

import increment, { value } from "./some/module"; console.log(value); // 1234 increment(1111); console.log(value); // 2345

In this example, the importing module is indirectly responsible for changing value by calling increment(1111) , but that’s possible only because ./some/module exported the increment function. The implementation of increment is still controlled by ./some/module , so it’s only at the whim of ./some/module that value can be updated in this way.

We say the live bindings are immutable because the importing module is forbidden from assigning anything to them directly. In other words, the following code throws an error much like assigning to a const variable:

import { value } from "./some/module"; value += 1111; // Error!

As we saw above, ./some/module can change the value of value , or even export a function like increment that allows other modules to influence value ’s value. So value is not exactly constant , since its value might change over time. The binding simply isn’t mutable (that is, able to be mutated) on the importing side.

So there you have it: import declarations create immutable live bindings , which allows imported symbols to remain up-to-date with export declarations in other modules.

If you found this explanation of live bindings confusing or inadequate, here’s a great post by Axel Rauschmayer on the same topic: http://2ality.com/2015/07/es6-module-exports.html

Meteor Babel

Before getting into the details of how Babel’s module compiler differs from the Reify compiler used by Meteor, I want to make something perfectly clear: this blog post is not about finding fault with Babel, or even with the way Babel compiles modules by default.

Meteor depends heavily on the Babel toolchain, and uses many Babel plugins that have nothing to do with modules. In fact, if you want to get really pedantic about it, we still use the babel-plugin-transform-es2015-modules-commonjs plugin to clean up import declarations inserted by other Babel plugins, especially babel-plugin-transform-runtime .

Triumphant blog posts that pretend to invalidate (or conveniently ignore) their competitor’s technologies are my least favorite part of the JavaScript ecosystem these days. The maintainers of Babel are absolutely not Meteor’s competitors. I myself am a frequent Babel contributor . If you get a boastful tone from this post, then I did a bad job of writing it, or maybe you’ve been primed to expect competition where there doesn’t have to be any.

I hope that I leave you

本文前端(javascript)相关术语:javascript是什么意思 javascript下载 javascript权威指南 javascript基础教程 javascript 正则表达式 javascript设计模式 javascript高级程序设计 精通javascript javascript教程

主题: JavaJavaScriptECMAScript
分页:12
转载请注明
本文标题:Reify: Meteor’s evolving JavaScript module compiler
本站链接:http://www.codesec.net/view/561324.html
分享请点击:


1.凡CodeSecTeam转载的文章,均出自其它媒体或其他官网介绍,目的在于传递更多的信息,并不代表本站赞同其观点和其真实性负责;
2.转载的文章仅代表原创作者观点,与本站无关。其原创性以及文中陈述文字和内容未经本站证实,本站对该文以及其中全部或者部分内容、文字的真实性、完整性、及时性,不作出任何保证或承若;
3.如本站转载稿涉及版权等问题,请作者及时联系本站,我们会及时处理。
登录后可拥有收藏文章、关注作者等权限...
技术大类 技术大类 | 前端(javascript) | 评论(0) | 阅读(28)