Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Angular + Closure 3p Library consumption #17

Closed
kylecordes opened this issue Apr 11, 2017 · 5 comments
Closed

Angular + Closure 3p Library consumption #17

kylecordes opened this issue Apr 11, 2017 · 5 comments

Comments

@kylecordes
Copy link
Collaborator

kylecordes commented Apr 11, 2017

Consuming libraries with Closure can be nontrivial. :-)

Here is an issue/thread to try to figure out how to do so most effectively. There seem to fundamentally be (at least) a few ways to consume a given library. Roughly they break down to:

  • Consume it as it is
  • Repackage it for better use from Closure, then urge upstream providers to include such results in their packages

Setting aside the social challenge of the latter for a moment, here are some thoughts on ways libraries can be packaged to make Closure consumption easier or harder.

CommonJS

Consume library code typically consumed with other tooling - which usually means CommonJS. Closure has a feature (but with open issues?) to help with this.

Advantages:

  • In theory this should "just work" with the whole ecosystem right away.

Disadvantages:

  • Obtains the least possible benefit from Closure. Certainly no ADVANCED_OPTIMIZATIONS of this code.
  • Externs files are almost never packaged with off-the-shelf libraries in the ecosystem, so we'll have to get those somewhere else anyway in most cases.

TypeScript code

It would be quite nice if software written in TypeScript was distributed in NPM in TypeScript. Another other things, such code could be easily passed through tsickle then Closure for optimal results.

Advantages:

  • The code would be passed through the exact same version of Tsickle and TSC as the consuming application
  • The code would benefit from further improvements to Tsickle/TSC

Disadvantages:

  • Possibly slower, since the whole consumer community is recompiling these libraries instead of using compiled output.

Flat ES2015-in-ES2015 with Closure JSDocs

Consume library code specifically packaged this way. This is how Angular is packaged, and many of us think this is the package format of the future for arbitrary code in NPM.

Advantages:

  • Works well with Closure
  • Works well for everything else also - i.e. Webpack, Rollup
  • This is probably the future, at least my best guess of the future

Disadvantages:

  • So far, Angular is the only thing packaged this way. (Update: also Material - so it's more correct to say that so far only the Angular team is packaging things this way.)
  • So far, minor efforts to nudge other libraries to consider this have been unsuccessful.
  • There is not yet an official standard way to label these in an NPM package; Angular uses "es2015".
  • Some node traditionalists may disagree that this is the future.

(Incidentally, I have shipped a way of consuming these with Rollup: https://www.npmjs.com/package/rollup-plugin-node-resolve-angular )

Specific RxJS thoughts

RxJS is at the forefront of the importance of working out the most effective library packaging and consumption, because it is a hard requirement of every Angular application. The specifics around RxJS have been written about and other issues in this repo and elsewhere, at the moment the most irritating one is that there is a Closure bug which breaks the import "rxjs/add/blah" pattern. That is likely moved in the near future though.

Special treatment for top-tier Angular-centric libraries?

It's possible that the answer to what kind of packaging make this the most sense, varies greatly between the top couple of dozen libraries used with Angular and the rest of the ecosystem. For example, offhand it seems extremely justifiable for Material to ship FESM with Closure JSDocs, while not justifiable for the 10,000th most popular JS library to even know Closure exists.

There may be an opportunity for the Google developed key libraries like Material to lead the way here.

What's next

One next action is for those of us inside Google and outside, who are tinkering with Closure with Angular, to pick up code that has third-party library requirements, hack away and get it to run, and raise issues for anything that requires special one-off treatment.

cc @alexeagle @thelgevold

Thoughts?

@thelgevold
Copy link
Contributor

I did an experiment yesterday with material and Closure. Material is already Closure compatible, so it works right out of the box. This is good news since it gives other library authors an example to follow.

I looked in their source and noticed that they even have tests to ensure compatibility.

As far as other non Angular projects goes:
I would love to be able to optimize as much as possible, but I suspect the success will vary greatly based on Closure compatibility.

Where it's not feasible to Closure compile the third party lib into our bundle, we may have to rely on community maintained externs to protect references to the libs external api in user code. In some ways this is similar to how we rely on typings from DefinitelyTyped. Not the same thing, but similar in that we rely on metadata maintained by others than the library authors.

@thelgevold
Copy link
Contributor

@alexeagle @kylecordes

I took a quick look at moment integration.

Moment doesn't seem to publish an ESM or CommonJS build. Instead they publish out a fixed IIFE build.

Based on that I don't think the import * as moment from 'moment' approach will work.

Instead we can do something like this:

import {Component, Injectable} from '@angular/core';

import 'moment';

declare var moment: any;

@Component({
  selector: 'basic',
  templateUrl: './basic.ng.html',
})
@Injectable()
export class Basic {
  ctxProp: string;
  constructor() { this.ctxProp = 'happy ' + moment().format('dddd'); }
}

This isn't super pretty, but it at least works.

Here is the new size:

42262 Apr 11 00:18 dist/bundle.js.brotli
47301 Apr 11 00:18 dist/bundle.js.gz

@thelgevold
Copy link
Contributor

thelgevold commented Apr 11, 2017

Oh. We also need an extern for moment

/** @externs */
var moment;

This can be added to vendor as moment_externs.js

@alexeagle alexeagle mentioned this issue Apr 13, 2017
@kylecordes
Copy link
Collaborator Author

kylecordes commented Apr 14, 2017

@thelgevold I don't think the masses of developers, bringing code over that compiles easily with other solutions, will be excited about changing application code as you showed, to make Moment work.

I've been trying to make Lodash work with Closure. Some of the example apps I AOT en masse, use Lodash - as do many other libraries out there, it is very common. So far, no success - though I'll try something like what you did with Moment.

@alexeagle
Copy link
Owner

Let's move to the compatibility-test repo
alexeagle/angular-closure-compatibility#4

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants