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

Some small optimizations for stylesheet injection #328

Closed
wants to merge 1 commit into from
Closed

Some small optimizations for stylesheet injection #328

wants to merge 1 commit into from

Conversation

developit
Copy link

This PR contains a:

  • bugfix
  • new feature
  • code refactor
  • test update (not yet!)
  • typo fix
  • metadata update

Motivation / Use-Case

There are a few cases where the code injected into a bundle could be a bit smaller. I've addressed two really simple ones here - removing the type property from <link rel=stylesheet>, and using document.head (IE9+) instead of getElementsByTagName('head')[0].

Breaking Changes

This requires IE9+. Not sure if there's a browser support target for mini-css-extract-plugin that makes this prohibitive.

@@ -353,7 +353,6 @@ class MiniCssExtractPlugin {
'}',
'var linkTag = document.createElement("link");',
'linkTag.rel = "stylesheet";',
'linkTag.type = "text/css";',
Copy link
Member

Choose a reason for hiding this comment

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

Why we need remove this? Not sure it is right idea

Copy link
Member

Choose a reason for hiding this comment

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

Removing text/css good for HTML5, but some browsers (include mobile) still have bad supporting HTML5

Copy link
Contributor

Choose a reason for hiding this comment

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

Keep compatibility as long as we can. Third-world countries and the corporations there can and usually are locked on older "legacy” devices or browsers

Copy link
Author

@developit developit Jan 8, 2019

Choose a reason for hiding this comment

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

The default value of the type attribute has always been text/css. The only difference in HTML5 was making it pass validation when omitted. There is no functionality change with regard to this behaviour between the two specs.

You can test this yourself - load this webpage in IE6:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html lang="en">
  <head>
    <title>HTML 4 Strict</title>
    <link rel="stylesheet" href="style.css">
    <!-- make sure style.css exists and and is not empty -->
  </head>  
  <body>
    <script>
      alert(document.styleSheets.length);
    </script>
  </body>
</html>

alert 1 in IE6

(also worth noting: an argument for specifying type on <link> tags implies we should do the same for <script>, which is universally regarded as unnecessary)

Copy link
Contributor

Choose a reason for hiding this comment

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

Nicely done

@@ -368,7 +367,7 @@ class MiniCssExtractPlugin {
'linkTag.href = fullhref;',
crossOriginLoading
? Template.asString([
`if (linkTag.href.indexOf(window.location.origin + '/') !== 0) {`,
`if (linkTag.href.indexOf(location.origin + '/') !== 0) {`,
Copy link
Member

Choose a reason for hiding this comment

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

Always need window, you can have scope problem in some rare cases

Copy link
Contributor

Choose a reason for hiding this comment

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

agreed, don't rely on global scope being there. explicit, no implicit is always my suggestion

Copy link
Author

Choose a reason for hiding this comment

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

What scope problem are you referring to?

var location = 1 or location=1 in global scope redirect the page, as does window.location=1 - it's exceptionally unlikely the value would be redefined. It could be shadowed, but that's equally true for any variable including window.

Choose a reason for hiding this comment

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

Note that the code already uses document rather than window.document.

Copy link
Contributor

Choose a reason for hiding this comment

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

Fair point... we should side with implicit or explicit conventions throughout

Copy link
Contributor

Choose a reason for hiding this comment

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

I’ve had scope issues before. Rarely but they do happen. Even if wasted bytes. This plugin gets like 5mil downloads a week. Eventually complaints would roll in. We are talking race conditions.

Stupid question, what if we declared window as a variable, then w.document or w.location? One way to save bytes maybe. Can’t speak if race conditions would come of this never tried

Choose a reason for hiding this comment

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

We are talking race conditions.

I don't see a race condition here.

what if we declared window as a variable, then w.document or w.location? One way to save bytes maybe.

If gzip's involved, that uses more bytes than window.document.

Fwiw I think omitting window is fine.

@@ -377,8 +376,7 @@ class MiniCssExtractPlugin {
'}',
])
: '',
'var head = document.getElementsByTagName("head")[0];',
'head.appendChild(linkTag);',
'document.head.appendChild(linkTag);',
Copy link
Member

Choose a reason for hiding this comment

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

Hm IE9 doesn't support getElementsByTagName?

Copy link
Contributor

Choose a reason for hiding this comment

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

Copy link
Member

Choose a reason for hiding this comment

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

@ScriptedAlchemy for me too, so i asked question why it was changed

Copy link
Contributor

Choose a reason for hiding this comment

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

Yeah good point. Though both of them do work with old I.E.

However I’m unsure how widely supported ‘document.head’ is especially in older browsers

Copy link
Author

Choose a reason for hiding this comment

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

Copy link
Author

Choose a reason for hiding this comment

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

Looks like Webpack core has also switched over to using document.head:
webpack/webpack#8467

@alexander-akait
Copy link
Member

/cc @developit friendly ping

@developit
Copy link
Author

Just to clarify my intention with this PR:

The code generated here is injected into a large percentage of websites. Each byte saved represents a nontrivial reduction in bundle size across the whole web.

Copy link
Member

@alexander-akait alexander-akait left a comment

Choose a reason for hiding this comment

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

Good for me, but it is breaking change, some people can use plugin for IE8 and after merge we break their app, we can separate PR on two parts

@Jessidhia
Copy link
Contributor

Jessidhia commented Jan 10, 2019

Do we really need to be this concerned about older browser support if #299 is not included?

Any browser that this PR would break is already broken by not having #299.

(EDIT: nevermind that as IE does support it; but webpack 2+ cannot bundle ES modules on IE<9 anyway because IE<9 don't have a working Object.defineProperty)

@alexander-akait
Copy link
Member

@Kovensky hm, I forgot that we need to use webpack@4 for this plugin 😄 So webpack@4 doesn't support IE8, right?

@Jessidhia
Copy link
Contributor

Jessidhia commented Jan 10, 2019

It depends on whether it's still possible to make a bundle that does not invoke Object.defineProperty (or __webpack_require__.d / __webpack_require__.n in this case; __webpack_require_.r can be faked in IE by es5-sham but not __webpack_require__.d or __webpack_require__.n)

@alexander-akait
Copy link
Member

@Kovensky thanks for information, what do you think should we merge this as patch or major release?

@Jessidhia
Copy link
Contributor

Jessidhia commented Jan 10, 2019

It looks like it is still possible if your code and entire dependency graph consists exclusively of CommonJS or AMD modules... I find that extremely unlikely.

Personally I'm OK with this break as it's overwhelmingly unlikely that it will break bundles that weren't already broken, I'm not sure if this might still affect people. It's not impossible that people might be intentionally using babel-loader + @babel/plugin-transform-modules-commonjs in loose: true mode to stop webpack from being able to see ES modules.

@ScriptedAlchemy
Copy link
Contributor

What about a feature release? Unless we are really making a heavy impact change? Are we losing compatibility with current PRd changes?

Don’t mind major version bump, just throwing the question out there

@ScriptedAlchemy
Copy link
Contributor

Yeah that’s fine then. Lets get this in as a major

brophdawg11 added a commit to brophdawg11/mini-css-extract-plugin that referenced this pull request Apr 1, 2019
This adds an new `insertInto` option that is optional and backards-compatible.  Specifying a CSS selector allows the user to specify a DOM node into which the async-loaded <link> tags should be inserted.

Closes webpack-contrib#370, related to webpack-contrib#328,webpack-contrib#331
brophdawg11 added a commit to brophdawg11/mini-css-extract-plugin that referenced this pull request Apr 1, 2019
This adds an new `insertInto` option that is optional and backards-compatible.  Specifying a CSS selector allows the user to specify a DOM node into which the async-loaded <link> tags should be inserted.

Closes webpack-contrib#370, related to webpack-contrib#328,webpack-contrib#331
brophdawg11 added a commit to brophdawg11/mini-css-extract-plugin that referenced this pull request Jun 27, 2019
This adds an new `insertInto` option that is optional and backards-compatible.  Specifying a CSS selector allows the user to specify a DOM node into which the async-loaded <link> tags should be inserted.

Closes webpack-contrib#370, related to webpack-contrib#328,webpack-contrib#331
@codecov
Copy link

codecov bot commented Jun 1, 2020

Codecov Report

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

Impacted file tree graph

@@          Coverage Diff           @@
##           master    #328   +/-   ##
======================================
  Coverage    0.00%   0.00%           
======================================
  Files           3       3           
  Lines         284     284           
  Branches       59      59           
======================================
  Misses        234     234           
  Partials       50      50           
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 7d1e0ca...ae6f0f1. Read the comment docs.

@sokra
Copy link
Member

sokra commented Jun 1, 2020

People are using webpack 4 for ie8. That's a supported use case. ESM is not supported, by there is a ton of commonjs or amd code that can be used.

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

Successfully merging this pull request may close these issues.

7 participants