DEV Community

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

Posted on Edited 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

Top comments (0)