Angular-cli: Add async attribute to script tags for

Created on 30 Nov 2016  路  24Comments  路  Source: angular/angular-cli

When trying to use the bootloader from AngularClass in combination with async script tags there is not currently a way to make this work with the CLI since the conversion to webpack adds the script tags programatically. Is there a way for us to manually define the script tags in the index.html and not have webpack add them?

OS?

All

Versions.

Beta.21

Repro steps.

Ng Build / Ng Serve produces the following in index.html

<script type="text/javascript" src="inline.js"></script><script type="text/javascript" src="styles.bundle.js"></script><script type="text/javascript" src="scripts.bundle.js"></script><script type="text/javascript" src="main.bundle.js"></script>

Most helpful comment

The answer over at #6634 is that "there's not a good enough use case."...

What about the fact that Google's PageSpeedInsights tool says specifically this:

Try to defer or asynchronously load blocking resources, or inline the critical portions of those resources directly in the HTML.

And since it's not possible, we receive a lower PageSpeed score, and Google is publicly using Website Speed as a ranking factor?

Seems important to Google

All 24 comments

Having more than one script tag requires a little more work to ensure order of execution. @angularclass/bootloader is only part of the story since it ensures a function passed to it gets invoked whenever the DOM is ready. I mentioned this to @TheLarkInn awhile back about a solution that should be on by default for webpack 3. I published @angularclass/bootloader to start pushing for async script tag support in the community since we're been ignore it for awhile now

If we add in an option to the cli to turn off inject, you can manually add them by changing your index.html file to an index.ejs file like so:
<% for (var chunk in htmlWebpackPlugin.files.chunks) { %> <script src="<%= htmlWebpackPlugin.files.chunks[chunk].entry %>"></script> <% } %>. This requires no additional dependencies as it is supported via the HtmlWebpackPlugin the cli uses.

@the-destro that looks like a great option. That would be good.

If async scripts are the goal, it should probably be baked into the CLI so everyone can easily benefit. Also, as previously mentioned but deserves to be repeated, order of execution is important and the CLI is the arbiter of that order.

also keep in mind, when using the async tag, the browser is also parsing all of the scripts in parallel so the order in which they will be done is out of our hands. This would require another plugin or as I mentioned webpack to bake this in by default (webpack maybe v5).

For what's desire you can think of it like this

Promise.all(
  <script async src="inline.js"></script>,
  <script async src="styles.js"></script>,
  <script async src="scripts.js"></script>,
  <script async src="main.js"></script>
)
.then(scripts => scripts[3].bootstrap() )

Also see a prototype of this plugin
https://gist.github.com/gdi2290/ac2affca14de4940f8e8d1e05516172b

It would also be great if this plugin was included by default which would add the async tags to the html plugin
https://github.com/numical/script-ext-html-webpack-plugin

PS: this pattern is also used all the time for analytics/error capturing scripts for tracking data before the actual script is loaded

There's also the question of deciding which scripts should be async and which shouldn't. The user should be able to decide that, for stuff like analytics (like @gdi2290 highlighted) but also polyfills.

Similar issue is to support defer attribute on scripts. With pure webpack config the ExtHtmlWebpackPlugin would be used:

new ExtHtmlWebpackPlugin({
    defaultAttribute: 'defer'
})

With defer we don't have to handle order of scripts:
defer scripts are also guarenteed to execute in the order that they appear in the document.
http://www.growingwiththeweb.com/2014/02/async-vs-defer-attributes.html

As webpack 3 has been released for a while, can we push this thread in a faster pace?

You can see this PR for further discussion and analysis: https://github.com/angular/angular-cli/pull/6634

Please see @clydin's comment for a link to a similar PR, for which the answer is the same as this issue.

The answer over at #6634 is that "there's not a good enough use case."...

What about the fact that Google's PageSpeedInsights tool says specifically this:

Try to defer or asynchronously load blocking resources, or inline the critical portions of those resources directly in the HTML.

And since it's not possible, we receive a lower PageSpeed score, and Google is publicly using Website Speed as a ranking factor?

Seems important to Google

+1 to this, when will we able to do this? I'm also hitting the pagespeed issue.

I don't think that, for pushing a feature you need thousands of use cases. Even 5-10 use cases are good enough for adding a feature. Also, Google is complaining about it so if the CLI does not provide a way to do this then using it is pointless.

+1

+1

+1

+1

+1
Whats the point if google is recommending something and itself doesn't want to do it !!! :)

+1

So almost a year now, still impossible to do this.

I find ridiculous that Angular, being Google's own project, fails its own Pagespeed tests even using a minimal app. I just made one using CLI 8 + Ivy and the result is the same.

Some development here would be awesome. I mean, if I wasn't doing a SPA adding "async" in the styles would've taken me 5 minutes. Waiting for the Angular dev team? 3 years and counting...

I mean, if I wasn't doing a SPA adding "async" in the styles would've taken me 5 minutes

If you've got a better solution and it's easy for you... Why not go for it? :man_shrugging:

That feature would be good, but I honestly think that will have a minimal impact and it's more important to focus on other things. If it lands into the CLI at some point, good. In the meantime, analyze your bundle to make sure you're not including unwanted libraries, use lazy loading etc.

I mean, if I wasn't doing a SPA adding "async" in the styles would've taken me 5 minutes

If you've got a better solution and it's easy for you... Why not go for it? 馃し鈥嶁檪

It's not a better solution. He made an IFTTT statement with no mention of the superiority of the alternative.

That feature would be good, but I honestly think that will have a minimal impact and it's more important to focus on other things. If it lands into the CLI at some point, good. In the meantime, analyze your bundle to make sure you're not including unwanted libraries, use lazy loading etc.

This strikes me as a filler response. Something more valuable would have been explaining why it has "minimal impact", explaining what "minimal" means, in this instance. Explaining what "more important" means, as a relative term. Giving some examples of how the complexity of adding this feature makes it less of a priority, etc. I'm sure there's more important things. I'm sure it doesn't have as much impact as some other priorities. But I can't actually glean anything substantive from this response. I'm not bashing, but this from a contributor doesn't seem constructive in the least, and the first comment sounds a bit rude tbh.

@maxime1992 well that's a nice contribution from your part, "contributor".

As @stephengardner said, I didn't mention any alternatives. Maybe because... I'm making a SPA? This issue hasn't been solved. You want solutions? Lost of people up there (@clydin , @PatrickJS, @moravcik, etc.) have proposed solutions already, the team just hasn't bothered to include them. Those solutions can help to pass the PageSpeed test correctly which is very important for SEO. Yet it seems it isn't too important for the team considering this issue is still happening after 3 years and counting.

Again, @maxime1992 if you care to read: All I did was to just create a normal Angular app, changed the home content, run ng build --prod and upload the files to my server. I'm not doing anything different than what the stock production build produces. I'm not stupid, I didn't include "unwanted libraries" and there's not even a chance to use lazy loading because I didn't include routing tbh, it's the most basic "Under construction" page you could build with the --minimal preset and some basic CSS.

So, it's up for the Angular CLI to make a fully compliant project from scratch. If you as a dev break it, cool, but it should pass the test with a stock, unaltered build.

All the repositories in the Angular organization are under our code of conduct. This thread seems to be crossing the edge of a productive, friendly, constructive conversation.

I know that we're all with good intentions to make Angular better, but I believe this is not the right way to do it. It's time to lock this issue. I'd suggest to keep the good tone in upcoming conversations. Thanks :)

As of version 8.2.0, defer attributes are automatically added to classic scripts (module scripts are deferred by default).

Was this page helpful?
0 / 5 - 0 ratings