├── .gitignore ├── LICENSE ├── README.md ├── images ├── css-in-js.png └── emotion-source-maps.gif ├── package.json ├── talks.md └── yarn.lock /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Stand With Ukraine](https://raw.githubusercontent.com/vshymanskyy/StandWithUkraine/main/banner2-direct.svg)](https://vshymanskyy.github.io/StandWithUkraine) 2 | 3 | # CSS-in-JS 101 [![Twitter Follow](https://img.shields.io/twitter/url/http/shields.io.svg?style=social&label=Follow)](https://twitter.com/stereobooster) 4 | 5 | ![CSS-in-JS 101](images/css-in-js.png) 6 | 7 | 8 | 9 | - [What is CSS-in-JS?](#what-is-css-in-js) 10 | - [Inline styles](#inline-styles) 11 | * [Pros](#pros) 12 | * [Cons](#cons) 13 | * [Inline styles vs CSS-in-JS](#inline-styles-vs-css-in-js) 14 | - [Style tag](#style-tag) 15 | * [Pros](#pros-1) 16 | * [Cons](#cons-1) 17 | - [CSS Modules](#css-modules) 18 | * [Pros](#pros-2) 19 | * [Cons](#cons-2) 20 | * [Dead Code Elimination, Critical CSS](#dead-code-elimination-critical-css) 21 | - [Global Name Space, Globally Unique Identifier](#global-name-space-globally-unique-identifier) 22 | - [Dependencies](#dependencies) 23 | - [Minification](#minification) 24 | * [Traditional CSS minification](#traditional-css-minification) 25 | * [Minification of class name](#minification-of-class-name) 26 | * [Dead Code Elimination](#dead-code-elimination) 27 | * [Critical CSS](#critical-css) 28 | * [Automatic Atomic CSS](#automatic-atomic-css) 29 | - [Sharing Constants, variables in CSS](#sharing-constants-variables-in-css) 30 | * [Sharing variables inside CSS](#sharing-variables-inside-css) 31 | * [Sharing variables in CSS and exposing it to JS](#sharing-variables-in-css-and-exposing-it-to-js) 32 | * [Passing variable from JS to CSS](#passing-variable-from-js-to-css) 33 | - [Non-deterministic Resolution](#non-deterministic-resolution) 34 | - [Isolation](#isolation) 35 | - [Theming](#theming) 36 | * [Overriding styles](#overriding-styles) 37 | * [Overriding theme variables](#overriding-theme-variables) 38 | - [SSR, Server-Side Rendering](#ssr-server-side-rendering) 39 | * [HTML SSR](#html-ssr) 40 | * [CSS SSR](#css-ssr) 41 | - [Zero runtime dependency](#zero-runtime-dependency) 42 | - [CSS-in-JS implementation specific features](#css-in-js-implementation-specific-features) 43 | * [Non-DOM targets](#non-dom-targets) 44 | * [CSS as object (object literal)](#css-as-object-object-literal) 45 | * [CSS as template literal](#css-as-template-literal) 46 | * [Framework agnostic](#framework-agnostic) 47 | * [Build step](#build-step) 48 | * [Dynamic](#dynamic) 49 | * [Generate components based on CSS](#generate-components-based-on-css) 50 | * [Developer tools integration](#developer-tools-integration) 51 | - [Progressive enhancement, graceful degradation](#progressive-enhancement-graceful-degradation) 52 | - [Uncovered subjects](#uncovered-subjects) 53 | * [Security](#security) 54 | * [Async components](#async-components) 55 | * [CSS-in-JS and Async components](#css-in-js-and-async-components) 56 | * [Atomic CSS](#atomic-css) 57 | * [Animations](#animations) 58 | 59 | 60 | 61 | ## What is CSS-in-JS? 62 | 63 | CSS-in-JS is an umbrella term for technologies which help you define styles in JS in more component-approach-way. The idea was introduced by `@vjeux` in 2014. Initially, it was described as inline styles, but since then battlefield changed a lot. There are about 50 different solutions in this area. 64 | 65 | #### References 66 | 67 | - [@vjeux, 2014][@vjeux, 2014] 68 | - [Big list of CSS-in-JS solutions](http://michelebertoli.github.io/css-in-js/) 69 | - [Comparison of CSS-in-JS by styled-components](https://github.com/styled-components/comparison/pull/44) 70 | - [Yet another comparison](http://seifi.org/css/sxsw-slides-css-in-react-the-good-the-bad-and-the-ugly.html) 71 | 72 | ## Inline styles 73 | 74 | This is built in feature of React. You can pass styles as an object to the component and it will be converted to the string and attached as style attribute to the element. 75 | 76 | ### Pros 77 | 78 | - No `global namespace` 79 | - `Full isolation` 80 | - No `non-deterministic resolution` 81 | - Clear `dependencies` 82 | - `Dead code elimination` 83 | - `Variables, Passing variable from JS to CSS` 84 | 85 | ### Cons 86 | 87 | - Code duplication in case of SSR. 88 | - Additional costs in JS payload. Remember that styles which are embedded in JS are not for free. It is not only about download time, it is also about parsing and compiling. See [this detailed explanation by Addy Osmani, why JS is expensive](https://medium.com/dev-channel/the-cost-of-javascript-84009f51e99e) 89 | - No media queries (`@media`) 90 | - No CSS animations (`@keyframes`) 91 | - No pseudo classes (`:hover`) 92 | - No web fonts (`@font`) 93 | - No autoprefixer (well there is [inline-style-prefixer](https://github.com/rofrischmann/inline-style-prefixer)) 94 | 95 | #### Example 96 | 97 | **TODO**: verify 98 | 99 | JSX: 100 | 101 | ```jsx 102 | hundred_length_array 103 | .map(x =>
) 104 | ``` 105 | 106 | Generated HTML: 107 | 108 | ```html 109 |
110 | ...(98 times) 111 |
112 | ``` 113 | 114 | ### Inline styles vs CSS-in-JS 115 | 116 | `@mxstbr` differentiate `Inline styles` and `CSS-in-JS`. By `Inline styles` he means React built-in support for style attribute and by `CSS-in-JS` he means a solution which generates CSS and injects it via style tag. 117 | 118 | On the other hand, `CSS-in-JS` is the term coined by `@vjeux` in 2014 and he meant `Inline styles`. `Inline styles` is not React-only feature. There is, for example, Radium which also uses `inline styles`. 119 | 120 | So I would suggest to use `CSS-in-JS` as an umbrella term and specify implementation: 121 | - inline styles 122 | - style tag. Also can be referred as "style element" or "real CSS" 123 | - mixed (like Radium) 124 | 125 | #### References 126 | 127 | - [@mxstbr, 2016][@mxstbr, 2016] 128 | 129 | ## Style tag 130 | 131 | This approach is alternative to `Inline styles`. Instead of attaching styles as property to the element you are inserting real CSS in style tag and append style tag to the document. 132 | 133 | Pros and cons can vary from implementation to implementation. But basically, it looks like this: 134 | 135 | ### Pros 136 | 137 | - (Almost) No `global namespace` 138 | - (Almost) `Full isolation` 139 | - (Almost) No `non-deterministic resolution` 140 | - Clear `dependencies` 141 | - `Dead code elimination` 142 | - `Variables` (depends on implementation) 143 | - No code duplication in case of SSR 144 | - Additional costs in JS payload (depends on implementation) 145 | - Media queries (`@media`) 146 | - CSS animations (`@keyframes`) 147 | - Pseudo-classes (`:hover`) 148 | - Web fonts (`@font`) 149 | 150 | ### Cons 151 | 152 | Cons depend on implementation. 153 | 154 | #### Example 155 | 156 | [from this blog post](https://medium.learnreact.com/the-style-tag-and-react-24d6dd3ca974): 157 | 158 | ```js 159 | const MyStyledComponent = props => 160 |
161 | Hover for red 162 | 174 |
175 | ``` 176 | 177 | ## CSS Modules 178 | 179 | A CSS Module is a CSS file in which all class names and animation names are scoped locally by default. All URLs (url(...)) and @imports are in module request format (./xxx and ../xxx means relative, xxx and xxx/yyy means in modules folder, i. e. in node_modules). 180 | 181 | ### Pros 182 | 183 | - (Almost) No `global namespace` 184 | - (Almost) `Full isolation` 185 | - (Almost) No `non-deterministic resolution` 186 | - Clear `dependencies` 187 | - (Almost) `Dead code elimination` 188 | - `Variables, Sharing variables in CSS and exposing it to JS` 189 | - No Code duplication in case of SSR 190 | - No Additional costs in JS payload. 191 | - Media queries (`@media`) 192 | - CSS animations (`@keyframes`) 193 | - Pseudo-classes (`:hover`) 194 | - Web fonts (`@font`) 195 | - Autoprefixer 196 | 197 | ### Cons 198 | 199 | See all points with "(Almost)" 200 | 201 | ### Dead Code Elimination, Critical CSS 202 | 203 | Strictly speaking, there are no official solutions to those problems in `CSS Modules`, but there is some work in this direction. Correct me if I'm wrong if there is one, why isn't it promoted? 204 | 205 | - [Comment by @sokra on critical CSS](https://github.com/webpack-contrib/style-loader/pull/159#issuecomment-286729044) 206 | - [isomorphic-style-loader](https://github.com/kriasoft/isomorphic-style-loader) 207 | - [Support Tree shaking of CSS ](https://github.com/webpack-contrib/css-loader/issues/506) 208 | - [Atomic CSS a la styletron](https://github.com/deamme/styletron-loader) 209 | - [CSSO scopes](https://github.com/css/csso#scopes) 210 | 211 | #### References 212 | 213 | - [css-modules](https://github.com/css-modules/css-modules) 214 | - [@markdalgleish, 2015][@markdalgleish, 2015] 215 | 216 | ## Global Name Space, Globally Unique Identifier 217 | 218 | All declarations in CSS are global, which is bad because you never know what part of application change in global scope will affect. 219 | 220 | #### Possible solutions 221 | 222 | - Attach styles to each element (`Inline styles`) 223 | - Use Globally Unique Identifiers for classes (`CSS modules`) 224 | - Use naming conventions (BEM and others) 225 | 226 | #### References 227 | 228 | - [@vjeux, 2014][@vjeux, 2014] 229 | 230 | ## Dependencies 231 | 232 | Ability to programmatically resolve dependency between component (JS and HTML) and styles, to decrease error of forgetting to provide appropriate styles, to decrease fear of renaming CSS classes or moving them between files. 233 | 234 | #### Possible solutions 235 | 236 | - bundle styles with-in component (CSS-in-JS) 237 | - `import styles from "styles.css"` (CSS modules) 238 | 239 | #### Related 240 | - `Dead Code Elimination` 241 | 242 | ## Minification 243 | 244 | There is more than one aspect of minification. Let's explore: 245 | 246 | ### Traditional CSS minification 247 | 248 | This is the simplest approach - remove whitespace, minify color name, remove unnecessary quotes, collapse CSS rules etc. See big list of minifiers [here](https://goalsmashers.github.io/css-minification-benchmark/) 249 | 250 | ### Minification of class name 251 | 252 | In CSS modules and CSS-in-JS you do not use class names directly, instead, you use JS variables, so class names can be easily mangled. 253 | 254 | Note: This type of minification is not possible for traditional CSS. 255 | 256 | #### Example 257 | 258 | ```js 259 | import styles from "styles.css"; 260 | 261 |
262 | ``` 263 | 264 | `styles` compiles to `{ example: "hASh"}` 265 | 266 | ### Dead Code Elimination 267 | 268 | Because there is no connection between JS/HTML and CSS, you cannot be sure if it is safe to remove some parts of CSS or not. If it is stale or not? If it is used somewhere or not? 269 | 270 | `CSS-in-JS` solves this problem because of a link between JS/HTML and CSS is known, so it is easy to track if this CSS rule required or not. 271 | 272 | #### Related 273 | - `Dependencies` 274 | - `Critical CSS` 275 | 276 | ##### References 277 | 278 | - [@vjeux, 2014][@vjeux, 2014] 279 | 280 | ### Critical CSS 281 | 282 | The ability of a system to extract and inline styles in head required for current page viewed by the user not more nor less. 283 | 284 | Note: this is slightly different from the definition by `@addyosmani`, [which defines critical as above-the-fold](https://github.com/addyosmani/critical). 285 | 286 | ##### Example 287 | 288 | [aphrodite](https://github.com/Khan/aphrodite): 289 | 290 | ```js 291 | import { StyleSheet, css } from 'aphrodite' 292 | 293 | const styles = StyleSheet.create({ 294 | heading: { color: 'blue' } 295 | }) 296 | 297 | const Heading = ({ children }) => ( 298 |

299 | { children } 300 |

301 | ) 302 | ``` 303 | 304 | ```js 305 | import { StyleSheetServer } from 'aphrodite' 306 | 307 | const { html, css } = StyleSheetServer.renderStatic( 308 | () => ReactDOMServer.renderToString() 309 | ) 310 | ``` 311 | 312 | #### Related 313 | 314 | - `Dependencies` 315 | - `Dead Code Elimination` 316 | - `SSR` 317 | 318 | ##### References 319 | 320 | - [@markdalgleish, 2017][@markdalgleish, 2017] 321 | 322 | ### Automatic Atomic CSS 323 | 324 | In CSS modules and CSS-in-JS you do not use class names directly, instead, you use JS variables, so class names can be easily mangled. The same as in "Minification of class name". But we can go further - generate smaller classes and reuse them to achieve smaller CSS 325 | 326 | Note: This type of minification is not possible for traditional CSS. 327 | 328 | #### Example 329 | 330 | [styletron](https://github.com/rtsao/styletron) 331 | 332 | ```js 333 | import {injectStyle} from 'styletron-utils'; 334 | injectStyle(styletron, { 335 | color: 'red', 336 | display: 'inline-block' 337 | }); 338 | // → 'a d' 339 | injectStyle(styletron, { 340 | color: 'red', 341 | fontSize: '1.6em' 342 | }); 343 | // → 'a e' 344 | ``` 345 | 346 | #### Related 347 | 348 | - [Atomic CSS](#atomic-css) 349 | 350 | ##### References 351 | 352 | - [@markdalgleish, 2017][@markdalgleish, 2017] 353 | 354 | ## Sharing Constants, variables in CSS 355 | 356 | There are different approaches. 357 | 358 | ### Sharing variables inside CSS 359 | 360 | - [CSS variables](https://developer.mozilla.org/en-US/docs/Web/CSS/Using_CSS_variables) 361 | - [Can I use css variables](https://caniuse.com/#feat=css-variables) 362 | - CSS variables in preprocessors, like PostCSS, SASS etc. 363 | 364 | ### Sharing variables in CSS and exposing it to JS 365 | 366 | This is mainly a feature of `CSS modules` with variables. 367 | 368 | #### Example 369 | 370 | [postcss-icss-values](https://github.com/css-modules/postcss-icss-values) 371 | 372 | ```css 373 | /* colors.css */ 374 | @value primary: #BF4040; 375 | ``` 376 | 377 | Sharing variables in CSS: 378 | ```css 379 | @value primary from './colors.css'; 380 | 381 | .panel { 382 | background: primary; 383 | } 384 | ``` 385 | 386 | Exposing it to JS: 387 | 388 | ```js 389 | import { primary } from './colors.css'; 390 | // will have similar effect 391 | console.log(primary); // -> #BF4040 392 | ``` 393 | 394 | ### Passing variable from JS to CSS 395 | 396 | This is only possible with `CSS-in-JS`. This approach gives maximum flexibility and dynamics. 397 | 398 | #### Example 399 | 400 | [styling](https://github.com/andreypopp/styling) 401 | 402 | ```js 403 | import styling from 'styling' 404 | import {baseColor} from './theme' 405 | 406 | export let button = styling({ 407 | backgroundColor: baseColor 408 | }) 409 | ``` 410 | 411 | #### Related 412 | 413 | - `Overriding theme variables` 414 | 415 | ## Non-deterministic Resolution 416 | 417 | Resolution depends on the order of declarations in stylesheets (if declarations have the same specificity). 418 | 419 | ##### References 420 | 421 | - [@vjeux, 2014][@vjeux, 2014] 422 | 423 | ## Isolation 424 | 425 | Because of CSS cascading nature and Global Name Space, there is no way to isolate things. Any other part code can use more specificity or use `!important` to override your "local" styles and it is hard to prevent this situation 426 | 427 | Strictly speaking, only inline styles gives full isolation. Every other solution gives just a bit more isolation over pure CSS, because of solving Global Name Space problem. 428 | 429 | ##### References 430 | 431 | - [@vjeux, 2014][@vjeux, 2014] 432 | 433 | 434 | 435 | ## Theming 436 | 437 | The idea is to be able to change the look of existing components without the need to change actual code. 438 | 439 | ### Overriding styles 440 | 441 | This way you can override styles based on "class names" (keys of objects in case of inline styles). 442 | 443 | #### Example 444 | 445 | [react-themeable](https://github.com/markdalgleish/react-themeable) 446 | 447 | With `CSS modules`: 448 | 449 | ```js 450 | import theme from './MyComponentTheme.css'; 451 | 452 | ``` 453 | 454 | Same with inline styles: 455 | 456 | ```js 457 | const theme = { 458 | foo: { 459 | 'color': 'red' 460 | }, 461 | bar: { 462 | 'color': 'blue' 463 | } 464 | }; 465 | 466 | ``` 467 | 468 | ### Overriding theme variables 469 | 470 | This way you can override styles based on variables passed to the theme. The theme basically works like a function - accepts variables as input and produce styles as a result. 471 | 472 | #### Related 473 | - `Variables, Passing variable from JS to CSS` 474 | 475 | ## SSR, Server-Side Rendering 476 | 477 | ### HTML SSR 478 | Make sure that `CSS-in-JS` solution doesn't brake default React isomorphism e.g. you are able to generate HTML on the server, but not necessary CSS. 479 | 480 | ### CSS SSR 481 | Be able to prerender CSS on the server the same way as HTML can be prerendered for React. 482 | 483 | #### Example 484 | 485 | [aphrodite](https://github.com/Khan/aphrodite): 486 | 487 | ```js 488 | import { StyleSheet, css } from 'aphrodite' 489 | 490 | const styles = StyleSheet.create({ 491 | heading: { color: 'blue' } 492 | }) 493 | 494 | const Heading = ({ children }) => ( 495 |

496 | { children } 497 |

498 | ) 499 | ``` 500 | 501 | ```js 502 | import { StyleSheetServer } from 'aphrodite' 503 | 504 | const { html, css } = StyleSheetServer.renderStatic( 505 | () => ReactDOMServer.renderToString() 506 | ) 507 | ``` 508 | 509 | **TODO**: add example with `Inline Styles` 510 | 511 | #### Related 512 | - `Critical CSS` 513 | 514 | ## Zero runtime dependency 515 | 516 | Almost all `CSS-in-JS` solutions have runtime dependency e.g. library required to generate styles at runtime and CSS encoded as JS. 517 | 518 | Some solutions do not have this issue, they basically vanished after build step. Examples: `CSS modules`, linaria. 519 | 520 | #### Example 521 | 522 | [linaria](https://github.com/callstack/linaria) 523 | 524 | ```js 525 | import React from 'react'; 526 | import { css, styles } from 'linaria'; 527 | 528 | const title = css` 529 | text-transform: uppercase; 530 | `; 531 | 532 | export function App() { 533 | return
; 534 | } 535 | ``` 536 | 537 | Transpiled to: 538 | 539 | ```css 540 | .title__jt5ry4 { 541 | text-transform: uppercase; 542 | } 543 | ``` 544 | 545 | ```js 546 | import React from 'react'; 547 | import { styles } from 'linaria/build/index.runtime'; 548 | 549 | const title = 'title__jt5ry4'; 550 | 551 | export function App() { 552 | return
; 553 | } 554 | ``` 555 | 556 | ## CSS-in-JS implementation specific features 557 | 558 | ### Non-DOM targets 559 | 560 | React can target different platforms, not just DOM. It would be nice to have `CSS-in-JS` solution which supports different platforms too. For example: [React Native](https://facebook.github.io/react-native/), [Sketch](https://github.com/airbnb/react-sketchapp). 561 | 562 | ### CSS as object (object literal) 563 | 564 | ```js 565 | const color = "red" 566 | const style = { 567 | color: 'red', 568 | } 569 | ``` 570 | 571 | ### CSS as template literal 572 | 573 | ```js 574 | const color = "red" 575 | const style = ` 576 | color: ${color}; 577 | ` 578 | ``` 579 | 580 | ### Framework agnostic 581 | 582 | Does it depend on React or not? 583 | 584 | ### Build step 585 | 586 | If build step required or not? 587 | 588 | #### Related 589 | 590 | - `SSR` 591 | - `Progressive enhancement` 592 | - `Dynamic` 593 | 594 | ### Dynamic 595 | 596 | If you can pass values to CSS at runtime. 597 | 598 | Note: it is not the same as `Variables, Passing variable from JS to CSS`, for example in [linaria](https://github.com/callstack/linaria) you can pass variables from JS to CSS, but only at build time. 599 | 600 | Note 2: cannot stop myself from drawing analogy between static and dynamic type systems. 601 | 602 | #### Related 603 | 604 | - `Build step` 605 | - `Variables, Passing variable from JS to CSS` 606 | 607 | ### Generate components based on CSS 608 | 609 | If your component has pretty simple structure and you care more about how it looks instead of markup (which most likely will be `div` anyway). You can go straight to write CSS and library will generate components for you. 610 | 611 | #### Examples 612 | 613 | [decss](https://github.com/kossnocorp/decss) 614 | 615 | ```js 616 | import React from 'react' 617 | import { Button } from './style.css' 618 | 619 | 622 | ``` 623 | 624 | [styled-components](https://github.com/styled-components/styled-components) 625 | 626 | ```js 627 | import React from 'react' 628 | import styled from 'styled' 629 | 630 | const Button = styled.button` 631 | background-color: red; 632 | `; 633 | 634 | 637 | ``` 638 | 639 | ### Developer tools integration 640 | 641 | If there are special perks for developer tools? 642 | 643 | #### Example 644 | 645 | [emotion](https://emotion.sh/) supports source maps for styles authored in javascript 646 | 647 | [GIF of source maps in action](images/emotion-source-maps.gif) 648 | 649 | ## Progressive enhancement, graceful degradation 650 | 651 | If you do not know what is it read this [article](https://www.shopify.com/partners/blog/what-is-progressive-enhancement-and-why-should-you-care). 652 | 653 | In the context of `CSS-in-JS` it boils down to one question - will your website be styled with disabled JS. 654 | 655 | The first requirement would be to have some HTML rendered on the server (SSR or [snapshoting](https://github.com/stereobooster/react-snap)). After this you have two options: 656 | 657 | - prebuild CSS e.g. `Build step` required 658 | - rendered CSS e.g. `CSS SSR` required 659 | 660 | #### Related 661 | 662 | - `SSR` 663 | - `Build step` 664 | 665 | ## Uncovered subjects 666 | 667 | ### Security 668 | 669 | See [this post](https://reactarmory.com/answers/how-can-i-use-css-in-js-securely) 670 | 671 | ### Async components 672 | 673 | Also known as `code splitting`, `dynamic import` 674 | 675 | Async component is a technique (typically implemented as a higher order component) for loading components with `dynamic import`. There are a lot of solutions in this field here are some examples: 676 | 677 | - [`loadable-components`](https://github.com/smooth-code/loadable-components) 678 | - [`react-loadable`](https://github.com/thejameskyle/react-loadable) 679 | - [`react-async-component`](https://github.com/ctrlplusb/react-async-component) 680 | - [`react-code-splitting`](https://github.com/didierfranc/react-code-splitting) 681 | 682 | #### References 683 | 684 | - [Dynamic import](https://github.com/tc39/proposal-dynamic-import) is the TC39 proposal. 685 | 686 | > Webpack has a feature to split your codebase into “chunks” which are loaded on demand. Some other bundlers call them “layers”, “rollups”, or “fragments”. This feature is called “code splitting”. 687 | > 688 | > — [Code splitting](https://webpack.github.io/docs/code-splitting.html) 689 | 690 | ### CSS-in-JS and Async components 691 | 692 | This works for most `CSS-in-JS` solutions because CSS is bundled inside JS. This is a more complicated task for CSS modules. See: [Guide To JavaScript Async Components](https://github.com/stereobooster/guide-to-async-components). 693 | 694 | ### Atomic CSS 695 | 696 | Also known as `immutable`, `functional`, `utility-class`. 697 | 698 | Idea boils down to use one property per class, so you create required look by composing more than one class. Because each class contains only one property, you do not override those properties and this can be interpreted as immutability. 699 | 700 | Do not confuse with [Atomic CSS](https://acss.io/) framework. 701 | 702 | #### References 703 | 704 | - [Functional CSS - The Good, The Bad, and Some Protips for React.js Users](https://github.com/chibicode/react-functional-css-protips#sunglasses-act-i-what-is-functional-css-and-why-would-i-want-to-use-it-sunglasses) 705 | - [immutable-css](https://github.com/johnotander/immutable-css) 706 | 707 | ### Animations 708 | 709 | #### Sequential 710 | 711 | Basically CSS3 animations. Pros: can be GPU accelerated. 712 | 713 | #### Interruptible 714 | 715 | Also known as `interactive`. 716 | 717 | Basically JS animations. Pros: can be interrupted. 718 | 719 | #### References 720 | 721 | - [Building Interruptible and Responsive Interactions](https://developer.apple.com/videos/play/wwdc2014/236/) 722 | 723 | --- 724 | 725 | [@vjeux, 2014]: http://blog.vjeux.com/2014/javascript/react-css-in-js-nationjs.html 726 | [@markdalgleish, 2015]: https://www.youtube.com/watch?v=zR1lOuyQEt8 727 | [@mxstbr, 2016]: https://www.youtube.com/watch?v=19gqsBc_Cx0 728 | [@markdalgleish, 2017]: https://www.youtube.com/watch?v=X_uTCnaRe94 729 | -------------------------------------------------------------------------------- /images/css-in-js.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stereobooster/css-in-js-101/e7e50cf29488edaeb4577840d3104cf702428aae/images/css-in-js.png -------------------------------------------------------------------------------- /images/emotion-source-maps.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stereobooster/css-in-js-101/e7e50cf29488edaeb4577840d3104cf702428aae/images/emotion-source-maps.gif -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "css-in-js-101", 3 | "version": "1.0.0", 4 | "main": "index.js", 5 | "repository": "https://github.com/stereobooster/css-in-js-101.git", 6 | "author": "stereobooster ", 7 | "license": "MIT", 8 | "dependencies": {}, 9 | "devDependencies": { 10 | "markdown-toc": "^1.2.0" 11 | }, 12 | "scripts": { 13 | "toc": "yarn run markdown-toc -i --maxdepth 3 README.md" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /talks.md: -------------------------------------------------------------------------------- 1 | # CSS in JS: talks 2 | 3 | Disclaimer: information on this page can be a bit outdated. See [Readme](README.md) for latest vision. 4 | 5 | ## CSS in JS by Christopher Chedeau (@vjeux), 2014 6 | 7 | [presentation](https://speakerdeck.com/vjeux/react-css-in-js), [video](http://blog.vjeux.com/2014/javascript/react-css-in-js-nationjs.html) 8 | 9 | ### 1. Global Name Space 10 | 11 | All declarations in CSS are global. 12 | 13 | **Example**: you declared `.button` in `a.css` other developer declared `.button` in `b.css`. You both have no idea you used the same name until you will get a bug. 14 | 15 | **CSS solution**: naming convention, like BEM. 16 | 17 | ### 2. Dependencies 18 | 19 | No connection between HTML/JS and CSS. 20 | 21 | **Example**: you used `
`, but forgot to load css file where it is declared. 22 | 23 | **CSS solution**: webpack's `require("a.css")` (kind of). 24 | 25 | ### 3. Dead Code Elimination 26 | 27 | Other consequences of "no connection between HTML/JS and CSS". 28 | 29 | **Example**: in your code, you use `
`, but in styles, you loaded much more classes and/or keyframes 30 | 31 | **CSS solution**: you can use something like critical, but it is hard. 32 | 33 | ### 4. Minification 34 | 35 | @vjeux talks about minification of class names. Obviously, there are a lot of general [CSS minifiers](https://goalsmashers.github.io/css-minification-benchmark/), but none of those can minify class names. 36 | 37 | **Note**: in the end, @vjeux suggests to use inline styles, so there are no class names anymore, and this point doesn't make sense `¯\_(ツ)_/¯`. 38 | 39 | **CSS solution**: none 40 | 41 | ### 5. Sharing Constants 42 | 43 | The point is that you can share variables between CSS in JS. 44 | 45 | **Example**: breakpoints or duration of animations. 46 | 47 | **CSS solution**: closest options are SASS, CSS variables, CSS preprocessor. 48 | 49 | ### 6. Non-deterministic Resolution 50 | 51 | Resolution depends on the order of declarations in stylesheets (if declarations have the same specificity). 52 | 53 | **Example**: you declared `.button` in `a.css` other developer declared `.button` in `b.css`. Depending on order of inclusion of files `.button` can be resolved to `a.css` or to `b.css`. 54 | 55 | **CSS solution**: increase specificity (which will increase fragility and decrease portability). 56 | 57 | ### 7. Isolation 58 | 59 | Because of CSS cascading nature and Global Name Space, there is no way to isolate things. 60 | 61 | **Example**: you declared class `.button`, but other developer declared CSS for `div`. 62 | 63 | 64 | 65 | ### Prposed solution: inline styles 66 | 67 | React: 68 | 69 | ```js 70 |
71 | ``` 72 | 73 | Generated HTML: 74 | 75 | ```html 76 |
77 | ``` 78 | 79 | **Downsides**: 80 | 1. Code duplication in case of SSR - imagine you have inline style for a repetitive element. 81 | 2. Additional costs in JS payload. Remember that styles which are embedded in JS are not for free. It is not only about download time, it is also about parsing and compiling. See [this detailed explanation by Addy Osmani, why JS is expensive](https://medium.com/dev-channel/the-cost-of-javascript-84009f51e99e) 82 | 3. No media queries 83 | 4. No CSS animations 84 | 5. No pseudo classes 85 | 6. No autoprefixer 86 | 7. No standard CSS minifiers 87 | 88 | ## The case for CSS modules by Mark Dalgleish (@markdalgleish), 2015 89 | 90 | [video](https://www.youtube.com/watch?v=zR1lOuyQEt8), [presentation](https://github.com/markdalgleish/presentation-the-case-for-css-modules/blob/master/src/index.jade) 91 | 92 | ### proposed solution: [CSS modules](https://github.com/css-modules/css-modules) 93 | 94 | **Editor note**: if you treat CSS-in-JS as an umbrella term than CSS modules fails into this category too. 95 | 96 | Please read the specification, but basic idea is to have local CSS declarations by default and expose them as JS module, which is basically a hash which maps local CSS values to globally unique values. 97 | 98 | Solves: 99 | 100 | 1. Global Name Space 101 | 2. Dependencies. With `import "a.css"` you will not forget to load your CSS file. Even more you can check if actual classes are declared in CSS file with [TypeScript](https://github.com/Quramy/typed-css-modules) or [Flow](https://github.com/skovhus/css-modules-flow-types). 102 | 3. Dead Code Elimination. **Not quite** - see section below. 103 | 4. Minification 104 | 5. Sharing Constants. Yes with variables 105 | 6. Non-deterministic Resolution. **No** - possible solution is to use linter 106 | 7. Isolation. **Yes and no**. You still can get yourself into troubles with `:global`, but this is antipattern 107 | 108 | And also: 109 | 110 | 1. No Code duplication in case of SSR 111 | 2. No Additional costs in JS payload, except objects with class names, like `import style from "a.css"`, where `style == {'a': ''}` 112 | 3. Media queries 113 | 4. CSS animations 114 | 5. Pseudo-classes 115 | 6. Autoprefixer 116 | 7. Standard CSS minifiers 117 | 118 | ### Dead Code Elimination 119 | 120 | Lets define some terminology: 121 | 122 | **Critical CSS** - critical-path (above-the-fold) CSS (according to **@addyosmani**) 123 | 124 | **Critical CSS** - CSS required to generate current page e.g. all components on the page (according to **@markdalgleish**). 125 | 126 | **Dead Code Elimination** - remove stale code not used anywhere in the project, still serving more than required per current page (according to **@vjuex**, based on screenshots). **Note**: he showed this in screenshots, but proposed solution (e.g. inline styles) is actually in the realm of Critical CSS `¯\_(ツ)_/¯`. 127 | 128 | Ordered by size (`>` stands for "is more than"): 129 | 130 | ``` 131 | CSS after Dead Code Elimination > Critical CSS according to @markdalgleish > Critical CSS according to @addyosmani 132 | ``` 133 | 134 | **Note** in further discussion I will stick to the definition of Critical CSS according to @markdalgleish. 135 | 136 | It is (almost) possible to do Dead Code Elimination in CSS modules. See [webpack-contrib/css-loader#506](https://github.com/webpack-contrib/css-loader/issues/506), [dead-css-loader](https://github.com/simlrh/dead-css-loader). 137 | 138 | To do Critical CSS, we need some solution to track what actually is required to render the current page at runtime. It could look something like this: 139 | 140 | ```js 141 | import { criticalTracker } from 'criticalModules' 142 | import { a, b } from "a.css"; 143 | 144 | // it should track styles on server, 145 | // but can be no-op at the client 146 | criticalTracker({ a, b }, "a.css"); 147 | 148 | const Heading = ({ children }) => ( 149 |

150 | { children } 151 |

152 | ) 153 | ``` 154 | 155 | And SSR will look like: 156 | 157 | ```js 158 | import { StyleSheetServer } from 'criticalModules' 159 | 160 | const { html, css } = StyleSheetServer.renderStatic( 161 | () => ReactDOMServer.renderToString() 162 | ) 163 | ``` 164 | 165 | **Related**: [CSS modulues in c-r-a](https://github.com/facebookincubator/create-react-app/pull/2285), [comment by @sokra](https://github.com/webpack-contrib/style-loader/pull/159#issuecomment-286729044) 166 | 167 | ### Theming 168 | 169 | #### Overriding styles 170 | 171 | Proposed solution: [react-themeable](https://github.com/markdalgleish/react-themeable) 172 | 173 | With CSS modules: 174 | 175 | ```js 176 | import theme from './MyComponentTheme.css'; 177 | 178 | ``` 179 | 180 | Same with inline styles: 181 | 182 | ```js 183 | const theme = { 184 | foo: { 185 | 'color': 'red' 186 | }, 187 | bar: { 188 | 'color': 'blue' 189 | } 190 | }; 191 | 192 | ``` 193 | 194 | #### Overriding theme variables 195 | 196 | For this you need CSS-in-JS. 197 | 198 | ## Styling React.JS applications by Max Stoiber (@mxstbr), 2016 199 | 200 | [video](https://www.youtube.com/watch?v=19gqsBc_Cx0), [code](https://github.com/styled-components/comparison) 201 | 202 | ### Inline styles vs CSS-in-JS 203 | @mxstbr differentiate `Inline styles` and `CSS-in-JS`. By `inline styles` he means React built-in support for style property and by `CSS-in-JS` he means a solution which generates CSS and injects via style tag. On the other hand, `CSS-in-JS` is the term coined by @vjeux in 2014 and he meant `Inline styles`. But there is Radium which also uses inline styles. Also sometimes people tend to use `CSS-in-JS` as an umbrella term and CSS modules fell into this category too `¯\_(ツ)_/¯` 204 | 205 | So I would suggest to use CSS-in-JS as an umbrella term and specify technique behind the implementation, like inline styles, style element, mixed (like Radium). 206 | 207 | ### No build requirements 208 | The title is pretty self-explanatory. You still need build step for JSX though. 209 | 210 | ### Small and lightweight 211 | This is a pretty hand-wavy category. @mxstbr never defines how much is a small size. 212 | 213 | Note: it doesn't make sense to measure gzipped KB of download - because this doesn't account the cost of JS parsing and compiling. See [this post by @addyosmani for details](https://medium.com/dev-channel/the-cost-of-javascript-84009f51e99e) 214 | 215 | Note: in the end, he will remove this column from comparison anyway `¯\_(ツ)_/¯` 216 | 217 | ### Supports global CSS 218 | @mxstbr mentions `@font-face`. I suppose all HTML elements and `@keyframes` fall into this category. 219 | 220 | Also, `@media` queries fall into this category. Important is to distinguish between real CSS and JS simulated `@media` queries. Second can't be prerendered as CSS at a server. 221 | 222 | ### Supports entirety of CSS 223 | @mxstbr mentions `:hover`, `:focus` (pseudo-classes). Important is to distinguish between real CSS and JS simulated pseudo-classes. Second can't be prerendered as CSS at a server. And not all of the pseudo-classes is easy to simulate with JS. 224 | 225 | ### Colocoted 226 | @mxstbr didn't explicitly explained it, but I suppose this is the same approach as BEM - CSS lives near the corresponding JS file. 227 | 228 | ### Isolated 229 | See "Isolation" according to @vjeux 230 | 231 | ### Easy to override 232 | Not sure what that suppose to mean. 233 | 234 | ### Theming 235 | I suppose @mxstbr keep in mind "Overriding theme variables" as explained by `@markdalgleish` 236 | 237 | ### SSR 238 | This requirement can mean two things: 239 | 240 | First. Be able to run React in server environment e.g. do not use `window` or any other browser specific APIs for injecting CSS. 241 | 242 | Second. Be able to prerender CSS on the server the same way as HTML can be prerendered for React (example Aphrodite). 243 | If you will prerender HTML, but not prerender CSS, you basically lose performance boost which you can have from prerendering HTML. But there is still a benefit for crawlers who cares mainly about HTML and not CSS. 244 | 245 | ### No wrapper components 246 | @mxstbr complains that it is kind of clumsy - you need to place wrappers everywhere and you need to remember the exact syntax. 247 | 248 | ## A Unified Styling Language by Mark Dalgleish (@markdalgleish), 2017 249 | 250 | [presentation](https://markdalgleish.github.io/presentation-a-unified-styling-language/), [video](https://www.youtube.com/watch?v=X_uTCnaRe94), [blog](https://medium.com/seek-blog/a-unified-styling-language-d0c208de2660) 251 | 252 | ### Real CSS 253 | 254 | When the library doesn't do inline styles - they generate real CSS. It means you can use pseudo-classes and media queries. 255 | 256 | Example (JSS): 257 | 258 | ```js 259 | const styles = { 260 | button: { 261 | padding: '10px', 262 | '&:hover': { 263 | background: 'blue' 264 | } 265 | }, 266 | '@media (min-width: 1024px)': { 267 | button: { 268 | padding: '20px' 269 | } 270 | } 271 | } 272 | ``` 273 | 274 | ### Critical CSS 275 | 276 | **Critical CSS** - CSS required to generate current page e.g. all components on the page 277 | 278 | Example (Aphrodite): 279 | 280 | ```js 281 | import { StyleSheet, css } from 'aphrodite' 282 | 283 | const styles = StyleSheet.create({ 284 | heading: { color: 'blue' } 285 | }) 286 | 287 | const Heading = ({ children }) => ( 288 |

289 | { children } 290 |

291 | ) 292 | ``` 293 | 294 | ```js 295 | import { StyleSheetServer } from 'aphrodite' 296 | 297 | const { html, css } = StyleSheetServer.renderStatic( 298 | () => ReactDOMServer.renderToString() 299 | ) 300 | ``` 301 | 302 | ### Atomic CSS 303 | 304 | A technique to minify CSS even more by extracting repeating parts into small (atomic) classes. 305 | 306 | Example: Styletron 307 | 308 | see [this slide](https://markdalgleish.github.io/presentation-a-unified-styling-language/#79) 309 | 310 | ### Functions in CSS 311 | 312 | Example: Polished 313 | 314 | ### Non DOM targets 315 | 316 | Exapmle: ReactNative 317 | 318 | -------------------------------------------------------------------------------- /yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | ansi-red@^0.1.1: 6 | version "0.1.1" 7 | resolved "https://registry.yarnpkg.com/ansi-red/-/ansi-red-0.1.1.tgz#8c638f9d1080800a353c9c28c8a81ca4705d946c" 8 | dependencies: 9 | ansi-wrap "0.1.0" 10 | 11 | ansi-wrap@0.1.0: 12 | version "0.1.0" 13 | resolved "https://registry.yarnpkg.com/ansi-wrap/-/ansi-wrap-0.1.0.tgz#a82250ddb0015e9a27ca82e82ea603bbfa45efaf" 14 | 15 | argparse@^1.0.7: 16 | version "1.0.9" 17 | resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.9.tgz#73d83bc263f86e97f8cc4f6bae1b0e90a7d22c86" 18 | dependencies: 19 | sprintf-js "~1.0.2" 20 | 21 | argparse@~0.1.15: 22 | version "0.1.16" 23 | resolved "https://registry.yarnpkg.com/argparse/-/argparse-0.1.16.tgz#cfd01e0fbba3d6caed049fbd758d40f65196f57c" 24 | dependencies: 25 | underscore "~1.7.0" 26 | underscore.string "~2.4.0" 27 | 28 | autolinker@~0.15.0: 29 | version "0.15.3" 30 | resolved "https://registry.yarnpkg.com/autolinker/-/autolinker-0.15.3.tgz#342417d8f2f3461b14cf09088d5edf8791dc9832" 31 | 32 | coffee-script@^1.12.4: 33 | version "1.12.7" 34 | resolved "https://registry.yarnpkg.com/coffee-script/-/coffee-script-1.12.7.tgz#c05dae0cb79591d05b3070a8433a98c9a89ccc53" 35 | 36 | concat-stream@^1.5.2: 37 | version "1.6.0" 38 | resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.0.tgz#0aac662fd52be78964d5532f694784e70110acf7" 39 | dependencies: 40 | inherits "^2.0.3" 41 | readable-stream "^2.2.2" 42 | typedarray "^0.0.6" 43 | 44 | core-util-is@~1.0.0: 45 | version "1.0.2" 46 | resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" 47 | 48 | diacritics-map@^0.1.0: 49 | version "0.1.0" 50 | resolved "https://registry.yarnpkg.com/diacritics-map/-/diacritics-map-0.1.0.tgz#6dfc0ff9d01000a2edf2865371cac316e94977af" 51 | 52 | esprima@^4.0.0: 53 | version "4.0.0" 54 | resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.0.tgz#4499eddcd1110e0b218bacf2fa7f7f59f55ca804" 55 | 56 | expand-range@^1.8.1: 57 | version "1.8.2" 58 | resolved "https://registry.yarnpkg.com/expand-range/-/expand-range-1.8.2.tgz#a299effd335fe2721ebae8e257ec79644fc85337" 59 | dependencies: 60 | fill-range "^2.1.0" 61 | 62 | extend-shallow@^2.0.1: 63 | version "2.0.1" 64 | resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-2.0.1.tgz#51af7d614ad9a9f610ea1bafbb989d6b1c56890f" 65 | dependencies: 66 | is-extendable "^0.1.0" 67 | 68 | fill-range@^2.1.0: 69 | version "2.2.3" 70 | resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-2.2.3.tgz#50b77dfd7e469bc7492470963699fe7a8485a723" 71 | dependencies: 72 | is-number "^2.1.0" 73 | isobject "^2.0.0" 74 | randomatic "^1.1.3" 75 | repeat-element "^1.1.2" 76 | repeat-string "^1.5.2" 77 | 78 | for-in@^1.0.2: 79 | version "1.0.2" 80 | resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80" 81 | 82 | gray-matter@^2.1.0: 83 | version "2.1.1" 84 | resolved "https://registry.yarnpkg.com/gray-matter/-/gray-matter-2.1.1.tgz#3042d9adec2a1ded6a7707a9ed2380f8a17a430e" 85 | dependencies: 86 | ansi-red "^0.1.1" 87 | coffee-script "^1.12.4" 88 | extend-shallow "^2.0.1" 89 | js-yaml "^3.8.1" 90 | toml "^2.3.2" 91 | 92 | inherits@^2.0.3, inherits@~2.0.3: 93 | version "2.0.3" 94 | resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" 95 | 96 | is-buffer@^1.1.5: 97 | version "1.1.6" 98 | resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" 99 | 100 | is-extendable@^0.1.0, is-extendable@^0.1.1: 101 | version "0.1.1" 102 | resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89" 103 | 104 | is-number@^2.1.0: 105 | version "2.1.0" 106 | resolved "https://registry.yarnpkg.com/is-number/-/is-number-2.1.0.tgz#01fcbbb393463a548f2f466cce16dece49db908f" 107 | dependencies: 108 | kind-of "^3.0.2" 109 | 110 | is-number@^3.0.0: 111 | version "3.0.0" 112 | resolved "https://registry.yarnpkg.com/is-number/-/is-number-3.0.0.tgz#24fd6201a4782cf50561c810276afc7d12d71195" 113 | dependencies: 114 | kind-of "^3.0.2" 115 | 116 | isarray@1.0.0, isarray@~1.0.0: 117 | version "1.0.0" 118 | resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" 119 | 120 | isobject@^2.0.0: 121 | version "2.1.0" 122 | resolved "https://registry.yarnpkg.com/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89" 123 | dependencies: 124 | isarray "1.0.0" 125 | 126 | isobject@^3.0.1: 127 | version "3.0.1" 128 | resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df" 129 | 130 | js-yaml@^3.8.1: 131 | version "3.10.0" 132 | resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.10.0.tgz#2e78441646bd4682e963f22b6e92823c309c62dc" 133 | dependencies: 134 | argparse "^1.0.7" 135 | esprima "^4.0.0" 136 | 137 | kind-of@^3.0.2: 138 | version "3.2.2" 139 | resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64" 140 | dependencies: 141 | is-buffer "^1.1.5" 142 | 143 | kind-of@^4.0.0: 144 | version "4.0.0" 145 | resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-4.0.0.tgz#20813df3d712928b207378691a45066fae72dd57" 146 | dependencies: 147 | is-buffer "^1.1.5" 148 | 149 | lazy-cache@^2.0.2: 150 | version "2.0.2" 151 | resolved "https://registry.yarnpkg.com/lazy-cache/-/lazy-cache-2.0.2.tgz#b9190a4f913354694840859f8a8f7084d8822264" 152 | dependencies: 153 | set-getter "^0.1.0" 154 | 155 | list-item@^1.1.1: 156 | version "1.1.1" 157 | resolved "https://registry.yarnpkg.com/list-item/-/list-item-1.1.1.tgz#0c65d00e287cb663ccb3cb3849a77e89ec268a56" 158 | dependencies: 159 | expand-range "^1.8.1" 160 | extend-shallow "^2.0.1" 161 | is-number "^2.1.0" 162 | repeat-string "^1.5.2" 163 | 164 | markdown-link@^0.1.1: 165 | version "0.1.1" 166 | resolved "https://registry.yarnpkg.com/markdown-link/-/markdown-link-0.1.1.tgz#32c5c65199a6457316322d1e4229d13407c8c7cf" 167 | 168 | markdown-toc@^1.2.0: 169 | version "1.2.0" 170 | resolved "https://registry.yarnpkg.com/markdown-toc/-/markdown-toc-1.2.0.tgz#44a15606844490314afc0444483f9e7b1122c339" 171 | dependencies: 172 | concat-stream "^1.5.2" 173 | diacritics-map "^0.1.0" 174 | gray-matter "^2.1.0" 175 | lazy-cache "^2.0.2" 176 | list-item "^1.1.1" 177 | markdown-link "^0.1.1" 178 | minimist "^1.2.0" 179 | mixin-deep "^1.1.3" 180 | object.pick "^1.2.0" 181 | remarkable "^1.7.1" 182 | repeat-string "^1.6.1" 183 | strip-color "^0.1.0" 184 | 185 | minimist@^1.2.0: 186 | version "1.2.0" 187 | resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284" 188 | 189 | mixin-deep@^1.1.3: 190 | version "1.2.0" 191 | resolved "https://registry.yarnpkg.com/mixin-deep/-/mixin-deep-1.2.0.tgz#d02b8c6f8b6d4b8f5982d3fd009c4919851c3fe2" 192 | dependencies: 193 | for-in "^1.0.2" 194 | is-extendable "^0.1.1" 195 | 196 | object.pick@^1.2.0: 197 | version "1.3.0" 198 | resolved "https://registry.yarnpkg.com/object.pick/-/object.pick-1.3.0.tgz#87a10ac4c1694bd2e1cbf53591a66141fb5dd747" 199 | dependencies: 200 | isobject "^3.0.1" 201 | 202 | process-nextick-args@~1.0.6: 203 | version "1.0.7" 204 | resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-1.0.7.tgz#150e20b756590ad3f91093f25a4f2ad8bff30ba3" 205 | 206 | randomatic@^1.1.3: 207 | version "1.1.7" 208 | resolved "https://registry.yarnpkg.com/randomatic/-/randomatic-1.1.7.tgz#c7abe9cc8b87c0baa876b19fde83fd464797e38c" 209 | dependencies: 210 | is-number "^3.0.0" 211 | kind-of "^4.0.0" 212 | 213 | readable-stream@^2.2.2: 214 | version "2.3.3" 215 | resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.3.tgz#368f2512d79f9d46fdfc71349ae7878bbc1eb95c" 216 | dependencies: 217 | core-util-is "~1.0.0" 218 | inherits "~2.0.3" 219 | isarray "~1.0.0" 220 | process-nextick-args "~1.0.6" 221 | safe-buffer "~5.1.1" 222 | string_decoder "~1.0.3" 223 | util-deprecate "~1.0.1" 224 | 225 | remarkable@^1.7.1: 226 | version "1.7.1" 227 | resolved "https://registry.yarnpkg.com/remarkable/-/remarkable-1.7.1.tgz#aaca4972100b66a642a63a1021ca4bac1be3bff6" 228 | dependencies: 229 | argparse "~0.1.15" 230 | autolinker "~0.15.0" 231 | 232 | repeat-element@^1.1.2: 233 | version "1.1.2" 234 | resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.2.tgz#ef089a178d1483baae4d93eb98b4f9e4e11d990a" 235 | 236 | repeat-string@^1.5.2, repeat-string@^1.6.1: 237 | version "1.6.1" 238 | resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" 239 | 240 | safe-buffer@~5.1.0, safe-buffer@~5.1.1: 241 | version "5.1.1" 242 | resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.1.tgz#893312af69b2123def71f57889001671eeb2c853" 243 | 244 | set-getter@^0.1.0: 245 | version "0.1.0" 246 | resolved "https://registry.yarnpkg.com/set-getter/-/set-getter-0.1.0.tgz#d769c182c9d5a51f409145f2fba82e5e86e80376" 247 | dependencies: 248 | to-object-path "^0.3.0" 249 | 250 | sprintf-js@~1.0.2: 251 | version "1.0.3" 252 | resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" 253 | 254 | string_decoder@~1.0.3: 255 | version "1.0.3" 256 | resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.0.3.tgz#0fc67d7c141825de94282dd536bec6b9bce860ab" 257 | dependencies: 258 | safe-buffer "~5.1.0" 259 | 260 | strip-color@^0.1.0: 261 | version "0.1.0" 262 | resolved "https://registry.yarnpkg.com/strip-color/-/strip-color-0.1.0.tgz#106f65d3d3e6a2d9401cac0eb0ce8b8a702b4f7b" 263 | 264 | to-object-path@^0.3.0: 265 | version "0.3.0" 266 | resolved "https://registry.yarnpkg.com/to-object-path/-/to-object-path-0.3.0.tgz#297588b7b0e7e0ac08e04e672f85c1f4999e17af" 267 | dependencies: 268 | kind-of "^3.0.2" 269 | 270 | toml@^2.3.2: 271 | version "2.3.3" 272 | resolved "https://registry.yarnpkg.com/toml/-/toml-2.3.3.tgz#8d683d729577cb286231dfc7a8affe58d31728fb" 273 | 274 | typedarray@^0.0.6: 275 | version "0.0.6" 276 | resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" 277 | 278 | underscore.string@~2.4.0: 279 | version "2.4.0" 280 | resolved "https://registry.yarnpkg.com/underscore.string/-/underscore.string-2.4.0.tgz#8cdd8fbac4e2d2ea1e7e2e8097c42f442280f85b" 281 | 282 | underscore@~1.7.0: 283 | version "1.7.0" 284 | resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.7.0.tgz#6bbaf0877500d36be34ecaa584e0db9fef035209" 285 | 286 | util-deprecate@~1.0.1: 287 | version "1.0.2" 288 | resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" 289 | --------------------------------------------------------------------------------