Skip to content

Commit 003f32c

Browse files
authored
Merge pull request #13 from apoorvdwi/feature/react-esbuild
React EsBuild Starter Kit
2 parents ff8e7c0 + 6ff9c94 commit 003f32c

File tree

11 files changed

+11940
-0
lines changed

11 files changed

+11940
-0
lines changed

README.md

+1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ Examples and Starter Kits using the new Metaplex JS SDK.
88
- [Getting Started with Metaplex and CRA 5](./getting-started-react-cra5) (React and Webpack 5)
99
- [Getting Started with Metaplex and Vite](./getting-started-vite) (React, Vue, Svelte, etc. and Vite/Rollup)
1010
- [Getting Started with Metaplex and Express.js](./getting-started-expressjs)
11+
- [Getting Started with Metaplex and EsBuild](./getting-started-react-esbuild/) (React and EsBuild)
1112

1213
## Reference Implementations
1314
- [Connect with wallets in the browser](./connect-wallet)
+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2+
3+
# dependencies
4+
/node_modules
5+
/.pnp
6+
.pnp.js
7+
8+
# testing
9+
/coverage
10+
11+
# production
12+
/build
13+
14+
# misc
15+
.DS_Store
16+
.env.local
17+
.env.development.local
18+
.env.test.local
19+
.env.production.local
20+
21+
npm-debug.log*
22+
yarn-debug.log*
23+
yarn-error.log*
+205
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,205 @@
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.
+88
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
const esbuild = require('esbuild');
2+
const plugin = require('node-stdlib-browser/helpers/esbuild/plugin');
3+
const stdLibBrowser = require('node-stdlib-browser');
4+
const fs = require('fs');
5+
const path = require('path');
6+
const servor = require('servor');
7+
8+
const outdirectory = 'public';
9+
10+
//clear out any old JS or CSS
11+
fs.readdir(outdirectory, (err, files) => {
12+
if (err) throw err;
13+
for (const file of files) {
14+
if (
15+
file.endsWith('.js') ||
16+
file.endsWith('.css') ||
17+
file.endsWith('.js.map')
18+
) {
19+
fs.unlink(path.join(outdirectory, file), (err) => {
20+
if (err) throw err;
21+
});
22+
}
23+
}
24+
});
25+
26+
async function dev() {
27+
console.log('Building development bundle ⏳');
28+
await esbuild.build({
29+
entryPoints: ['src/index.js'],
30+
outdir: outdirectory,
31+
bundle: true,
32+
define: {
33+
'process.env.NODE_ENV': '"development"',
34+
global: 'global',
35+
process: 'process',
36+
Buffer: 'Buffer',
37+
},
38+
minify: false,
39+
watch: true,
40+
inject: [require.resolve('node-stdlib-browser/helpers/esbuild/shim')],
41+
plugins: [plugin(stdLibBrowser)],
42+
loader: {
43+
'.js': 'jsx',
44+
},
45+
});
46+
console.log('Development bundle built ✅');
47+
console.log('Running server from: http://localhost:8000');
48+
await servor({
49+
browser: true,
50+
root: outdirectory,
51+
port: 8000,
52+
});
53+
}
54+
55+
async function prod() {
56+
console.log('Build started ⏳');
57+
await esbuild.build({
58+
entryPoints: ['src/index.js'],
59+
outdir: outdirectory,
60+
bundle: true,
61+
define: {
62+
'process.env.NODE_ENV': '"production"',
63+
global: 'global',
64+
process: 'process',
65+
Buffer: 'Buffer',
66+
},
67+
minify: true,
68+
inject: [require.resolve('node-stdlib-browser/helpers/esbuild/shim')],
69+
plugins: [plugin(stdLibBrowser)],
70+
loader: {
71+
'.js': 'jsx',
72+
},
73+
});
74+
console.log('Build completed ✅');
75+
}
76+
77+
//defaults to build
78+
let config = '-build';
79+
if (process.argv.length > 2) {
80+
config = process.argv[2];
81+
}
82+
83+
// Builds the bundle for dvelopment and runs a local web server
84+
// with livereload when -watch is set
85+
config === '-watch' && dev();
86+
87+
// Builds optimized bundle for production
88+
config === '-build' && prod();

0 commit comments

Comments
 (0)