question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Migrating from Closure for compilation/type-checking --> esbuild/babel/terser for compilation and tsc for type-checking

See original GitHub issue

Closure --> esbuild/babel/terser/tsc

This I2I is to spark the discussion on whether we’d like to migrate off of Closure for production builds, as well as move off of its type system. While technically both the compilation and type checking aspects of this I2I could be pursued separately, I don’t believe it would make sense to do that. For example, using TS types while compiling with Closure means that as time goes on Closure will slowly become less and less efficient as it understands less of our typing.

POCs for the migration

Related I2I on using TS in AMP: https://github.com/ampproject/amphtml/issues/13791

Motivation

DevEx:

  • We can significantly reduce build times for prod builds. For example, in my current PR prod builds goes from 12m --> 7.5m (with further low hanging fruit).
  • We can take advantage of the much more powerful (and pleasant to use) TS type system in new code.
  • We could seamlessly start writing Bento components with TS markup.

Community alignment:

  • Most OSS projects do not use Closure – and instead choose alternatives. Using its API is not easy, and we’ve written thousands of LOC to make it work.

Cons:

  • Bundle size: Currently, even with prop mangling turned on, the terser output is still ~2kb larger for v0.mjs. Hopefully we can further close the gap, but a bigger bundle size is directly at odds with our project policy of prioritizing end user over developer.
  • Project stability: We are confident in Closure’s stability and staying power (Google is heavily invested in it). We can’t be sure of this with a new project like esbuild maintained by an individual.

Alternative Solutions

Do nothing.

Launch Tracker

No response

Notifications

/cc @ampproject/wg-approvers @ampproject/wg-performance @ampproject/wg-infra

Issue Analytics

  • State:closed
  • Created 2 years ago
  • Comments:10 (10 by maintainers)

github_iconTop GitHub Comments

2reactions
alanorozcocommented, Jul 21, 2021

I like this proposal.

Regarding byte-size, one of the problems with the minified esbuild output is that static methods are not treated as standalone functions like Closure would. As a result, “getter classes” like Services are included as a whole:

Wi = class {
  static accessServiceForDoc(t) {
    return ji(t, "access", "amp-access");
  }
  static accessServiceForDocOrNull(t) {
    return zi(t, "access", "amp-access");
  }
  static subscriptionsServiceForDoc(t) {
    return ji(t, "subscriptions", "amp-subscriptions");
  }
  // ...
}

Conversely, Closure would inline the used methods as standalone functions and thus DCE the rest of the class, like in this caller example ("platform", "performance"):

ud(self.document, function () {
  let a = Kl.getAmpDoc(self.document);
  K(self, "platform", Fi);
  K(self, "performance", Fl);
  let b = M(self, "performance");
  self.document.documentElement.hasAttribute("i-amphtml-no-boilerplate") &&
    b.addEnabledExperiment("no-boilerplate");
  b.addEnabledExperiment("esm");
  xe();
  b.tick("is");
  Jl(a, b);
});

There’s an easy win to be made for Services specifically. We introduced this class in order to allow stubbing of the service getter themselves (#10128) like so:

// impl
import Services from '(...)services';
Services.accessServiceForDoc(...);
// test
import Services from '(...)services';
env.sandbox.stub(Services, 'accessServiceForDoc')

However, we can now stub module members directly. This would allow us to rewrite static method getters like accessServiceForDoc as functions, which esbuild would then be able to inline and DCE piece-meal, thus reducing the size of the output.

// impl
import {accessServiceForDoc} from '(...)services';
accessServiceForDoc(...);
// test
import * as Services from '(...)services';
env.sandbox.stub(Services, 'accessServiceForDoc')
1reaction
samouricommented, Dec 14, 2021

Stable is now built with esbuild/babel/terser and we are actively removing Closure Compiler from the codebase. @rcebulko and I have been gradually adding tsc based typechecking with small targeted PRs – starting with src/core and now expanding to src/preact.

Onwards! 🚀

Read more comments on GitHub >

github_iconTop Results From Across the Web

Maxime Chéramy on Twitter: "There are many minifiers such ...
The most popular JavaScript compiler is Babel ( ... won't check your types, but you can compile with these tools and typecheck using...
Read more >
Comparing the New Generation of Build Tools - CSS-Tricks
First-class support for native JavaScript modules; TypeScript compilation (but not type checking); JSX; Plugin API for extensibility; A built-in ...
Read more >
FAQ - ESBuild
TypeScript type checking (just run tsc separately); An API for custom AST manipulation; Hot-module reloading; Module federation. I hope that the extensibility ...
Read more >
I'm porting the TypeScript type checker tsc to Go - Hacker News
Just a note that TypeScripts type checking & compilation are two separate systems. It's never a compilation error because it always compiles.
Read more >
Speed Up Your Webpack Build with Esbuild - Morioh
However, esbuild-loader can still speed up your build by removing the bottlenecks created by babel-loader , ts-loader , Terser, etc. Will there be...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found