styled-components: Angular.js causes styled-components to break on IE 11

Version

1.4.4 (maybe a lot older too)

Reproduction

Webpackbin doesn’t work on IE 11… So here’s a repo! https://github.com/dfrankland/styled-components-angular-ie-11-conflict

Steps to reproduce

Follow steps in linked repo.

Expected Behavior

Work like normal.

Actual Behavior

No CSS rules are applied to the style element.

Why?

Angular will recompile all the individual DOM elements including those in the head. Normally, on Chrome and other browsers this isn’t an issue, but on IE 11 this causes text nodes to lose their parentNode. This could occur due to anything though, it doesn’t have to be Angular. The more longwinded explanation:

  1. Style elements and text nodes get inserted in ComponentStyle

  2. Afterwards, anything could mutate the DOM, such as Angular, causing issues later

  3. A styled component is ready to render so generateAndInjectStyles inside of ComponentStyle is called

  4. appendRule inside the Glamor sheet tries to mutate a text node, but it has already been removed from the DOM, thus no styles are applied to the style tags created in step 1

Fix

I propose to move the appending of text nodes to the style element DOM only once the component is ready to render, rather than doing it preemptively.

https://github.com/styled-components/styled-components/blob/master/src/vendor/glamor/sheet.js#L125

const textNode = document.createTextNode(rule)
- last(this.tags).appendChild(textNode)
- insertedRule = { textNode, appendRule: newCss => textNode.appendData(newCss)}
+ insertedRule = {
+   textNode,
+   appendRule: newCss => textNode.appendData(newCss),
+   appendNode: () => last(this.tags).appendChild(textNode),
+ };

https://github.com/styled-components/styled-components/blob/master/src/models/ComponentStyle.js#L39

const selector = nameGenerator(hash)
inserted[hash] = selector
const root = parse(`.${selector} { ${flatCSS} }`)
postcssNested(root)
autoprefix(root)
this.insertedRule.appendRule(root.toResult().css)
+ this.insertedRule.appendNode()

About this issue

  • Original URL
  • State: closed
  • Created 7 years ago
  • Reactions: 2
  • Comments: 17 (7 by maintainers)

Most upvoted comments

Just a heads-up. If you use auto-bootstrapping with ng-app on the html tag of your index.html, you can try moving ng-app to the body tag. That resolved it for me.

- angular.bootstrap(document, ['blah'], {});
+ angular.bootstrap(document.body, ['blah'], {});

I think at this point you should consider opening an issue on their repo instead 😉

@HashemKhalifa, using react2angular doesn’t really affect the way the fix is implemented.

Following the react2angular example, you only need to add one line:

import { react2angular } from 'react2angular'

angular
  .module('myModule', [])
  .component('myComponent', react2angular(MyComponent, ['fooBar', 'baz']))
+ .element(document).ready(() => angular.bootstrap(document.body, ['myModule'], {}));

If you need any other help, you may want to open an issue for react2angular.