Skip to content
This repository was archived by the owner on Jan 13, 2025. It is now read-only.
This repository was archived by the owner on Jan 13, 2025. It is now read-only.

Research Closure Compiler + Typescript Support #134

@traviskaufman

Description

@traviskaufman

By the time MDC-Web reaches beta, we need to provide support for typed ECMA variants. Specifically, we need support for Closure Compiler (Closure) and Typescript (TS). This is the issue where all research around our strategy for supporting Closure + TS should be done.

Closure Compiler Support

Google Closure Compiler support is required in order to support the Google projects and properties which are built around this toolchain. Concretely, MDC-Web must be able to compile with ADVANCED_OPTIMIZATIONS enabled, and produce no errors or warnings. There are implications for internal support as well, but that is outside the scope of this issue.

Verification Plan

  • Introduce a "build test", e.g. npm run test:closure which runs closure on all packages, but does not output anything. This can be done using closure's --checks_only flag. The advantage here is that nothing about our build system changes.
  • OPTIONAL: Switch out uglifyJS for the closure compiler webpack plugin, and use that to minify our code. The advantage here is we not only get type-checking but we also take advantage of closure's extremely sophisticated optimization techniques. The disadvantage is that it's way slower to optimize, and we may have to restructure some of our code for it to work correctly.

Typescript support

Typescript is angular's de facto language choice. It also seems to be the most popular typed ECMAScript variant. For these reason, I believe it's important to provide first-class support for Typescript users wanting to use MDC-Web. Concretely, MDC-Web should provide type declaration files for all components, foundations, and adapters.

The type declaration files can live in the component package directory, and should be called index.d.ts This will allow typescript's module resolution algorithm to automatically discover these typings. Furthermore, having type declarations should become a requirement for all components moving forward. The TS handbook as a module declaration file template that we could use as a starting point for our TS modules.

Verification Plan

I'm not sure how to validate type declaration files alone, so more research has to be done on this.

Implementation Options

There are a few implementation options which I will discuss below. Any additional implementation options surfaced by the community should be added to this section. I personally think all of these options should be experimented with, but we could rule some out via discussion on this issue.

Closure-annotated source files + manual typings

All source files are annotated using JSDoc for the closure compiler.

Type declaration files are manually authored in addition to adding closure compiler annotations.

A page within docs/ could be created outlining any non-standard practices within our source code that are closure-specific (e.g. using expressions for @typedefs, using dummy classes for @record types, etc.)

Pros

  • Requires the least amount of changes to tooling and infrastructure
  • Source code will be idiomatic for closure compiler users, and will yield optimal closure compiler optimizations.
  • Type declarations will be idiomatic for TS users.

Cons

  • More work for developers to implement components.
  • Duplication of effort specifying same types for two different type systems.
  • Type declarations and closure annotations prone to go out-of-sync. Tooling may be needed to verify that changes to JSDocs are reflected by changes to type declarations, and vice-versa.

Closure-annotated source files + Clutz

All source files are annotated using JSDoc for the closure compiler.

Angular's Clutz tool is used to emit type declaration files from closure-annotated source files. This can be added as part of a pre-commit hook.

Pros

  • Source files remain in ES2015, and ensure highest level of optimization from Closure
  • No duplication of effort maintaining both Closure annotations and type decls
  • Source files are idiomatic for closure compiler users
  • Speculatively, it seems that TS can support Closure's type system much better than Closure can support TS's type system. Thus, transpilation from Closure to TS may be more high-quality than the other way around (see below).

Cons

  • Clutz requires Java, as well as some extra set up on our end
  • Unsure of the quality of type declarations emitted by clutz. Research has to be done on this.

Typescript Source files + Tsickle

Instead of writing source files in ES2015, source files are written using Typescript.

Before publishing to npm, and extra build step will be added to transpile them to their ES2015 sources using CommonJS as its module system. This would ensure the built source files would work with module loading systems such as webpack. Alternatively, we could preserve the ES2015 imports.

Angular's Tsickle could be used to annotate the source files for closure.

The TS compiler could output proper declaration files for our project, which could be added to version control since the declarations files would reflect the public API.

Pros

  • We get all of the nice language tooling around working on large-scale TS codebases
  • TS becomes our single source of truth. Declarations and closure-compatible JS could all be emitted from our source files, reducing duplication of effort and number of manual tasks needed to implement a component.
  • Source code feels idiomatic to the closure community

Cons

  • Doing this would require a rewrite of all of current components to TS, as well as all agreeing on a new source language that we're using.
  • Doing this would require an overhaul to our build system
  • The use of TS - while popular - still means using a base language different from plain ECMAScript, which is what we strive for in order to facilitate the maximum amount of community contribution.
  • Tsickle has many open issues denoting that the quality of the transpilation of TS sources might not be up-to-par with the quality of hand-written JSDoc. This may preclude its use within internal apps since it would lead to poorer optimization. In my limited experience with Tsickle, it's been okay but we'd have to test this out on a non-trivial component (such as @material/ripple before deeming it viable).

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions