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

fix(index): dynamic css loading support for older browsers #134

Open
wants to merge 3 commits into
base: master
Choose a base branch
from

Conversation

gaterking
Copy link

This PR contains a:

  • bugfix
  • new feature
  • code refactor
  • test update
  • typo fix
  • metadata update

Motivation / Use-Case

Breaking Changes

Additional Info

In old browser, such as android 4.3, link tag not support 4.3. Although these devices is few, the onload callback resolve function will not be called. This PR ignore onload for these devices and resolve immediately.

@jsf-clabot
Copy link

jsf-clabot commented May 8, 2018

CLA assistant check
All committers have signed the CLA.

@alexander-akait
Copy link
Member

@gaterking can you provide minimum reproducible test repo and browser version to ensure it is does not works for all, thanks!

@gaterking
Copy link
Author

@evilebottnawi http://pie.gd/test/script-link-events/
From this test page, we can see many old browsers not support link tag onload event.

@alexander-akait
Copy link
Member

@gaterking also please accept CLA

@alexander-akait
Copy link
Member

@gaterking can you faced this problem ?

src/index.js Outdated
@@ -338,8 +338,10 @@ class MiniCssExtractPlugin {
]),
'}',
'var linkTag = document.createElement("link");',
'var isOldWebKit = Number(navigator.userAgent.replace(/.*AppleWebKit\\/(\\d+)..*/, "$1")) < 536;',
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we can find better solution for check this, can you investigate how this do example jquery or other frontend libraries?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

At present, old browser is less. I only use regex to match AppleWebKit 536, bescause I think it will cover most of old browser. There is another solution to check version:
https://github.com/filamentgroup/loadCSS/blob/master/src/onloadCSS.js
As bellow is another solution to check if css is loaded:
http://www.backalleycoder.com/2011/03/20/link-tag-css-stylesheet-load-event/
https://www.zachleat.com/web/load-css-dynamically/
Another question: Why we need to wait resolve for css chunks is loaded? CSS chunkses are appended in sequence, they can't impact each other. The waiting will increase js render time inversely. There is so less case we need to caculate element style when the the self css is loaded but next css is not loaded.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@gaterking http://www.backalleycoder.com/2011/03/20/link-tag-css-stylesheet-load-event/ looks universal, but create new dom node looks overload.

Give me time on thinking about best solution, ping be tomorrow and we find better.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

https://github.com/guybedford/require-css/blob/master/css.js
A CSS Loader plugin for RequireJS which can be refered to.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@gaterking looks solid, maybe we can port solution here?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, it's solid. We can remove some inspections such as ie or low version firefox. Webpack 4 don't support ie6 to 8.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@gaterking we can avoid part of code for old ie

@gaterking
Copy link
Author

@evilebottnawi Yes, I faced it in my vue project. Android 4.3 browser will fail, bescause some lazy load modules with css chunk not resolve.

@alexander-akait
Copy link
Member

@gaterking looks good solution, but i think we should search better solution for detecting this

@Jessidhia
Copy link
Contributor

This also happened to be a blocker for a smartphone-specific project at work. I'll link this to the person involved so he can check if this works 🤔

@Jessidhia
Copy link
Contributor

Note that it's important to know when a dynamically inserted style is loaded. Not knowing this leads to FOUC, which can be disastrous if you're doing things like getBoundingClientRect on component mount if it happens before the load is done.

@gaterking
Copy link
Author

index.js
@evilebottnawi Can you review my new code? If OK, I will create a new PR.
Refer to RequieJS plugin, it use regex to check browser, but it don't check webkit version.
In new solution, I refer to Dojo plugin and xstyle. I use setInterval to check css file is loaded in this case.
I am sure we need to support webkit < 536 only, Becase of Webpack 4.

@gaterking
Copy link
Author

what the next step for this PR?

@@ -349,7 +362,25 @@ class MiniCssExtractPlugin {
'reject(err);',
]),
'};',
'linkTag.href = fullhref;',
'} else {',
'var errorTimeout = 60000;',
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about is loading more than 60000 ?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's a timeout threshold for css loading. To make sure chunk is resolved, I think we need a stop time to clear setInterval when the css loaded fail.

@michael-ciniawsky michael-ciniawsky changed the title dynamic import css chunk support old browser fix(index): dynamic import css chunk support older browsers Aug 6, 2018
@michael-ciniawsky michael-ciniawsky added this to the 0.4.2 milestone Aug 6, 2018
@michael-ciniawsky michael-ciniawsky changed the title fix(index): dynamic import css chunk support older browsers fix(index): dynamic css loading support for older browsers Aug 6, 2018
@hxlniada
Copy link

may be this is a better solution: https://stackoverflow.com/a/5371426

@alexander-akait
Copy link
Member

/cc @gaterking

@gaterking
Copy link
Author

I think this PR is not necessary for most developer, maybe we can close it. If somebody need to support old browser, I suggest to clone own repo.

@lili21
Copy link

lili21 commented Oct 16, 2018

@evilebottnawi what do you think?

@lili21
Copy link

lili21 commented Oct 16, 2018

@hxlniada It's a neat solution, just need a little change.

...
var img = document.createElement('img');
img.onerror = function (e) {
  var request = event && event.target && event.target.src || fullhref;
  var i = document.styleSheets.length;
  while(i--) {
    if (document.styleSheets[i].href === request) {
      return resolve();
    }
  }
  var err = new Error('Loading CSS chunk ' + chunkId + ' failed.\n(' + request + ')');
  err.request = request;
  reject(err);
};
img.src = fullhref;
...

@gaterking
Copy link
Author

gaterking commented Nov 14, 2018

#299 similar PR

'linkTag.href = fullhref;',
"// old webkit's would claim to have onload, but didn't really support it",
'// https://github.com/kriszyp/xstyle/blob/master/core/load-css.js',
'var webkitVersion = navigator.userAgent.match(/AppleWebKit\\/(\\d+\\.?\\d*)/);',
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This extra check affects only 0.02% of the internet. I don't think it's worth including this workaround of everybody.

'// most browsers support this onload function now',
'linkTag.onload = function(){',
'// cleanup',
'linkTag.onload = null;',
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

indent

'var startTime = Date.now();',
'var interval = setInterval(function(){',
'if(linkTag.style){',
'clearInterval(interval);',
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

indent

'clearInterval(interval);',
'resolve();',
'}',
'if(!linkTag.style && (Date.now() - startTime) > errorTimeout){',
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The support for onload and onerror differ. Make sure to handle them separately. Use a setTimeout for error handling and don't merge it into the setInterval for onload.

'var errorTimeout = 60000;',
'var startTime = Date.now();',
'var interval = setInterval(function(){',
'if(linkTag.style){',
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of polling this seem to be a better solution for this problem: https://github.com/webpack-contrib/mini-css-extract-plugin/pull/299/files

@codecov
Copy link

codecov bot commented May 3, 2020

Codecov Report

Merging #134 into master will not change coverage.
The diff coverage is n/a.

Impacted file tree graph

@@          Coverage Diff           @@
##           master    #134   +/-   ##
======================================
  Coverage    0.00%   0.00%           
======================================
  Files           3       3           
  Lines         241     241           
  Branches       49      49           
======================================
  Misses        198     198           
  Partials       43      43           
Impacted Files Coverage Δ
src/index.js 0.00% <ø> (ø)

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 41347f7...bd891a0. Read the comment docs.

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

Successfully merging this pull request may close these issues.

None yet

8 participants