Closed naveedahmed1 closed 4 years ago
Actually there could be two approaches,
Critical
plugin. preload
tag.Apps using Universal
as well as App Shell
should equally benefit from this.
There's also an official webpack plugin (https://github.com/numical/script-ext-html-webpack-plugin) which could be helpful.
I tried adding below to my extend.webpack.config.js
file but somehow it didn't work (may be I'm missing something):
const HtmlWebpackPlugin = require('html-webpack-plugin')
const ScriptExtHtmlWebpackPlugin = require("script-ext-html-webpack-plugin");
module.exports = {
plugins: [
new HtmlWebpackPlugin(),
new ScriptExtHtmlWebpackPlugin({
preload: /\.css$/
})
}
Here's the similar plugin for Vuejs
https://github.com/andreashuber69/async-css-plugin
With a default Angular application, pre-loading the styles won't do any good. The whole application is rendered using JavaScript, so unless you are using Angular Universal, this extra configuration is of no real help.
And to avoid having huge initial styles, you can minimize your global styles (defined in angular.json) by using lazy modules and defining the module specific styles inside components for that module; You could have something like a wrapping "shell" component with ViewEncapsulation.None
.
In which Angular CLI could automatically identify Critical Path CSS using Critical plugin.
Because of the dynamic nature of Angular application and the complexity behind the routing system that supports lazy modules, modules like that won't be of any use. Your best bet is to use lazy-modules with a shell component that deals with more generic styles and in general: just be careful when splitting the application into lazy-modules.
Thank you so much @SchnWalter. I agree to your comment, my suggestion is mainly for the Universal apps and those apps that are using appshell model. What if we could add an option of preload
in angular.json with each stylesheet, that when specified should generate something like <link href="/style.96106fab.css" rel="preload" as="style" onload="this.rel='stylesheet'">
Yes, but that's not for "Render-Blocking CSS", that's for all the global CSS, and for most angular projects, that won't give a noticeable performance boost for such a feature to be added to the core Angular tooling; this is something for a 3rd party builder.
Ok, from your comment https://github.com/angular/angular-cli/issues/17764#issuecomment-633515912 I am trying another approach, adding critical path css to the index.html
and setting "extractCss": false,
.
extractCss
is intended to be used only for development to speed up rebuild times.
In general injected global css should be render blocking as otherwise it will cause flickering when there is the transition between the server and client.
My recommendation would be to use both injected and non injected global styles and load the non injected global styles eagerly. Again this might cause flickering when used with SSR.
This issue is also related to https://github.com/angular/angular-cli/issues/11395 which I think it make sense to continue tracking over there.
Closing in favour of #11395. If there is a reason why this should be tracked separately please let me know.
Thanks @alan-agius4 . I thinks its a different feature request but I wont mind if this could be merged and tracked with https://github.com/angular/angular-cli/issues/11395 since the objective in both cases is almost same.
Originally my request was that Angular CLI should automatically detect the css for the critical/“above-the-fold”
using https://github.com/addyosmani/critical plugin by Addy Osmani and put it inline in index.html where as remaining css should be loaded lazily and CLI should generate a tag similar to this for remaining css:
<link href="/style.96106fab.css" rel="preload" as="style" onload="this.rel='stylesheet'">
If this is too complex to implement and you think it wont add much value, at least there should be an option for user to specify how a particular style file should be added to production output.
For example, it would be great to add inline
and preload
options in styles
in angular.json
file.
"styles": [
{ "input": "src/critical-path-styles.scss", "inline": true },
{ "input": "src/lazy-styles.scss", "preload": true }
]
With above settings, Angular CLI should inline the contents of critical-path-styles.scss
in head tag, and it should generate <link href="/lazy-styles.96106fab.css" rel="preload" as="style" onload="this.rel='stylesheet'">
for lazy-styles.scss
.
Originally my request was that Angular CLI should automatically detect the css for the critical/“above-the-fold” using https://github.com/addyosmani/critical plugin by Addy Osmani and put it inline in index.html where as remaining css should be loaded lazily and CLI should generate a tag similar to this for remaining css:
Unless I am misunderstanding something. This plugin will not work with JS frameworks such as Angular, because the plugin takes an HTML to detect which CSS classes are critical.
With regards to preload and inlining the entire contents, this actually can already be done by extending the default CLI builder.
That said inlining CSS, opens up another discussion around CSP (Content security policy).
Unless I am misunderstanding something. This plugin will not work with JS frameworks such as Angular, because the plugin takes an HTML to detect which CSS classes are critical.
I had some idea, and it probably could work only in case of universal/prerendered app or apps using app-shell.
With regards to preload and inlining the entire contents, this actually can already be done by extending the default CLI builder.
Can you please share some more details on this? some docs or example may be?
That said inlining CSS, opens up another discussion around CSP (Content security policy).
I think Google also suggest inlining critical styles and asynchronously loading rest of the styles https://web.dev/render-blocking-resources/ , btw when we're using SSR it also inlines the styles in head of the document.
I had some idea, and it probably could work only in case of universal/prerendered app or apps using app-shell.
This will potentially slow down universal, because each response will need to get parsed and generate critical stylesheet on the fly because each page will have different critical css, with regards to pre-render, you might end up with different stylesheets for each page.
Can you please share some more details on this? some docs or example may be?
There are no docs about this, because while we allow customising your build we don't support it. You can take a look at https://www.npmjs.com/package/@angular-builders/custom-webpack#index-transform
btw when we're using SSR it also inlines the styles in head of the document.
Yeah indeed, that doesn't that's it's not a problem though.
@naveedahmed1 we're looking into this with Chrome. Discussing pros and cons of different approaches.
That's great, Thank you so much @mgechev for the update :)
This issue has been automatically locked due to inactivity. Please file a new issue if you are encountering a similar or related problem.
Read more about our automatic conversation locking policy.
This action has been performed automatically by a bot.
🚀 Feature request
Command (mark with an
x
)Description
The size of CSS for a normal website could be from 100kb to few hundred KBs.
For better performance we should inline the critical css in the head of the html document and lazy load rest of the css through an external file.
Currently Angular CLI adds the css file to the head of the index.html, which makes it
render blocking
.Ideally we should have a solution like the one mentioned here https://dzone.com/articles/critical-css-and-webpack-automatically-minimize-re , so that during the build process Angular CLI automatically identify the css of the critical path, inline it in head of the
index.html
, and lazy load rest of the css usingpreload
e.g.:<link href="/style.96106fab.css" rel="preload" as="style" onload="this.rel='stylesheet'">
I am not sure how practical the solution described in this post is, but I think the least we could do is allow lazy loading of css e.g through an option in
angular.json
file that allow us to specify that this particular css file should be lazy loaded and when that option is enabled, Angular CLI should create below tag:<link href="/style.hash.css" rel="preload" as="style" onload="this.rel='stylesheet'">
instead of
<link rel="stylesheet" href="styles.hash.css">
assuming we have already inline the critical css in index.html.
This Webpack plugin might be relevant and helpful https://www.npmjs.com/package/preload-webpack-plugin