mirror of
https://github.com/zoriya/react-native-web.git
synced 2026-05-24 07:09:03 +00:00
[change] StyleSheet: support code-splitting / export smaller API
Quick-fix for code-splitting support by updating the rendered style sheet in place. Reduce the API to `create`, as the rest is now internal to the framework. Fix #34
This commit is contained in:
@@ -110,7 +110,8 @@ const Html = () => (
|
||||
)
|
||||
```
|
||||
|
||||
Rendering on the client automatically includes your app styles:
|
||||
Rendering on the client automatically includes your app styles and supports
|
||||
progressive app loading (i.e. code-splitting / lazy bundle loading):
|
||||
|
||||
```js
|
||||
// client.js
|
||||
|
||||
+17
-24
@@ -37,24 +37,10 @@ Use styles:
|
||||
</View>
|
||||
```
|
||||
|
||||
Render styles on the server or in the browser:
|
||||
|
||||
```js
|
||||
StyleSheet.renderToString()
|
||||
```
|
||||
|
||||
## Methods
|
||||
|
||||
**create**(obj: {[key: string]: any})
|
||||
|
||||
**destroy**()
|
||||
|
||||
Clears all style information.
|
||||
|
||||
**renderToString**()
|
||||
|
||||
Renders a CSS Style Sheet.
|
||||
|
||||
## About
|
||||
|
||||
### Strategy
|
||||
@@ -71,9 +57,9 @@ CSS](https://speakerdeck.com/vjeux/react-css-in-js):
|
||||
6. Non-deterministic resolution
|
||||
7. Breaking isolation
|
||||
|
||||
The strategy also minimizes the amount of generated CSS, making it more viable
|
||||
to inline the style sheet when pre-rendering pages on the server. There is one
|
||||
unique selector per unique style _declaration_.
|
||||
The strategy minimizes the amount of generated CSS, making it viable to inline
|
||||
the style sheet when pre-rendering pages on the server. There is one unique
|
||||
selector per unique style _declaration_.
|
||||
|
||||
```js
|
||||
// definition
|
||||
@@ -88,7 +74,7 @@ unique selector per unique style _declaration_.
|
||||
}
|
||||
}
|
||||
|
||||
// css
|
||||
// css output
|
||||
//
|
||||
// .a { color: gray; }
|
||||
// .b { font-size: 2rem; }
|
||||
@@ -130,16 +116,17 @@ In production the class names are obfuscated.
|
||||
(CSS libraries like [Atomic CSS](http://acss.io/),
|
||||
[Basscss](http://www.basscss.com/), [SUIT CSS](https://suitcss.github.io/), and
|
||||
[tachyons](http://tachyons.io/) are attempts to limit style scope and limit
|
||||
style sheet growth in a similar way. But they're CSS utility libraries, each with a
|
||||
particular set of classes and features to learn. All of them require developers
|
||||
to manually connect CSS classes for given styles.)
|
||||
style sheet growth in a similar way. But they're CSS utility libraries, each
|
||||
with a particular set of classes and features to learn. And all of them require
|
||||
developers to manually connect CSS classes for given styles.)
|
||||
|
||||
### Reset
|
||||
|
||||
React Native for Web includes a very small CSS reset taken from
|
||||
[normalize.css](https://necolas.github.io/normalize.css/). It removes unwanted
|
||||
User Agent styles from (pseudo-)elements beyond the reach of React (e.g.,
|
||||
`html`, `body`) or inline styles (e.g., `::-moz-focus-inner`).
|
||||
[normalize.css](https://necolas.github.io/normalize.css/) – **you do not need
|
||||
to include normalize.css**. It removes unwanted User Agent styles from
|
||||
(pseudo-)elements beyond the reach of React (e.g., `html`, `body`) or inline
|
||||
styles (e.g., `::-moz-focus-inner`).
|
||||
|
||||
```css
|
||||
html {
|
||||
@@ -162,4 +149,10 @@ input[type="search"]::-webkit-search-cancel-button,
|
||||
input[type="search"]::-webkit-search-decoration {
|
||||
-webkit-appearance: none;
|
||||
}
|
||||
|
||||
ol,
|
||||
ul,
|
||||
li {
|
||||
list-style:none
|
||||
}
|
||||
```
|
||||
|
||||
+1
-1
@@ -7,7 +7,7 @@
|
||||
"dist"
|
||||
],
|
||||
"scripts": {
|
||||
"build": "rm -rf ./dist && mkdir dist && babel src -d dist --ignore src/**/__tests__,src/modules/specHelpers",
|
||||
"build": "rm -rf ./dist && mkdir dist && babel src -d dist --ignore **/__tests__,src/modules/specHelpers",
|
||||
"build:umd": "webpack --config config/webpack.config.js --sort-assets-by --progress",
|
||||
"examples": "webpack-dev-server --config config/webpack.config.example.js --inline --hot --colors --quiet",
|
||||
"lint": "eslint config examples src",
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
/* eslint-env mocha */
|
||||
|
||||
import * as utils from '../modules/specHelpers'
|
||||
import assert from 'assert'
|
||||
import React from '..'
|
||||
|
||||
|
||||
+1
-1
@@ -15,7 +15,7 @@ import Touchable from './components/Touchable'
|
||||
import View from './components/View'
|
||||
|
||||
const renderStyle = () => {
|
||||
return `<style id='react-stylesheet'>${StyleSheet.renderToString()}</style>`
|
||||
return `<style id='react-stylesheet'>${StyleSheet._renderToString()}</style>`
|
||||
}
|
||||
|
||||
const render = (element, container, callback) => {
|
||||
|
||||
@@ -8,24 +8,40 @@ const styles = { root: { borderWidth: 1 } }
|
||||
|
||||
suite('modules/StyleSheet', () => {
|
||||
setup(() => {
|
||||
StyleSheet.destroy()
|
||||
StyleSheet._destroy()
|
||||
})
|
||||
|
||||
test('create', () => {
|
||||
assert.equal(StyleSheet.create(styles), styles)
|
||||
})
|
||||
suite('create', () => {
|
||||
const div = document.createElement('div')
|
||||
|
||||
test('renderToString', () => {
|
||||
StyleSheet.create(styles)
|
||||
assert.equal(
|
||||
StyleSheet.renderToString(),
|
||||
`${resetCSS}\n${predefinedCSS}\n` +
|
||||
`/* 4 unique declarations */\n` +
|
||||
`.borderBottomWidth\\:1px{border-bottom-width:1px;}\n` +
|
||||
`.borderLeftWidth\\:1px{border-left-width:1px;}\n` +
|
||||
`.borderRightWidth\\:1px{border-right-width:1px;}\n` +
|
||||
`.borderTopWidth\\:1px{border-top-width:1px;}`
|
||||
)
|
||||
setup(() => {
|
||||
document.body.appendChild(div)
|
||||
StyleSheet.create(styles)
|
||||
div.innerHTML = `<style id='react-stylesheet'>${StyleSheet._renderToString()}</style>`
|
||||
})
|
||||
|
||||
teardown(() => {
|
||||
document.body.removeChild(div)
|
||||
})
|
||||
|
||||
test('returns styles object', () => {
|
||||
assert.equal(StyleSheet.create(styles), styles)
|
||||
})
|
||||
|
||||
test('updates already-rendered style sheet', () => {
|
||||
StyleSheet.create({ root: { color: 'red' } })
|
||||
|
||||
assert.equal(
|
||||
document.getElementById('react-stylesheet').textContent,
|
||||
`${resetCSS}\n${predefinedCSS}\n` +
|
||||
`/* 5 unique declarations */\n` +
|
||||
`.borderBottomWidth\\:1px{border-bottom-width:1px;}\n` +
|
||||
`.borderLeftWidth\\:1px{border-left-width:1px;}\n` +
|
||||
`.borderRightWidth\\:1px{border-right-width:1px;}\n` +
|
||||
`.borderTopWidth\\:1px{border-top-width:1px;}\n` +
|
||||
`.color\\:red{color:red;}`
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
test('resolve', () => {
|
||||
@@ -34,4 +50,17 @@ suite('modules/StyleSheet', () => {
|
||||
StyleSheet.create(styles)
|
||||
assert.deepEqual(StyleSheet.resolve(props), expected)
|
||||
})
|
||||
|
||||
test('_renderToString', () => {
|
||||
StyleSheet.create(styles)
|
||||
assert.equal(
|
||||
StyleSheet._renderToString(),
|
||||
`${resetCSS}\n${predefinedCSS}\n` +
|
||||
`/* 4 unique declarations */\n` +
|
||||
`.borderBottomWidth\\:1px{border-bottom-width:1px;}\n` +
|
||||
`.borderLeftWidth\\:1px{border-left-width:1px;}\n` +
|
||||
`.borderRightWidth\\:1px{border-right-width:1px;}\n` +
|
||||
`.borderTopWidth\\:1px{border-top-width:1px;}`
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -13,6 +13,24 @@ const initialState = { classNames: predefinedClassNames }
|
||||
const options = { obfuscateClassNames: process.env.NODE_ENV === 'production' }
|
||||
const createStore = () => new Store(initialState, options)
|
||||
let store = createStore()
|
||||
let isRendered = false
|
||||
|
||||
/**
|
||||
* Destroy existing styles
|
||||
*/
|
||||
const _destroy = () => {
|
||||
store = createStore()
|
||||
isRendered = false
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the styles as a CSS style sheet
|
||||
*/
|
||||
const _renderToString = () => {
|
||||
const css = store.toString()
|
||||
isRendered = true
|
||||
return `${resetCSS}\n${predefinedCSS}\n${css}`
|
||||
}
|
||||
|
||||
/**
|
||||
* Process all unique declarations
|
||||
@@ -33,24 +51,20 @@ const create = (styles: Object): Object => {
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
// update the style sheet in place
|
||||
if (isRendered) {
|
||||
const stylesheet = document.getElementById('react-stylesheet')
|
||||
if (stylesheet) {
|
||||
stylesheet.textContent = _renderToString()
|
||||
} else if (process.env.NODE_ENV !== 'production') {
|
||||
console.error('ReactNativeWeb: cannot find "react-stylesheet" element')
|
||||
}
|
||||
}
|
||||
|
||||
return styles
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroy existing styles
|
||||
*/
|
||||
const destroy = () => {
|
||||
store = createStore()
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the styles as a CSS style sheet
|
||||
*/
|
||||
const renderToString = () => {
|
||||
const css = store.toString()
|
||||
return `${resetCSS}\n${predefinedCSS}\n${css}`
|
||||
}
|
||||
|
||||
/**
|
||||
* Accepts React props and converts inline styles to single purpose classes
|
||||
* where possible.
|
||||
@@ -81,8 +95,8 @@ const resolve = ({ className = '', style = {} }) => {
|
||||
}
|
||||
|
||||
export default {
|
||||
_destroy,
|
||||
_renderToString,
|
||||
create,
|
||||
destroy,
|
||||
renderToString,
|
||||
resolve
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user