yarn-workspaces-cra-crna

by viewstools

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

132 Stars 22 Forks Last release: Not found 25 Commits 0 Releases

Available items

No Items, yet!

The developer of this repository has not created any items for sale yet. Need a bug fixed? Help with integration? A different license? Create a request here:

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: - facebook/metro#1, - react-community/create-react-native-app#232, - react-community/create-react-native-app#340, - react-community/create-react-native-app#408, - facebookincubator/create-react-app#3405, - facebookincubator/create-react-app#3435, - yarnpkg/yarn#3882.

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
:
js
import value from './value'
export default value

value.native.js
:
js
export default 'value in native'

value.web.js
:
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:
bash
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:
bash
yarn add --dev react-app-rewired react-app-rewire-yarn-workspaces

Swap the

start
,
build
, and
test
scripts in
package.json
for these:
json
    "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: ```js 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: ```js 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 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: ```js import App from './App'; import Expo from 'expo'; import React from 'react';

const AwakeInDevApp = props => [ , process.env.NODE_ENV === 'development' ? ( ) : null, ]; Expo.registerRootComponent(AwakeInDevApp); ```

After that, in

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

Then, replace

app.json
for this:
json
{
  "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
:
bash
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:
js
require('crna-make-symlinks-for-yarn-workspaces')(__dirname)

Add

prestart
script to your native project's
package.json
:
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: ```js 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 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 nodemodules of each project and starting from scratch: ```bash cd ~/workspaces rm -rf nodemodules core/nodemodules views/nodemodules native/nodemodules web/nodemodules 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:
bash
yarn web

For native, in the

views
folder, run:
bash
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!

We use cookies. If you continue to browse the site, you agree to the use of cookies. For more information on our use of cookies please see our Privacy Policy.