• Stars
    star
    152
  • Rank 244,685 (Top 5 %)
  • Language
    JavaScript
  • Created almost 7 years ago
  • Updated about 6 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

How to use yarn workspaces with Create React App and Create React Native App (Expo) to share common code across

How to use yarn workspaces with Create React App and Create React Native App (Expo) to share common code across

This post is on medium too!

The goal of this tutorial is to make a monorepo using yarn workspaces to share common code across a Create React App (CRA) and a Create React Native App (CRNA/Expo).

There are currently some issues with the projects that when fixed, these workarounds shouldn't be needed anymore:

Some of the solutions below may also help for lerna setups.

Pre-requisites

Make sure you're running node ~ version 8 and at least yarn 1.3.0 and have create-react-app and create-react-native-app installed.

Setup workspaces

In this guide, we'll setup four folders but feel free to structure it as you see fit:

  • web the CRA project,
  • native the CRNA project,
  • core common logic, and
  • views for shared UI.

Make a new folder where you want your workspaces to be and add a package.json that looks like this:

{
  "private": true,
  "workspaces": [
    "web",
    "native",
    "core",
    "views"
  ]
}

For the rest of this guide, we're going to assume that this folder is called workspaces and it's in your home directory. We will refer to it as ~/workspaces.

Setup core

core in our example will be just an empty project. Make a core folder and put this package.json inside:

{
  "name": "core",
  "version": "0.0.1"
}

Let's put a few sample files in there to use as a test. We'll also leverage the project specific extensions in web and native.

test.js:

import value from './value'
export default value

value.native.js:

export default 'value in native'

value.web.js:

export default 'value in web'

Setup views

We will use Views for our UI. If you want to use React directly, you may still benefit from this folder by putting shared components across your projects here. Otherwise, just skip this section.

views is where our UI sits. Make a views folder and put this package.json inside:

{
  "name": "views",
  "version": "0.0.1",
  "scripts": {
    "native": "views-morph . --as react-native --watch",
    "native:build": "views-morph . --as react-native",
    "web": "views-morph . --as react-dom --watch",
    "web:build": "views-morph . --as react-dom"
  }
}

Then add the latest views-morph to it:

yarn add --dev views-morph

Add a file called Test.view with this:

Test Vertical
backgroundColor deepskyblue
margin 50
onClick props.onClick
Text
fontSize 28
text Hey I'm a button!

Views uses some CSS defaults that make it behave close to how React Native renders the UI, add them by copying views.css to src/index.css.

Views is a productive way to create interfaces together with your design team and design in production. If you want to learn more about it, reach out at https://twitter.com/viewsdx or join the conversation at https://slack.viewsdx.com :).

Web

There are some issues with running CRA's init scripts inside the workspace, so just go to a temporary folder anywhere and make a new project:

# go to some temporary location
cd /tmp
# make the app
create-react-app web
# get rid of node modules and yarn.lock
rm -rf web/node_modules web/yarn.lock
# move it to the workspaces
mv web ~/workspaces
cd ~/workspaces/web

The next step is to have CRA compile your other workspaces code if they're imported by your app.

Install react-app-rewired and react-app-rewire-yarn-workspaces in the web project:

yarn add --dev react-app-rewired react-app-rewire-yarn-workspaces

Swap the start, build, and test scripts in package.json for these:

    "start": "react-app-rewired start",
    "build": "react-app-rewired build",
    "test": "react-app-rewired test --env=jsdom",

And add a file called config-overrides.js with this:

const rewireYarnWorkspaces = require('react-app-rewire-yarn-workspaces');

module.exports = function override(config, env) {
  return rewireYarnWorkspaces(config, env);
};

To test the connection with core, add this to src/App.js:

import test from 'core/test'

alert(test)

If you're using Views, test it by overwriting App.js with this:

import React, {Component} from 'react';
import test from 'core/test';
import Test from 'views/Test.view.js';

alert(test);

class App extends Component {
  render() {
    return <Test onClick={() => alert('just clicked a button!')} />;
  }
}

export default App;

Native

There are some issues with running CRNA's init scripts inside the workspace, so just go to a temporary folder anywhere and make a new project:

# go to some temporary location
cd /tmp
# make the app
create-react-native-app native
# get rid of node modules and yarn.lock
rm -rf native/node_modules native/yarn.lock
# move it to the workspaces
mv native ~/workspaces
cd ~/workspaces/native

We'll first need to swap CRNA's entry point because the way it picks up our App.js is very much dependent on the location of files, so it's easier this way. We'll call that file crna-entry.js.

Either get the original file from here. If you do, make sure you change import App from '../../../../App'; for import App from './App'; so it picks up your app.

...or, use this version want to avoid wrapping your app in a View. Add a file called crna-entry.js with this:

import App from './App';
import Expo from 'expo';
import React from 'react';

const AwakeInDevApp = props => [
  <App key="app" {...props} />,
  process.env.NODE_ENV === 'development' ? (
    <Expo.KeepAwake key="keep-awake" />
  ) : null,
];
Expo.registerRootComponent(AwakeInDevApp);

After that, in package.json, replace:

  "main": "./node_modules/react-native-scripts/build/bin/crna-entry.js",

for:

  "main": "crna-entry.js",

Then, replace app.json for this:

{
  "expo": {
    "sdkVersion": "23.0.0",
    "ignoreNodeModulesValidation": true,
    "packagerOpts": {
      "config": "rn-cli.config.js",
      "projectRoots": ""
    }
  }
}

Note that this guide was created when Expo's SDK was at v23.0.0. If your app.json has a different version, use that instead.

Install metro-bundler-config-yarn-workspaces and crna-make-symlinks-for-yarn-workspaces:

yarn add --dev metro-bundler-config-yarn-workspaces crna-make-symlinks-for-yarn-workspaces

Add a file called rn-cli.config.js with this:

const getConfig = require('metro-bundler-config-yarn-workspaces')
module.exports = getConfig(__dirname)

If your workspaces are not located in the root folder (e.g. root/packages/*) you must provide a nodeModules option indicating where the node_modules root folder is located as described below:

import test from 'core/test'

const getConfig = require('metro-bundler-config-yarn-workspaces')

const options = { nodeModules: path.resolve(__dirname, '..', '..') }

module.exports = getConfig(__dirname, options)  

Add a file called link-workspaces.js with this:

require('crna-make-symlinks-for-yarn-workspaces')(__dirname)

Add prestart script to your native project's package.json:

    "prestart": "node link-workspaces.js",

To test the connection with core, add this to App.js:

import test from 'core/test'

alert(test)

If you're using Views, test it by overwriting App.js with this:

import React, {Component} from 'react';
import test from 'core/test';
import Test from 'views/Test.view.js';

alert(test);

class App extends Component {
  render() {
    return <Test onClick={() => alert('just clicked a button!')} />;
  }
}

export default App;

If you get an error like Cannot find entry file crna-entry.js in any of the roots..., press shift+R when you start the expo runner so it restarts the packager and clears the cache.

Part of the setup may also come in handy for React Native CLI. See this comment. I also wanted to thank Neil Ding @GingerBear for his gist, without it metro-bundler-config-yarn-workspaces wouldn't be possible.

Before starting the apps...

At this point, I'd probably recommend wiping all the node_modules of each project and starting from scratch:

cd ~/workspaces
rm -rf node_modules core/node_modules views/node_modules native/node_modules web/node_modules
yarn

Dependencies are still added to the different project folders.

If you're using Views, you need to start the morpher by project type until viewsdx/morph#31 is implemented.

For web, in the views folder, run:

yarn web

For native, in the views folder, run:

yarn native

We'll be providing a concurrent process runner like the one implemented in https://github.com/viewsdx/use soon.

I hope the process works for you! This is the GitHub repo that contains a sample project and the supporting dev packages used in here. If you find any issues or have suggestions around some of the steps, feel free to open an issue.

Thanks to Larissa and Neil for their help 🙏.

Happy hacking!

More Repositories

1

docs

Views Tools docs
JavaScript
69
star
2

use-masked-input

A React hook to mask an input using text-mask.
JavaScript
16
star
3

demo

Views demo app
JavaScript
7
star
4

react-dom-animated

Animated wrapper for ReactDOM that works with React 16
JavaScript
6
star
5

use

A tool to help you install Views in your create-react-app or create-react-native-app project
JavaScript
5
star
6

bluebank-on-views-playground

BlueBank API on Views playground
JavaScript
4
star
7

syntax-atom

Views Tools language support in Atom
CSS
3
star
8

asnack

turn your react native app into an expo.io snack
JavaScript
3
star
9

react-yue-app

react-yue-app setup for live reloading and bundling of the app
JavaScript
3
star
10

syntax-vim

Views Tools language syntax highlighter for VIM.
Vim Script
2
star
11

test-rollup

Views (viewsdx.com), React, and rollup test app
JavaScript
2
star
12

codemods

Helpers to migrate your code to newer versions of Views Tools
JavaScript
2
star
13

animations

Views animations wrapper around react-spring
JavaScript
2
star
14

dealing-with-global-app-state

Some ways of dealing with global state and passing less props down your components
JavaScript
2
star
15

syntax-sublime

Views Tools language support in Sublime
2
star
16

e2e

Views E2E test helpers
JavaScript
1
star
17

create-react-app

1
star
18

local

Get your Views text into a JSON for ready for I18n
JavaScript
1
star
19

amenuapp

a menu app
JavaScript
1
star
20

www

Views Tools website
HTML
1
star
21

only-react-css-property-operations

JavaScript
1
star
22

morph

Views Tools morpher
JavaScript
1
star
23

viewsdx.com

viewsdx.com website
HTML
1
star
24

colour-picker

A mobile-ready colour picker made in Views and React
JavaScript
1
star
25

rollup-plugin-views

Views (viewsdx.com) language morpher's rollup plugin
JavaScript
1
star