|
| 1 | +# Getting Started with Metaplex and Esbuild |
| 2 | + |
| 3 | +This example sets up a new React app with Metaplex using Esbuild. |
| 4 | + |
| 5 | +This example has been generated using the following steps: |
| 6 | + |
| 7 | +1. **Create a new project using NPM.** |
| 8 | + |
| 9 | + Esbuild does not have any standard template for React which can be utilized for initializing the project like CRA or Vite. So, we will be creating an empty npm project and setup everything from scratch. |
| 10 | + |
| 11 | + ```sh |
| 12 | + mkdir getting-started-react-esbuild |
| 13 | + cd getting-started-react-esbuild |
| 14 | + npm init -y |
| 15 | + ``` |
| 16 | + |
| 17 | + Once the empty npm project is ready, we will set up a basic directory structure with mainly `public` and `src` folders and a config file (`build.js`) which will be used for compiling and bundling the react app with esbuild. |
| 18 | + |
| 19 | + ``` |
| 20 | + getting-started-react-esbuild/ |
| 21 | + ├── public/ |
| 22 | + │ └── index.html |
| 23 | + ├── src/ |
| 24 | + │ ├── app.jsx |
| 25 | + │ ├── index.css |
| 26 | + │ └── index.js |
| 27 | + ├── build.js |
| 28 | + └── package.json |
| 29 | + ``` |
| 30 | + |
| 31 | +2. **Install React, EsBuild and the Metaplex SDK.** |
| 32 | + |
| 33 | + ```sh |
| 34 | + npm install react react-dom esbuild @metaplex-foundation/js @solana/web3.js |
| 35 | + ``` |
| 36 | + |
| 37 | +3. **Install some polyfills.** |
| 38 | + |
| 39 | + <details> |
| 40 | + <summary>Why?</summary> |
| 41 | + Some dependencies of the Metaplex SDK are still relying on NPM packages that are not available in the browser. To make sure that the Metaplex SDK works in the browser, we need to install some polyfills. |
| 42 | + </details> |
| 43 | + |
| 44 | + ```sh |
| 45 | + npm install -D node-stdlib-browser |
| 46 | + ``` |
| 47 | + |
| 48 | +4. **Install Servor for Development** |
| 49 | + |
| 50 | + <details> |
| 51 | + <summary>Why?</summary> |
| 52 | + Esbuild does not include any server that could be used to preview our app in the browser. So we will be using servor for that. |
| 53 | + </details> |
| 54 | + |
| 55 | + ```sh |
| 56 | + npm install -D servor |
| 57 | + ``` |
| 58 | + |
| 59 | +5. **Update your build.js file**. |
| 60 | + |
| 61 | + Add the following code to the `build.js` file we created earlier. |
| 62 | + |
| 63 | + <details> |
| 64 | + <summary>Why?</summary> |
| 65 | + The following code will build and bundle your react app with EsBuild. It will also start a dev server when used in development. |
| 66 | + </details> |
| 67 | + |
| 68 | + ```js |
| 69 | + const esbuild = require('esbuild'); |
| 70 | + const plugin = require('node-stdlib-browser/helpers/esbuild/plugin'); |
| 71 | + const stdLibBrowser = require('node-stdlib-browser'); |
| 72 | + const fs = require('fs'); |
| 73 | + const path = require('path'); |
| 74 | + const servor = require('servor'); |
| 75 | + |
| 76 | + const outdirectory = 'public'; |
| 77 | + |
| 78 | + // Clean previously built assets. |
| 79 | + fs.readdir(outdirectory, (err, files) => { |
| 80 | + if (err) throw err; |
| 81 | + for (const file of files) { |
| 82 | + if ( |
| 83 | + file.endsWith('.js') || |
| 84 | + file.endsWith('.css') || |
| 85 | + file.endsWith('.js.map') |
| 86 | + ) { |
| 87 | + fs.unlink(path.join(outdirectory, file), (err) => { |
| 88 | + if (err) throw err; |
| 89 | + }); |
| 90 | + } |
| 91 | + } |
| 92 | + }); |
| 93 | + |
| 94 | + async function dev() { |
| 95 | + console.log('Building development bundle ⏳'); |
| 96 | + await esbuild.build({ |
| 97 | + entryPoints: ['src/index.js'], |
| 98 | + outdir: outdirectory, |
| 99 | + bundle: true, |
| 100 | + define: { |
| 101 | + 'process.env.NODE_ENV': '"development"', |
| 102 | + global: 'global', |
| 103 | + process: 'process', |
| 104 | + Buffer: 'Buffer', |
| 105 | + }, |
| 106 | + minify: false, |
| 107 | + watch: true, |
| 108 | + inject: [require.resolve('node-stdlib-browser/helpers/esbuild/shim')], |
| 109 | + plugins: [plugin(stdLibBrowser)], |
| 110 | + loader: { |
| 111 | + '.js': 'jsx', |
| 112 | + }, |
| 113 | + }); |
| 114 | + console.log('Development bundle built ✅'); |
| 115 | + console.log('Running server from: http://localhost:8000'); |
| 116 | + await servor({ |
| 117 | + browser: true, |
| 118 | + root: outdirectory, |
| 119 | + port: 8000, |
| 120 | + }); |
| 121 | + } |
| 122 | + |
| 123 | + async function prod() { |
| 124 | + console.log('Build started ⏳'); |
| 125 | + await esbuild.build({ |
| 126 | + entryPoints: ['src/index.js'], |
| 127 | + outdir: outdirectory, |
| 128 | + bundle: true, |
| 129 | + define: { |
| 130 | + 'process.env.NODE_ENV': '"production"', |
| 131 | + global: 'global', |
| 132 | + process: 'process', |
| 133 | + Buffer: 'Buffer', |
| 134 | + }, |
| 135 | + minify: true, |
| 136 | + inject: [require.resolve('node-stdlib-browser/helpers/esbuild/shim')], |
| 137 | + plugins: [plugin(stdLibBrowser)], |
| 138 | + loader: { |
| 139 | + '.js': 'jsx', |
| 140 | + }, |
| 141 | + }); |
| 142 | + console.log('Build completed ✅'); |
| 143 | + } |
| 144 | + |
| 145 | + //defaults to build |
| 146 | + let config = '-build'; |
| 147 | + if (process.argv.length > 2) { |
| 148 | + config = process.argv[2]; |
| 149 | + } |
| 150 | + |
| 151 | + // Builds the bundle for dvelopment and runs a local web server |
| 152 | + // with livereload when -watch is set |
| 153 | + config === '-watch' && dev(); |
| 154 | + |
| 155 | + // Builds optimized bundle for production |
| 156 | + config === '-build' && prod(); |
| 157 | + ``` |
| 158 | + |
| 159 | +6. **Update your `package.json`.** |
| 160 | + |
| 161 | + Add the following scripts to your `package.json` file. |
| 162 | + |
| 163 | + ```diff |
| 164 | + "scripts": { |
| 165 | + + "build": "node build.js -build", |
| 166 | + + "dev": "node build.js -watch" |
| 167 | + }, |
| 168 | + ``` |
| 169 | + |
| 170 | +7. **Update your `index.html`.** |
| 171 | + |
| 172 | + Add the following code in your `index.html` file. |
| 173 | + |
| 174 | + ```html |
| 175 | + <!DOCTYPE html> |
| 176 | + <html lang="en"> |
| 177 | + <head> |
| 178 | + <meta charset="utf-8" /> |
| 179 | + <meta name="viewport" content="width=device-width, initial-scale=1" /> |
| 180 | + <meta name="theme-color" content="#000000" /> |
| 181 | + <meta name="description" content="EsBuild + Metaplex" /> |
| 182 | + <title>EsBuild + Metaplex</title> |
| 183 | + <script src="index.js" async defer></script> |
| 184 | + <link rel="stylesheet" href="index.css" /> |
| 185 | + </head> |
| 186 | + <body> |
| 187 | + <noscript>You need to enable JavaScript to run this app.</noscript> |
| 188 | + <div id="root"></div> |
| 189 | + </body> |
| 190 | + </html> |
| 191 | + ``` |
| 192 | + |
| 193 | +8. **That's it!** 🎉 |
| 194 | + |
| 195 | + You're now ready to start building your app. You can use the following commands to build and serve your app. |
| 196 | + |
| 197 | + ```sh |
| 198 | + # Build and serve for development. |
| 199 | + npm run dev |
| 200 | + |
| 201 | + # Build for production. |
| 202 | + npm run build |
| 203 | + ``` |
| 204 | + |
| 205 | + If you're interested in how this example app is using the Metaplex SDK, check out the [`App.js`](./src/App.js) and [`App.css`](./src/App.css) files in the `src` directory. |
0 commit comments