tangle frontend

May 25, 2020

this post documents setting up the frontend portion of tangle

this post documents setting up the frontend portion of tangle.

This section covers the technical foundations including

  • bootstrapping the lerna repo
  • adding eslint and prettier
  • setting up the frontend

bootstrap lerna repo

yarn init
yarn add lerna --dev
yarn lerna init

Add to package.json:

'name': 'root',
'private': true,
'workspaces': [

Update lerna.json:

'packages': ['packages/*'],
'version': 'independent',
'npmClient': 'yarn',
'useWorkspaces': true



Copy/paste eslint and prettier

yarn add babel-eslint eslint eslint-config-airbnb
eslint-config-prettier eslint-plugin-import
eslint-plugin-jsx-a11y eslint-plugin-prettier
eslint-plugin-react prettier -W -D

-W for root flag

-D for dev dependencies

Add to package.json

'lint': 'eslint --fix . && echo 'Lint complete.'',

Commit [init].

frontend / next.js

mkdir packages/web
npx create-next-app packages/web

Select Default starter app

Update name of web app to @tangle/web

Add command to root package.json

'web': 'lerna run --scope @tangle/web dev --stream'

commit [web] init

We want to share react and next across the codebase. Add these as devDependencies to the root and add them as peerDependencies in whatever packages need them.

component library

mkdir packages/components
cd packages/components && yarn init -y

Name package @tangle/components.

Add peer dependencies

yarn workspace @tangle/components add -P react react-dom next

Add dependencies

yarn workspace @tangle/components add @emotion/styled @theme-ui/color styled-system theme-ui prop-types

Make a component


import React from 'react';
import PropTypes from 'prop-types';
import styled from '@emotion/styled';
const StyledButton = styled.button` color: red; background-color: blue; `;
function Button({ children }) {
return <StyledButton>{children}</StyledButton>;
Button.propTypes = {
* content of button
children: PropTypes.string
Button.defaultProps = {
children: null
export default Button;

Add storybook

yarn add -W -D @storybook/react @storybook/addon-actions
@storybook/addon-docs babel-loader @babel/core

Add .storybook directory w/ config.js and main.js


import { configure, addDecorator } from '@storybook/react';
addDecorator(storyFn => (storyFn()))
configure(require.context('../packages/components/src', true, /\.stories\.js$/), module);


module.exports = {
stories: ['../packages/**/*.stories.js'],
addons: ['@storybook/addon-docs']

Add a story for the button


import React from 'react';
import { action } from '@storybook/addon-actions';
import { storiesOf } from '@storybook/react';
import Button from './Button';
storiesOf('Button', module).add('default', () => (
<Button onClick={action('clicked')}>test</Button>

update root package.json

'stories': 'start-storybook'

Run storybook.

clean up and code share

babel-plugin-module-resolver helps us keep things looking clean.

yarn add -D -W babel-plugin-module-resolver eslint-plugin-import
eslint-import-resolver-babel-module eslint-import-resolver-alias

add a .babelrc file

'plugins': [
['module-resolver', {
'root': ['./'],
'alias': {
'@components': './packages/components/src',
'@web': './packages/web'

add to .eslintrc.js

settings: {
'import/resolver': {
'babel-module': {},
alias: {
map: [['@components', './packages/components/src']],
extensions: ['.ts', '.js', '.jsx', '.json']

add an index.js file to components/src and export the button component from there. Update the import in the Button.stories.js file to reflect the update

import { Button } from '@components';

Run storybook to test.

Time to add the button to Next.js

Add a babel.config.js to the next app

module.exports = {
babelrcRoots: ['../packages/*'],
presets: ['next/babel'],
plugins: [
root: ['./'],
alias: {
'@components': '../components/src'

We need to transpile the components as they come in:

yarn workspaces @tangle/web next-transpile-modules

Transpile components in the next.config.js

const withTM = require('next-transpile-modules')([
module.exports = withTM();

Call the Button in your index to test. Run your next app.