Compile Solidity In The Browser
Tags: solidity, webworker, react, javascript
Published: 2022-10-03 15:40:21

Like me, if you have run into issues using Browser-solc when trying to create an app that could compile solidity in the client using ReactJS, this article is for you. We'll see how to use of `@agnostico/browser-solidity-compiler` to acheive our result shortly, getting rid of common issues you are likely to face.

There are many reasons why you may want to compile a solidity smart contract in the browser; Maybe you are building the next [remix](https://remix.ethereum.org) or you are building an entirely different application and you simply want to have the client fully take control of what is compiled as with the case with what I am building, [Agnostico](https://agnostico.xyz).

Since the `eth_compile` API was [deprecated](https://github.com/ethereum/EIPs/issues/209), the available alternatives ([Solc-JS](https://github.com/ethereum/solc-js) and the extended [Browser-Solc](https://github.com/ericxtang/browser-solc)) work best in a server setup or is tightly coupled to the HTML DOM, they are not so flexible to work with in modern Javascript library environment such as ReactJS, well at least, not so straight-forward. This will make your application throw tantrums as you develop with them which, from my experience, is a terrible developer experience.

To allow others build their applications with ease, I built on the provisions of solcjs and created a package that can work efficiently in such development environments (and with typescript support). It uses [webworkers](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API) under the hood to offload heavy compilation computations from our main thread. Let's take a look at it in action.

The project is available in the [example](https://github.com/rexdavinci/browser-solidity-compiler/tree/example) branch of the repo. I will explain how it works here with snippets so let's get to it.

The example repository is built with [create-react-app](https://github.com/facebook/create-react-app#readme), and to install our package, we run 
```npm i @agnostico/browser-solidity-compiler```

Using the package in our application,
```
// App.tsx
...
import {
  getCompilerVersions,
  solidityCompiler,
} from '@agnostico/browser-solidity-compiler';
...
```
the `getCompilerVersions` is an async operation that fetches the list of existing solidity versions from `https://binaries.soliditylang.org/bin/list.json`. 

```
// App.tsx
...
const loadVersions = async () => {
 const { releases, latestRelease, builds } = await getCompilerVersions()
};

// Load versions immediately page is mounted
useEffect(() => {
 (async () => { 
   await loadVersions() 
  })();
 }, []);
...
```
Our returned object looks like this

![Solidity Versions](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/r3nicxqqpgrb676p9n4n.png)

And then to compile our contracts, we select the  we simply pass the required arguments into the compiler object. Our version will look similar to this if we are not using a template literal: `https://binaries.soliditylang.org/bin/soljson-v0.8.17+commit.8df45f5f.js` (If we are using solidity version 0.8.17). But to make it dynamic in cases where the user can switch between versions, we implement like this.


```
// App.tsx
...
const compiled = (await solidityCompiler({ 
version: `https://binaries.soliditylang.org/bin/${usingVersion}`,
 contractBody: content,
 options,
}));
...
```
The `contractBody` is the string of the contract(s) to be compiled. while `options` the optimization object. It is optional. For example, you could have optimization looking like this
```
options.optimizer = {
  enabled: true,
  runs: 200,
};
```

Our contracts in the example repo was returned in the compiled variable, stored in state and accessed this way

```
// App.tsx
Object.keys(compiledContract?.contracts?.Compiled_Contracts).map((cont) => (
  <div key={cont}>
   <p>{cont}</p>

  <span>Bytecode</span>: <small>
{
                      compiledContract?.contracts?.Compiled_Contracts[cont]?.evm?.bytecode?.object
 }
   </small>
 </div>
 )
)
```
The contract(s) are stored in a property of the returned object called `Compiled_Contracts` where we can access their information such as the `abi` or `bytecode` and shown above.


**Reference:**
[Solc-JS](https://github.com/ethereum/solc-js)
[@agnostico/browser-solidity-compiler](https://github.com/rexdavinci/browser-solidity-compiler/tree/main)