-
Notifications
You must be signed in to change notification settings - Fork 61
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
docs: add pages about Atomic CSS, build time optimisations #217
Merged
Merged
Changes from all commits
Commits
Show all changes
5 commits
Select commit
Hold shift + click to select a range
8de3420
docs: add pages about Atomic CSS, build time optimisations
layershifter 09aa5cb
Apply suggestions from code review
layershifter 9397d67
fix typo
layershifter 1bbbeae
add enumeration section
layershifter 4f90c93
Update apps/website/docs/react/guides/limitations.md
layershifter File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
diff --git a/lib/Mermaid.mjs b/lib/Mermaid.mjs | ||
index 5140cd5e556ede3debb33ae2202f04480b288d2f..204a3f97d590c9a384ed1bdcfcf7b0dc1375c616 100644 | ||
--- a/lib/Mermaid.mjs | ||
+++ b/lib/Mermaid.mjs | ||
@@ -45,7 +45,7 @@ const Mermaid = ({ chart, config: configSrc }) => { | ||
if (typeof window === 'undefined') { | ||
return React.createElement("div", { className: "mermaid", "data-mermaid-src": chart }, chart); | ||
} | ||
- const config = useMemo(() => typeof configSrc === 'string' ? JSON.parse(configSrc) : configSrc, [configSrc]); | ||
+ const config = useMemo(() => typeof configSrc === 'string' ? JSON.parse(configSrc) : configSrc || {}, [configSrc]); | ||
const html = document.querySelector('html'); | ||
const [rerender, setRerender] = useState(false); | ||
const theme = useMemo(() => getTheme(html, config), [config, rerender]); |
5 changes: 5 additions & 0 deletions
5
apps/website/docs/react/ahead-of-time-compilation/_category_.json
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
{ | ||
"label": "Ahead-of-time compilation", | ||
"collapsed": false, | ||
"position": 4 | ||
} |
14 changes: 14 additions & 0 deletions
14
apps/website/docs/react/ahead-of-time-compilation/introduction.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
--- | ||
sidebar_position: 1 | ||
--- | ||
|
||
# Introduction | ||
|
||
While there is nothing wrong with the associated runtime costs of a CSS-in-JS engine, larger and more complex applications might want to optimize for performance. | ||
|
||
Griffel only does the expensive runtime on the first render of the component. This work can be further optimized at build time by pre-computing and transforming styles. | ||
|
||
## What to use? | ||
|
||
- For library developers, please use [Babel preset](/react/ahead-of-time-compilation/with-babel) | ||
- For application developers, please use [Webpack loader](/react/ahead-of-time-compilation/with-webpack) (supports Next.js) |
146 changes: 146 additions & 0 deletions
146
apps/website/docs/react/ahead-of-time-compilation/technical-details.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,146 @@ | ||
--- | ||
sidebar_position: 4 | ||
--- | ||
|
||
# Technical details | ||
|
||
## What is being optimized with AOT (Ahead Of Time) compilation? | ||
|
||
:::info | ||
|
||
Style resolution only needs to happen on the initial render of a component. Therefore, without build time optimization the performance is comparable with the 2nd and consecutive renders. | ||
|
||
It is reasonable to introduce build time optimization if/when it is required. | ||
|
||
::: | ||
|
||
```jsx | ||
import { makeStyles } from '@griffel/react'; | ||
|
||
// 1. Invocation of makeStyles creates a styling hook that will be used inside a component. | ||
const useStyles = makeStyles({ | ||
root: { paddingLeft: '1px', display: 'flex' }, | ||
}); | ||
|
||
function Component() { | ||
// 2. The hook call resolves styles which are injected into the document. | ||
const classes = useStyles(); | ||
|
||
return <div className={classes.root} />; | ||
} | ||
``` | ||
|
||
You can look at the graph below which describes what work is done during style resolution: | ||
|
||
```mermaid | ||
stateDiagram-v2 | ||
direction LR | ||
|
||
INVOKE_USE_STYLES: useStyles() invocation | ||
COMPUTE_RTL_STYLES: Compute RTL styles | ||
COMPUTE_CSS_CLASSES: Compute CSS classes | ||
COMPUTE_CSS_RULES: Compute CSS rules | ||
INSERT_TO_DOM: Insert to DOM | ||
|
||
INVOKE_USE_STYLES --> COMPUTE_RTL_STYLES | ||
COMPUTE_RTL_STYLES --> COMPUTE_CSS_CLASSES | ||
COMPUTE_CSS_CLASSES --> COMPUTE_CSS_RULES | ||
COMPUTE_CSS_RULES --> INSERT_TO_DOM | ||
|
||
note right of INVOKE_USE_STYLES | ||
{ | ||
paddingLeft: '1px', | ||
display: 'flex' | ||
} | ||
end note | ||
note right of COMPUTE_RTL_STYLES | ||
{ | ||
paddingLeft: '1px', | ||
paddingRight: '1px', | ||
display: 'flex' | ||
} | ||
end note | ||
note right of COMPUTE_CSS_CLASSES | ||
{ | ||
paddingLeft: '1px', // .f10xn8zz | ||
paddingRight: '1px', // .f136y8j8 | ||
display: 'flex' // .f22iagw | ||
} | ||
end note | ||
note right of COMPUTE_CSS_RULES | ||
.f10xn8zz { padding-left: 1px } | ||
.f136y8j8 { padding-right: 1px } | ||
.f22iagw { display: flex } | ||
end note | ||
``` | ||
|
||
:::note | ||
|
||
This work only happens once, during first render. | ||
|
||
::: | ||
|
||
The final result before the CSS rules are inserted into DOM can be compiled ahead of time during build time through the methods described above. | ||
Once the styles of our simple example are transformed at build time the resulting bundle contains a result similar to what is in our diagram. | ||
|
||
The actual runtime code of `makeStyles` is completely stripped from the bundle and replaced with a lightweight function (`__styles`) that simply concatenates the CSS classes and inserts them to DOM. | ||
|
||
```jsx | ||
const useStyles = __styles( | ||
{ | ||
root: { | ||
mc9l5x: 'f22iagw', | ||
uwmqm3: ['f10xn8zz', 'f136y8j8'], | ||
}, | ||
}, | ||
{ | ||
d: ['.f22iagw{display:flex;}', '.f10xn8zz{padding-left:1px;}', '.f136y8j8{padding-right:1px;}'], | ||
}, | ||
); | ||
|
||
function Component() { | ||
const classes = useStyles(); | ||
|
||
return <div className={classes.root} />; | ||
} | ||
``` | ||
|
||
## Module evaluation process | ||
|
||
Let's consider the following scenario: | ||
|
||
```js | ||
// constants.js | ||
export const PADDING_TOKEN = '1px'; | ||
``` | ||
|
||
```js | ||
// common.js | ||
export const commonStyles = () => ({ | ||
display: 'flex', | ||
justifyContent: 'center', | ||
alignItems: 'center', | ||
}); | ||
``` | ||
|
||
```js | ||
// styles.js | ||
import { makeStyles } from '@griffel/react'; | ||
import { PADDING_TOKEN } from './constants'; | ||
import { commonStyles } from './common'; | ||
|
||
const useStyles = makeStyles({ | ||
root: { paddingLeft: PADDING_TOKEN, ...commonStyles() }, | ||
}); | ||
``` | ||
|
||
It's perfectly fine, and even recommended to reuse common tokens and create style helpers across an application. | ||
It's one of the main benefits of using CSS-in-JS. | ||
|
||
However, this means that the build time transforms which are described above are not trivial to compute because code needs to be evaluated to know what styles to transform. | ||
In the example above, in order to transform the `styles.js` file, the code needs to be executed/evaluated by importing the extra modules that it depends on (`constants.js` and `common.js`). | ||
|
||
Griffel uses style evaluation from [Linaria](https://linaria.dev/). | ||
The build-time evaluation happens as a part of the Babel transforms in Griffel. All styles that require evaluation will be batched and done in single evaluation context. | ||
Linaria's Babel config is separate to any config used by the application. | ||
Therefore, additional language features may require [extra configuration](/react/ahead-of-time-compilation/with-babel#configuration). |
41 changes: 41 additions & 0 deletions
41
apps/website/docs/react/ahead-of-time-compilation/with-babel.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
--- | ||
sidebar_position: 3 | ||
--- | ||
|
||
import Tabs from '@theme/Tabs'; | ||
import TabItem from '@theme/TabItem'; | ||
|
||
# With Babel | ||
|
||
## Install | ||
|
||
<Tabs> | ||
<TabItem value="yarn" label="Yarn"> | ||
|
||
```shell | ||
yarn add --dev @griffel/babel-preset | ||
``` | ||
|
||
</TabItem> | ||
<TabItem value="npm" label="NPM"> | ||
|
||
```shell | ||
npm install --save-dev @griffel/babel-preset | ||
``` | ||
|
||
</TabItem> | ||
</Tabs> | ||
|
||
## Usage | ||
|
||
Modify `.babelrc` to include: | ||
|
||
```json | ||
{ | ||
"presets": ["@griffel"] | ||
} | ||
``` | ||
|
||
## Configuration | ||
|
||
Please check [the README](https://github.com/microsoft/griffel/tree/main/packages/babel-preset) of `@griffel/babel-preset` to check how to configure module evaluation and imports. |
130 changes: 130 additions & 0 deletions
130
apps/website/docs/react/ahead-of-time-compilation/with-webpack.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,130 @@ | ||
--- | ||
sidebar_position: 2 | ||
--- | ||
|
||
import Tabs from '@theme/Tabs'; | ||
import TabItem from '@theme/TabItem'; | ||
|
||
# With Webpack | ||
|
||
## Install | ||
|
||
<Tabs> | ||
<TabItem value="yarn" label="Yarn"> | ||
|
||
```shell | ||
yarn add --dev @griffel/webpack-loader | ||
``` | ||
|
||
</TabItem> | ||
<TabItem value="npm" label="NPM"> | ||
|
||
```shell | ||
npm install --save-dev @griffel/webpack-loader | ||
``` | ||
|
||
</TabItem> | ||
</Tabs> | ||
|
||
## Usage | ||
|
||
Webpack documentation: [Loaders](https://webpack.js.org/loaders/) | ||
|
||
Within your webpack configuration object, you'll need to add the `@griffel/webpack-loader` to the list of modules, like so: | ||
|
||
```js | ||
module.exports = { | ||
module: { | ||
rules: [ | ||
{ | ||
test: /\.(js|jsx)$/, | ||
exclude: /node_modules/, | ||
use: { | ||
loader: '@griffel/webpack-loader', | ||
}, | ||
}, | ||
|
||
// If your project uses TypeScript | ||
{ | ||
test: /\.(ts|tsx)$/, | ||
exclude: /node_modules/, | ||
use: { | ||
loader: '@griffel/webpack-loader', | ||
options: { | ||
babelOptions: { | ||
presets: ['@babel/preset-typescript'], | ||
}, | ||
}, | ||
}, | ||
}, | ||
], | ||
}, | ||
}; | ||
``` | ||
|
||
While the loader itself has a short circuit to avoid processing (invoking Babel transforms) it's better to reduce the scope of processed files. For example, you can enforce a restriction to have `makeStyles()` calls only in `.styles.ts` files: | ||
|
||
```js | ||
module.exports = { | ||
module: { | ||
rules: [ | ||
{ | ||
test: /\.styles.ts$/, | ||
exclude: /node_modules/, | ||
use: { | ||
loader: '@griffel/webpack-loader', | ||
options: { | ||
babelOptions: { | ||
presets: ['@babel/preset-typescript'], | ||
}, | ||
}, | ||
}, | ||
}, | ||
], | ||
}, | ||
}; | ||
``` | ||
|
||
## Usage with Next.js | ||
|
||
Next.js lets users [tweak Webpack's config](https://nextjs.org/docs/api-reference/next.config.js/custom-webpack-config) so the same options are applicable to its config. | ||
|
||
```js | ||
// next.config.js | ||
|
||
module.exports = { | ||
webpack: (config, { buildId, dev, isServer, defaultLoaders, nextRuntime, webpack }) => { | ||
config.module.rules.unshift({ | ||
test: /\.(js|jsx)$/, | ||
exclude: /node_modules/, | ||
use: [ | ||
{ | ||
loader: '@griffel/webpack-loader', | ||
}, | ||
], | ||
}); | ||
|
||
// If your project uses TypeScript | ||
config.module.rules.unshift({ | ||
test: /\.(ts|tsx)$/, | ||
exclude: /node_modules/, | ||
use: [ | ||
{ | ||
loader: '@griffel/webpack-loader', | ||
options: { | ||
babelOptions: { | ||
presets: ['next/babel'], | ||
}, | ||
}, | ||
}, | ||
], | ||
}); | ||
|
||
return config; | ||
}, | ||
}; | ||
``` | ||
|
||
## Configuration | ||
|
||
Please check [the README](https://github.com/microsoft/griffel/tree/main/packages/webpack-loader) of `@griffel/webpack-loader` to check how to configure module evaluation and imports. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
{ | ||
"label": "CSS extraction 🚧", | ||
"collapsed": false, | ||
"position": 5 | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
--- | ||
sidebar_position: 1 | ||
--- | ||
|
||
# Introduction | ||
|
||
:::caution | ||
|
||
This technology is experimental, please [report any issues](https://github.com/microsoft/griffel/issues) if found. | ||
|
||
::: | ||
|
||
While [ahead-of-time compilation allows](/react/ahead-of-time-compilation/introduction) performs optimization to reduce runtime work, the goal of CSS extraction is to remove runtime insertion to DOM and produce CSS stylesheets. | ||
|
||
## When to use it? | ||
|
||
It's designed to be used **only** in applications. | ||
|
||
## How it works | ||
|
||
The tool relies on assets transformed by [ahead-of-time compilation](/react/ahead-of-time-compilation/introduction), its usage is a **prerequisite**. CSS extraction transforms code to remove generated CSS from JavaScript files and create CSS assets. | ||
|
||
_Currently, all CSS rules will be extracted to a single CSS file i.e. [code splitting](https://webpack.js.org/guides/code-splitting/) for extracted CSS **will not work**._ |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
sjwall/mdx-mermaid#67