From a5b7b6a9aac40dc9c6d174f3cdca072e623cb70e Mon Sep 17 00:00:00 2001 From: Oleg Isonen Date: Tue, 21 Apr 2020 11:29:26 +0200 Subject: [PATCH] compile target --- text/0000-cssom.md | 87 +++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 83 insertions(+), 4 deletions(-) diff --git a/text/0000-cssom.md b/text/0000-cssom.md index 97f74088..7c6c4179 100644 --- a/text/0000-cssom.md +++ b/text/0000-cssom.md @@ -14,6 +14,7 @@ While there are many options for authoring CSS, it is super tiresome to convince ### Goals +- CSS scoping (unique selector) - High-performance rendering of static styles via CSSOM. - CSS Rules can be reused across components. - Components have no additional overhead for styling. @@ -57,12 +58,71 @@ That being said using a new prop like `css` is also an option: render(); ``` -### Babel plugin +### A new primitive -Babel plugin can be optional and can enable advanced features like: +Once style or css prop accepts an object that contains CSS, we are essentially creating a new primitive. This primitive can be passed arround, reused, overriden and React will know what to do with it. This opens a number of new doors in the future. + +### Compile target + +This new primitive can be targeted by compilers (babel plugins and co.). In the simplest scenario it will work without any compilation steps. With compilation it would be possible to compile for example CSS modules into something that React can take and render. + +Example of CSS modules being rendered by the new primitive: + +```js +import styles from "./button.css"; +render(); +``` + +What happens right now with CSS loader: + +```js +// button.js +import styles from "./button.css"; +render(); +``` + +Compiles `button.css` to: + +```js +// button.css +const createStyleNode = (id, content) => { + const style = document.createElement("style"); + style.id = id; + style.textContent = content; + document.head.appendChild(style); +}; + +createStyleNode( + "/src/button.css:-css", + ".button-some-suffix {\n color: red;\n}" +); +``` + +Instead, it could compile to something like this: + +```js +// button.css +export default { + button: { + css: ".button-some-suffix {\n color: red;\n}", + id: "/src/button.css:-css", + }, +}; +``` + +and + +```js +// button.js +import styles from "./button.css"; +render(); +``` + +Optionally many other compiler-based things can be enabled: - vendor prefixing -- optimizations +- optimizations for compression +- linting - other preprocessing options e.g. using PostCSS After babel plugin the call into `css` tag function can be removed and the result of the above example can be compiled to: @@ -72,6 +132,25 @@ const buttonStyle = { css: ".css-0 { color: red; }" }; render(); ``` +### Object based styles syntax + +It is still possible to use object based syntax like in [JSS](https://github.com/cssinjs/jss/blob/master/docs/jss-syntax.md) or React Native. It is possible because in the end it's still going to be a CSS string which can be passed to React: + +```js +const styles = StyleSheet.create({ + container: { + flex: 1, + justifyContent: "center", + alignItems: "center", + }, +}); // {container: {css: ".r-d23pfw {flex: 1; justify-content: center; align-items: center;"}} +render( + + Hi + +); +``` + # Drawbacks - we are adding a new area of responsibility to React, which will require more work to maintain it, but hopefully can be parallelized @@ -96,7 +175,7 @@ It is a primitive interface for passing CSS to React to integrate with component # Unresolved questions -- Unique class names generation algorithm +- Specific algorithm for unique class names generation - Composition - Overrides - Dynamic or state-based styling