styledux
A new approach of isomorphic css resolution with webpack, css-loader(css-modules) powered by redux.
IT'S style-dux, not styled-ux.
Status: alpha version
Installation
For npm
npm install @styledux/loader --save-dev
npm install @styledux/core @styledux/adapter-default --save
For yarn
yarn add @styledux/loader --dev
yarn add @styledux/core @styledux/adapter-default
Configuration
Add @styledux/loader
before css-loader
to your webpack configuration.
module: {
rules: [
{
test: /\.css$/,
use: [
{
loader: '@styledux/loader'
},
{
loader: 'css-loader',
options: {
modules: true,
importLoaders: 1,
localIdentName: isProd ? '_[hash:base64:8]' : '[name]__[local]___[hash:base64:5]',
minimize: target === 'client' && isProd,
sourceMap: !isProd,
}
},
{
loader: 'postcss-loader'
}
]
}
]
}
@styledux/loader
is simply to export locals that generated from css-loader and wrap original css contents with a function_()
.
@withStyle
Decorate react components with ExampleComponent.css
.Block {
background-color: green;
display: block;
left: 0;
opacity: 0;
position: fixed;
width: 200px;
height: 200px;
}
.SubModule {
background-color: blue;
display: block;
width: 20px;
height: 20px;
}
ExampleComponent.js
import { withStyle } from '@styledux/core'
import style from './ExampleComponent.css';
@withStyle(style)
export class ExampleComponent extends React.Component {
render() {
return (
<div className={style.Block}>
<div className={style.SubModule} />
</div>
);
}
}
For stateless component
ExampleStatelessComponent.js
import { withStyle } from '@styledux/core'
import style from './ExampleComponent.css';
function ExampleStatelessComponent() {
return (
<div className={style.Block}>
<div className={style.SubModule} />
</div>
);
}
const component = withStyle(style)(ExampleStatelessComponent);
export default component;
Server side rendering
import ReactDOMServer from 'react-dom/server';
import { createStyleduxStore, StyleduxProvider } from '@styledux/core';
import { mapStateOnServer } from '@styledux/adapter-default';
export function renderHTML(App) {
const styleStore = createStyleduxStore();
const appHtml = ReactDOMServer.renderToString(
<StyleduxProvider store={styleStore}>
<App />
</StyleduxProvider>
);
const styles = mapStateOnServer(styleStore);
return [
'<!doctype html><html><head>',
...styles,
'<style id="main_css"></style>', // for options.insertInto on client side
// You can also add other styles which have higher priority
'</head><body><div id="app">',
appHtml,
'</div></body></html>',
].join('');
}
Client Side Rendering
import ReactDOM from 'react-dom';
import { createStyleduxStore, StyleduxProvider } from '@styledux/core';
import { handleStateChangeOnClient } from '@styledux/adapter-default';
function rehydrateApp(App) {
ReactDOM.hydrate(
<StyleduxProvider store={createStyleduxStore(handleStateChangeOnClient({ insertAt: '#main_css' }))}>
<App />
</StyleduxProvider>,
document.getElementById('app')
);
}
API
Package: @styledux/core
<StyleduxProvider store>
See https://github.com/reactjs/react-redux/blob/master/docs/api.md#provider-store
Props
-
store
: Plain redux store that created withcreateStyleduxStore()
children
Example:
import { StyleduxProvider } from '@styledux/core';
ReactDOM.render(
<StyleduxProvider store={styleStore}>
{your_app_component}
</StyleduxProvider>,
rootElement
)
createStyleduxStore(...middlewares)
Arguments
- middlewares: Plain redux middlewares.
You can create your own middlewares to handle state changes.
handleStateChangeOnClient(options)
of @styledux/adapter-default
creates a middleware that mount styles like style-loader
.
Example
On server:
import { createStyleduxStore } from '@styledux/core';
const styleStore = createStyleduxStore();
On client:
import { createStyleduxStore } from '@styledux/core';
import { handleStateChangeOnClient } from '@styledux/adapter-default';
const middleware = handleStateChangeOnClient({ insertAt: '#main_css' });
const styleStore = createStyleduxStore(middleware);
withStyle(style)
Decorate a react component with style. It monitors render()
of react component.
It dispatches an ADD_STYLE
action when render()
returned non-empty result, and dispatches a REMOVE_STYLE
action when render()
returned null
.
Arguments
- style (Object | Array): style object that was generated by
@styledux/loader
.
Example
import { withStyle } from '@styledux/core';
import style1 from './style1.css';
import style2 from './style2.css';
@withStyle([style1, style2])
class ExampleComponent extends React.Component {
}
import { withStyle } from '@styledux/core';
import style from './style.css';
@withStyle(style)
class ExampleComponent extends React.Component {
}
Package: @styledux/loader
Use it before css-loader in webpack configuration.
Package: @styledux/adapter-default
The default adapter for styledux.
Make sure mapStateOnServer(options)
and handleStateChangeOnClient(options)
use the same options.
options:
-
attrs
(Object): Add custom attrs to<style></style>
(default: {}). -
transform
(Function): Transform/Conditionally load CSS by passing a transform/condition function. (**default: (obj) => obj **) -
transformId
(Function): Transform webpack module id to element id. (**default: ** see getOptions ) -
insertAt
(null|String): Inserts <style></style> at the given position. Different fromstyle-loader
. (default: null) -
insertInto
(String): Inserts <style></style> into the given position. (default: )
mapStateOnServer(styleduxStore, options)
Generate <style>
from styleduxStore on server side.
Example
const styleStore = createStyleduxStore();
const content = ReactDOMServer.renderToString(
<StyleduxProvider store={styleStore}>
<App />
</StyleduxProvider>
);
const styles = mapStateOnServer(styleStore);
const html = [
'<!doctype html><html><head>',
...styles,
'<style id="main_css"></style>', // The position for insert_at
'<link rel="stylesheet" type="text/css" href="custom_theme.css">', // Other styles that may have higher priority
'<script src="main.js" defer></script>',
'</head><body><div id="app">',
content,
'</div></body></html>'
].join('');
handleStateChangeOnClient(options)
Handling state changes and mount styles dynamically on client side.
Example
const styleStore = createStyleduxStore(handleStateChangeOnClient({
insertAt: '#main_css'
}));
const app = (
<StyleduxProvider store={styleStore}>
<App />
</StyleduxProvider>
);
ReactDOM.hydrate(app, document.getElementById('app'));
LICENSE
MIT