Research Closure Compiler + Typescript Support
See original GitHub issueBy 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 @typedef
s, 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).
Issue Analytics
- State:
- Created 7 years ago
- Reactions:5
- Comments:11 (8 by maintainers)
Top GitHub Comments
The linked milestone in the last comment has disappeared. Is there a new public location that’s tracking the status of the Closure/TypeScript project?
The most probable way is through webpack/gulp/grunt via google-closure-compiler-js.
The trickiest part is module resolution. While all of our code will be compilable via closure, there’s still the matter of resolving ES2015 import statements. Because closure has no notion of node’s module resolution mechanics, the code will have to be pre-processed in such a way that its dependencies are resolved. I’m currently looking into how we’re going to do this in order to test that our code is compilable via closure, as well as to produce the correct Typescript typings via clutz if that’s possible.
As alluded to above, yes, as long as they make closure aware of how to resolve module dependencies within MDC-Web.