|
| 1 | +--- |
| 2 | +title: Upgrading Vite (4 → 8) |
| 3 | +description: Step-by-step guide for moving an older Needle Engine project from the pinned Vite 4 setup to Vite 8. |
| 4 | +--- |
| 5 | + |
| 6 | +# <logo-header logo="/imgs/vite-logo.webp" alt="Vite">Upgrading Vite (4 → 8)</logo-header> |
| 7 | + |
| 8 | +Needle projects created before early 2026 pinned Vite to `<= 4.3.9`. This was a deliberate workaround for a Vite HTTP/2 bug that caused dev-server session-memory timeouts. That bug is resolved in modern Vite, and the current template ships against **Vite 8**. |
| 9 | + |
| 10 | +In practice the Vite 4 → 8 jump happens together with the **Needle Engine 4 → 5** upgrade — they were updated in the same template change. This guide covers the Vite-side changes. |
| 11 | + |
| 12 | +:::tip Upgrading is optional |
| 13 | +Vite 4 still works, so you don't have to update. We recommend updating older projects to pick up newer Vite features and fixes. `package.json` and `vite.config.js` are part of your project (the Unity / Blender integrations don't overwrite them), so the steps below apply however your project was created. |
| 14 | +::: |
| 15 | + |
| 16 | +--- |
| 17 | + |
| 18 | +## 1. Check your Node.js version |
| 19 | + |
| 20 | +This is the most common upgrade blocker. Vite 8 requires: |
| 21 | + |
| 22 | +- **Node.js 20.19+** or **22.12+** |
| 23 | + |
| 24 | +Older Needle projects ran fine on Node 14/16. Vite dropped those long ago: |
| 25 | + |
| 26 | +| Vite | Minimum Node.js | |
| 27 | +|------|-----------------| |
| 28 | +| 4 | 14.18+ / 16+ | |
| 29 | +| 5 | 18+ | |
| 30 | +| 6 | 18+ / 20+ / 22+ | |
| 31 | +| 7 | 20.19+ / 22.12+ | |
| 32 | +| 8 | 20.19+ / 22.12+ | |
| 33 | + |
| 34 | +Check yours with `node -v` and update if needed before continuing. |
| 35 | + |
| 36 | +--- |
| 37 | + |
| 38 | +## 2. Update `package.json` |
| 39 | + |
| 40 | +Update the relevant dependency versions. Before: |
| 41 | + |
| 42 | +```json |
| 43 | +"dependencies": { |
| 44 | + "@needle-tools/engine": "^4.17.0-alpha", |
| 45 | + "three": "npm:@needle-tools/three@^0.169.19" |
| 46 | +}, |
| 47 | +"devDependencies": { |
| 48 | + "@needle-tools/helper": "^1.11.4", |
| 49 | + "@types/three": "0.169.0", |
| 50 | + "@vitejs/plugin-basic-ssl": "^1.0.1", |
| 51 | + "typescript": "^5.0.4", |
| 52 | + "vite": "<= 4.3.9", |
| 53 | + "vite-plugin-compression": "^0.5.1" |
| 54 | +} |
| 55 | +``` |
| 56 | + |
| 57 | +After: |
| 58 | + |
| 59 | +```json |
| 60 | +"dependencies": { |
| 61 | + "@needle-tools/engine": "^5.0.0", |
| 62 | + "three": "npm:@needle-tools/three@0.169.19" |
| 63 | +}, |
| 64 | +"devDependencies": { |
| 65 | + "@needle-tools/helper": "^1.11.4", |
| 66 | + "@types/three": "0.169.0", |
| 67 | + "@vitejs/plugin-basic-ssl": "2", |
| 68 | + "typescript": "^5.0.4", |
| 69 | + "vite": "8" |
| 70 | +} |
| 71 | +``` |
| 72 | + |
| 73 | +Key changes: |
| 74 | + |
| 75 | +- **`vite`** `<= 4.3.9` → `8` — remove the version cap entirely. |
| 76 | +- **`@needle-tools/engine`** → `^5.0.0` (or the latest version). |
| 77 | +- **`@vitejs/plugin-basic-ssl`** `^1.0.1` → `2` — v2 is required for Vite 5+. |
| 78 | +- **`vite-plugin-compression` is optional** — the current template drops it. If you [deploy to Needle Cloud](/docs/cloud/), assets are gzip/brotli compressed on deploy, so you don't need the plugin. It still works with Vite 8 if you keep it (`^0.5.1` declares `vite >=2.0.0`), which is useful when self-hosting on a server that doesn't compress responses for you. If you remove it, also remove its entry from `vite.config.js` (see below). |
| 79 | + |
| 80 | +After editing, delete `node_modules` and your lockfile, then reinstall: |
| 81 | + |
| 82 | +```bash |
| 83 | +rm -rf node_modules package-lock.json |
| 84 | +npm install |
| 85 | +``` |
| 86 | + |
| 87 | +--- |
| 88 | + |
| 89 | +## 3. Update `vite.config.js` |
| 90 | + |
| 91 | +The config got simpler — Vite-version workarounds and manual setup that Needle now handles automatically can be removed. |
| 92 | + |
| 93 | +Before (the old pinned-Vite config): |
| 94 | + |
| 95 | +```js |
| 96 | +import { defineConfig } from 'vite'; |
| 97 | +import viteCompression from 'vite-plugin-compression'; |
| 98 | + |
| 99 | +export default defineConfig(async ({ command }) => { |
| 100 | + const { needlePlugins, useGzip, loadConfig } = await import("@needle-tools/engine/plugins/vite/index.js"); |
| 101 | + const needleConfig = await loadConfig(); |
| 102 | + return { |
| 103 | + base: "./", |
| 104 | + plugins: [ |
| 105 | + useGzip(needleConfig) ? viteCompression({ deleteOriginFile: true }) : null, |
| 106 | + needlePlugins(command, needleConfig, { /** custom options */ }), |
| 107 | + ], |
| 108 | + server: { |
| 109 | + https: false, |
| 110 | + proxy: { |
| 111 | + 'https://localhost:3000': 'https://localhost:3000', |
| 112 | + }, |
| 113 | + strictPort: true, |
| 114 | + port: 3000, |
| 115 | + hmr: false, |
| 116 | + }, |
| 117 | + build: { |
| 118 | + outDir: "./dist", |
| 119 | + emptyOutDir: true, |
| 120 | + } |
| 121 | + } |
| 122 | +}); |
| 123 | +``` |
| 124 | + |
| 125 | +After: |
| 126 | + |
| 127 | +```js |
| 128 | +import { defineConfig } from 'vite'; |
| 129 | + |
| 130 | +export default defineConfig(async ({ command }) => { |
| 131 | + const { needlePlugins, loadConfig } = await import("@needle-tools/engine/vite"); |
| 132 | + const needleConfig = await loadConfig(); |
| 133 | + return { |
| 134 | + base: "./", |
| 135 | + plugins: [ |
| 136 | + needlePlugins(command, needleConfig, { /** custom options */ }), |
| 137 | + ], |
| 138 | + server: { |
| 139 | + https: false, |
| 140 | + proxy: { |
| 141 | + 'https://localhost:3000': 'https://localhost:3000', |
| 142 | + }, |
| 143 | + strictPort: true, |
| 144 | + port: 3000, |
| 145 | + hmr: false, |
| 146 | + }, |
| 147 | + build: { |
| 148 | + outDir: "./dist", |
| 149 | + emptyOutDir: true, |
| 150 | + } |
| 151 | + } |
| 152 | +}); |
| 153 | +``` |
| 154 | + |
| 155 | +What changed: |
| 156 | + |
| 157 | +- **Import path** `@needle-tools/engine/plugins/vite/index.js` → `@needle-tools/engine/vite`. The old path still resolves (it's an alias), but the short form is the current convention. |
| 158 | +- **Dropped the `vite-plugin-compression`** import and the `useGzip(...) ? viteCompression(...) : null` plugin entry, matching the current template. This is optional — keep both if you want the plugin to compress your build output (see step 2). Needle Cloud compresses on deploy regardless. |
| 159 | +- **Removed manual `basicSsl()` and `resolve.alias`** entries if your project still has them from a very old template — `needlePlugins` sets up three.js / engine aliases for you. See [Vite Plugin Configuration](/docs/reference/needle-vite-plugin#aliases). |
| 160 | + |
| 161 | +:::tip Why the HTTP/2 proxy line is still there |
| 162 | +The `proxy` entry was originally a workaround for the Vite HTTP/2 session-memory bug. It's harmless on Vite 8 and the current template keeps it, so you can leave it as-is. |
| 163 | +::: |
| 164 | + |
| 165 | +--- |
| 166 | + |
| 167 | +## 4. Test the dev server and a production build |
| 168 | + |
| 169 | +```bash |
| 170 | +npm run dev # or: npm start |
| 171 | +npm run build # production build into ./dist |
| 172 | +``` |
| 173 | + |
| 174 | +The build script name depends on your `package.json`. Current templates have `build` (production) and `build:dev` (uncompressed). Older templates may only have `build:dev` and `build:production` — run whichever your project defines (`npm run build:production`, etc.). |
| 175 | + |
| 176 | +If the dev server starts and a production build completes, the upgrade is done. |
| 177 | + |
| 178 | +--- |
| 179 | + |
| 180 | +## Troubleshooting |
| 181 | + |
| 182 | +### `Vite requires Node.js version 20.19+ or 22.12+` |
| 183 | + |
| 184 | +Your Node.js is too old. See [step 1](#_1-check-your-node-js-version). |
| 185 | + |
| 186 | +### `@vitejs/plugin-basic-ssl` errors / wrong default export |
| 187 | + |
| 188 | +Make sure it's on `2`, not `^1.x`. |
| 189 | + |
| 190 | +### Module resolution / duplicate three.js issues |
| 191 | + |
| 192 | +Enable alias debug logging with `debugAlias: true`. See [Debugging alias resolution](/docs/reference/needle-vite-plugin#debugging-alias-resolution). |
| 193 | + |
| 194 | +### Still stuck? |
| 195 | + |
| 196 | +Ask on [Discord](https://discord.needle.tools) or the [Forum](https://forum.needle.tools). |
| 197 | + |
| 198 | +--- |
| 199 | + |
| 200 | +## See Also |
| 201 | + |
| 202 | +- [Vite Plugin Configuration](/docs/reference/needle-vite-plugin) — Full reference for `needlePlugins` options |
| 203 | +- [Templates](/docs/reference/templates) — Start from an up-to-date project template |
| 204 | +- [Official Vite migration guide](https://vite.dev/guide/migration) — Vite's own breaking-change notes per version |
0 commit comments