Setting up Playroom in a custom Component Library

Mandy Michael
Pixel and Ink
Published in
8 min readJul 13, 2020
#Spoilers — Playroom setup working for our Component Library

This is a story of setting up Playroom in my component library may it help you through some of the bumps (specifically the ones I hit) along the way. Spoiler alert, I did get it running. 😄

First things first, the basic setup was pretty much as the Getting Started section of the readme explains — install playroom, setup the config. I set up a index.ts file inside my component library that manually listed the components I wanted playroom to have access too, I started with just one super basic component to keep things simple— a heading (we will talk more complex ones further on in the post).

It was literally just:

export { Headline } from './publication/Headline/Headline'

Once I got the initial stuff set up I started hitting problems.

Issue #1 — totally awesome Type Error. 🤨 Issue #2 — Can’t find my files 😒

These two issues were related.

TypeError: Cannot read property '0' of undefined 
at Parser.getComponentInfo (/node_modules/playroom/node_modules/react-docgen-typescript/lib/parser.js)
at /node_modules/playroom/node_modules/react-docgen-typescript/lib/parser.js
(node:63647) UnhandledPromiseRejectionWarning: Error: Cannot find module './src/component-library'

Both of these errors I was able to resolve with the help of the Fenders community, specifically Luke (It’s totally in the readme on Github as well — folks you gotta learn to read stuff, don’t be impatient like me 🙈). You have to make sure you are including the typeScriptFiles property in your playroom.config.js file (I just whacked it at the end).

For example:

typeScriptFiles: 
['./component-library/**/*.tsx', '!**/node_modules'],

💬 Narrator: Mandy was in fact very happy at this point.

Mission #1&2 Complete ✅ 🎉

Issue #3 — Can’t find the playroom files for Snippets and frameComponent.
No probs, I’ll just comment that out for now, you don’t need it to get started. Let’s get back to this later.

💬 Narrator: Mandy would later regret this decision.

Mission #2 Complete 🙈

Issue #4 —Loader Issues 😒

Module parse failed: Unexpected token 
You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file.

Need some loaders, cool cool. Thankfully Playroom had an example in the Github Repo so copy-paste that example and you should be good to go.

webpackConfig: () => ({
module: {
rules: [{
test: /\.tsx?$/,
include: __dirname,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: [
'@babel/preset-env',
'@babel/preset-typescript',
'@babel/preset-react',
],
},
},
}],
},
resolve: {
extensions: ['.js', '.ts', '.tsx'],
},
}),

Stuff is compiling now success. 👍 Except now I’m getting new errors…

Mission #4 Complete ✅

Issue #5 — Dependency Issues 😩

This dependency was not found:
component-library/typography/Heading/Heading.styled in ./src/component-library/src/typography/Heading/Heading.tsx

Now that I’ve got stuff running I get a delightful blank screen. But that’s okay because I also got the above error.

This happens because inside each of our components we reference other dependencies, whether it’s helper functions, styling etc. Our codebase uses aliases to simplify the paths in our projects, so I need to set this up in the Playroom custom webpage config as well. I had a slight issue here because I’d copied it from our tsconfig which has wildcards in, which I totally didn’t need.

With that in mind let’s add that in:

resolve: {
extensions: ['.js', '.ts', '.tsx'],
alias: {
'component-library':
path.resolve(__dirname, 'src/component-library/'),
},
},

👍 Yeah. Mission #5 Complete ✅ (I’m on a roll)

💬 Narrator: Mandy was getting very enthusiastic at this point

Issue #6 — Syntax Errors 😒

Syntax Error: SyntaxError: //src/component-library/__product/index.ts: 'const' enums are not supported.

This one wasn’t so bad, we already have all our plugins defined for our component library configuration so I just had to copy-paste the ones we already had set up into the playroom.config.js file (I just put if after my presets inside the webpackConfig).

You can see an example of what we needed below:

"plugins": [
["const-enum",
{
"transform": "constObject"
}
],
"@emotion",
"@babel/plugin-syntax-dynamic-import",
"@loadable/babel-plugin",
"@babel/plugin-proposal-class-properties",
"@babel/plugin-proposal-numeric-separator"
]

Mission #6 Complete ✅. Right now I’m feeling pretty good about myself.

💬 Narrator: Mandy’s confidence is being restored.

Now we are getting somewhere. At this point, Playroom is now compiling. Unfortunately, I’m getting some console errors.

Issue #7 — Styling 🤔

Our components have themes for three different products, as a result our styling makes heavy use of theming. To get this moving I set up a simplified use case of setting up the ThemeProvider with a preset theme for one of our products.

You might recall that earlier I commented out some code in the playroom.config.js file — specifically the frameComponent property. Now it’s time to set that up to pass through our themes.

I basically copied the one that Playroom has up on Github, mine looks like this.

import React from 'react'
import { ThemeProvider } from '@emotion/react'
import { thewest } from 'component-library/__styling/themes'
export default ({ theme, children }) => (
<ThemeProvider theme={thewest}>
<React.Fragment>{children}</React.Fragment>
</ThemeProvider>
)

Then I had to set the path in the playroom.config.js file

frameComponent: './src/playroom/FrameComponent.js',

🙈 Mandy’s Note: Friends, I spent an uncomfortable amount of time wondering why this wasn’t working before I realised that I still had the property commented out in the playroom config file. 😅 Don’t make the same mistake.

💬 Narrator: This was when Mandy had regrets on her previous choices.

So with the Frame Component set up, I start getting some new errors. My current loader in webpack was set up only for tsxso it started throwing an error about missing loaders. As a result, I had to update this to work with js as well. Inside my playroom.config.js file so I just set it up for js as well

{test: /\.js$/,
include: __dirname,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env', '@babel/preset-react'],
},
},
}

Mission #7 Complete ✅

💬 Narrator: At this point a component rendered and Mandy cheered and messaged some people on slack to let them know of her accomplishment. She also tweeted, knowing that it was just into the void.

Success with a simple component rendering in Playroom

Issue #8 — Adding the other Themes 😎

Once I’d confirmed that my component was loading and rendering the correct styles I wanted to include the other themes we had set up in our component library. I honestly thought this would be a pain in the bumbag, but in reality, it was very straightforward for our codebase.

To do this I went back into the playroom config file and updated the theme property to reference our component library themes which we already had setup. ✨ Spectactular.

themes: ‘./src/component-library/__styling/themes.ts’,

Everything worked 🎉. Mission #8 Complete ✅

Themes for the Headline component

💬 Narrator: At this moment Mandy made videos of playroom in action to send the team. It’s unknown if they were as enthusiastic as she was, but Mandy liked to think they were.

Issue #9 — Complicated Components 😫

After successfully rendering a simple Headline component I took the next steps to render some more complicated ones.

🧐 Mandy’s Note: While setting this up I noticed a bunch of flaws in the way some of our components, particularly our older ones from about 4 years ago were setup. So it was a nice exercise in flagging areas of improvement.

Step 1

I hit a few issues with this, mostly around wiring up data. This was thankfully fairly straightforward for me to set up given that we already have code in our codebase that handles this for our tests and rendering out components in the style guide.

This is pretty specific to our codebase so there isn’t much to show but what I did was set up our Provider and the test redux store— if you have a custom component library you probably have something similar setup already.

My FrameComponent.js file is starting to look like this

<ThemeProvider theme={theme}>
<Provider store={store}>
<React.Fragment>
<style>{`html, body { margin: 0; }`}</style>
{children}
<React.Fragment>
</Provider>
</ThemeProvider>

Step 2 — Location

Some of our components have this custom web link that requires access to Location. I added a StaticRouter from react-router-dom to resolve this — using the defaults worked fine.

<ThemeProvider theme={theme}>
<StaticRouter>
<Provider store={store}>
<React.Fragment>
<style>{`html, body { margin: 0; }`}</style>
{children}
<React.Fragment>
</Provider>
</StaticRouter
</ThemeProvider>

Step 3 — Fallback Images

Some of our components have fallback images that render when no image is provided by our content API. I needed to make these available to the ThemeProvider. I ended up hacking this but I figure that’s later Mandy’s problem.

💬 Narrator: At this point, Mandy is getting impatient again

Issue #10 — too much data 🤦‍♀️

Some of our components have an unnecessary amount of data and this caused some problems with rendering. Clearing the cache fixes temporarily but eventually, Chrome gets pretty sad again.. I didn't really resolve this, but it did flag some areas we could simplify some of our APIs.

Bonus: Issue #11 — Uncaught ReferenceError: Card is not defined 💜

If you hit something like this, you probably forgot to add the component into your index file where you define all your components 😄

It’s easy to forget this stuff when you have been trawling through errors for a while. So don’t sweat it.

In Conclusion

It’s working, mostly, there are still some components that aren’t super happy but we’ll add those and fix over time.

In review, Playroom is mostly a step by step process to set up. A lot of the time is spent getting the Webpack config right and setting up the FrameComponent. If you aren’t super familiar with Webpack you might have some trouble here, so don’t be afraid to ask some folks for help. Otherwise, if your components aren’t overly complex I think you will have a pretty good time.

If your component library is doing a lot of stuff with data, locations, paths etc you might have a tougher road. It’s not that it’s impossible, it’s just more effort than a plug and play type situation. It becomes a little tedious as you step through each error — thankfully most of the errors are pretty helpful so it’s not like you are doing a lot of wild guessing.

This was my experience, it might not cover all your errors but I hope it helps some people get playroom into their component libraries, it really is a great tool. ☺️

Thanks for playing ✨💜

--

--

Mandy Michael
Pixel and Ink

Lover of CSS, and Batman. Front End Developer, Writer, Speaker, Development Manager | Founder & Organiser @fendersperth | Organiser @mixinconf