DEV Community

Cover image for How to Compile Smart Contracts in React
Duc Nguyen
Duc Nguyen

Posted on • Updated on

How to Compile Smart Contracts in React

Demo Compiling Solidity Smart Contract in React with WebWorker

In this post I gonna compile a Solidity program with Solidity Compiler JS in browsers supported WebWorker.

Tools and plugins:

nx@12.7.1
worker-plugin@5.0.1
solc@0.8.7-fixed
webpack@4 (included in NX)
Enter fullscreen mode Exit fullscreen mode

Compiling a smart contract with Solc is a heavy task for browsers, and for such heavy task we need to use WebWorker.

The tool for setting up the project is NX. it is great tool to create monos-repository.

Configuring WebWorker for NX

NX is using Webpack underhood, In this post we use worker-plugin to make WebWorker work with Webpack. In order to config worker-plugin we need to extend the default configuration of Webpack inside NX.

  1. Create webpack.json in root folder of frontend module.

    const WorkerPlugin = require('worker-plugin');
    const nrwlConfig = require('@nrwl/react/plugins/webpack.js');
    
    module.exports = (config, context) => {
        nrwlConfig(config);
        return {
            ...config,
            node: {
                Buffer: true,
                module: 'empty',
            },
            plugins: [new WorkerPlugin(), ...config.plugins],
        };
    };
    

    As you can see we have some polyfill configurations for NodeJS in Webpack

  2. Add webpack.json to workspace.json file.

    "webpackConfig": "apps/frontend/webpack.config.js"
    

Here is the detail of webpackConfig option.

Compile Solidity Smart Contract with WebWorker

  1. Solc@0.8.7-fixed doesn't have typescript declaration yet, we have to add a type declaration manually. Simply add declare module 'solc/wrapper'; to *.d.ts file in your project.

  2. Creating a worker SolcJs.worker.ts file.

    /* eslint-disable no-restricted-globals */
    import * as wrapper from 'solc/wrapper';
    const ctx: Worker = self as any;
    
    importScripts(
        'https://solc-bin.ethereum.org/bin/soljson-v0.8.6+commit.11564f7e.js'
    );
    
    ctx.addEventListener('message', ({ data }) => {
        const solc = wrapper((ctx as any).Module);
        const compileResult = solc.compile(
            createCompileInput(data.contractFileName, data.content)
        );
        ctx.postMessage(compileResult);
    });
    
    function createCompileInput(
        fileName = 'storage.sol',
        fileContent: string
    ): string {
        const CompileInput = {
            language: 'Solidity',
            sources: {
                [fileName]: {
                    content: fileContent,
                },
            },
            settings: {
                outputSelection: {
                    '*': {
                        '*': ['*'],
                    },
                },
            },
        };
        return JSON.stringify(CompileInput);
    }
    
  3. Create a Promisify function to call SolcJs.worker.ts and wait until the compilation finished.

    const compileWithWorker = async (data: any) => {
            return new Promise((resolve, reject) => {
                const worker = new Worker('../../SolcJs.worker.ts', {
                    type: 'module',
                });
                worker.postMessage(data);
                worker.onmessage = function (event: any) {
                    resolve(event.data);
                };
                worker.onerror = reject;
            });
    };
    

    Thank to the great answer from T.J. Crower

  4. Now we are ready to use WebWorker to compile a Simple Solidity Smart Contract.

    const handleCompile = async () => {
            setCompiling(true);
            const result = await compileWithWorker({
                content: SimpleStorageContact,
            });
            setCompileResult(result as string);
            setCompiling(false);
    };
    

SourceCode in Github - nx-webworker-sample

Discussion (0)