Permanently deploy decentralized React frontends to Arweave

The need for permanent and decentralized frontend deployments

Most frontend devs I know in web3 use Next.js + Vercel for their frontends. Probably for good reason, too. Next.js is fast & feature-packed, and no other platform has a better developer experience than Vercel.

While this stack serves well for most, it is a very centralized solution. Your frontend will be at the mercy of Vercel, who use AWS behind the scenes. Not very web3.

To be fair, most people don't need a decentralized frontend setup. But in some cases, it is an absolute necessity. For example, a decentralized exchange like Uniswap should never solely rely on a centralized provider. (not saying Uniswap uses Vercel, just an example. I have no idea what they use lol)

It makes sense to use a centralized provider as the primary option for speed & scale, but it is vital to have a backup that is permanent and decentralized to fight censorship. So if Vercel doesn't like Uniswap anymore, it doesn't mean Uniswap becomes inaccessible via the web right away. The idea here is to have a decentralized deployment ready, at least as a fallback.

Arweave lets you permanently deploy webpages to a decentralized network. This is why we will be going through the process of setting up a React app for deployment to Arweave in this article.

What we will be building

We will be building a very simple React app that lets people connect their wallets, and deploy it to Arweave.

You can also visit the live deployed page and try it out yourself: https://arweave.net/wI-CGD-uca4Dx_KNODXPg1ypjd5acWQ0ZM4UHZRh99Q

Tech stack

We will be using Vite instead of Next.js for this project, for several reasons:

  1. Vite is FAST ⚡️ (follow along and you'll find out)
  2. Next.js is basically a server that serves webpages. On the other hand, Vite runs fully on the client-side i.e. in the browser. For a frontend to be really decentralized, it should ideally be running fully on the client. We are going for an extreme here, but why not?
  3. It is super-easy to generate a fully static site using Vite. Using Next.js, it's a bit of a pain in the ass.

Apart from that, we will be using Rainbowkit 🌈 to setup our connect wallet functionality.

Make sure you have Node.js and Yarn installed.

Project setup

Let's start off by setting up some boilerplate using Vite's handy CLI tool. In your terminal, run the following command:

Select the options just like in the screenshot above and hit Enter. The next thing we want to do is cd into our newly-created project's directory and install our dependencies. We will also initialize an empty local git repo in the folder while we're at it.

Awesome! Let's now try running our app by running yarn dev. Your app will be live on http://localhost:3000. It should look like this:

You see how fast that was? 😄 Vite means speed.

Building out the UI

Let's add a connect wallet button to our app now. We will need to install some dependencies for that:

Once that's done, let's setup Rainbowkit in our code. I'm just following the Rainbowkit installation docs here, nothing fancy!

Make sure your main.jsx looks like this:

import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
import './index.css';

import '@rainbow-me/rainbowkit/styles.css';
import { getDefaultWallets, RainbowKitProvider } from '@rainbow-me/rainbowkit';
import { chain, configureChains, createClient, WagmiConfig } from 'wagmi';
import { jsonRpcProvider } from 'wagmi/providers/jsonRpc';
import { publicProvider } from 'wagmi/providers/public';

const { chains, provider } = configureChains(
  [chain.mainnet],
  [
    jsonRpcProvider({
      rpc: () => {
        return {
          http: 'https://rpc.ankr.com/eth',
        };
      },
    }),
    publicProvider(),
  ]
);

const { connectors } = getDefaultWallets({
  appName: 'My RainbowKit App',
  chains,
});

const wagmiClient = createClient({
  autoConnect: true,
  connectors,
  provider,
});

ReactDOM.createRoot(document.getElementById('root')).render(
  <React.StrictMode>
    <WagmiConfig client={wagmiClient}>
      <RainbowKitProvider chains={chains}>
        <App />
      </RainbowKitProvider>
    </WagmiConfig>
  </React.StrictMode>
);

And your App.jsx like this:

import { ConnectButton } from '@rainbow-me/rainbowkit';

function App() {
  return (
    <div>
      <div
        style={{ display: 'flex', justifyContent: 'center', marginTop: '20px' }}
      >
        <ConnectButton />
      </div>
    </div>
  );
}

export default App;

Your app should now look like this:

Try clicking that button and connecting your wallet. It should work perfectly fine. Rainbowkit is great! 🌈❤️

That's all I'm going to do for the UI but feel free to get create and add whatever you want! I am moving on to the deployment setup now.

Prep for deployment to Arweave

To make sure our Vite app gets built and deployed to Arweave correctly, we need to make small adjustments to two files.

  1. File: vite.config.js
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [react()],
++  base: '',
});
  1. File: package.json
{
  "name": "vite-arweave",
  "private": true,
  "version": "0.0.0",
  "scripts": {
    "dev": "vite",
    "build": "vite build",
    "preview": "vite preview",
++  "deploy": "yarn build && arweave deploy-dir dist --key-file wallet.json"
  },
  "dependencies": {
    "react": "^18.0.0",
    "react-dom": "^18.0.0",
  },
  "devDependencies": {
    "@types/react": "^18.0.0",
    "@types/react-dom": "^18.0.0",
    "@vitejs/plugin-react": "^1.3.0",
    "vite": "^2.9.9"
  },
++  "homepage": "./"
}

The base and homepage options make sure that our app gets built and loaded on Arweave correctly.

We also added a deploy script that we will run when we want to deploy our app to Arweave.

The next step is to create an Arweave account if you don't have one already and grab some test funds from the faucet. Go to this link: https://faucet.arweave.net/ and follow the instructions.

IMPORTANT: Don't forget to download your wallet during the step I've shown in the screenshot below and keep that file handy. You will need this later on.

After following all the instructions on the faucet page, install the arweave-deploy CLI. We will make use of this tool to deploy our app. Run the following command to install it:

Quickly verify if the installation was successful or not by running this:

If all looks good, create a new file called wallet.json at the root of your project. Copy and paste the contents of the wallet file you downloaded from the faucet into this file.

The wallet.json file contains the seed phrase/private key for your Arweave wallet so let's make sure it does not get committed to Git. Add this line to the bottom of your .gitignore file:

wallet.json

Now we're all set. It is time to yeet our app straight to the Arweave network! 🚀

Arweave deployment

All you need to do now is to run yarn deploy at the root of your project:

Remember to type in CONFIRM when prompted! Now all you have to do is sit back and wait for your files to get uploaded to Arweave!

You will see a message similar to that if the deployment was successful. Let's check out what our app looks like. Click on that URL!

LFGG! 🎉 YOU JUST PERMANENTLY DEPLOYED A REACT APP TO ARWEAVE! 🫡

Give yourself a pat on the back. This page will now live on Arweave FOREVER. No one can take this down. That right there is extremely powerful. 💪

You can find the final code in this repo for reference: https://github.com/Dhaiwat10/vite-arweave

Don't forget to follow me on Twitter or I'll be very sad :'(

Thanks for reading and feel free to DM me if you need help! Ciao! :)

Subscribe to Dhaiwat Pandya
Receive the latest updates directly to your inbox.
Verification
This entry has been permanently stored onchain and signed by its creator.