highcharts / highcharts-angular

Highcharts official integration for Angular
Other
425 stars 117 forks source link

Dynamically Import Highcharts #163

Open Robinyo opened 4 years ago

Robinyo commented 4 years ago

Requested feature description

Take advantage of ECMAScript's support for dynamic import() in order to load Highcharts dynamically at runtime.

As we're using Angular and the Angular CLI uses webpack, we can rely on webpack to replace calls to import() with its own dynamic loading function.

See: Dynamically Importing Highcharts

KacperMadej commented 4 years ago

Hi @Robinyo

Thank you for suggesting the enhancement.

What will be required for the new feature to work? I imagine that a type-less version of the component could do the trick, but maybe there are other requirements? The import of Highcharts in the wrapper component is purely for TS definitions, so without them the import could be removed.

BTW: Nice article!

Robinyo commented 4 years ago

Hi @KacperMadej,

-> What will be required for the new feature to work?

tsconfig.json:

"module": "esnext"

-> I imagine that a type-less version of the component could do the trick?

Yes, that's what I tried and its working for me.

At the start of the file you will notice the following import statement:

import * as Highcharts from 'highcharts';

However, as the HighchartsChartComponent accepts Highcharts as an @Input() I commented out this line and I updated all references to Highcharts types to <any>.

-> The import of Highcharts in the wrapper component is purely for TS definitions, so without them the import could be removed.

Yes.

-> BTW: Nice article!

Thanks :)

Cheers Rob

kumar-tadepalli commented 4 years ago

Any update on ETA?

KacperMadej commented 4 years ago

Please vote up with your reaction ( 👍 ) on the opening comment of this issue thread to let us know how much the feature is requested. As far as I can tell right now, it looks like the changes would require creating another wrapper that will be a type-less version (when it comes to the Highcharts properties) to keep the code clean and clear.

stevethemacguy commented 4 years ago

@Robinyo, Does this remove the ability to use HighCharts' types? For example, would it still be possible to specify types when creating a chart?

legend: {
  enabled: false
} as LegendOptions,
title: {
  text: 'hello',
} as TitleOptions
...
jdelaune commented 3 years ago

+1

alexmuch commented 3 years ago

Any updates on this feature? It would be great if we could dynamically load natively. In OP's example it looks like to use this in a component, you have to make a separate component that acts as an override for highcharts-angular. It would be stellar if we didn't have to make this go-between.

mateuszkornecki commented 3 years ago

@alexmuch I can see more and more people voting for adding this functionality, and I can agree that it might be a pretty neat feature. However, we need to keep all available highcharts wrappers(highcharts-react-official, highcharts-vue...) consistent. I will consult all possibilities with my colleagues responsible for other wrappers and post an update if anything changes regarding this feature.

kumar-tadepalli commented 3 years ago

Any update on this feature?

mateuszkornecki commented 3 years ago

Unfortunately for now the solution posted by Robinyo is the only solution. https://github.com/highcharts/highcharts-angular/issues/163#issue-497372364

BregtDeLange commented 1 year ago

Any updates on this one?

PowerKiKi commented 1 month ago

Original article by @Robinyo is now available at https://rob-ferguson.me/dynamically-importing-highcharts/

Has anybody succeeded in using Highcharts with ESM and proper typing (what I'd consider bare minimum for an Angular app), and also lazy-loading the entire Highchart library to avoid the hit on Initial Total size ?

I've been struggling with this issue on and off for months now. And everytime I only end up being frustrated by the state of this repos and lack of documentation for lazy loading the lib :disappointed:

@mateuszkornecki has anything changed on your side in the meantime ?

karolkolodziej commented 1 month ago

@PowerKiKi It is possible to import Highcharts as ESM- see the demo.

import Highcharts from 'highcharts/es-modules/masters/highcharts.src';

You are right we don't mention how to do it anywhere in the documentation. We will try to improve it and prepare a demo where we dynamically import Higcharts.

PowerKiKi commented 1 month ago

@karolkolodziej one thing that would really improve usage of this lib would be to leverage Angular DI via providers.

So in HighchartsChartComponent, instead of:

- @Input() Highcharts: typeof Highcharts | typeof HighchartsESM;

we would have an injectable, so something more like:

  constructor(
    private el: ElementRef,
    private _zone: NgZone // #75
+   @Inject(HIGHCHARTS) Highcharts: typeof HighchartsESM,
  ) {}

Notice how it only accepts HighchartsESM, and not Highcharts, because non-ESM must not be used anymore in Angular ecosystem.

Then we can provide HIGHCHARTS with a new built-in provider function provideHighcharts(). The provider function would accept arguments to configure optional features with ease in a tree-shakable way.

So final usage for end-user would look more like:

@Component({
    selector: 'app-chart',
    standalone: true,
    template: `<highcharts-chart [options]="options" />`,
    imports: [HighchartsChartComponent],
    providers: [
        provideHighcharts({
            // ... some configuration here, included which modules should be included
        }),
    ],
})
export class ChartComponent {
    public options = {}; // ... real options here

    public constructor(
        @Inject(HIGHCHARTS) Highcharts: typeof HighchartsESM, // Optionally, if we need to access some functions provided by Highcharts in our component
    ) {
        // not much to do...
    }
}

The fact that provideHighcharts() is used in the component itself, and not at the application level, makes it easy to be tree-shakable, as long as the route is lazy-loaded or the template is @defered. It is overall even simpler to use and more idiomatic to Angular.

This kind of approach is used in ng2-charts since v6 with success. I think it should be adopted here too, or some similar alternatives.

The only thing to figure out is how to write the new provideHighcharts() and its arguments to be ESM and tree-shakeable.

karolkolodziej commented 1 month ago

@PowerKiKi Thank you for all the valid points! I like the idea of provideHighcharts! I'll try that then.

In the meantime please look at the repo where I use import() to load Highcharts dynamically (without using highcharts-angular ).