guui
Frontend rendering framework for theguardian.com.
Slack channel: #dotcom-future
Requirements
Install
$ npm install @guardian/guui
Configure
h()
for all JSX modules
Provide $ npm install babel-plugin-provide-modules
{
"plugins": [
["provide-modules", {
"@guardian/guui": ["h"]
}]
]
}
Use Webpack loaders
// webpack.config.js
module.exports = {
// ...
resolveLoader: {
modules: [
path.resolve('node_modules', '@guardian', 'guui', 'dist', 'lib', 'loaders'),
'node_modules'
]
},
module: {
rules: [
{
test: /\.svg$/,
use: ['guui-svg-loader']
},
{
test: /\.css$/,
use: ['guui-css-loader']
}
]
}
}
API
JSX
Components are written using JSX
export default () => <h1>Hello World</h1>
Styling
You may declare your styles in separate *.css
files. Under the hood, guui
generates CSS using
Emotion. As a result, you may define your styles using the Emotion API.
// header.css
.heading {
color: ghostwhite;
&:hover {
color: palevioletred;
}
}
// header.jsx
import { heading } from './header.css'
export default () => <h1 style={heading}>Hello World</h1>
Exentions to standard CSS
Some Sass-like features are available to use in .css
files.
Custom property and media queries
Both of these are transpiled to more compatible CSS in compilation:
@custom-media --unusual-breakpoint (max-width: 30em);
:root {
--my-value: 20px;
}
.big {
font-size: var(--my-value);
@media (--unusual-breakpoint) {
color: hotpink;
}
}
@apply
To avoid too much duplicating of rules in some circumstances, the @apply
rule can be used:
:root {
--button: {
border-radius: 28px;
};
--news-colour: blue;
}
.button {
@apply --button;
}
.button--news {
@apply --button;
background-color: --news-colour;
}
SVGs
import MySVG from './my-svg.svg';
SVGs are loaded using guui-svg-loader.js
, which runs them through svgo
then returns
them as JSX objects.
You can use the JSXified SVG as a normal JSX import:
<!-- my-svg.svg -->
<svg xmlns="http://www.w3.org/2000/svg" width="320" height="60"><path ... /></svg>
import MySVG from './my-svg.svg'
export default () => <div><MySVG /></div>
// <div><svg width="320" height="60"><path ... /></svg></div>
Styling the SVG
<MySVG style={{ fill: "red" }} />
import MySVG from './my-svg.svg'
const style = {
color: 'red'
}
export default () => <MySVG style={style} />
// <svg style="color: red"><path ... /></svg>
Rendering
Server
import { server } from '@guardian/guui';
import Application from './components/app';
const app = server();
export const render = (props) => {
const body = app.renderToString(<Application {...props} />);
const css = app.extractCriticalCss(body);
return `
<!DOCTYPE html>
<html>
<head>
${css}
<script>
window.props = ${JSON.stringify(props)};
</script>
</head>
<body>
${body}
</body>
</html>
`.trim();
};
Browser
import { render } from '@guardian/guui';
const container = document.body;
const renderApp = () => {
const props = window.props;
if (container) {
render(
<Application {...props} />,
container.parentElement,
container
);
}
};
renderApp();