Migrating to Linaria theme

The way theming works has changed slightly in Flight 5.0 in order to be compatible with Linaria, to make switching between themes easier, and to make it possible to autocomplete theme values in your editor.

Step one

First, create a theme-variables.js in your src directory. Copy the default values in to it:

Copy
Copied
module.exports = {
  default: {
    colors: {
      white: "#FFFFFF",
      black: "#000000",
      main: "#000000",
      grey: "#878787",
      lightgrey: "#E8E8E8",
      tablegrey: "#F3F3F3",
      beige: "#f5f5dc",
      loadingBar: "#2f80ed",
      blue: "#2f80ed",
      red: "#FF0000",
      background: "#f7f7f7",
      darkgrey: "#333",
      mediumgrey: "#9a9a9a",
      highlight: "#2f80ed",
    },
    fontWeights: {
      light: 300,
      regular: 400,
      semibold: 700,
    },
    breakpoints: {
      xs: "20rem",
      sm: "40rem",
      md: "50rem",
      lg: "64rem",
      xl: "80rem",
    },
    fontSizes: [
      "12px",
      "14px",
      "16px",
      "20px",
      "24px",
      "32px",
      "48px",
      "64px",
      "72px",
    ],
    space: [
      "0px",
      "8px",
      "16px",
      "24px",
      "32px",
      "40px",
      "48px",
      "56px",
      "64px",
    ],
    fonts: {
      primary: "Source Sans Pro",
    },
  },
};

Go ahead and update those values to match your previous Theme.js.

Step two

Injecting global styles is handled differently in Linaria. If you have any global styles in Theme.js, move them to a separate globalStyles.js file:

Copy
Copied
import { css } from "linaria";

css`
  :global() {
    ${globals};
  }
`;

const globals = `
    html,
    body {
      height: 100%;
      font-family: '-apple-system', 'BlinkMacSystemFont', 'Segoe UI', 'Roboto',
        'Oxygen', 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans',
        'Helvetica Neue', 'Arial', 'sans-serif';
    }
`;

And import it to the Shop.js file:

Copy
Copied
import "../path/to/globalStyles";

Fonts

Another common use case for injectGlobal in previous versions was for loading custom fonts in loadFontCss.js. Similarly with globalStyles.js, you wrap the styles in css:

Copy
Copied
import { css } from "linaria";

export default function loadCss() {
  return css`
    :global(html) {
      @font-face {
        font-family: "Font Name";
        src: local("Font Name");
        font-weight: 400;
        font-style: normal;
        font-display: swap;
      }
    }
  `;
}

You don't have to make any changes for the fonts in shop.js if it is imported and passed to the <CustomFont /> component.

Step three

Now that your theme-variables.js is ready, replace Theme.js with the following:

Copy
Copied
import themeVariables from "../theme-variables.js";
import { createTheme } from "@jetshop/ui/Theme/createTheme";

// Edit your theme values at `src/theme-variables.js`
const theme = createTheme(themeVariables);

export { theme };

Whenever you create a styled component with Linaria, it does not have the theme object anymore. Therefore the following code would not work

Copy
Copied
const Container = styled("div")`
  color: ${({ theme }) => theme.colors.red};
`;

You have to import the theme object from the Theme.js file to make it work Whenever you want to use theme values in your CSS, import the theme from Theme.js like this:

Copy
Copied
import { theme } from "../path/to/Theme";

const Container = styled("div")`
  color: ${theme.colors.red};
`;

Step four

Add your theme to shop.config.js. This is necessary so that we can use values from your theme in ui and core components.

In src/shop.config.js:

Copy
Copied
import { theme } from "./components/Theme";

export default {
  theme,
  //... the rest of your config
};

Step five

If you are using sanitizeCss to reset your CSS, you should simply import it in your Shop.js:

Copy
Copied
import "@jetshop/ui/Theme/sanitizeCss";

Step six

You have to update both the client.js and the server.js files, so <Shop /> is no longer wrapped in <Theme />. Example for client.js file:

Copy
Copied
import React from "react";
import boot from "@jetshop/core/boot/client";
import Shop from "./components/Shop";
import config from "./shop.config";

boot(<Shop />, config);

Step seven

As Linaria styled component no longer has the theme object, you can't use theme function from @jetshop/ui/utils/theme anymore. Update your code to import the theme object from your local Theme.js file and use it as an object (and not as a function).

Common issues when upgrading

Invalid theme references

Previously, if you referenced an invalid theme value in your CSS, the React app would still happily render, although the generated css would include undefined in place of the invalid value. For example:

Copy
Copied
const styles = css`
  color: ${theme.this.doesnt.exist}
`

// the above would yield

.dfgkjdfhg { color: undefined }

Linaria is more strict about this, and will throw errors in the build if you try to access a theme value that does not exist. This is a common issue when upgrading stores.

In that case, you may see an error in the console referencing this:

Malformed CSS

If the CSS has syntax errors in it, Linaria will throw a less-obvious error.

In this case, it can be a little harder to track down. You may need to search your project for the CSS that is referenced by the error, and scan it to make sure it is valid.

For example, the above error was created by the following syntax in a styled component:

Copy
Copied
const Component = styled("div")`
  #{$theme.above.md} {
    color: red;
  }
`;

Note the #{$theme.above.md} is not valid syntax.

Multiple themes

Sometimes you may want the user to be able to switch themes through the shop’s UI. For example, this might be useful for a dark and light theme.

You may have noticed the default key in theme-variables.js. It’s now possible to add multiple themes to your theme-variables.js just by adding keys for them.

For example, to add a theme named alt:

Copy
Copied
{
  "default": {
    "colors": {
      "primary": "blue",
      "secondary": "#000"
    }
  },
  "alt": {
    "colors": {
      "primary": "pink"
    }
  }
}

Any properties in the alt theme will override those in the default theme. So in the example above, the primary colour in the alt theme will be pink, and the secondary colour will be black.

Using different theme variables per— shop ID

Some stores are based off the same repository, but with different shop IDs. In this case, you may want to load different theme variables depending on which shop ID the app is built with.

To do this, you can dynamically import your theme variables like so:

In Theme.js:

Copy
Copied
const theme = createTheme(
  process.env.REACT_APP_SHOP_ID === "demostore"
    ? require("../theme-variables.js")
    : require("../theme-variables-alt.js")
);

Note that one of your theme variable files must be named theme-variables.js.

Using multiple deploys with different themes within one repo

Some stores will have channels within the same shop that use different themes. In this case, you may want to change the gitlab-ci to deploy two different deploys for each channel.

Instructions for this can be found here.

Copyright © Norce 2023. All right reserved.