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

Create Post “getting-started-with-emotion-and-gatsby” #74

Merged
merged 7 commits into from Jan 26, 2019
@@ -0,0 +1,275 @@
---
title: Getting started with Emotion and Gatsby
date: 2019-01-26T03:57:21.781Z
tags:
- css-in-js
- javascript
- gatsby
- emotion
---
[Emotion](https://emotion.sh/) is a library for authoring and composing CSS rulesets in a performant way. Here's how to get started using it with [Gatsby](https://www.gatsbyjs.org/).

First, we'll boot up a fresh gatsby site using the default starter and install the Gatsby plugin (as well as Emotion itself).

```shell
gatsby new my-emotion-site
yarn add gatsby-plugin-emotion @emotion/core
```

Then we need to add `gatsby-plugin-emotion` to our `gatsby-config.js`. We'll add it at the top of our plugins list.

```js
module.exports = {
siteMetadata: {
title: `Gatsby Default Starter`,
description: `Kick off your next, great Gatsby project with this default starter. This barebones starter ships with the main Gatsby configuration files you might need.`,
author: `@gatsbyjs`,
},
plugins: [
`gatsby-plugin-emotion`,
`gatsby-plugin-react-helmet`,
{
resolve: `gatsby-source-filesystem`,
options: {
name: `images`,
path: `${__dirname}/src/images`,
},
},
`gatsby-transformer-sharp`,
`gatsby-plugin-sharp`,
{
resolve: `gatsby-plugin-manifest`,
options: {
name: `gatsby-starter-default`,
short_name: `starter`,
start_url: `/`,
background_color: `#663399`,
theme_color: `#663399`,
display: `minimal-ui`,
icon: `src/images/gatsby-icon.png`, // This path is relative to the root of the site.
},
},
// this (optional) plugin enables Progressive Web App + Offline functionality
// To learn more, visit: https://gatsby.app/offline
// 'gatsby-plugin-offline',
],
}
```

We can run `yarn develop` to run our new Gatsby site. The output will look something like this.

```
➜ yarn develop
yarn run v1.13.0
$ gatsby develop
success open and validate gatsby-configs — 0.009 s
success load plugins — 0.232 s
success onPreInit — 0.515 s
success delete html and css files from previous builds — 0.007 s
success initialize cache — 0.013 s
success copy gatsby files — 0.078 s
success onPreBootstrap — 0.008 s
success source and transform nodes — 0.064 s
success building schema — 0.333 s
success createPages — 0.001 s
success createPagesStatefully — 0.047 s
success onPreExtractQueries — 0.004 s
success update schema — 0.167 s
success extract queries from components — 0.137 s
success run graphql queries — 0.200 s — 8/8 40.32 queries/second
success write out page data — 0.004 s
success write out redirect data — 0.001 s
Generating image thumbnails [==============================] 6/6 0.2 secs 100%

info bootstrap finished - 5.413 s

⡀ onPostBootstrapdone generating icons for manifest
success onPostBootstrap — 0.212 s
DONE Compiled successfully in 4075ms 8:18:42 PM


You can now view gatsby-starter-default in the browser.

http://localhost:8000/

View GraphiQL, an in-browser IDE, to explore your site's data and schema

http://localhost:8000/___graphql

Note that the development build is not optimized.
To create a production build, use gatsby build

ℹ 「wdm」:
ℹ 「wdm」: Compiled successfully.
>
```

## Converting to Emotion

The default starter comes with no external styling implementation. There are no CSS files and no other libraries to implement styling. If we look at our index page at `src/pages/index.js`, we see the default starter uses inline styles.

```js
import React from 'react'
import { Link } from 'gatsby'

import Layout from '../components/layout'
import Image from '../components/image'
import SEO from '../components/seo'

const IndexPage = () => (
<Layout>
<SEO title="Home" keywords={[`gatsby`, `application`, `react`]} />
<h1>Hi people</h1>
<p>Welcome to your new Gatsby site.</p>
<p>Now go build something great.</p>
<div style={{ maxWidth: `300px`, marginBottom: `1.45rem` }}>
<Image />
</div>
<Link to="/page-2/">Go to page 2</Link>
</Layout>
)

export default IndexPage
```

The result of this page (specifically the `div` containing inline styles and the image) is more complex than you might think because the image is processed into many different resolutions automatically by Gatsby. We'll ignore most of the output and focus on the root `div` with the inline styles. We can see that they compile to a `style` attribute.

```html
<div style="max-width: 300px; margin-bottom: 1.45rem;">
<div
class=" gatsby-image-wrapper"
style="position: relative; overflow: hidden;"
>
<div style="width: 100%; padding-bottom: 100%;"></div>
<img
src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAIAAAAC64paAAAACXBIWXMAAAsSAAALEgHS3X78AAACYklEQVQ4y42Uy28SQRjA+dM8efDmwYN6qF6qiSY+Y/WgQRMibY00TaWNBSRSCraYQtHl/bR0KyxQWCgWWAqU8izl/Sq7rLNsRHlVJpvJtzPfb77nDIOcZHSoqZSrp4+KtXIziubaLRysMCZiCYqOoVnhjNEi8RcztdxxeTzc6VBfT+5O2Vhpb+vw4wMdZ0ppWvP9xzLeJoDNThf2W+Nz1+XzNxQubSToSKKW+BDc+WOnkshhSVgeCiGpViZMEg1oxc26Knt+ae3bEtJTZwzE1kXLccG0+sOOlrcvZXvsczPkITfsa20vwIKnhsh+BnjUarT74Gb13CY7KBVJMv3z4N1NszQYsMWM62HNrCis/GxXn0iYls23uz5LPBcv0bH8hUH2XRoM85ySXv7JBtO87jMIvWq+H5GoYIHCLA1ZxD6Qap3Ak8IKfW7TJ50lK6uP9E6RgndHaODtCJ6Z5RyHfnE7j6gRbcKlCYNSt+rtETHTpUGgEP8FYmdNqd/Mo7aiVWTfuH2L9xASvfxxlqr01EYkrJszvNkgW9bH0OuFr+99m+y9IOeyU6zIp/Hubp/yMEztlzFPwOhdvq+nIoS1JNn4t2sugCmVsDvPe2KKolnZLCxhOcAKQRDDXTQaVi46lqYhIBwHTrl3oWqhMRDtaJge37lOBMKo4tfbqhVX0J7snTsWps8uZWuoOQY6CcjpSIF55UvmqNgr5wUwtV1IVdnXtnSfPEB2qjDNqnvczRl0m+j6Jn5lXb6nAQJqinmN0ZEBj03YLzghY8PnTRz80o/GRJZpOLCb0PM9BN7pvUEjx28V00WUg9jIVwAAAABJRU5ErkJggg=="
alt=""
style="position: absolute; top: 0px; left: 0px; width: 100%; height: 100%; object-fit: cover; object-position: center center; opacity: 0; transition: opacity 0.5s ease 0.5s;"
/><picture
><source
srcset="
/static/6d91c86c0fde632ba4cd01062fd9ccfa/0552a/gatsby-astronaut.png 75w,
/static/6d91c86c0fde632ba4cd01062fd9ccfa/fc3be/gatsby-astronaut.png 150w,
/static/6d91c86c0fde632ba4cd01062fd9ccfa/045aa/gatsby-astronaut.png 300w,
/static/6d91c86c0fde632ba4cd01062fd9ccfa/24f49/gatsby-astronaut.png 450w,
/static/6d91c86c0fde632ba4cd01062fd9ccfa/5497d/gatsby-astronaut.png 600w,
/static/6d91c86c0fde632ba4cd01062fd9ccfa/483e1/gatsby-astronaut.png 800w
"
sizes="(max-width: 300px) 100vw, 300px"/>
<img
alt=""
src="/static/6d91c86c0fde632ba4cd01062fd9ccfa/045aa/gatsby-astronaut.png"
style="position: absolute; top: 0px; left: 0px; width: 100%; height: 100%; object-fit: cover; object-position: center center; opacity: 1; transition: opacity 0.5s ease 0s;"/></picture

><noscript
><picture
><source
srcset="
/static/6d91c86c0fde632ba4cd01062fd9ccfa/0552a/gatsby-astronaut.png 75w,
/static/6d91c86c0fde632ba4cd01062fd9ccfa/fc3be/gatsby-astronaut.png 150w,
/static/6d91c86c0fde632ba4cd01062fd9ccfa/045aa/gatsby-astronaut.png 300w,
/static/6d91c86c0fde632ba4cd01062fd9ccfa/24f49/gatsby-astronaut.png 450w,
/static/6d91c86c0fde632ba4cd01062fd9ccfa/5497d/gatsby-astronaut.png 600w,
/static/6d91c86c0fde632ba4cd01062fd9ccfa/483e1/gatsby-astronaut.png 800w
"
sizes="(max-width: 300px) 100vw, 300px"/>
<img
src="/static/6d91c86c0fde632ba4cd01062fd9ccfa/045aa/gatsby-astronaut.png"
alt=""
style="position:absolute;top:0;left:0;transition:opacity 0.5s;transition-delay:0.5s;opacity:1;width:100%;height:100%;object-fit:cover;object-position:center"/></picture
></noscript>
</div>
</div>
```

Most people want to keep inline styles to a minimum unless they're performing an intensive animation on one of the values, so let's convert this to use Emotion. The only change we need to make in this file is to swap `styles` for `css`.

```js
import React from 'react'
import { Link } from 'gatsby'

import Layout from '../components/layout'
import Image from '../components/image'
import SEO from '../components/seo'

const IndexPage = () => (
<Layout>
<SEO title="Home" keywords={[`gatsby`, `application`, `react`]} />
<h1>Hi people</h1>
<p>Welcome to your new Gatsby site.</p>
<p>Now go build something great.</p>
<div css={{ maxWidth: `300px`, marginBottom: `1.45rem` }}>
<Image />
</div>
<Link to="/page-2/">Go to page 2</Link>
</Layout>
)

export default IndexPage
```

Yeah, that's it. Let's take a look at how it renders again.

```html
<div class="css-ehkvu9-IndexPage">
<div
class=" gatsby-image-wrapper"
style="position: relative; overflow: hidden;"
>
<div style="width: 100%; padding-bottom: 100%;"></div>
<img
src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAIAAAAC64paAAAACXBIWXMAAAsSAAALEgHS3X78AAACYklEQVQ4y42Uy28SQRjA+dM8efDmwYN6qF6qiSY+Y/WgQRMibY00TaWNBSRSCraYQtHl/bR0KyxQWCgWWAqU8izl/Sq7rLNsRHlVJpvJtzPfb77nDIOcZHSoqZSrp4+KtXIziubaLRysMCZiCYqOoVnhjNEi8RcztdxxeTzc6VBfT+5O2Vhpb+vw4wMdZ0ppWvP9xzLeJoDNThf2W+Nz1+XzNxQubSToSKKW+BDc+WOnkshhSVgeCiGpViZMEg1oxc26Knt+ae3bEtJTZwzE1kXLccG0+sOOlrcvZXvsczPkITfsa20vwIKnhsh+BnjUarT74Gb13CY7KBVJMv3z4N1NszQYsMWM62HNrCis/GxXn0iYls23uz5LPBcv0bH8hUH2XRoM85ySXv7JBtO87jMIvWq+H5GoYIHCLA1ZxD6Qap3Ak8IKfW7TJ50lK6uP9E6RgndHaODtCJ6Z5RyHfnE7j6gRbcKlCYNSt+rtETHTpUGgEP8FYmdNqd/Mo7aiVWTfuH2L9xASvfxxlqr01EYkrJszvNkgW9bH0OuFr+99m+y9IOeyU6zIp/Hubp/yMEztlzFPwOhdvq+nIoS1JNn4t2sugCmVsDvPe2KKolnZLCxhOcAKQRDDXTQaVi46lqYhIBwHTrl3oWqhMRDtaJge37lOBMKo4tfbqhVX0J7snTsWps8uZWuoOQY6CcjpSIF55UvmqNgr5wUwtV1IVdnXtnSfPEB2qjDNqnvczRl0m+j6Jn5lXb6nAQJqinmN0ZEBj03YLzghY8PnTRz80o/GRJZpOLCb0PM9BN7pvUEjx28V00WUg9jIVwAAAABJRU5ErkJggg=="
alt=""
style="position: absolute; top: 0px; left: 0px; width: 100%; height: 100%; object-fit: cover; object-position: center center; opacity: 0; transition: opacity 0.5s ease 0.5s;"
/><picture
><source
srcset="
/static/6d91c86c0fde632ba4cd01062fd9ccfa/0552a/gatsby-astronaut.png 75w,
/static/6d91c86c0fde632ba4cd01062fd9ccfa/fc3be/gatsby-astronaut.png 150w,
/static/6d91c86c0fde632ba4cd01062fd9ccfa/045aa/gatsby-astronaut.png 300w,
/static/6d91c86c0fde632ba4cd01062fd9ccfa/24f49/gatsby-astronaut.png 450w,
/static/6d91c86c0fde632ba4cd01062fd9ccfa/5497d/gatsby-astronaut.png 600w,
/static/6d91c86c0fde632ba4cd01062fd9ccfa/483e1/gatsby-astronaut.png 800w
"
sizes="(max-width: 300px) 100vw, 300px"/>
<img
alt=""
src="/static/6d91c86c0fde632ba4cd01062fd9ccfa/045aa/gatsby-astronaut.png"
naptha_cursor="text"
style="position: absolute; top: 0px; left: 0px; width: 100%; height: 100%; object-fit: cover; object-position: center center; opacity: 1; transition: opacity 0.5s ease 0s;"/></picture

><noscript
><picture
><source
srcset="
/static/6d91c86c0fde632ba4cd01062fd9ccfa/0552a/gatsby-astronaut.png 75w,
/static/6d91c86c0fde632ba4cd01062fd9ccfa/fc3be/gatsby-astronaut.png 150w,
/static/6d91c86c0fde632ba4cd01062fd9ccfa/045aa/gatsby-astronaut.png 300w,
/static/6d91c86c0fde632ba4cd01062fd9ccfa/24f49/gatsby-astronaut.png 450w,
/static/6d91c86c0fde632ba4cd01062fd9ccfa/5497d/gatsby-astronaut.png 600w,
/static/6d91c86c0fde632ba4cd01062fd9ccfa/483e1/gatsby-astronaut.png 800w
"
sizes="(max-width: 300px) 100vw, 300px"/>
<img
src="/static/6d91c86c0fde632ba4cd01062fd9ccfa/045aa/gatsby-astronaut.png"
alt=""
style="position:absolute;top:0;left:0;transition:opacity 0.5s;transition-delay:0.5s;opacity:1;width:100%;height:100%;object-fit:cover;object-position:center"/></picture
></noscript>
</div>
</div>
```

This time we can see that the containing div has a classname on it instead of inline styles... but where are the styles? Well in `<head>` there's a new `<style>` tag that includes our styles and a source map (this is development mode after all).

```html
<style data-emotion="css">
.css-ehkvu9-IndexPage {
max-width: 300px;
margin-bottom: 1.45rem;
} /*# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInNyYy9wYWdlcy9pbmRleC5qcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFhUyIsImZpbGUiOiJzcmMvcGFnZXMvaW5kZXguanMiLCJzb3VyY2VSb290IjoiL1VzZXJzL2NocmlzL3RtcC9teS1lbW90aW9uLXNpdGUiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgUmVhY3QgZnJvbSAncmVhY3QnXG5pbXBvcnQgeyBMaW5rIH0gZnJvbSAnZ2F0c2J5J1xuXG5pbXBvcnQgTGF5b3V0IGZyb20gJy4uL2NvbXBvbmVudHMvbGF5b3V0J1xuaW1wb3J0IEltYWdlIGZyb20gJy4uL2NvbXBvbmVudHMvaW1hZ2UnXG5pbXBvcnQgU0VPIGZyb20gJy4uL2NvbXBvbmVudHMvc2VvJ1xuXG5jb25zdCBJbmRleFBhZ2UgPSAoKSA9PiAoXG4gIDxMYXlvdXQ+XG4gICAgPFNFTyB0aXRsZT1cIkhvbWVcIiBrZXl3b3Jkcz17W2BnYXRzYnlgLCBgYXBwbGljYXRpb25gLCBgcmVhY3RgXX0gLz5cbiAgICA8aDE+SGkgcGVvcGxlPC9oMT5cbiAgICA8cD5XZWxjb21lIHRvIHlvdXIgbmV3IEdhdHNieSBzaXRlLjwvcD5cbiAgICA8cD5Ob3cgZ28gYnVpbGQgc29tZXRoaW5nIGdyZWF0LjwvcD5cbiAgICA8ZGl2IGNzcz17eyBtYXhXaWR0aDogYDMwMHB4YCwgbWFyZ2luQm90dG9tOiBgMS40NXJlbWAgfX0+XG4gICAgICA8SW1hZ2UgLz5cbiAgICA8L2Rpdj5cbiAgICA8TGluayB0bz1cIi9wYWdlLTIvXCI+R28gdG8gcGFnZSAyPC9MaW5rPlxuICA8L0xheW91dD5cbilcblxuZXhwb3J0IGRlZmF1bHQgSW5kZXhQYWdlXG4iXX0= */
</style>
```

## Fin

This is how Emotion supports the full breadth of CSS which using a syntax that *looks* like inline styles. It uses built-in browser APIs (the CSSOM APIs) to insert styles in a performant way. The syntax we used to replace the `style` prop is know as the "CSS Prop", named for the `css` prop we used on our React components. In our next posts, we'll explore more of the Emotion API, composition of styles, theming, and how to use both the `styled` and `css` style APIs.
Binary file not shown.
Copy path View file
@@ -8,6 +8,7 @@ module.exports = {
twitter: `chrisbiscardi`
}
},
mapping: { "Mdx.fields.featuredImage": `File.absolutePath` },
plugins: [
`gatsby-plugin-sharp`,
`gatsby-transformer-sharp`,
Copy path View file
@@ -1,5 +1,6 @@
const path = require(`path`);
const slugify = require("slugify");
const fs = require("fs");

exports.createPages = ({ graphql, actions }) => {
const { createPage } = actions;
@@ -106,5 +107,17 @@ exports.onCreateNode = ({ node, actions, getNode }) => {
node,
value: `https://www.christopherbiscardi.com${slug}/`
});

if (parent.internal.type === "File") {
const ext = path.extname(parent.absolutePath);
const featuredImage = parent.absolutePath.replace(ext, ".png");
if (fs.existsSync(featuredImage)) {
createNodeField({
name: `featuredImage`,
node,
value: featuredImage
});
}
}
}
};
Copy path View file
@@ -10,7 +10,8 @@ import SiteLayout from "./site-layout";
export default class BlogPost extends Component {
render() {
const { data } = this.props;
const imageRoot = data.mdx.frontmatter.featuredImage;
const imageRoot =
data.mdx.frontmatter.featuredImage || data.mdx.fields.featuredImage;
let src = undefined;
if (imageRoot) {
src = imageRoot.childImageSharp.fixed.src;
@@ -145,6 +146,15 @@ export const pageQuery = graphql`
body
}
excerpt
fields {
featuredImage {
childImageSharp {
fixed {
src
}
}
}
}
frontmatter {
title
featuredImage {
Copy path View file
@@ -58,20 +58,21 @@ export default class IndexPage extends Component {
}
}

const FeaturedPost = ({ id, frontmatter, excerpt }) => {
if (!frontmatter.featuredImage) {
const FeaturedPost = ({ id, frontmatter, fields, excerpt }) => {
if (!frontmatter.featuredImage && !fields.featuredImage) {
return (
<div css={({ colors }) => ({ background: colors.raw.neutral[70] })}>
<Heading>{frontmatter.title}</Heading>
<Text>{excerpt}</Text>
</div>
);
}
const featuredImage = frontmatter.featuredImage || fields.featuredImage;
return (
<Img
alt={frontmatter.title}
key={id}
fluid={frontmatter.featuredImage.childImageSharp.fluid}
fluid={featuredImage.childImageSharp.fluid}
/>
);
};
@@ -88,6 +89,14 @@ export const query = graphql`
excerpt
fields {
slug
featuredImage {
id
childImageSharp {
fluid(maxWidth: 700) {
...GatsbyImageSharpFluid
}
}
}
}
frontmatter {
title
ProTip! Use n and p to navigate between commits in a pull request.