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

Add an asyncMedia option to prevent parser-blocking async css #736

Closed
jpnelson opened this issue Apr 9, 2021 · 6 comments
Closed

Add an asyncMedia option to prevent parser-blocking async css #736

jpnelson opened this issue Apr 9, 2021 · 6 comments

Comments

@jpnelson
Copy link

jpnelson commented Apr 9, 2021

  • Operating System: All
  • Node Version: v12
  • NPM Version: v7
  • webpack Version: 4 / 5
  • mini-css-extract-plugin Version: Suggested to be 1.5.0

Feature Proposal

I would suggest adding an asyncMedia option to the plugin that would allow loading of async css bundles with the media attribute set to print (or something else), which is then switched out to all on load.

Eg.

new MiniCssExtractPlugin({
  filename: '[name].[contenthash:8].css',
  chunkFilename: '[id].[contenthash:8].css',
  asyncMedia: 'print',
}),

would add a link attribute with:

<link rel="stylesheet" type="text/css" href="..." crossorigin="anonymous" media="print">

and an onload handler which would replace this with:

<link rel="stylesheet" type="text/css" href="..." crossorigin="anonymous" media="all">

when the stylesheet has been downloaded.

I would suggest the default for this option is print but that it is customizable

Feature Use Case

This is the best practice way of loading async css – without it, the page pauses while downloading the async css as it's appended to the head.

This use case was previously mentioned in #721 , but it cannot be easily implemented due to the fact that the onload attribute is in use by the plugin logic itself. For that reason I think it makes sense to implement this as an option in this plugin.

(I'd be happy to implement this myself if you think it makes sense)

@alexander-akait
Copy link
Member

alexander-akait commented Apr 9, 2021

https://github.com/webpack-contrib/mini-css-extract-plugin#attributes, you can do it using this, changing print to all is unsafe, because user can be in print mode

@jpnelson
Copy link
Author

jpnelson commented Apr 9, 2021

Thanks for the suggestion – my understanding from #721 was that this specific use case wasn't supported with the attributes option, due to the need to change the attribute in the onload handler, which is in use by the plugin. I agree that this is a tradeoff though as media="print" might be a use case for some people (faux media attributes are another way of achieving this but that has its own drawbacks)

@alexander-akait
Copy link
Member

alexander-akait commented Apr 9, 2021

Why do you need this? I recommend to use rel="preload", it is widely supported right now, no need to support old browsers using unsafe hacks, also async loading will do FOUC, it is not good

@jpnelson
Copy link
Author

jpnelson commented Apr 9, 2021

I'm looking for a way to download CSS files without blocking javascript parsing. By inserting a <link> tag into the document head, additional javascript parsing is paused until that CSS file download is complete.

If we were to add a rel="preload" in the server response, there's a good chance that the file would already be downloaded by the time the <link> tag is inserted, so that would partly solve the problem, yes. If that preload didn't complete (maybe it was too slow, or the preload request failed) I think this would still be needed.

An alternative is to instead of doing the <link media="print" ...> to insert <link rel="preload" ...>, but swapping that back to media="all" or rel="stylesheet" would still require some API to make that useful I think. An API suggestion for that would be:

new MiniCssExtractPlugin({
  filename: '[name].[contenthash:8].css',
  chunkFilename: '[id].[contenthash:8].css',
  asyncPreload: true,
}),

would add a link attribute with:
<link rel="preload" as="stylesheet" type="text/css" href="..." crossorigin="anonymous">

and an onload handler which would replace this with:
<link rel="stylesheet" type="text/css" href="..." crossorigin="anonymous">

One difference doing this would be that the CSS gets downloaded with the highest priority, but probably that'd be what you'd want in this case anyway.

By "async" what I mean is really what the plugin does already, here: https://github.com/webpack-contrib/mini-css-extract-plugin/blob/master/src/index.js#L783 . My understanding was that this type of insertion would be safe against FOUC because it doesn't call resolve() until the onload handler is complete

@alexander-akait
Copy link
Member

It still have FOUC when we change media

@alexander-akait
Copy link
Member

Close in favor #949

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

2 participants