Mine’s a private repo (and definitely a work in progress), so can’t share the entire thing, but I think I can describe what’s unique about our implementation of a separate shared repo compared to the typical node module.
The shared library
Everything’s pretty typical here compared to the average React Native library. You’ll want to keep anything like React, RN, Expo, out of your dependencies (since you can only have a single instance of those), but you’ll want things in your devDependencies to facilitate imports, linking, etc.
"dependencies": {
"luxon": "^1.2.1"
},
"peerDependencies": {
"react": "^16.3.1"
},
"devDependencies": {
"eslint": "^4.19.1",
"eslint-config-universe": "^1.0.7",
"prettier": "^1.13.4",
"react": "16.3.1",
"expo": "^27.0.0",
"react-native": "^0.55.0"
}
Test examples
In my shared library, I embed both a web and a CRNA project in an /examples folder, (e.g., /examples/web, /examples/native). This should make it easier to test changes without always having to integrate it back into the actual apps. For the native app, I follow React Navigation’s example exactly. See their repo and their example build instructions. I use CRNA here instead of Expo for the ease of avoiding a global dependency.
I did a pretty vanilla webpack/ babel implementation for the web example.
In each example, you refer to your library using a relative path, like:
"dependencies": {
"react": "^16.3.1",
"react-dom": "^16.3.1",
"common-lib": "link:../.."
},
Thus, you can run each example, and they’ll both get updates when the library code changes via metro/ webpack hot reloading.
The webpack.config.js for the web example project has some special stuff in the rules. This is because a) I’m leaving my library code in ES6, but it’s typical for web modules to be transpiled down already, and b) I don’t have a .babelrc in the library’s top-level folder (there might be a way to get this to work with a babelrc at each level, but I kept having issues):
rules: [
{
test: /\.(js|jsx)$/,
use: {
loader: 'babel-loader',
options: {
babelrc: false,
//presets: ['env', 'react', 'stage-2'],
// weird trick to get babel presets here to work for higher-level folders
// https://github.com/babel/babel-preset-env/issues/186
presets: ['babel-preset-env', 'babel-preset-react', 'babel-preset-stage-2'].map(
require.resolve
),
},
},
exclude: /node_modules\/(?!(common-lib)\/).*/,
},
],
So, all this basically tells the example app to transpile the library (but that’s the only thing it transpiles from node_modules) and to transpile it using the rules for the example app.
Worth noting that you don’t need any of this for the native app because native libraries are typically distributed in ES6!
The web project
As I mentioned before, when you import the library into your web project, you need to make sure it gets transpiled by babel. You don’t have to worry about the whole .babelrc outer-folder weirdness, so you can just stick this in your rules for webpack.config.js:
rules: [
{
test: /\.(js|jsx)$/,
use: ['babel-loader'],
exclude: /node_modules\/(?!(common-lib)\/).*/,
},
],
You could probably avoid this by using rollup or something like that to transpile your library just for web use. I’ve never done that before, and also you’d have to specifically transpile it for web and not transpile it for native (or add it to an ignore on the native side).
Native app
As mentioned before, metro bundler is already set to automatically transpile your node_modules, so just import your library and go.