├── src ├── vite-env.d.ts ├── main.tsx ├── App.css ├── App.tsx ├── index.css └── assets │ └── react.svg ├── bun.lockb ├── scripts └── build.sh ├── vite.config.ts ├── tsconfig.node.json ├── .gitignore ├── index.html ├── tsconfig.json ├── package.json ├── netlify.toml ├── public └── vite.svg └── README.md /src/vite-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /bun.lockb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JLarky/bun-netlify/HEAD/bun.lockb -------------------------------------------------------------------------------- /scripts/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | curl -fsSL https://bun.sh/install | bash 4 | export PATH="/opt/buildhome/.bun/bin:$PATH" 5 | bun --version 6 | bun install 7 | bun --bun run build 8 | -------------------------------------------------------------------------------- /vite.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite' 2 | import react from '@vitejs/plugin-react' 3 | 4 | // https://vitejs.dev/config/ 5 | export default defineConfig({ 6 | plugins: [react()], 7 | }) 8 | console.log(typeof Bun === "object" && Bun); 9 | -------------------------------------------------------------------------------- /tsconfig.node.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "composite": true, 4 | "skipLibCheck": true, 5 | "module": "ESNext", 6 | "moduleResolution": "bundler", 7 | "allowSyntheticDefaultImports": true 8 | }, 9 | "include": ["vite.config.ts"] 10 | } 11 | -------------------------------------------------------------------------------- /src/main.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import ReactDOM from 'react-dom/client' 3 | import App from './App.tsx' 4 | import './index.css' 5 | 6 | ReactDOM.createRoot(document.getElementById('root')!).render( 7 | 8 | 9 | , 10 | ) 11 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | .netlify 26 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Vite + React + TS 8 | 9 | 10 |
11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2020", 4 | "useDefineForClassFields": true, 5 | "lib": ["ES2020", "DOM", "DOM.Iterable"], 6 | "module": "ESNext", 7 | "skipLibCheck": true, 8 | 9 | /* Bundler mode */ 10 | "moduleResolution": "bundler", 11 | "allowImportingTsExtensions": true, 12 | "resolveJsonModule": true, 13 | "isolatedModules": true, 14 | "noEmit": true, 15 | "jsx": "react-jsx", 16 | 17 | /* Linting */ 18 | "strict": true, 19 | "noUnusedLocals": true, 20 | "noUnusedParameters": true, 21 | "noFallthroughCasesInSwitch": true 22 | }, 23 | "include": ["src"], 24 | "references": [{ "path": "./tsconfig.node.json" }] 25 | } 26 | -------------------------------------------------------------------------------- /src/App.css: -------------------------------------------------------------------------------- 1 | #root { 2 | max-width: 1280px; 3 | margin: 0 auto; 4 | padding: 2rem; 5 | text-align: center; 6 | } 7 | 8 | .logo { 9 | height: 6em; 10 | padding: 1.5em; 11 | will-change: filter; 12 | transition: filter 300ms; 13 | } 14 | .logo:hover { 15 | filter: drop-shadow(0 0 2em #646cffaa); 16 | } 17 | .logo.react:hover { 18 | filter: drop-shadow(0 0 2em #61dafbaa); 19 | } 20 | 21 | @keyframes logo-spin { 22 | from { 23 | transform: rotate(0deg); 24 | } 25 | to { 26 | transform: rotate(360deg); 27 | } 28 | } 29 | 30 | @media (prefers-reduced-motion: no-preference) { 31 | a:nth-of-type(2) .logo { 32 | animation: logo-spin infinite 20s linear; 33 | } 34 | } 35 | 36 | .card { 37 | padding: 2em; 38 | } 39 | 40 | .read-the-docs { 41 | color: #888; 42 | } 43 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vite-project", 3 | "private": true, 4 | "version": "0.0.0", 5 | "type": "module", 6 | "scripts": { 7 | "dev": "vite", 8 | "build": "tsc && vite build", 9 | "lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0", 10 | "preview": "vite preview" 11 | }, 12 | "dependencies": { 13 | "react": "^18.2.0", 14 | "react-dom": "^18.2.0" 15 | }, 16 | "devDependencies": { 17 | "@types/react": "^18.2.15", 18 | "@types/react-dom": "^18.2.7", 19 | "@typescript-eslint/eslint-plugin": "^6.0.0", 20 | "@typescript-eslint/parser": "^6.0.0", 21 | "@vitejs/plugin-react": "^4.0.3", 22 | "eslint": "^8.45.0", 23 | "eslint-plugin-react-hooks": "^4.6.0", 24 | "eslint-plugin-react-refresh": "^0.4.3", 25 | "typescript": "^5.0.2", 26 | "vite": "^4.4.5" 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /netlify.toml: -------------------------------------------------------------------------------- 1 | # example netlify.toml 2 | [build] 3 | functions = "netlify/functions" 4 | # custom build command that install bun and run build 5 | command = "./scripts/build.sh" 6 | # vite output folder 7 | publish = "dist" 8 | 9 | [build.environment] 10 | # disable NPM install 11 | NPM_FLAGS = "--version" 12 | 13 | ## Uncomment to use this redirect for Single Page Applications like create-react-app. 14 | ## Not needed for static site generators. 15 | #[[redirects]] 16 | # from = "/*" 17 | # to = "/index.html" 18 | # status = 200 19 | 20 | ## (optional) Settings for Netlify Dev 21 | ## https://github.com/netlify/cli/blob/main/docs/netlify-dev.md#project-detection 22 | #[dev] 23 | # command = "yarn start" # Command to start your dev server 24 | # port = 3000 # Port that the dev server will be listening on 25 | # publish = "dist" # Folder with the static content for _redirect file 26 | 27 | ## more info on configuring this file: https://docs.netlify.com/configure-builds/file-based-configuration/ 28 | -------------------------------------------------------------------------------- /src/App.tsx: -------------------------------------------------------------------------------- 1 | import { useState } from 'react' 2 | import reactLogo from './assets/react.svg' 3 | import viteLogo from '/vite.svg' 4 | import './App.css' 5 | 6 | function App() { 7 | const [count, setCount] = useState(0) 8 | 9 | return ( 10 | <> 11 |
12 | 13 | Vite logo 14 | 15 | 16 | React logo 17 | 18 |
19 |

20 | Vite + React +{" "} 21 | 25 | Bun 26 | 27 |

28 |
29 | 32 |

33 | Edit src/App.tsx and save to test HMR 34 |

35 |
36 |

37 | Click on the Vite and React logos to learn more 38 |

39 | 40 | ) 41 | } 42 | 43 | export default App 44 | -------------------------------------------------------------------------------- /public/vite.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/index.css: -------------------------------------------------------------------------------- 1 | :root { 2 | font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif; 3 | line-height: 1.5; 4 | font-weight: 400; 5 | 6 | color-scheme: light dark; 7 | color: rgba(255, 255, 255, 0.87); 8 | background-color: #242424; 9 | 10 | font-synthesis: none; 11 | text-rendering: optimizeLegibility; 12 | -webkit-font-smoothing: antialiased; 13 | -moz-osx-font-smoothing: grayscale; 14 | -webkit-text-size-adjust: 100%; 15 | } 16 | 17 | a { 18 | font-weight: 500; 19 | color: #646cff; 20 | text-decoration: inherit; 21 | } 22 | a:hover { 23 | color: #535bf2; 24 | } 25 | 26 | body { 27 | margin: 0; 28 | display: flex; 29 | place-items: center; 30 | min-width: 320px; 31 | min-height: 100vh; 32 | } 33 | 34 | h1 { 35 | font-size: 3.2em; 36 | line-height: 1.1; 37 | } 38 | 39 | button { 40 | border-radius: 8px; 41 | border: 1px solid transparent; 42 | padding: 0.6em 1.2em; 43 | font-size: 1em; 44 | font-weight: 500; 45 | font-family: inherit; 46 | background-color: #1a1a1a; 47 | cursor: pointer; 48 | transition: border-color 0.25s; 49 | } 50 | button:hover { 51 | border-color: #646cff; 52 | } 53 | button:focus, 54 | button:focus-visible { 55 | outline: 4px auto -webkit-focus-ring-color; 56 | } 57 | 58 | @media (prefers-color-scheme: light) { 59 | :root { 60 | color: #213547; 61 | background-color: #ffffff; 62 | } 63 | a:hover { 64 | color: #747bff; 65 | } 66 | button { 67 | background-color: #f9f9f9; 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/assets/react.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # How to quickly deploy Bun React project to Netlify 2 | 3 | This is a template showing how you can use Bun to build React project and deploy it to Netlify. We are using Vite and React, if you want to change this for your project, please do. 4 | 5 | # Important clarifications 6 | 7 | A few notes on bun vs bun :) 8 | 9 | When you run `bun dev` it will use `bun` just as a script runner, and your vite will actually be running in Node. But if you run `bun --bun dev` if will use Bun JavaScript runtime to run Vite. 10 | 11 | If this all sounds crazy, just do this (after following the guide below)): 12 | 13 | ```bash 14 | echo 'console.log(Bun);' >> vite.config.ts 15 | bun --bun dev # to test it 16 | bun dev # to see that it crashes 17 | ``` 18 | 19 | Again, this doesn't actually matter that much, since it only afffects vite plugins and such, your users are just going to get the same application bundle no matter what runtime vite was using :) 20 | 21 | # Requirements 22 | 23 | - [Bun 1.0 or higher](https://bun.sh/) 24 | 25 | # What to do 26 | 27 | You can clone this repo or just follow the steps below. 28 | 29 | ## 1. Create new React project with Vite using Bun 30 | 31 | ```bash 32 | bunx --bun create-vite -t react-ts 33 | cd vite-project 34 | bun install 35 | ``` 36 | 37 | ## 2. Development 38 | 39 | ``` 40 | bun --bun dev 41 | ``` 42 | 43 | open http://localhost:5173/ 44 | 45 | ## 3. Build 46 | 47 | ``` 48 | bun --bun run build 49 | ``` 50 | 51 |
52 | 53 | Is it fast? Well, almost as fast as Node https://twitter.com/jarredsumner/status/1700680788231311789 :) 54 | 55 | 56 | Keep in mind that `bun run build` or even `npm run build` will probably run slightly faster. Let me say it again, currently building Vite using Node runtime is faster (shocking, I know). 57 | 58 | ``` 59 | $ hyperfine --warmup=2 "bun --bun run build" "bun run build" "npm run build" 60 | 61 | Benchmark 1: bun --bun run build 62 | Time (mean ± σ): 2.052 s ± 0.012 s [User: 2.098 s, System: 0.176 s] 63 | Range (min … max): 2.037 s … 2.072 s 10 runs 64 | 65 | Benchmark 2: bun run build 66 | Time (mean ± σ): 1.363 s ± 0.021 s [User: 1.210 s, System: 0.090 s] 67 | Range (min … max): 1.344 s … 1.410 s 10 runs 68 | 69 | Benchmark 3: npm run build 70 | Time (mean ± σ): 1.599 s ± 0.029 s [User: 2.527 s, System: 0.192 s] 71 | Range (min … max): 1.570 s … 1.666 s 10 runs 72 | 73 | Summary 74 | 'bun run build' ran 75 | 1.17 ± 0.03 times faster than 'npm run build' 76 | 1.51 ± 0.03 times faster than 'bun --bun run build' 77 | ``` 78 |
79 | 80 | ## 4. Connect to Netlify 81 | 82 | make sure to connect your repo to github and netlify to enable automatic builds. 83 | 84 | ``` 85 | ntl init 86 | ``` 87 | 88 | Edit `netlify.toml`: 89 | 90 | ```toml 91 | [build] 92 | # custom build command that install bun and run build 93 | command = "./scripts/build.sh" 94 | # vite output folder 95 | publish = "dist" 96 | 97 | [build.environment] 98 | # disable NPM install 99 | NPM_FLAGS = "--version" 100 | ``` 101 | 102 | Edit `scripts/build.sh`: 103 | 104 | ```sh 105 | #!/bin/bash 106 | set -e 107 | curl -fsSL https://bun.sh/install | bash 108 | export PATH="/opt/buildhome/.bun/bin:$PATH" 109 | bun --version 110 | bun install 111 | bun --bun run build 112 | ``` 113 | 114 | ## 5. Deploy 115 | 116 | Just push to github and netlify will build and deploy your site. 117 | 118 | ## Learn More 119 | 120 | - [How to build production build of Bun React](https://dev.to/ashirbadgudu/create-a-react-app-with-bun-125o) 121 | - [How to install Bun](https://bun.sh/) 122 | - [Install Deno on Netlify](https://dbushell.com/2021/07/22/netlify-deno-builds/) --- we use the same idea to install Bun 123 | - [How to disable NPM install](https://answers.netlify.com/t/prevent-npm-from-running-on-deploy/66882/3) 124 | - [How to use Bun with Netlify](https://stackoverflow.com/a/74883541) 125 | 126 | ## Note on `bun dev` 127 | 128 | This repo used to use `bun dev` which was deprecated in Bun 1.0 but you can still see those branches: 129 | 130 | - [Using "bun dev" and react-scripts for prod](https://github.com/JLarky/bun-netlify/tree/react-scripts) 131 | - [Using "bun dev" and vite for prod](https://github.com/JLarky/bun-netlify/tree/vite) 132 | --------------------------------------------------------------------------------