From 1957b95be4f4cb220939ea3febcde150c16532eb Mon Sep 17 00:00:00 2001 From: mitchellhamilton Date: Mon, 16 Jul 2018 22:26:05 +1000 Subject: [PATCH 01/32] Update benchmarks from rnw --- scripts/benchmarks/README.md | 71 ++++- scripts/benchmarks/benchmark.js | 98 ------ scripts/benchmarks/createRenderBenchmark.js | 30 -- scripts/benchmarks/index.html | 9 +- scripts/benchmarks/index.js | 71 ----- scripts/benchmarks/package.json | 63 ++-- scripts/benchmarks/run-headless.js | 61 ---- scripts/benchmarks/send-results.js | 38 --- scripts/benchmarks/src/app/App.js | 297 ++++++++++++++++++ scripts/benchmarks/src/app/Benchmark/index.js | 253 +++++++++++++++ scripts/benchmarks/src/app/Benchmark/math.js | 27 ++ .../benchmarks/src/app/Benchmark/timing.js | 18 ++ scripts/benchmarks/src/app/Benchmark/types.js | 31 ++ scripts/benchmarks/src/app/Button.js | 71 +++++ scripts/benchmarks/src/app/Icons.js | 55 ++++ scripts/benchmarks/src/app/Layout.js | 68 ++++ scripts/benchmarks/src/app/ReportCard.js | 83 +++++ scripts/benchmarks/src/app/Text.js | 30 ++ scripts/benchmarks/src/app/theme.js | 101 ++++++ .../src/cases/SierpinskiTriangle.js | 90 ++++++ scripts/benchmarks/src/cases/Tree.js | 45 +++ .../src/components/Box/css-modules.js | 24 -- .../src/components/Box/emotion-obj.js | 31 -- .../benchmarks/src/components/Box/emotion.js | 31 -- .../src/components/Box/glamorous.js | 31 -- .../src/components/Box/styled-components.js | 31 -- .../benchmarks/src/components/Box/styles.css | 36 --- .../benchmarks/src/components/Dot/emotion.js | 17 - .../benchmarks/src/components/Dot/glamor.js | 23 -- .../benchmarks/src/components/NestedTree.js | 38 --- .../src/components/SierpinskiTriangle.js | 73 ----- .../src/components/View/css-modules.js | 15 - .../src/components/View/emotion-obj.js | 20 -- .../benchmarks/src/components/View/emotion.js | 19 -- .../src/components/View/glamorous.js | 20 -- .../src/components/Wrapper/emotion.js | 14 - .../src/components/Wrapper/glamor.js | 15 - scripts/benchmarks/src/css-modules.js | 9 - scripts/benchmarks/src/emotion-css.js | 7 - scripts/benchmarks/src/emotion-obj.js | 7 - scripts/benchmarks/src/emotion.js | 11 - scripts/benchmarks/src/glamor.js | 11 - scripts/benchmarks/src/glamorous.js | 7 - scripts/benchmarks/src/impl.js | 37 +++ .../src/implementations/aphrodite/Box.js | 50 +++ .../src/implementations/aphrodite/Provider.js | 2 + .../src/implementations/aphrodite/View.js | 31 ++ .../src/implementations/aphrodite/index.js | 9 + .../src/implementations/css-modules/Box.js | 18 ++ .../implementations/css-modules/Provider.js | 2 + .../src/implementations/css-modules/View.js | 13 + .../css-modules/box-styles.css | 37 +++ .../src/implementations/css-modules/index.js | 9 + .../css-modules/view-styles.css} | 0 .../emotion/Box.js} | 35 +-- .../src/implementations/emotion/Dot.js | 33 ++ .../src/implementations/emotion/Provider.js | 2 + .../emotion/View.js} | 12 +- .../src/implementations/emotion/index.js | 11 + .../glamor/Box.js} | 35 +-- .../src/implementations/glamor/Dot.js | 33 ++ .../src/implementations/glamor/Provider.js | 2 + .../glamor/View.js} | 12 +- .../src/implementations/glamor/index.js | 11 + .../src/implementations/inline-styles/Box.js | 49 +++ .../src/implementations/inline-styles/Dot.js | 35 +++ .../implementations/inline-styles/Provider.js | 2 + .../src/implementations/inline-styles/View.js | 36 +++ .../implementations/inline-styles/index.js | 11 + .../src/implementations/radium/Box.js | 50 +++ .../src/implementations/radium/Dot.js | 36 +++ .../src/implementations/radium/Provider.js | 2 + .../src/implementations/radium/View.js | 31 ++ .../src/implementations/radium/index.js | 11 + .../src/implementations/react-fela/Box.js | 46 +++ .../src/implementations/react-fela/Dot.js | 28 ++ .../implementations/react-fela/Provider.js | 19 ++ .../src/implementations/react-fela/View.js | 24 ++ .../src/implementations/react-fela/index.js | 11 + .../src/implementations/react-jss/Box.js | 51 +++ .../src/implementations/react-jss/Dot.js | 26 ++ .../src/implementations/react-jss/Provider.js | 2 + .../src/implementations/react-jss/View.js | 32 ++ .../src/implementations/react-jss/index.js | 11 + .../implementations/react-native-web/Box.js | 49 +++ .../implementations/react-native-web/Dot.js | 33 ++ .../react-native-web/Provider.js | 2 + .../react-native-web/Tweet/AppText.js | 108 +++++++ .../react-native-web/Tweet/AspectRatio.js | 41 +++ .../react-native-web/Tweet/GridView.js | 53 ++++ .../Tweet/IconDirectMessage.js | 20 ++ .../react-native-web/Tweet/IconHeart.js | 19 ++ .../react-native-web/Tweet/IconReply.js | 19 ++ .../react-native-web/Tweet/IconRetweet.js | 19 ++ .../react-native-web/Tweet/TweetAction.js | 78 +++++ .../react-native-web/Tweet/TweetActionsBar.js | 52 +++ .../react-native-web/Tweet/TweetText.js | 29 ++ .../react-native-web/Tweet/TweetTextPart.js | 113 +++++++ .../react-native-web/Tweet/UserAvatar.js | 65 ++++ .../react-native-web/Tweet/UserNames.js | 52 +++ .../react-native-web/Tweet/index.js | 144 +++++++++ .../react-native-web/Tweet/styles.js | 15 + .../react-native-web/Tweet/theme.js | 40 +++ .../implementations/react-native-web/index.js | 11 + .../src/implementations/reactxp/Box.js | 49 +++ .../src/implementations/reactxp/Dot.js | 35 +++ .../src/implementations/reactxp/Provider.js | 31 ++ .../src/implementations/reactxp/index.js | 11 + .../implementations/styled-components/Box.js | 31 ++ .../implementations/styled-components/Dot.js | 25 ++ .../styled-components/Provider.js | 2 + .../styled-components/View.js} | 6 +- .../styled-components/index.js | 11 + .../src/implementations/styled-jsx/Box.js | 46 +++ .../src/implementations/styled-jsx/Dot.js | 36 +++ .../implementations/styled-jsx/Provider.js | 2 + .../src/implementations/styled-jsx/View.js | 32 ++ .../src/implementations/styled-jsx/index.js | 11 + .../implementations/styletron-react/Box.js | 47 +++ .../implementations/styletron-react/Dot.js | 25 ++ .../styletron-react/Provider.js | 19 ++ .../implementations/styletron-react/View.js | 26 ++ .../implementations/styletron-react/index.js | 11 + scripts/benchmarks/src/index.js | 75 +++++ scripts/benchmarks/src/styled-components.js | 7 - scripts/benchmarks/tests/renderDeepTree.js | 22 -- .../tests/renderSierpinskiTriangle.js | 79 ----- scripts/benchmarks/tests/renderWideTree.js | 22 -- scripts/benchmarks/webpack.config.js | 55 ++-- 129 files changed, 3646 insertions(+), 1039 deletions(-) mode change 100755 => 100644 scripts/benchmarks/README.md delete mode 100755 scripts/benchmarks/benchmark.js delete mode 100755 scripts/benchmarks/createRenderBenchmark.js delete mode 100755 scripts/benchmarks/index.js mode change 100755 => 100644 scripts/benchmarks/package.json delete mode 100644 scripts/benchmarks/run-headless.js delete mode 100644 scripts/benchmarks/send-results.js create mode 100644 scripts/benchmarks/src/app/App.js create mode 100644 scripts/benchmarks/src/app/Benchmark/index.js create mode 100644 scripts/benchmarks/src/app/Benchmark/math.js create mode 100644 scripts/benchmarks/src/app/Benchmark/timing.js create mode 100644 scripts/benchmarks/src/app/Benchmark/types.js create mode 100644 scripts/benchmarks/src/app/Button.js create mode 100644 scripts/benchmarks/src/app/Icons.js create mode 100644 scripts/benchmarks/src/app/Layout.js create mode 100644 scripts/benchmarks/src/app/ReportCard.js create mode 100644 scripts/benchmarks/src/app/Text.js create mode 100644 scripts/benchmarks/src/app/theme.js create mode 100644 scripts/benchmarks/src/cases/SierpinskiTriangle.js create mode 100644 scripts/benchmarks/src/cases/Tree.js delete mode 100755 scripts/benchmarks/src/components/Box/css-modules.js delete mode 100755 scripts/benchmarks/src/components/Box/emotion-obj.js delete mode 100755 scripts/benchmarks/src/components/Box/emotion.js delete mode 100755 scripts/benchmarks/src/components/Box/glamorous.js delete mode 100755 scripts/benchmarks/src/components/Box/styled-components.js delete mode 100755 scripts/benchmarks/src/components/Box/styles.css delete mode 100644 scripts/benchmarks/src/components/Dot/emotion.js delete mode 100644 scripts/benchmarks/src/components/Dot/glamor.js delete mode 100644 scripts/benchmarks/src/components/NestedTree.js delete mode 100644 scripts/benchmarks/src/components/SierpinskiTriangle.js delete mode 100755 scripts/benchmarks/src/components/View/css-modules.js delete mode 100755 scripts/benchmarks/src/components/View/emotion-obj.js delete mode 100755 scripts/benchmarks/src/components/View/emotion.js delete mode 100755 scripts/benchmarks/src/components/View/glamorous.js delete mode 100644 scripts/benchmarks/src/components/Wrapper/emotion.js delete mode 100644 scripts/benchmarks/src/components/Wrapper/glamor.js delete mode 100755 scripts/benchmarks/src/css-modules.js delete mode 100755 scripts/benchmarks/src/emotion-css.js delete mode 100755 scripts/benchmarks/src/emotion-obj.js delete mode 100755 scripts/benchmarks/src/emotion.js delete mode 100755 scripts/benchmarks/src/glamor.js delete mode 100755 scripts/benchmarks/src/glamorous.js create mode 100644 scripts/benchmarks/src/impl.js create mode 100644 scripts/benchmarks/src/implementations/aphrodite/Box.js create mode 100644 scripts/benchmarks/src/implementations/aphrodite/Provider.js create mode 100644 scripts/benchmarks/src/implementations/aphrodite/View.js create mode 100644 scripts/benchmarks/src/implementations/aphrodite/index.js create mode 100644 scripts/benchmarks/src/implementations/css-modules/Box.js create mode 100644 scripts/benchmarks/src/implementations/css-modules/Provider.js create mode 100644 scripts/benchmarks/src/implementations/css-modules/View.js create mode 100644 scripts/benchmarks/src/implementations/css-modules/box-styles.css create mode 100644 scripts/benchmarks/src/implementations/css-modules/index.js rename scripts/benchmarks/src/{components/View/styles.css => implementations/css-modules/view-styles.css} (100%) mode change 100755 => 100644 rename scripts/benchmarks/src/{components/Box/glamor.js => implementations/emotion/Box.js} (50%) mode change 100755 => 100644 create mode 100644 scripts/benchmarks/src/implementations/emotion/Dot.js create mode 100644 scripts/benchmarks/src/implementations/emotion/Provider.js rename scripts/benchmarks/src/{components/View/emotion-css.js => implementations/emotion/View.js} (67%) mode change 100755 => 100644 create mode 100644 scripts/benchmarks/src/implementations/emotion/index.js rename scripts/benchmarks/src/{components/Box/emotion-css.js => implementations/glamor/Box.js} (50%) mode change 100755 => 100644 create mode 100644 scripts/benchmarks/src/implementations/glamor/Dot.js create mode 100644 scripts/benchmarks/src/implementations/glamor/Provider.js rename scripts/benchmarks/src/{components/View/glamor.js => implementations/glamor/View.js} (78%) mode change 100755 => 100644 create mode 100644 scripts/benchmarks/src/implementations/glamor/index.js create mode 100644 scripts/benchmarks/src/implementations/inline-styles/Box.js create mode 100644 scripts/benchmarks/src/implementations/inline-styles/Dot.js create mode 100644 scripts/benchmarks/src/implementations/inline-styles/Provider.js create mode 100644 scripts/benchmarks/src/implementations/inline-styles/View.js create mode 100644 scripts/benchmarks/src/implementations/inline-styles/index.js create mode 100644 scripts/benchmarks/src/implementations/radium/Box.js create mode 100644 scripts/benchmarks/src/implementations/radium/Dot.js create mode 100644 scripts/benchmarks/src/implementations/radium/Provider.js create mode 100644 scripts/benchmarks/src/implementations/radium/View.js create mode 100644 scripts/benchmarks/src/implementations/radium/index.js create mode 100644 scripts/benchmarks/src/implementations/react-fela/Box.js create mode 100644 scripts/benchmarks/src/implementations/react-fela/Dot.js create mode 100644 scripts/benchmarks/src/implementations/react-fela/Provider.js create mode 100644 scripts/benchmarks/src/implementations/react-fela/View.js create mode 100644 scripts/benchmarks/src/implementations/react-fela/index.js create mode 100644 scripts/benchmarks/src/implementations/react-jss/Box.js create mode 100644 scripts/benchmarks/src/implementations/react-jss/Dot.js create mode 100644 scripts/benchmarks/src/implementations/react-jss/Provider.js create mode 100644 scripts/benchmarks/src/implementations/react-jss/View.js create mode 100644 scripts/benchmarks/src/implementations/react-jss/index.js create mode 100644 scripts/benchmarks/src/implementations/react-native-web/Box.js create mode 100644 scripts/benchmarks/src/implementations/react-native-web/Dot.js create mode 100644 scripts/benchmarks/src/implementations/react-native-web/Provider.js create mode 100644 scripts/benchmarks/src/implementations/react-native-web/Tweet/AppText.js create mode 100644 scripts/benchmarks/src/implementations/react-native-web/Tweet/AspectRatio.js create mode 100644 scripts/benchmarks/src/implementations/react-native-web/Tweet/GridView.js create mode 100644 scripts/benchmarks/src/implementations/react-native-web/Tweet/IconDirectMessage.js create mode 100644 scripts/benchmarks/src/implementations/react-native-web/Tweet/IconHeart.js create mode 100644 scripts/benchmarks/src/implementations/react-native-web/Tweet/IconReply.js create mode 100644 scripts/benchmarks/src/implementations/react-native-web/Tweet/IconRetweet.js create mode 100644 scripts/benchmarks/src/implementations/react-native-web/Tweet/TweetAction.js create mode 100644 scripts/benchmarks/src/implementations/react-native-web/Tweet/TweetActionsBar.js create mode 100644 scripts/benchmarks/src/implementations/react-native-web/Tweet/TweetText.js create mode 100644 scripts/benchmarks/src/implementations/react-native-web/Tweet/TweetTextPart.js create mode 100644 scripts/benchmarks/src/implementations/react-native-web/Tweet/UserAvatar.js create mode 100644 scripts/benchmarks/src/implementations/react-native-web/Tweet/UserNames.js create mode 100644 scripts/benchmarks/src/implementations/react-native-web/Tweet/index.js create mode 100644 scripts/benchmarks/src/implementations/react-native-web/Tweet/styles.js create mode 100644 scripts/benchmarks/src/implementations/react-native-web/Tweet/theme.js create mode 100644 scripts/benchmarks/src/implementations/react-native-web/index.js create mode 100644 scripts/benchmarks/src/implementations/reactxp/Box.js create mode 100644 scripts/benchmarks/src/implementations/reactxp/Dot.js create mode 100644 scripts/benchmarks/src/implementations/reactxp/Provider.js create mode 100644 scripts/benchmarks/src/implementations/reactxp/index.js create mode 100644 scripts/benchmarks/src/implementations/styled-components/Box.js create mode 100644 scripts/benchmarks/src/implementations/styled-components/Dot.js create mode 100644 scripts/benchmarks/src/implementations/styled-components/Provider.js rename scripts/benchmarks/src/{components/View/styled-components.js => implementations/styled-components/View.js} (81%) mode change 100755 => 100644 create mode 100644 scripts/benchmarks/src/implementations/styled-components/index.js create mode 100644 scripts/benchmarks/src/implementations/styled-jsx/Box.js create mode 100644 scripts/benchmarks/src/implementations/styled-jsx/Dot.js create mode 100644 scripts/benchmarks/src/implementations/styled-jsx/Provider.js create mode 100644 scripts/benchmarks/src/implementations/styled-jsx/View.js create mode 100644 scripts/benchmarks/src/implementations/styled-jsx/index.js create mode 100644 scripts/benchmarks/src/implementations/styletron-react/Box.js create mode 100644 scripts/benchmarks/src/implementations/styletron-react/Dot.js create mode 100644 scripts/benchmarks/src/implementations/styletron-react/Provider.js create mode 100644 scripts/benchmarks/src/implementations/styletron-react/View.js create mode 100644 scripts/benchmarks/src/implementations/styletron-react/index.js create mode 100644 scripts/benchmarks/src/index.js delete mode 100755 scripts/benchmarks/src/styled-components.js delete mode 100755 scripts/benchmarks/tests/renderDeepTree.js delete mode 100644 scripts/benchmarks/tests/renderSierpinskiTriangle.js delete mode 100755 scripts/benchmarks/tests/renderWideTree.js mode change 100755 => 100644 scripts/benchmarks/webpack.config.js diff --git a/scripts/benchmarks/README.md b/scripts/benchmarks/README.md old mode 100755 new mode 100644 index 3d65490d0..95e5045a7 --- a/scripts/benchmarks/README.md +++ b/scripts/benchmarks/README.md @@ -1,7 +1,70 @@ -# Benchmarks +# benchmarks -These benchmarks test how fast various css-in-js libraries render with react components. They do not necessarily represent how fast a css-in-js library will be in the real world and are used by emotion to stop performance regressions in render performance/caching. +Try the [benchmarks app](https://necolas.github.io/react-native-web/benchmarks) online. -To run these benchmarks run `npm run benchmark` in the root directory. These benchmarks should generally be run on Travis and not locally. +To run the benchmarks locally: -These benchmarks are a modified version of [react-native-web's benchmarks](https://github.com/necolas/react-native-web/tree/master/benchmarks). \ No newline at end of file +``` +yarn benchmarks +open ./packages/benchmarks/dist/index.html +``` + +Develop against these benchmarks: + +``` +yarn compile --watch +yarn benchmarks --watch +``` + +## Notes + +These benchmarks are approximations of extreme cases that libraries may +encounter. Their purpose is to provide an early-warning signal for performance +regressions. Each test report includes the mean and standard deviation of the +timings, and approximations of the time spent in scripting (S) and layout (L). + +The components used in the render benchmarks are simple enough to be +implemented by multiple UI or style libraries. The benchmark implementations +and the features of the style libraries are _only approximately equivalent in +functionality_. + +No benchmark will run for more than 20 seconds. + +### Mount deep/wide tree + +These cases look at the performance of mounting and rendering large trees of +elements that use static styles. + +### Update dynamic styles + +This case looks at the performance of repeated style updates to a large mounted +tree. Some libraries choose to inject new styles for each "dynamic style", +whereas others choose to use inline styles. Libraries without built-in support +for dynamic styles (i.e., they rely on user-authored inline styles) are not +included. + +## Example results + +### MacBook Pro (2011) + +MacBook Pro (13-inch, Early 2011); 2.3 GHz Intel Core i5; 8 GB 1333 MHz DDR3 RAM. Google Chrome 63. + +Typical render timings: mean ± standard deviations. + +| Implementation | Mount deep tree (ms) | Mount wide tree (ms) | Dynamic update (ms) | +| :--- | ---: | ---: | ---: | +| `css-modules` | `30.19` `±04.84` | `38.25` `±04.85` | - | +| `react-native-web@0.4.0` | `36.40` `±04.98` | `51.28` `±05.58` | `19.36` `±02.56` | +| `inline-styles` | `64.12` `±07.69` | `94.49` `±11.34` | `09.84` `±02.36` | + +### Moto G4 + +Moto G4 (Android 7); Octa-core (4x1.5 GHz & 4x1.2 Ghz); 2 GB RAM. Google Chrome 63. + +Typical render timings: mean ± standard deviations. + +| Implementation | Mount deep tree (ms) | Mount wide tree (ms) | Dynamic update (ms) | +| :--- | ---: | ---: | ---: | +| `css-modules` | `98.24` `±20.26` | `143.75` `±25.50` | - | +| `react-native-web@0.4.0` | `131.46` `±18.96` | `174.70` `±14.88` | `60.87` `±06.32` | +| `inline-styles` | `184.58` `±26.23` | `273.86` `±26.23` | `30.28` `±07.44` | diff --git a/scripts/benchmarks/benchmark.js b/scripts/benchmarks/benchmark.js deleted file mode 100755 index 6fa2c42f8..000000000 --- a/scripts/benchmarks/benchmark.js +++ /dev/null @@ -1,98 +0,0 @@ -import * as marky from 'marky' - -export const fmt = time => Math.round(time * 100) / 100 - -const measure = (name, fn) => { - marky.mark(name) - fn() - const performanceMeasure = marky.stop(name) - return performanceMeasure.duration -} - -export const mean = values => { - const sum = values.reduce((sum, value) => sum + value, 0) - return sum / values.length -} - -export const median = values => { - if (!Array.isArray(values)) { - return 0 - } - if (values.length === 1) { - return values[0] - } - - const numbers = [...values].sort((a, b) => a - b) - return (numbers[(numbers.length - 1) >> 1] + numbers[numbers.length >> 1]) / 2 -} - -export const standardDeviation = values => { - const avg = mean(values) - - const squareDiffs = values.map(value => { - const diff = value - avg - return diff * diff - }) - - const meanSquareDiff = mean(squareDiffs) - return Math.sqrt(meanSquareDiff) -} - -const benchmark = ({ name, description, setup, teardown, task, runs }) => { - return new Promise(resolve => { - const durations = [] - let i = 0 - - setup() - const first = measure('first', task) - teardown() - - const done = () => { - const stdDev = standardDeviation(durations) - const formattedFirst = fmt(first) - const formattedMean = fmt(mean(durations)) - const formattedMedian = fmt(median(durations)) - const formattedStdDev = fmt(stdDev) - - console.log({ - name, - description, - first: formattedFirst, - mean: formattedMean, - median: formattedMedian, - stdDev: formattedStdDev, - durations - }) - resolve() - } - - const a = () => { - setup() - window.requestAnimationFrame(b) - } - - const b = () => { - const duration = measure('mean', task) - durations.push(duration) - window.requestAnimationFrame(c) - } - - const c = () => { - teardown() - window.requestAnimationFrame(d) - } - - const d = () => { - i += 1 - if (i < runs) { - window.requestAnimationFrame(a) - } else { - window.requestAnimationFrame(done) - } - } - - window.requestAnimationFrame(a) - }) -} - -export default benchmark diff --git a/scripts/benchmarks/createRenderBenchmark.js b/scripts/benchmarks/createRenderBenchmark.js deleted file mode 100755 index fd1570431..000000000 --- a/scripts/benchmarks/createRenderBenchmark.js +++ /dev/null @@ -1,30 +0,0 @@ -import benchmark from './benchmark' -import ReactDOM from 'react-dom' - -const node = document.querySelector('.root') - -const createRenderBenchmark = ({ - description, - getElement, - name, - runs, - flush -}) => () => { - const setup = () => {} - const teardown = () => { - ReactDOM.unmountComponentAtNode(node) - } - - return benchmark({ - name, - description, - runs, - setup, - teardown, - task: () => { - ReactDOM.render(getElement(), node) - } - }) -} - -export default createRenderBenchmark diff --git a/scripts/benchmarks/index.html b/scripts/benchmarks/index.html index a69e76e90..4d68cb72e 100644 --- a/scripts/benchmarks/index.html +++ b/scripts/benchmarks/index.html @@ -1,11 +1,16 @@ - Performance tests + +
+ - \ No newline at end of file + diff --git a/scripts/benchmarks/index.js b/scripts/benchmarks/index.js deleted file mode 100755 index 4d3797c4e..000000000 --- a/scripts/benchmarks/index.js +++ /dev/null @@ -1,71 +0,0 @@ -import cssModules from './src/css-modules' -import emotion from './src/emotion' -import emotionCSS from './src/emotion-css' -import emotionObj from './src/emotion-obj' -import glamor from './src/glamor' -import glamorous from './src/glamorous' -import styledComponents from './src/styled-components' - -import renderDeepTree from './tests/renderDeepTree' -import renderWideTree from './tests/renderWideTree' -import renderSierpinskiTriangle from './tests/renderSierpinskiTriangle' - -const allTests = { - emotion: [ - () => renderSierpinskiTriangle('emotion', emotion), - () => renderDeepTree('emotion', emotion), - () => renderWideTree('emotion', emotion) - ], - emotionCSS: [ - () => renderDeepTree('emotionCSS', emotionCSS), - () => renderWideTree('emotionCSS', emotionCSS) - ], - emotionObj: [ - () => renderDeepTree('emotionObj', emotionObj), - () => renderWideTree('emotionObj', emotionObj) - ], - glamor: [ - () => renderSierpinskiTriangle('glamor', glamor), - () => renderDeepTree('glamor', glamor), - () => renderWideTree('glamor', glamor) - ], - glamorous: [ - () => renderDeepTree('glamorous', glamorous), - () => renderWideTree('glamorous', glamorous) - ], - 'styled-components': [ - () => renderDeepTree('styled-components', styledComponents), - () => renderWideTree('styled-components', styledComponents) - ], - 'css-modules': [ - () => renderDeepTree('css-modules', cssModules), - () => renderWideTree('css-modules', cssModules) - ] -} - -const tests = [] - -if (window.location.hash) { - window.location.hash - .slice(1) - .split(',') - .forEach(test => { - if (Array.isArray(allTests[test])) { - tests.push(...allTests[test]) - } else { - throw new Error(`Benchmark for ${test} not found`) - } - }) -} else { - tests.push(...allTests.emotion) - tests.push(...allTests.emotionObj) - tests.push(...allTests.emotionCSS) - tests.push(...allTests['css-modules']) - tests.push(...allTests.glamorous) - tests.push(...allTests.glamor) - tests.push(...allTests['styled-components']) -} - -tests.push(() => () => Promise.resolve(console.log('done'))) - -tests.reduce((promise, test) => promise.then(test()), Promise.resolve()) diff --git a/scripts/benchmarks/package.json b/scripts/benchmarks/package.json old mode 100755 new mode 100644 index 7fa5afea3..90b7fe5bd --- a/scripts/benchmarks/package.json +++ b/scripts/benchmarks/package.json @@ -1,38 +1,37 @@ { - "name": "benchmarks", "private": true, + "name": "benchmarks", + "version": "0.8.8", + "scripts": { + "build": "mkdir -p dist && cp -f index.html dist/index.html && ./node_modules/.bin/webpack-cli --config ./webpack.config.js", + "release": "yarn build && git checkout gh-pages && rm -rf ../../benchmarks && mv dist ../../benchmarks && git add -A && git commit -m \"Benchmarks deploy\" && git push origin gh-pages && git checkout -" + }, "dependencies": { - "apollo-fetch": "^0.6.0", - "classnames": "^2.2.5", - "d3-scale-chromatic": "^1.1.1", - "emotion": "^9.2.5", - "glamor": "^2.20.37", - "glamorous": "^4.1.0", - "marky": "^1.2.0", - "postcss": "^6.0.8", - "react": "^16.2.0", - "react-dom": "^16.2.0", - "react-emotion": "^9.2.5", - "styled-components": "^2.2.1" + "aphrodite": "^2.2.2", + "classnames": "^2.2.6", + "d3-scale-chromatic": "^1.3.0", + "emotion": "^9.2.4", + "fela": "^6.1.9", + "glamor": "2.20.40", + "radium": "^0.24.0", + "react": "^16.4.1", + "react-dom": "^16.4.1", + "react-fela": "^7.3.1", + "react-jss": "^8.6.1", + "react-native-web": "0.8.8", + "reactxp": "^1.3.0", + "styled-components": "^3.3.3", + "styled-jsx": "^2.2.7", + "styletron-engine-atomic": "^1.0.5", + "styletron-react": "^4.3.1" }, "devDependencies": { - "babel-loader": "^7.1.1", - "babel-plugin-macros": "^2.0.0", - "babel-polyfill": "^6.26.0", - "cli-chart": "^0.3.1", - "cli-table": "^0.3.1", - "css-loader": "^0.28.4", - "html-webpack-plugin": "^2.30.1", - "puppeteer": "^0.10.1", - "react-addons-perf": "^15.6.0-rc.1", - "serve": "^6.0.6", - "style-loader": "^0.18.2", - "webpack": "^3.4.1", - "webpack-bundle-analyzer": "^2.9.0" - }, - "scripts": { - "build:benchmark": "webpack", - "benchmark": "npm run build:benchmark && node run-headless.js" - }, - "version": "9.2.5" + "babel-plugin-react-native-web": "0.8.8", + "css-loader": "^1.0.0", + "style-loader": "^0.21.0", + "url-loader": "^1.0.1", + "webpack": "^4.15.1", + "webpack-bundle-analyzer": "^2.13.1", + "webpack-cli": "^3.0.8" + } } diff --git a/scripts/benchmarks/run-headless.js b/scripts/benchmarks/run-headless.js deleted file mode 100644 index 62bf46c92..000000000 --- a/scripts/benchmarks/run-headless.js +++ /dev/null @@ -1,61 +0,0 @@ -const puppeteer = require('puppeteer') -const Table = require('cli-table') -const path = require('path') - -const sendResult = require('./send-results') - -const { - TRAVIS_BRANCH = 'test', - TRAVIS_COMMIT = 'test', - TRAVIS_COMMIT_MESSAGE = 'test', - TRAVIS_PULL_REQUEST = 'test' -} = process.env - -// need to add a timeout if it never completes -// needs error handling - -async function run() { - const browser = await puppeteer.launch() - const page = await browser.newPage() - await page.goto(`file://${path.resolve(__dirname, './dist/index.html')}`) - - const results = [] - let done = false - page.on('console', async result => { - if (result && result.name) { - console.log(`${result.name}: Mean ${result.mean}ms`) - results.push(result) - if (done) { - try { - await sendResult({ - branch: TRAVIS_BRANCH, - commit: TRAVIS_COMMIT, - commitMessage: TRAVIS_COMMIT_MESSAGE, - pr: TRAVIS_PULL_REQUEST, - results: results.map(r => ({ - name: r.name, - duration: parseInt(r.mean, 10), - type: r.name.toLowerCase().includes('deep') - ? 'DEEP' - : r.name.toLowerCase().includes('wide') ? 'WIDE' : 'TRIANGLE' - })) - }) - } catch (e) { - console.log('graphql failed') - console.log(e.message) - } - - const table = new Table() - table.push(['Benchmark', 'Mean (ms)']) - table.push(...results.map(res => [res.name, res.mean])) - console.log(table.toString()) - await browser.close() - } - } - if (result === 'done') { - done = true - } - }) -} - -run() diff --git a/scripts/benchmarks/send-results.js b/scripts/benchmarks/send-results.js deleted file mode 100644 index 7a05ca584..000000000 --- a/scripts/benchmarks/send-results.js +++ /dev/null @@ -1,38 +0,0 @@ -const { createApolloFetch } = require('apollo-fetch') - -const { GRAPH_TOKEN } = process.env - -const client = createApolloFetch({ - uri: 'https://api.graph.cool/simple/v1/cj83urcdm0u420180bqw9w4mu' -}) - -client.use(({ request, options }, next) => { - if (!options.headers) { - options.headers = {} // Create the headers object if needed. - } - options.headers['Authorization'] = 'Bearer ' + GRAPH_TOKEN || '' - - next() -}) - -module.exports = function sendResult(vars) { - return client({ - query: ` - mutation createRunAndResults($branch: String, $pr: String, $commit: String, $commitMessage: String, $results: [RunresultsResult!]) { - createRun(results: $results, branch: $branch, pr: $pr, commit: $commit, commitMessage: $commitMessage) { - createdAt - branch - pr - commit - commitMessage - results { - name - duration - type - } - } - } - `, - variables: vars - }) -} diff --git a/scripts/benchmarks/src/app/App.js b/scripts/benchmarks/src/app/App.js new file mode 100644 index 000000000..4460553e4 --- /dev/null +++ b/scripts/benchmarks/src/app/App.js @@ -0,0 +1,297 @@ +/* eslint-disable react/prop-types */ + +import Benchmark from './Benchmark'; +import { Picker, StyleSheet, ScrollView, TouchableOpacity, View } from 'react-native'; +import React, { Component } from 'react'; +import Button from './Button'; +import { IconClear, IconEye } from './Icons'; +import ReportCard from './ReportCard'; +import Text from './Text'; +import Layout from './Layout'; +import { colors } from './theme'; + +const Overlay = () => ; + +export default class App extends Component { + static displayName = '@app/App'; + + constructor(props, context) { + super(props, context); + const currentBenchmarkName = Object.keys(props.tests)[0]; + this.state = { + currentBenchmarkName, + currentLibraryName: 'react-native-web', + status: 'idle', + results: [] + }; + } + + render() { + const { tests } = this.props; + const { currentBenchmarkName, status, currentLibraryName, results } = this.state; + const currentImplementation = tests[currentBenchmarkName][currentLibraryName]; + const { Component, Provider, getComponentProps, sampleCount } = currentImplementation; + + return ( + + + + Library + {currentLibraryName} + + + {Object.keys(tests[currentBenchmarkName]).map(libraryName => ( + + ))} + + + + + Benchmark + {currentBenchmarkName} + + {Object.keys(tests).map(test => ( + + ))} + + + + + + + -

- This has a black background and - is hotpink. Try moving where - hotpink is in the css call and - see if the color changes. +

This is hotpink

+ +

+ This has a black background and is hotpink. Try moving where hotpink is in + the css call and see if the color changes.

) diff --git a/docs/styled.md b/docs/styled.md index 7256cd057..1625a0049 100644 --- a/docs/styled.md +++ b/docs/styled.md @@ -2,16 +2,16 @@ title: "Styled Components" --- -`styled` is a way to create React or Preact components that have styles attached to them. It's available from [react-emotion](/packages/react-emotion) and [preact-emotion](/packages/preact-emotion). `styled` was heavily inspired by [styled-components](https://www.styled-components.com/) and [glamorous](https://glamorous.rocks/) +`styled` is a way to create React or Preact components that have styles attached to them. It's available from [@emotion/styled](/packages/@emotion/styled) and [TODO](/packages/preact-emotion). `styled` was heavily inspired by [styled-components](https://www.styled-components.com/) and [glamorous](https://glamorous.rocks/) ### Styling elements and components `styled` is very similar to `css` except you call it with an html tag or React/Preact component and then call that with a template literal for string styles or a regular function call for object styles. ```jsx live -import styled from 'react-emotion' +import styled from '@emotion/styled' -const Button = styled('button')` +const Button = styled.button` color: turquoise; ` @@ -23,14 +23,14 @@ render() Any interpolations or arguments that are functions in `styled` are called with `props`, this allows you to change the styles of a component based on the props. ```jsx live -import styled from 'react-emotion' +import styled from '@emotion/styled' -const Button = styled('button')` +const Button = styled.button` color: ${props => props.primary ? 'hotpink' : 'turquoise'}; ` -const Container = styled('div')(props => ({ +const Container = styled.div(props => ({ display: 'flex', flexDirection: props.column && 'column' })) @@ -52,7 +52,7 @@ render( `styled` can style any component as long as it accepts a `className` prop. ```jsx live -import styled from 'react-emotion' +import styled from '@emotion/styled' const Basic = ({ className }) => (
Some text
) @@ -64,17 +64,17 @@ const Fancy = styled(Basic)` render() ``` - ### Change the rendered tag using `withComponent` Sometimes you want to create some styles with one component but then use those styles again with another component, the `withComponent` method can be used for this. This was inspired by [styled-components' `withComponent`](https://www.styled-components.com/docs/api#withcomponent). ```jsx live -// Create a section element -const Section = styled('section')` +import styled from '@emotion/styled' + +const Section = styled.section` background: #333; ` -// Create an aside element with the same styles as Section +// this component has the same styles as Section but it renders an aside const Aside = Section.withComponent('aside') render(
@@ -89,11 +89,13 @@ render( Similar to [styled-components](https://www.styled-components.com/docs/faqs#can-i-refer-to-other-components), emotion allows for emotion components to be targeted like regular CSS selectors when using [babel-plugin-emotion](/packages/babel-plugin-emotion.md). ```jsx live -const Child = styled('div')` +import styled from '@emotion/styled' + +const Child = styled.div` color: red; ` -const Parent = styled('div')` +const Parent = styled.div` ${Child} { color: green; } @@ -111,11 +113,13 @@ render( Component selectors can also be used with object styles. ```jsx live -const Child = styled('div')({ +import styled from '@emotion/styled' + +const Child = styled.div({ color: 'red' }) -const Parent = styled('div')({ +const Parent = styled.div({ [Child]: { color: 'green' } @@ -131,68 +135,10 @@ render( ) ``` -### Pass refs down using `innerRef` - -Sometimes you need to get a [ref](https://reactjs.org/docs/refs-and-the-dom.html) but passing `ref` to a styled component will return a ref to the styled component, not the component that it renders which is generally the one you want. You can pass `innerRef` instead of `ref` to get the ref of the component that styled renders. - -```jsx live -const Input = styled('input')` - color: hotpink; -` - -const Button = styled('button')` - color: green; -` - -function TextInput(props) { - let textInput = null - function handleClick() { - textInput.focus() - } - return ( -
- { - textInput = input - }} - /> - -
- ) -} -render() -``` - -### Element Shorthand - -> Note: - -> `babel-plugin-emotion` is required for the element shorthand - -Instead of using the function call syntax(`styled('div')`), you can use create components by using a property, where the property refers to an HTML tag(`styled.div`). - -```jsx live -const DivWithoutShorthand = styled('div')` - color: green; -` - -const DivWithShorthand = styled.div` - color: hotpink; -` - -render( - - This is green. This is hotpink. - -) -``` - ### Object styles ```jsx live -import styled from 'react-emotion' +import styled from '@emotion/styled' const H1 = styled.h1( { @@ -208,8 +154,4 @@ render( ) ``` -This API was inspired by [glamorous](https://github.com/paypal/glamorous). - -### withConfig is not a function error - -This error is caused by using the shorthand syntax for styled such as `styled.div` without the Babel plugin. To fix this, [install `babel-plugin-emotion`](/docs/babel.md) +This API was inspired by [glamorous](https://github.com/paypal/glamorous). ❤️ diff --git a/site/plugins/gatsby-remark-live-code/index.js b/site/plugins/gatsby-remark-live-code/index.js index afab0a29d..99dd5d25c 100644 --- a/site/plugins/gatsby-remark-live-code/index.js +++ b/site/plugins/gatsby-remark-live-code/index.js @@ -11,7 +11,7 @@ module.exports = ({ markdownAST }) => { }" compiled="${ Babel.transform(node.value, { presets: ['es2015', 'react', 'stage-1'], - plugins: [require('babel-plugin-emotion').default] + plugins: [require('@emotion/babel-plugin-core').default] }).code }">` } diff --git a/site/src/components/Playground.js b/site/src/components/Playground.js index 22443e052..a83a207a7 100644 --- a/site/src/components/Playground.js +++ b/site/src/components/Playground.js @@ -2,17 +2,11 @@ import React, { Component } from 'react' import styled from '@emotion/styled' import Live, { compile, Editor, ErrorBoundary } from './live' -import { ThemeProvider, withTheme } from 'emotion-theming' import Box from '../components/Box' import { openColors as colors, fonts } from '../utils/style' import '../utils/highlight-css' -import * as emotion from 'emotion' export const scope = { - ...emotion, - styled, - ThemeProvider, - withTheme, require(moduleName: string) { switch (moduleName) { case 'emotion': @@ -20,6 +14,14 @@ export const scope = { case 'react-emotion': case 'preact-emotion': return require('react-emotion') + case '@emotion/core': + return require('@emotion/core') + case '@emotion/styled': + return require('@emotion/styled') + case '@emotion/styled-base': + return require('@emotion/styled-base') + case '@emotion/css': + return require('@emotion/css') case 'emotion-theming': return require('emotion-theming') case 'recompose/withProps': diff --git a/site/src/components/live/worker.js b/site/src/components/live/worker.js index 12db1f3ca..4333cc149 100644 --- a/site/src/components/live/worker.js +++ b/site/src/components/live/worker.js @@ -2,7 +2,7 @@ importScripts('https://unpkg.com/@babel/standalone@7.0.0-beta.49/babel.min.js') -const babelPluginEmotion = require('babel-plugin-emotion').default +const babelPluginEmotion = require('@emotion/babel-plugin-core').default global.window = global diff --git a/site/src/pages/index.js b/site/src/pages/index.js index b68982a33..00ad010f1 100644 --- a/site/src/pages/index.js +++ b/site/src/pages/index.js @@ -65,6 +65,8 @@ function getCode(htmlAst): Code { return ret } +let localScope = { ...scope, styled } + class IndexPage extends React.Component { state = { mode: 'string', @@ -80,7 +82,7 @@ class IndexPage extends React.Component { Date: Sun, 29 Jul 2018 16:43:05 +1000 Subject: [PATCH 25/32] moar stuff --- docs/keyframes.md | 24 +++--- docs/migrating-to-emotion-10.md | 148 ++++++++++++++++++++++++++++++++ docs/object-styles.md | 2 +- docs/ssr.md | 11 +++ docs/theming.md | 7 +- docs/with-props.md | 20 +++++ 6 files changed, 197 insertions(+), 15 deletions(-) create mode 100644 docs/migrating-to-emotion-10.md diff --git a/docs/keyframes.md b/docs/keyframes.md index f2c6330ed..12755fd55 100644 --- a/docs/keyframes.md +++ b/docs/keyframes.md @@ -4,8 +4,9 @@ title: "Keyframes" If you need more control over an animation, you can use `keyframes` with the same JS interpolation as `css`. The `keyframes` function takes in a css keyframe definition and returns an animation name so that you can include it in other styles. This is similar to how `css` takes in styles and returns a className that you can use to apply the styles. -```jsx live -import styled, { keyframes } from 'react-emotion' +```jsx +/** @jsx jsx */ +import { jsx, css, keyframes } from '@emotion/core' const bounce = keyframes` from, 20%, 53%, 80%, to { @@ -25,13 +26,14 @@ const bounce = keyframes` } ` -const Avatar = styled('img')` - width: 96px; - height: 96px; - border-radius: 50%; - animation: ${bounce} 1s ease infinite; - transform-origin: center bottom; -` - -render() +render( +
+ some bouncing text! +
+) ``` diff --git a/docs/migrating-to-emotion-10.md b/docs/migrating-to-emotion-10.md new file mode 100644 index 000000000..885dbb2a5 --- /dev/null +++ b/docs/migrating-to-emotion-10.md @@ -0,0 +1,148 @@ +--- +title: "Migrating to Emotion 10" +--- + +Emotion 10 is a large change to Emotion so it requires some changes to your code. + +# Thinking + +The biggest change in Emotion 10 is that it doesn't let you easily access the underlying class names. Instead of thinking in class names, you have to think in terms of styles and composing them together. + +For example, in Emotion 9, you might have had two classes from `css` and compose them together with `cx` but in Emotion 10, you create 2 styles and compose them together in the css prop like this + +```jsx +// Emotion 9 +import { css, cx } from 'emotion' + +let basic = css` + color: green; +` + +let important = css` + color: hotpink; +` + +const SomeComponent = props => ( +
+) +``` + +```jsx +// Emotion 10 +/** @jsx jsx */ +import { css, jsx } from '@emotion/core' + +let basic = css` + color: green; +` + +let important = css` + color: hotpink; +` + +const SomeComponent = props => ( +
+) +``` + +# Incremental Migration + +Incremental migration is something really important to Emotion because we don't want anyone to have to rewrite your entire app instantly. + +The upgrades to emotion 10 are split into two parts. The first part can be done automatically by a codemod. + +* Change all react-emotion imports so that styled is imported from `@emotion/styled` and all the emotion exports are split into a second import. + +```jsx +import styled, { css } from 'react-emotion' +// ↓ ↓ ↓ ↓ ↓ ↓ +import styled from '@emotion/styled' +import { css } from 'emotion' +``` + +* Add a css call to the css prop when a template literal is used. + +```jsx +let element = ( +
+) + +// ↓ ↓ ↓ ↓ ↓ ↓ + +import { css } from '@emotion/core' + +let element = ( +
+) +``` + +* Add a `jsx` import and set jsx pragma +* Alternatively, you use this TODO babel preset + +```jsx +import { css } from '@emotion/core' + +let element = ( +
+) +``` + +## Manual Steps + +* Add compat cache with provider + +```jsx +import { render } from 'react-dom' +import App from './App' +import * as emotion from 'emotion' +import createCompatCache from '@emotion/compat-cache' +import { Provider } from '@emotion/provider' + +let compatCache = createCompatCache(emotion) + +render( + + + , + rootNode +) +``` + +## Manual Steps over time + +* Change css usage to css prop + +```jsx +import { css } from 'emotion' +let element = ( +
+) + +// ↓ ↓ ↓ ↓ ↓ ↓ +/** @jsx jsx */ +import { jsx, css } from '@emotion/core' + +let element = ( +
+) +``` diff --git a/docs/object-styles.md b/docs/object-styles.md index af6612bb3..471bfceeb 100644 --- a/docs/object-styles.md +++ b/docs/object-styles.md @@ -46,7 +46,7 @@ render( ### Child Selectors -```jsx +```jsx live /* @jsx jsx */ import { jsx } from '@emotion/core' diff --git a/docs/ssr.md b/docs/ssr.md index c9137c12d..c28d0659b 100644 --- a/docs/ssr.md +++ b/docs/ssr.md @@ -2,6 +2,17 @@ title: "Server Side Rendering" --- +Server side rendering works out of the box in emotion 10 and above + +```jsx +import { renderToString } from 'react-dom/server' +import App from './App' + +const html = renderToString() +``` + +If you're u + ## API ### renderStylesToString diff --git a/docs/theming.md b/docs/theming.md index 9599cbd01..a4935a1f1 100644 --- a/docs/theming.md +++ b/docs/theming.md @@ -8,10 +8,10 @@ Themes are provided by the library [`emotion-theming`](https://github.com/emotio npm install -S emotion-theming ``` -Add `ThemeProvider` to the top level of your app and access the theme with `props.theme` in a styled component. The api is laid out in detail [in the documentation](https://github.com/emotion-js/emotion/tree/master/packages/emotion-theming). +Add `ThemeProvider` to the top level of your app and access the theme with `props.theme` in a styled component or provide a function that accepts the theme as the css prop. The api is laid out in detail [in the documentation](https://github.com/emotion-js/emotion/tree/master/packages/emotion-theming). -```jsx live -import styled from 'react-emotion' +```jsx +import styled from '@emotion/styled' import { ThemeProvider } from 'emotion-theming' const theme = { @@ -29,6 +29,7 @@ const Avatar = styled('img')` render( +
) ``` diff --git a/docs/with-props.md b/docs/with-props.md index 863157042..dfc020e60 100644 --- a/docs/with-props.md +++ b/docs/with-props.md @@ -7,6 +7,7 @@ Sometimes it's useful to create components that already have props applied, like **[`withProps` documentation](https://github.com/acdlite/recompose/blob/master/docs/API.md#withprops)** ```jsx live +import styled from '@emotion/styled' import withProps from 'recompose/withProps' const RedPasswordInput = withProps({ @@ -17,3 +18,22 @@ const RedPasswordInput = withProps({ render() ``` + +Alternatively, you can use the css prop and create a regular component like this. + +```jsx live +/** @jsx jsx */ +import { jsx, css } from '@emotion/core' + +const RedPasswordInput = props => ( + +) + +render() +``` From 3803426c1b8568821d9073c95f93f857fad69f03 Mon Sep 17 00:00:00 2001 From: mitchellhamilton Date: Wed, 8 Aug 2018 21:02:34 +1000 Subject: [PATCH 26/32] Change to // @live comments --- docs/css-prop.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/css-prop.md b/docs/css-prop.md index b437fd5af..5deb0b2e6 100644 --- a/docs/css-prop.md +++ b/docs/css-prop.md @@ -6,7 +6,8 @@ The primary way to style things in emotion is with the css prop, to use the css To pass string styles, you must use `css` which is exported by `@emotion/core`, it can be used as a [tagged template literal](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals) like below. -```jsx live +```jsx +// @live // this comment tells babel to convert jsx to calls to a function called jsx instead of React.createElement /** @jsx jsx */ import { css, jsx } from '@emotion/core' @@ -29,7 +30,8 @@ render( You can also pass objects directly to the css prop, for more usage with objects, go [here](/docs/object-styles.md). -```jsx live +```jsx +// @live /** @jsx jsx */ import { jsx } from '@emotion/core' From 1eda8d7fcf30eb79d67d0f0c2c7a29bc54972a70 Mon Sep 17 00:00:00 2001 From: mitchellhamilton Date: Sat, 11 Aug 2018 09:57:50 +1000 Subject: [PATCH 27/32] migration stuff --- docs/docs.yaml | 5 +++-- docs/migrating-to-emotion-10.md | 16 +++++++++++----- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/docs/docs.yaml b/docs/docs.yaml index 9842d7c86..143a18a3f 100644 --- a/docs/docs.yaml +++ b/docs/docs.yaml @@ -1,5 +1,5 @@ - title: Getting Started - items: + items: - introduction - install - css-prop @@ -20,6 +20,7 @@ - labels - configurable-imports - instances + - migrating-to-emotion-10 #- benchmarks - title: Tooling @@ -40,7 +41,7 @@ - emotion-server - emotion-theming - jest-emotion - - "@emotion/primitives" + - '@emotion/primitives' - create-emotion - create-emotion-styled - create-emotion-server diff --git a/docs/migrating-to-emotion-10.md b/docs/migrating-to-emotion-10.md index 885dbb2a5..1cdc9968f 100644 --- a/docs/migrating-to-emotion-10.md +++ b/docs/migrating-to-emotion-10.md @@ -2,11 +2,11 @@ title: "Migrating to Emotion 10" --- -Emotion 10 is a large change to Emotion so it requires some changes to your code. +Emotion 10 is a large change to Emotion so it requires some changes to your code. Some of the changes can be done automatically via a codemod and the rest can be done incrementally. # Thinking -The biggest change in Emotion 10 is that it doesn't let you easily access the underlying class names. Instead of thinking in class names, you have to think in terms of styles and composing them together. +The biggest change in Emotion 10 is that it doesn't let you easily access the underlying class names. Instead of thinking in class names, you have to think in terms of styles and composing them together. (you can still use classnames if you want to but it's not recommended except during migration) For example, in Emotion 9, you might have had two classes from `css` and compose them together with `cx` but in Emotion 10, you create 2 styles and compose them together in the css prop like this @@ -23,7 +23,9 @@ let important = css` ` const SomeComponent = props => ( -
+
) ``` @@ -47,10 +49,12 @@ const SomeComponent = props => ( # Incremental Migration -Incremental migration is something really important to Emotion because we don't want anyone to have to rewrite your entire app instantly. +Incremental migration is something really important to Emotion because we don't want anyone to have to rewrite their entire app. The upgrades to emotion 10 are split into two parts. The first part can be done automatically by a codemod. +## Codemoddable + * Change all react-emotion imports so that styled is imported from `@emotion/styled` and all the emotion exports are split into a second import. ```jsx @@ -85,7 +89,7 @@ let element = ( ``` * Add a `jsx` import and set jsx pragma -* Alternatively, you use this TODO babel preset +* Alternatively, use this TODO babel preset ```jsx import { css } from '@emotion/core' @@ -146,3 +150,5 @@ let element = ( /> ) ``` + +* TODO: add a render prop component that can add multiple class names at once. From 3d3c0240a910273c75fa3b501fa528d8fabe8950 Mon Sep 17 00:00:00 2001 From: mitchellhamilton Date: Sat, 11 Aug 2018 11:16:25 +1000 Subject: [PATCH 28/32] Fix some stuff --- docs/globals.md | 3 ++- docs/install.md | 3 ++- docs/styled.md | 3 +-- docs/theming.md | 20 +++++++++---------- site/plugins/gatsby-remark-live-code/index.js | 6 +++++- 5 files changed, 20 insertions(+), 15 deletions(-) diff --git a/docs/globals.md b/docs/globals.md index 5e071ee47..2e88aa9fb 100644 --- a/docs/globals.md +++ b/docs/globals.md @@ -4,7 +4,8 @@ title: "Global Styles" Sometimes it's useful to insert global css like resets or font faces. The `Global` component can be used for this. It accepts a `styles` prop which accepts the same values as the `css` prop except it inserts styles globally. Global styles are also removed when the styles change or when the Global component unmounts. -```jsx live +```jsx +// @live import { Global, css } from '@emotion/core' render( diff --git a/docs/install.md b/docs/install.md index 51d1e285c..dc5b81c91 100644 --- a/docs/install.md +++ b/docs/install.md @@ -71,7 +71,8 @@ npm install --save @emotion/styled npm install --save @emotion/preact-styled ``` -```jsx live +```jsx +// @live // change this import to @emotion/preact-styled // if you're using Preact import styled from '@emotion/styled' diff --git a/docs/styled.md b/docs/styled.md index 593b851ca..8ab947e24 100644 --- a/docs/styled.md +++ b/docs/styled.md @@ -139,7 +139,7 @@ render( ### Object styles -````jsx +```jsx // @live import styled from '@emotion/styled' @@ -154,4 +154,3 @@ render(

This is lightgreen.

) ``` This API was inspired by [glamorous](https://github.com/paypal/glamorous). ❤️ -```` diff --git a/docs/theming.md b/docs/theming.md index 38edb9509..137d43000 100644 --- a/docs/theming.md +++ b/docs/theming.md @@ -13,24 +13,24 @@ Add `ThemeProvider` to the top level of your app and access the theme with `prop ```jsx // @live import styled from '@emotion/styled' -import { ThemeProvider } from 'emotion-theming' +import ThemeProvider from '@emotion/provider' const theme = { - borderRadius: '50%', - borderColor: '#BF67AD' + colors: { + primaryColors: 'hotpink' + } } -const Avatar = styled('img')` - width: 96px; - height: 96px; - border-radius: ${props => props.theme.borderRadius}; - border: 1px solid ${props => props.theme.borderColor}; +const SomeText = styled.div` + color: ${props => props.theme.colors.primary}; ` render( - -
some text +
({ color: theme.colors.primary })}> + some other text +
) ``` diff --git a/site/plugins/gatsby-remark-live-code/index.js b/site/plugins/gatsby-remark-live-code/index.js index ca216ffc7..11e4c0f7e 100644 --- a/site/plugins/gatsby-remark-live-code/index.js +++ b/site/plugins/gatsby-remark-live-code/index.js @@ -7,7 +7,11 @@ let livePattern = /^\s*\/\/ @live/ module.exports = ({ markdownAST }) => { visit(markdownAST, `code`, node => { if (node.lang === 'jsx live') { - throw new Error('something has jsx live') + throw new Error( + `The following code block has the language jsx live which is no longer allowed:\n${ + node.value + }` + ) } if ( node.lang === 'jsx' && From 3e4604b37f787c2b2322c8d692a0e989ebd2e01e Mon Sep 17 00:00:00 2001 From: mitchellhamilton Date: Tue, 28 Aug 2018 17:59:56 +1000 Subject: [PATCH 29/32] Remove configurable imports as it's not relevant anymore --- docs/configurable-imports.md | 123 ----------------------------------- docs/docs.yaml | 1 - 2 files changed, 124 deletions(-) delete mode 100644 docs/configurable-imports.md diff --git a/docs/configurable-imports.md b/docs/configurable-imports.md deleted file mode 100644 index ef66ad4f7..000000000 --- a/docs/configurable-imports.md +++ /dev/null @@ -1,123 +0,0 @@ ---- -title: "Configurable Imports" ---- - -Because `babel-plugin-emotion` optimizes code by transforming `css` and other calls, `babel-plugin-emotion` needs to know which functions are emotion's and which are not. By default `babel-plugin-emotion` will transform all calls to functions that have the same name as emotion's exports. `babel-plugin-emotion` will transform calls with different names in two circumstances. - -## ES Module Imports - -The first circumstance when `babel-plugin-emotion` will transform different calls is when using [ES Module imports](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import), when using ES Module imports, the local name in a module is will be the one transformed by `babel-plugin-emotion`. - -```js -import something, { css as emotion } from 'react-emotion' - -const classes = emotion` - color: red; -` - -export default something.div` - background: blue; -` -``` - -## Babel Options - -`babel-plugin-emotion` also supports setting the name of emotion's exports via the `importedNames` option. ~~This is useful for targetting a prop other than `css` for processing.~~(this will change to be a seperate option) - - - -```json -{ - "plugins": [ - ["emotion", { "importedNames": { "css": "emotion" } }] - ] -} -``` - -Beware that if you use the babel configuration, you must import as the same name. In the previous example, you would have to use `import { css as emotion } from 'emotion'` and use `emotion` instead of `css`. - -# Use Case - -One use case for this functionality is to migrate incrementally from a styled-jsx application. When compiling the following file with emotion and styled-jsx. - -```js -import styled, { css } from 'react-emotion' - -export default () => ( -
-

only this paragraph will get the style :)

- {/* you can include s here that include - other

s that don't get unexpected styles! */} - -

-) -``` - -The old combination would conflict on the `css` prop that styled-jsx outputs. - -```js -import _JSXStyle from 'styled-jsx/style' -import styled, { css } from 'react-emotion' - -export default () => ( -
-

- only this paragraph will get the style :) -

- {} - <_JSXStyle - styleId={2648947580} - className={ - /*#__PURE__*/ _css( - [], - [], - function createEmotionStyledRules() { - return [ - { - 'p[data-jsx="2648947580"]': { - color: 'red' - } - } - ] - } - ) - } - /> -
-) -``` - -By adding the babel opt config rename as such. - -```js -{ - "plugins": [ - "styled-jsx/babel", - ["emotion", { "importedNames": { "css": "emotion" }}] - ] -} -``` - -We can avoid re-compiling the `css` props and instead use `emotion` for our template literals, etc. - -```js -import _JSXStyle from 'styled-jsx/style' -import styled, { css as emotion } from 'react-emotion' - -export default () => ( -
-

- only this paragraph will get the style :) -

- {} - <_JSXStyle - styleId={2648947580} - css={'p[data-jsx="2648947580"]{color:red}'} - /> -
-) -``` diff --git a/docs/docs.yaml b/docs/docs.yaml index 143a18a3f..4d20de619 100644 --- a/docs/docs.yaml +++ b/docs/docs.yaml @@ -18,7 +18,6 @@ - with-props - theming - labels - - configurable-imports - instances - migrating-to-emotion-10 #- benchmarks From c3c6222fa9d4eb0939ca275ca5cd065ee12ea101 Mon Sep 17 00:00:00 2001 From: mitchellhamilton Date: Wed, 12 Sep 2018 16:09:32 +1000 Subject: [PATCH 30/32] stuff --- docs/docs.yaml | 1 - docs/ssr.md | 24 ++++++++++++++++++++++-- 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/docs/docs.yaml b/docs/docs.yaml index 4d20de619..d3ef97a9b 100644 --- a/docs/docs.yaml +++ b/docs/docs.yaml @@ -13,7 +13,6 @@ - title: Advanced items: - keyframes - - cx - ssr - with-props - theming diff --git a/docs/ssr.md b/docs/ssr.md index b5cadce01..3a8402115 100644 --- a/docs/ssr.md +++ b/docs/ssr.md @@ -8,10 +8,30 @@ Server side rendering works out of the box in emotion 10 and above import { renderToString } from 'react-dom/server' import App from './App' -const html = renderToString() +let html = renderToString() ``` -If you're u +## Using Emotion 10 with the old SSR APIs + +It's still possible to use emotion 10 with the SSR api's in previous versions of emotion. It primarily exists for compatibility reasons. + +```jsx +import createEmotionServer from 'create-emotion-server' +import createCache from '@emotion/cache' +import { renderToString } from 'react-dom/server' + +let cache = createCache() + +let { renderStylesToString } = createEmotionServer(cache) + +let element = ( + + + +) + +let html = renderStylesToString(renderToString(element)) +``` ## API From e057d2e667f584d028c2aab83c7f0f9ca7cf4182 Mon Sep 17 00:00:00 2001 From: mitchellhamilton Date: Mon, 1 Oct 2018 10:22:36 +1000 Subject: [PATCH 31/32] Fix site --- site/plugins/gatsby-remark-live-code/index.js | 2 +- site/src/components/live/worker.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/site/plugins/gatsby-remark-live-code/index.js b/site/plugins/gatsby-remark-live-code/index.js index 11e4c0f7e..846e29315 100644 --- a/site/plugins/gatsby-remark-live-code/index.js +++ b/site/plugins/gatsby-remark-live-code/index.js @@ -24,7 +24,7 @@ module.exports = ({ markdownAST }) => { node.value = escapeGoat.escapeTag`` } diff --git a/site/src/components/live/worker.js b/site/src/components/live/worker.js index aabf1d021..caa675bb9 100644 --- a/site/src/components/live/worker.js +++ b/site/src/components/live/worker.js @@ -2,7 +2,7 @@ importScripts('https://unpkg.com/@babel/standalone@7.0.0/babel.min.js') -const babelPluginEmotion = require('@emotion/babel-plugin-core').default +const babelPluginEmotion = require('babel-plugin-emotion').default global.window = global From 60e3d505e95fb46a8541941a49c0ca3777e616e6 Mon Sep 17 00:00:00 2001 From: mitchellhamilton Date: Mon, 1 Oct 2018 11:34:58 +1000 Subject: [PATCH 32/32] Lots of docs changes --- docs/class-names.md | 33 ++++++++++++++++++ docs/css-prop.md | 6 ++-- docs/docs.yaml | 2 +- docs/keyframes.md | 7 ++-- docs/migrating-to-emotion-10.md | 58 +++++++++++++++++++++++-------- docs/object-styles.md | 7 ++-- docs/styled.md | 23 ++++++++++-- docs/testing.md | 23 +++++++----- docs/theming.md | 10 +++--- docs/with-props.md | 22 ++---------- site/src/components/Playground.js | 2 ++ 11 files changed, 131 insertions(+), 62 deletions(-) create mode 100644 docs/class-names.md diff --git a/docs/class-names.md b/docs/class-names.md new file mode 100644 index 000000000..00febaa0b --- /dev/null +++ b/docs/class-names.md @@ -0,0 +1,33 @@ +--- +title: 'Class Names' +--- + +It can be useful to create to create a className that is not passed to a component, for example if a component accepts a `wrapperClassName` prop or similar. To do this, Emotion exposes a render prop component which you can pass a function which accepts `css` and `cx`. If you have used versions of Emotion prior to Emotion 10 or used vanilla Emotion, the `css` and `cx` functions work exactly like they do in versions. + +```jsx +// @live +import { ClassNames } from '@emotion/core' + +// this might be a component from npm that accepts a wrapperClassName prop +let SomeComponent = props => ( +
+ in the wrapper! +
{props.children}
+
+) + +render( + + {({ css, cx }) => ( + + from children!! + + )} + +) +``` diff --git a/docs/css-prop.md b/docs/css-prop.md index 5deb0b2e6..7cfda6e9d 100644 --- a/docs/css-prop.md +++ b/docs/css-prop.md @@ -1,8 +1,8 @@ --- -title: "The css Prop" +title: 'The css Prop' --- -The primary way to style things in emotion is with the css prop, to use the css prop you need to ...jsx comment +The primary way to style things in emotion is with the css prop, to use the css prop you need to import `jsx` from `@emotion/core` and set it as the jsx pragma by adding a comment like this `/** @jsx jsx */` To pass string styles, you must use `css` which is exported by `@emotion/core`, it can be used as a [tagged template literal](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals) like below. @@ -28,7 +28,7 @@ render( ) ``` -You can also pass objects directly to the css prop, for more usage with objects, go [here](/docs/object-styles.md). +You can also pass objects directly to the css prop, for more usage with objects, look at [the object styles page](/docs/object-styles.md). ```jsx // @live diff --git a/docs/docs.yaml b/docs/docs.yaml index 02a26f403..f261d3229 100644 --- a/docs/docs.yaml +++ b/docs/docs.yaml @@ -17,7 +17,7 @@ - with-props - theming - labels - - instances + - class-names - migrating-to-emotion-10 #- benchmarks diff --git a/docs/keyframes.md b/docs/keyframes.md index 61ab80e9d..f823b8e30 100644 --- a/docs/keyframes.md +++ b/docs/keyframes.md @@ -1,8 +1,8 @@ --- -title: "Keyframes" +title: 'Keyframes' --- -If you need more control over an animation, you can use `keyframes` with the same JS interpolation as `css`. The `keyframes` function takes in a css keyframe definition and returns an animation name so that you can include it in other styles. This is similar to how `css` takes in styles and returns a className that you can use to apply the styles. +If you need more control over an animation, you can use `keyframes` with the same JS interpolation as `css`. The `keyframes` function takes in a css keyframe definition and an object which can be interpolated in styles. ```jsx // @live @@ -30,8 +30,7 @@ const bounce = keyframes` render(
some bouncing text! diff --git a/docs/migrating-to-emotion-10.md b/docs/migrating-to-emotion-10.md index 1cdc9968f..ad4c53530 100644 --- a/docs/migrating-to-emotion-10.md +++ b/docs/migrating-to-emotion-10.md @@ -1,5 +1,5 @@ --- -title: "Migrating to Emotion 10" +title: 'Migrating to Emotion 10' --- Emotion 10 is a large change to Emotion so it requires some changes to your code. Some of the changes can be done automatically via a codemod and the rest can be done incrementally. @@ -55,7 +55,7 @@ The upgrades to emotion 10 are split into two parts. The first part can be done ## Codemoddable -* Change all react-emotion imports so that styled is imported from `@emotion/styled` and all the emotion exports are split into a second import. +- Change all react-emotion imports so that styled is imported from `@emotion/styled` and all the emotion exports are split into a second import. ```jsx import styled, { css } from 'react-emotion' @@ -64,7 +64,7 @@ import styled from '@emotion/styled' import { css } from 'emotion' ``` -* Add a css call to the css prop when a template literal is used. +- Add a css call to the css prop when a template literal is used. ```jsx let element = ( @@ -88,8 +88,8 @@ let element = ( ) ``` -* Add a `jsx` import and set jsx pragma -* Alternatively, use this TODO babel preset +- Add a `jsx` import and set jsx pragma +- Alternatively, use this TODO babel preset ```jsx import { css } from '@emotion/core' @@ -105,28 +105,27 @@ let element = ( ## Manual Steps -* Add compat cache with provider +- Add compat cache with provider + +This step is necessary if you still use `css`, `keyframes` or `injectGlobal` from `emotion`. Once you remove all the usages of them in your app, you can remove this. ```jsx import { render } from 'react-dom' import App from './App' -import * as emotion from 'emotion' -import createCompatCache from '@emotion/compat-cache' -import { Provider } from '@emotion/provider' - -let compatCache = createCompatCache(emotion) +import { cache } from 'emotion' +import { CacheProvider } from '@emotion/provider' render( - + - , + , rootNode ) ``` ## Manual Steps over time -* Change css usage to css prop +- Change css usage to css prop ```jsx import { css } from 'emotion' @@ -151,4 +150,33 @@ let element = ( ) ``` -* TODO: add a render prop component that can add multiple class names at once. +If you have components that accepts props like `wrapperClassName` or etc. you can use the [`ClassNames` component](./class-names.md). + +```jsx +import { css } from 'emotion' +import { SomeComponent } from 'somewhere' +let element = ( + +) + +// ↓ ↓ ↓ ↓ ↓ ↓ + +import { ClassNames } from '@emotion/core' +import { SomeComponent } from 'somewhere' + +let element = ( + + {({ css }) => ( + + )} + +) +``` diff --git a/docs/object-styles.md b/docs/object-styles.md index e23023110..0b8767ced 100644 --- a/docs/object-styles.md +++ b/docs/object-styles.md @@ -1,11 +1,9 @@ --- -title: "Object Styles" +title: 'Object Styles' --- Writing styles with objects is a powerful pattern built directly into the core of emotion. Instead of writing css properties in `kebab-case` like regular css, you write them in `camelCase`, for example `background-color` would be `backgroundColor`. Object styles are especially useful with the css prop because you don't need a css call like with string styles but object styles can also be used with styled. -## ADD LINKS TO THE ABOVE STUFF - ### Examples #### With the css prop @@ -65,7 +63,8 @@ render( } }} > - This is darkorchid.
This is orange
+ This is darkorchid. +
This is orange
) ``` diff --git a/docs/styled.md b/docs/styled.md index 8ab947e24..17544214d 100644 --- a/docs/styled.md +++ b/docs/styled.md @@ -1,8 +1,8 @@ --- -title: "Styled Components" +title: 'Styled Components' --- -`styled` is a way to create React or Preact components that have styles attached to them. It's available from [@emotion/styled](/packages/@emotion/styled) and [TODO](/packages/preact-emotion). `styled` was heavily inspired by [styled-components](https://www.styled-components.com/) and [glamorous](https://glamorous.rocks/) +`styled` is a way to create React or Preact components that have styles attached to them. It's available from [@emotion/styled](/packages/@emotion/styled) and [@emotion/preact-styled](/packages/@emotion/preact-styled). `styled` was heavily inspired by [styled-components](https://www.styled-components.com/) and [glamorous](https://glamorous.rocks/) ### Styling elements and components @@ -154,3 +154,22 @@ render(

This is lightgreen.

) ``` This API was inspired by [glamorous](https://github.com/paypal/glamorous). ❤️ + +### Customizing prop forwarding + +By default, Emotion will pass all props to custom components and only props that are valid html attributes for string tags. This is can be customized by passing a custom `shouldForwardProp` function. You can also use `@emotion/is-prop-valid` to filter out props that are not valid as html attributes, it is what emotion uses internally. + +```jsx +// @live +import isPropValid from '@emotion/is-prop-valid' +import styled from '@emotion/styled' + +const H1 = styled('h1', { + shouldForwardProp: prop => + isPropValid(prop) && prop !== 'color' +})(props => ({ + color: 'hotpink' +})) + +render(

This is lightgreen.

) +``` diff --git a/docs/testing.md b/docs/testing.md index f271e25e1..4540df5e3 100644 --- a/docs/testing.md +++ b/docs/testing.md @@ -1,5 +1,5 @@ --- -title: "Snapshot Testing" +title: 'Snapshot Testing' --- Adding [snapshot tests with Jest](https://facebook.github.io/jest/docs/en/snapshot-testing.html) is a great way to help avoid unintended changes to your app's UI. @@ -31,16 +31,21 @@ Writing a test with `jest-emotion` involves creating a snapshot from the `react- ```jsx import React from 'react' -import * as emotion from 'emotion' -import { createSerializer } from 'jest-emotion' -import styled from 'react-emotion' +import serializer from 'jest-emotion' +/** @jsx jsx */ +import { jsx } from '@emotion/core' import renderer from 'react-test-renderer' -expect.addSnapshotSerializer(createSerializer(emotion)) +expect.addSnapshotSerializer(serializer) -const Button = styled('div')` - color: hotpink; -` +const Button = props => ( +