After developing the smart contracts for 8x, I thought it was all over. That was far from the truth. The requirements for a decentralized protocol are slowly increasing over time with the need for:
Each of these requirements, more or less, requires its own repo. Before you know it you’ll be managing over 7 different repos with version control on each of them. Suddenly, making a small change in one package will require an npm install
in at least another 2 packages (best case).
So what’s the answer to this madness? A monorepo.
The first time I saw a monorepo, I felt a little something like this:
It feels a bit counter intuitive at first, why would you have one repo that contains all your repos? The answer has been outlined by many large companies such as Microsoft, Facebook and Google who all have a single repo for their entire code base. Here are some of them:
Some of this may seem a bit abstract but I promise you’ll see the light eventually.
To create our monorepo we’re going to use Lerna: https://github.com/lerna/lern
Here’s what you’re going to want to do inside a new folder
1. Create a new directory mkdir monorepo && cd $_
2. Install lerna globally npm install -g lerna
3. Create the structure for your new monorepolerna init
4. Import your existing smart contracts repo with lerna import /path/to/your/contracts/repo
(this will keep your commit history so don’t worry about starting from scratch young one).
Okay so before we carry on, you’re soon going to have a structure that looks a little like this:
monorepo/├── package.json├── packages│ └── contracts│ └── package.json│ └── another_one│ └── package.json│ └── another_one│ └── package.json
Essentially what this means is that all your dependencies will be symlink'd
to each other so changes in one repo will immediately show up in the others since they’re referring the same path in your local file system rather than containing duplicated code throughout. All you need to do is run lerna bootstrap
once.
But you can also start doing cool things such as:
lerna run build
which will run npm run build
inside each repo OR
lerna publish
which will upgrade all your packages to the same version (useful if you’re going to deploy a new set of smart contracts). This becomes even better if you add a prepublish
script inside all your repos which will in turn clean
your dist
folder, lint
your code base and generate your final dist
folder.
"scripts": {
"clean": "rimraf -rf ./dist",
"lint": "tslint --project tsconfig.json -c tslint.json",
"build": "npm run clean && npm run lint && tsc,
"prepublishOnly": "npm run build"
}
If you’re going to be putting all your eggs in one basket, make sure that basket looks decent!
Inside the root of your monorepo
folder, create a new file call readme.mustache
I know, you’re wondering why not readme.md
? We’ll come back to this later but for now here’s how you can swag up your repo:
<p align="center"><img src="your-logo" width="280"/></p>
<p align="center">
insert-description-here
</p>
<p align="center">
<a href="https://opensource.org/licenses/Apache-2.0"><img src="https://img.shields.io/badge/LICENSE-APACHE2.0-3DA639.svg"/></a>
</p>
That will give you something a little like this (less the chat and solidity badges and after we convert it to markdown):
It’s a great start but your fellow developers want to see all the packages in your monorepo and their respective versions. Let’s add some more code to our readme.mustache
:
## Packages
### Published
| Package | Version | Description |-----------------------------------------------
|[`name`](/packages/path) | [![npm](https://img.shields.io/npm/v/name.svg)](https://www.npmjs.com/package/name) | a description |
### Private
| Package | Description |---------------------------------|[`name`](/packages/path) | a description |
In case you’re wondering, published packages are ones you’re going to publish with npm to be used in other repos. Private packages are ones that you wouldn’t import into another project. Examples include smart contracts, marketing website etc. So what did the above net us? This:
Now, the next bit of code we’re going to add is:
### Contracts (insert network here)
Contract Name |
Address |
---|
{{#network.addresses}}| {{name}} | {{address}} |{{/network.addresses}}
We’ll revisit this bit later, but for now you’re going to want to insert the network your project is currently on (kovan, main-net, etc).
We now have the very basics for creating our actual protocol with the relevant resources for any visitors to find what they want (almost).
Stay tuned for the next edition of the tutorial where we go into the details of generating Typescript artifacts and writing a subsequent JS library to be consumed by other developers.