How to compile Smart Contracts in React with WebWorker
In this post I gonna compile a Solidity Smart Contract 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)
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. NX is a 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.
-
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
-
Add
webpack.json
to workspace.json file.```js "webpackConfig": "apps/frontend/webpack.config.js" ```
Here is the detail of webpackConfig option.
Compile Solidity Smart Contract with WebWorker
-
Solc@0.8.7-fixed
doesn’t have typescript declaration yet, we have to add a type declaration manually. Simply adddeclare module 'solc/wrapper';
to*.d.ts
file in your project. -
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); }
-
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 this great answer from T.J. Crower
-
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