Gatsby: Trying to add stylable to my gatsby setup

Created on 1 Jun 2019  路  11Comments  路  Source: gatsbyjs/gatsby

Summary

Relevant information

I'm trying to integrate stylable into my Gatsby setup, so far I've installed stylable via npm and have added the stylable webpack config into my gatsby-node.js file. when i run gatsby develop everything compiles fine and the page I want to look at opens fine but when I import in my header.st.css file into my header.js at first the page loads fine, but when I add the necessary {...style("root", {}, props)} to my the root element of my component I get an error in my browser saying "TypeError: _header_st_css__WEBPACK_IMPORTED_MODULE_4___default(...) is not a function". See below for the code in my files.

How can i get it working properly?

Environment (if relevant)

I'm running my build simply using gatsby develop

File contents (if changed)

gatsby-config.js: N/A
package.json: N/A
gatsby-node.js:

const StylableWebpackPlugin = require("@stylable/webpack-plugin")

exports.onCreateWebpackConfig = ({
  stage,
  rules,
  loaders,
  plugins,
  actions,
}) => {
  actions.setWebpackConfig({
    module: {
      rules: [
        {
          test: /\.(png|jpg|gif)$/,
          use: [loaders.css({ importLoaders: 1 }), `url-loader`],
        },
      ],
    },
    plugins: [plugins.define(new StylableWebpackPlugin())],
  })
}

gatsby-browser.js: N/A
gatsby-ssr.js: N/A

header.js:

import { Link } from "gatsby"
import PropTypes from "prop-types"
import React from "react"
import style from "./header.st.css"

const Header = props => (
  <header {...style("root", {}, props)}>
    <div
      style={{
        margin: `0 auto`,
        maxWidth: 960,
        padding: `1.45rem 1.0875rem`,
      }}
    >
      <h1 style={{ margin: 0 }}>
        <Link
          to="/"
          style={{
            color: `white`,
            textDecoration: `none`,
          }}
        >
          {props.siteTitle}
        </Link>
      </h1>
    </div>
  </header>
)

Header.propTypes = {
  siteTitle: PropTypes.string,
}

Header.defaultProps = {
  siteTitle: ``,
}

export default Header

header.st.css:

.root {
  background: blue;
}

image

Most helpful comment

@barak007 you had the right idea! I opened a PR https://github.com/azharulc/bjjfreak-frontend/pull/1 with a slightly cleaner implementation that makes use of rule.exclude to exclude .st.css files from normal loading and instead use the stylable plugin. It's working on my machine, so hopefully this solves it for you!

All 11 comments

Just checking are we talking about https://github.com/wix/stylable?
Do you mind pushing an example to github? it works a bit better than copy pasting.

Hi @wardpeet, thank you so much for the reply. Yes, we're talking about wix-stylable. We are basically trying to figure out how to follow this configuration instructions on stylable website using the custom webpack config in Gatsby. We'll soon share the code. https://stylable.io/docs/getting-started/install-configure

Hey @Nicotu, I think I may know what's causing your problem. Gatsby's webpack config already has rules defined under module.rules for loading .css files. These make use of css-loader so the default export of a .css file is just a filename string, so of course you cannot call a string as a function, hence your error.

In order to get stylable working correctly, you'll need to follow the instructions here on overriding Gatsby's existing module.rules and change the test for css files from /\.css$/ to /^(?!.*\.st\.css$).*\.css/, in addition to the steps you've already taken. This way, css-loader will load any normal .css files and the stylable plugin will load all .st.css files :smiley:

Hi @wardpeet & @superhawk610 thank you for your replies. The documentation of stylable seems to have been updated, but now I'm being faced with a different issue when trying to use my imported header.st.css file it gives me an error of TypeError: Cannot read property 'root' of undefined

@superhawk610 I've tried using your solution but it doesn't seem to have worked.

I've made my repo public here https://github.com/azharulc/bjjfreak-frontend/tree/stylable-build as per @wardpeet's request

The file I've been working from can be found under /src/components/organisms/header/header.js

Thanks for your help!

Thanks for posting the source, I'll take a look at your repo this afternoon and see if I can find anything further and update accordingly.

I have managed to make it work by removing the built in css support.
The solution is far from being good but I am sure that there is a safer way to do it.

here is the gatsby-node.js

/**
 * Implement Gatsby's Node APIs in this file.
 *
 * See: https://www.gatsbyjs.org/docs/node-apis/
 */

const path = require("path")

process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0"

const { StylableWebpackPlugin } = require("@stylable/webpack-plugin")

exports.onCreateWebpackConfig = ({
  stage,
  rules,
  loaders,
  plugins,
  actions,
  getConfig,
}) => {

  // REMOVE BUILT IN CSS SUPPORT
  const config = getConfig()
  config.module.rules = config.module.rules.filter(r => {
    // this is a total hack. there must be a better way
    return !JSON.stringify(r).match("css")
  })

  actions.setWebpackConfig({
    module: {
      rules: [
        {
          test: /\.(png|jpg|gif)$/,
          use: [`url-loader`],
        },
        {
          exclude: /\.st\.css$/,
          include: /\.css$/,
          use: [loaders.css({ importLoaders: 1 }), `css-loader`],
        },
      ],
    },
    plugins: [new StylableWebpackPlugin({ experimentalHMR: true })],
  })
}

exports.createPages = ({ graphql, actions }) => {
  const { createPage } = actions
  const BlogPostTemplate = path.resolve(
    "./src/components/templates/blog-post/blog-post.js"
  )
  return graphql(`
    {
      allWordpressPost {
        edges {
          node {
            slug
            wordpress_id
          }
        }
      }
    }
  `).then(result => {
    if (result.errors) {
      throw result.errors
    }

    const BlogPosts = result.data.allWordpressPost.edges
    BlogPosts.forEach(post => {
      createPage({
        path: `/post/${post.node.slug}`,
        component: BlogPostTemplate,
        context: {
          id: post.node.wordpress_id,
        },
      })
    })
  })
}

@barak007 you had the right idea! I opened a PR https://github.com/azharulc/bjjfreak-frontend/pull/1 with a slightly cleaner implementation that makes use of rule.exclude to exclude .st.css files from normal loading and instead use the stylable plugin. It's working on my machine, so hopefully this solves it for you!

Thank you so much!!!! It works well, I was attempting something similar all evening, but just couldn't get it working, thanks again!

I've pasted @superhawk610's working solution just incase I make the repo private -

exports.onCreateWebpackConfig = ({ actions, getConfig }) => {
  const config = getConfig()

  // replace regex for builtin CSS support to exclude .st.css files
  for (let i = 0; i < config.module.rules.length; i++) {
    const rule = config.module.rules[i]
    if (!rule.oneOf) continue

    const handler = rule.oneOf[0]
    const use = handler.use

    for (let j = 0; j < use.length; j++) {
      const loader = use[j]
      if (!loader.loader.match(/postcss/)) continue

      rule.exclude = /\.st\.css$/
      break
    }
  }

  // add stylable plugin
  config.plugins.push(new StylableWebpackPlugin({ experimentalHMR: true }))

  actions.replaceWebpackConfig(config)
}

Since this is a somewhat involved solution and it sucks to dig through closed issues for debugging, I'll write a Gatsby plugin for stylable that handles this setup for you, stay tuned :)

Alright, plugin is here: gatsby-plugin-stylable 馃摝

Was this page helpful?
0 / 5 - 0 ratings

Related issues

dustinhorton picture dustinhorton  路  3Comments

magicly picture magicly  路  3Comments

jimfilippou picture jimfilippou  路  3Comments

theduke picture theduke  路  3Comments

3CordGuy picture 3CordGuy  路  3Comments