Code N Solve ๐: Vite ๋ฐฐํฌ ์ค๋ฅ ํด๊ฒฐ - xdg-open, CJS API, npm ๋ฒ์ ์ถฉ๋ ๋ฌธ์ ๋ถ์
Vite ํ๋ก์ ํธ๋ฅผ Render์์ ๋ฐฐํฌํ๋ ๊ณผ์ ์์ ๋ช ๊ฐ์ง ์ค๋ฅ๊ฐ ๋ฐ์ํ๋ค.
์ฒ์์๋ ๋ธ๋ผ์ฐ์ ์๋ ์คํ ๋ฌธ์ , ์ดํ์๋ Vite์ CJS API ๊ฒฝ๊ณ , npm ๋ฒ์ ์ถฉ๋ ๋ฌธ์ ๊ฐ ์์๋ค.
๊ฐ๊ฐ์ ์ค๋ฅ๋ฅผ ๋ถ์ํ๊ณ ํด๊ฒฐํ ๊ณผ์ ์ ๋ํด ์์๋ณด์.
Vite๋? โก
Vite1๋ ํ๋์ค์ด๋ก "๋น ๋ฅด๋ค"๋ฅผ ๋ปํ๋ ์ด๋ฆ ๊ทธ๋๋ก, ๊ธฐ์กด ๋ฒ๋ค๋ฌ๋ค์ ๋๋ฆฐ ๊ฐ๋ฐ ์๋ฒ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํด ๋ง๋ค์ด์ง ์ฐจ์ธ๋ ํ๋ก ํธ์๋ ๋น๋ ๋๊ตฌ๋ค. Evan You(Vue.js ์ฐฝ์์)๊ฐ ๊ฐ๋ฐํ์ผ๋ฉฐ, Vue๋ฟ๋ง ์๋๋ผ React, Svelte, Vanilla JS ๋ฑ ๋ค์ํ ํ๋ ์์ํฌ๋ฅผ ์ง์ํ๋ค.
Vite vs Webpack: ๋ฌด์์ด ๋ค๋ฅธ๊ฐ
๊ฐ๋ฐ ์๋ฒ ๋ฐฉ์์ ์ฐจ์ด
Webpack์ ๊ฐ๋ฐ ์๋ฒ๋ฅผ ์์ํ ๋ ํ๋ก์ ํธ ์ ์ฒด๋ฅผ ๋ฒ๋ค๋งํ ๋ค ์๋ฒ๋ฅผ ์คํํ๋ค. ํ๋ก์ ํธ๊ฐ ์ปค์ง์๋ก ์ด ์ด๊ธฐ ๋ฒ๋ค๋ง ์๊ฐ์ด ์์ญ ์ด์์ ์ ๋ถ๊น์ง ๋์ด๋ฌ๋ค.
Vite๋ ์ ํ ๋ค๋ฅธ ์ ๊ทผ์ ์ทจํ๋ค.
Vite๋ ๊ฐ๋ฐ ์๋ฒ๋ฅผ ์ฆ์ ์์ํ๊ณ , ๋ธ๋ผ์ฐ์ ๊ฐ ํน์ ๋ชจ๋์ ์์ฒญํ ๋๋ง ๊ทธ ํ์ผ์ ๋ณํํ๋ค. ์ด๊ฒ์ด ๊ฐ๋ฅํ ์ด์ ๋ ํ๋ ๋ธ๋ผ์ฐ์ ๊ฐ **ESM(ECMAScript Module)**์ ๋ค์ดํฐ๋ธ๋ก ์ง์ํ๊ธฐ ๋๋ฌธ์ด๋ค.
HMR (Hot Module Replacement) ์ฐจ์ด
ํ์ผ์ ์์ ํ ๋ ํ์ด์ง ์ ์ฒด๋ฅผ ์๋ก๊ณ ์นจํ์ง ์๊ณ ๋ณ๊ฒฝ๋ ๋ชจ๋๋ง ๊ต์ฒดํ๋ ๊ธฐ๋ฅ์ด HMR์ด๋ค.
- Webpack HMR: ๋ณ๊ฒฝ๋ ํ์ผ๋ถํฐ ์ํธ๋ฆฌ ํฌ์ธํธ๊น์ง ์ ์ฒด ์์กด์ฑ ํธ๋ฆฌ๋ฅผ ๋ค์ ๋ฒ๋ค๋ง
- Vite HMR: ๋ณ๊ฒฝ๋ ํ์ผ ํ๋๋ง ๋ธ๋ผ์ฐ์ ์ ์ง์ ์ ๋ฌ, ์์กด์ฑ ํฌ๊ธฐ์ ๋ฌด๊ดํ๊ฒ ์ผ์ ํ ์๋ ์ ์ง
ํ๋ก๋์ ๋น๋
๊ฐ๋ฐ ์๋ฒ๋ ESM ๋ฐฉ์์ด์ง๋ง, ํ๋ก๋์ ๋น๋๋ Rollup์ ์ฌ์ฉํด ์ต์ ํ๋ ๋ฒ๋ค์ ์์ฑํ๋ค. Tree-shaking, ์ฝ๋ ๋ถํ (Code Splitting), ์์ฐ ์ธ๋ผ์ด๋ ๋ฑ์ด ์๋์ผ๋ก ์ ์ฉ๋๋ค.
| ํญ๋ชฉ | Vite | Webpack |
|---|---|---|
| ๊ฐ๋ฐ ์๋ฒ ์์ ์๊ฐ | ์๋ฐฑ ms | ์์ญ ์ด~ |
| HMR ์๋ | ํ์ผ ํฌ๊ธฐ์ ๋ฌด๊ด, ์ฆ๊ฐ | ์์กด์ฑ ํด์๋ก ๋๋ ค์ง |
| ์ค์ ๋ณต์ก๋ | ๋ฎ์ (๊ธฐ๋ณธ๊ฐ ์ต์ ํ) | ๋์ |
| ํ๋ฌ๊ทธ์ธ ์ํ๊ณ | Rollup ํ๋ฌ๊ทธ์ธ ํธํ | ๋ฐฉ๋ํ Webpack ์ํ๊ณ |
| ํ๋ก๋์ ๋ฒ๋ค๋ฌ | Rollup | Webpack |
| ESM ์ง์ | ๋ค์ดํฐ๋ธ | ๋ณํ ํ์ |
Render.com์ด๋? ๐
Render6๋ Heroku์ ๋์์ผ๋ก ๋ง์ด ์ฌ์ฉ๋๋ ํด๋ผ์ฐ๋ ๋ฐฐํฌ ํ๋ซํผ์ด๋ค. GitHub ์ ์ฅ์์ ์ฐ๊ฒฐํ๋ฉด pushํ ๋๋ง๋ค ์๋์ผ๋ก ๋น๋ ๋ฐ ๋ฐฐํฌ๋ฅผ ์ํํ๋ค.
Render์ ์ฃผ์ ํน์ง
- ๋ฌด๋ฃ ํ๋: ์ ์ ์ฌ์ดํธ ๋ฌด๋ฃ, ์น ์๋น์ค๋ ์ผ์ ์๊ฐ ํ ์ฌ๋ฆฝ ๋ชจ๋
- ์๋ ๋ฐฐํฌ: GitHub/GitLab ์ฐ๋์ผ๋ก push ์ ์๋ ๋ฐฐํฌ
- Docker ์ง์: Dockerfile๋ก ์์ ํ ํ๊ฒฝ ์ ์ด ๊ฐ๋ฅ
- ํ๊ฒฝ ๋ณ์ ๊ด๋ฆฌ: ์น ๋์๋ณด๋์์ ํ๊ฒฝ ๋ณ์ ์ค์
- ๋ฌด๋ฃ SSL: ์๋ HTTPS ์ธ์ฆ์ ๋ฐ๊ธ
Render์์ Vite ํ๋ก์ ํธ ๋ฐฐํฌ ํ๋ฆ
๐จ ์ค๋ฅ 1: xdg-open ์ค๋ฅ โ "spawn xdg-open ENOENT"
๋ฌธ์ ์ํฉ
Vite ๊ฐ๋ฐ ์๋ฒ ์คํ ์ ๋ค์๊ณผ ๊ฐ์ ์ค๋ฅ๊ฐ ๋ฐ์ํ๋ค.
Error: spawn xdg-open ENOENT
at ChildProcess._handle.onexit (node:internal/child_process:284:19)
at onErrorNT (node:internal/child_process:477:16)
at process.processTicksAndRejections (node:internal/process/task_queues:82:21)์์ธ ๋ถ์
xdg-open์ Linux ํ๊ฒฝ์์ ๊ธฐ๋ณธ ์น ๋ธ๋ผ์ฐ์ ๋ฅผ ์ฌ๋ ๋ช
๋ น์ด๋ค.
Render์ ์ปจํ
์ด๋ ํ๊ฒฝ์์ vite dev๋ฅผ ์คํํ๋ฉด, Vite๊ฐ ์๋ฒ ์์ ํ ๋ธ๋ผ์ฐ์ ๋ฅผ ์๋์ผ๋ก ์ด๋ ค๊ณ ์๋ํ๋ค.
๊ทธ๋ฐ๋ฐ ์๋ฒ ์ปจํ
์ด๋์๋ GUI ํ๊ฒฝ์ด ์์ผ๋ฏ๋ก xdg-open์ด ์ค์น๋์ด ์์ง ์๊ณ , ์คํ๋ ๋ถ๊ฐ๋ฅํ๋ค.
์ฆ, Vite์ --open ์ต์
(๋๋ server.open: true ์ค์ )์ด ํ์ฑํ๋ ์ํ์์ headless ์๋ฒ ํ๊ฒฝ์์ ์คํ๋ ๋ ๋ฐ์ํ๋ ๋ฌธ์ ๋ค.
ํด๊ฒฐ ๋ฐฉ๋ฒ
๋ฐฉ๋ฒ 1: ํ๊ฒฝ ๋ณ์๋ก ๋ธ๋ผ์ฐ์ ์๋ ์คํ ๋นํ์ฑํ (๊ถ์ฅ)
Render ๋์๋ณด๋ โ Environment ํญ์์ ํ๊ฒฝ ๋ณ์ ์ถ๊ฐ:
BROWSER=noneVite๋ BROWSER ํ๊ฒฝ ๋ณ์๊ฐ none์ด๋ฉด ๋ธ๋ผ์ฐ์ ์๋ ์คํ์ ๊ฑด๋๋ด๋ค.
๋ฐฉ๋ฒ 2: vite.config.js์์ server.open ๋นํ์ฑํ
import { defineConfig } from 'vite'
export default defineConfig({
server: {
host: true, // 0.0.0.0์ผ๋ก ๋ฐ์ธ๋ฉ (์ธ๋ถ ์ ๊ทผ ํ์ฉ)
port: 3000,
open: false, // ๋ธ๋ผ์ฐ์ ์๋ ์คํ ๋นํ์ฑํ
},
})๋ฐฉ๋ฒ 3: xdg-utils ํจํค์ง ์ค์น
๊ฐ๋ฐ ํ๊ฒฝ์์ xdg-open์ด ์์ ๊ฒฝ์ฐ:
# Ubuntu/Debian
sudo apt update && sudo apt install xdg-utils
# CentOS/RHEL
sudo yum install xdg-utils๋จ, Render ์ปจํ ์ด๋์์๋ ๋ฐฉ๋ฒ 1์ด๋ 2๊ฐ ํจ์ฌ ๊ฐ๋จํ๋ค.2
์ด๋ค ๋ฐฉ๋ฒ์ ์ ํํด์ผ ํ๋๊ฐ?
- Render/์๋ฒ ๋ฐฐํฌ ํ๊ฒฝ: ๋ฐฉ๋ฒ 1 (ํ๊ฒฝ ๋ณ์) โ Dockerfile ์์ ์์ด ๊ฐ๋จ
- ๋ก์ปฌ ๊ฐ๋ฐ ํ๊ฒฝ๋ง: ๋ฐฉ๋ฒ 2 (
vite.config.js) โ ์ฝ๋ ๋ ๋ฒจ์์ ์ ์ด - ๊ฐ๋ฐ ์๋ฒ์์ ์ค์ ๋ก xdg-open ํ์: ๋ฐฉ๋ฒ 3
๐จ ์ค๋ฅ 2: Vite CJS API ์ฌ์ฉ ๊ฒฝ๊ณ
๋ฌธ์ ์ํฉ
Vite ์คํ ์ ๋ค์๊ณผ ๊ฐ์ ๊ฒฝ๊ณ ๋ฉ์์ง๊ฐ ์ถ๋ ฅ๋๋ค.
The CJS build of Vite's Node API is deprecated.
See https://vite.dev/guide/troubleshooting.html#vite-cjs-node-api-deprecated for more details.๋น๋๊ฐ ์คํจํ์ง๋ ์์ง๋ง, ๋ฏธ๋ ๋ฒ์ ์์๋ ์ค๋ฅ๋ก ์ฒ๋ฆฌ๋ ์ ์์ด ๋ฌด์ํ๋ฉด ์ ๋๋ค.
์์ธ ๋ถ์
JavaScript ๋ชจ๋ ์์คํ ์๋ ๋ ๊ฐ์ง ๋ฐฉ์์ด ์๋ค.
CJS (CommonJS): Node.js์ ์ ํต์ ์ธ ๋ชจ๋ ๋ฐฉ์
// CJS ๋ฐฉ์
const vite = require('vite')
module.exports = { ... }ESM (ECMAScript Module): ํ๋ JavaScript ํ์ค
// ESM ๋ฐฉ์
import { defineConfig } from 'vite'
export default defineConfig({ ... })Vite 5 ๋ฒ์ ๋ถํฐ๋ CJS ๋ฐฉ์์ Node API ์ง์์ deprecated ์ฒ๋ฆฌํ๋ค.3
๊ธฐ์กด์ vite.config.js๊ฐ CJS ๋ฐฉ์์ ๋ฐ๋ฅด๊ณ ์์ผ๋ฉด ์ด ๊ฒฝ๊ณ ๊ฐ ์ถ๋ ฅ๋๋ค.
Node.js๊ฐ .js ํ์ผ์ CJS๋ก ์ฒ๋ฆฌํ ์ง ESM์ผ๋ก ์ฒ๋ฆฌํ ์ง๋:
package.json์"type"ํ๋๋ก ๊ฒฐ์ "type": "module"โ.jsํ์ผ์ ESM์ผ๋ก ์ฒ๋ฆฌ"type": "commonjs"๋๋ ํ๋ ์์ โ.jsํ์ผ์ CJS๋ก ์ฒ๋ฆฌ.mjsํ์ฅ์ โ ํญ์ ESM,.cjsํ์ฅ์ โ ํญ์ CJS
ํด๊ฒฐ ๋ฐฉ๋ฒ
๋ฐฉ๋ฒ 1: vite.config.js๋ฅผ vite.config.mjs๋ก ๋ณ๊ฒฝ
mv vite.config.js vite.config.mjsํ์ผ ์ด๋ฆ๋ง ๋ฐ๊ฟ๋ Node.js๊ฐ ESM์ผ๋ก ์ฒ๋ฆฌํ๋ฏ๋ก ๊ฒฝ๊ณ ๊ฐ ์ฌ๋ผ์ง๋ค.
๊ธฐ์กด require/module.exports ๊ตฌ๋ฌธ์ด ์๋ค๋ฉด import/export default๋ก ๋ณ๊ฒฝํด์ผ ํ๋ค.
// vite.config.mjs
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
export default defineConfig({
plugins: [react()],
server: {
host: true,
port: 3000,
open: false,
},
})๋ฐฉ๋ฒ 2: package.json์ "type": "module" ์ถ๊ฐ
{
"name": "my-vite-app",
"version": "1.0.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "vite build",
"preview": "vite preview"
}
}์ด๋ ๊ฒ ํ๋ฉด ํ๋ก์ ํธ ์ ์ฒด์ .js ํ์ผ์ด ESM์ผ๋ก ์ฒ๋ฆฌ๋๋ค.
๋จ, ์ด ๊ฒฝ์ฐ CJS ๋ฐฉ์์ ๋ค๋ฅธ ์ค์ ํ์ผ๋ค(์: jest.config.js)๋ ์ํฅ์ ๋ฐ์ ์ ์์ผ๋ ์ฃผ์ํ๋ค.
๋ฐฉ๋ฒ 3: require ๊ตฌ๋ฌธ์ import๋ก ๋ณ๊ฒฝ
๊ธฐ์กด vite.config.js ๋ด์ฉ์ด CJS ๋ฐฉ์์ด๋ผ๋ฉด:
// ๋ณ๊ฒฝ ์ (CJS)
const { defineConfig } = require('vite')
const react = require('@vitejs/plugin-react')
module.exports = defineConfig({
plugins: [react()],
})// ๋ณ๊ฒฝ ํ (ESM)
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
export default defineConfig({
plugins: [react()],
})์ด๋ค ๋ฐฉ๋ฒ์ด ์ ํฉํ๊ฐ?
| ์ํฉ | ๊ถ์ฅ ๋ฐฉ๋ฒ |
|---|---|
| Vite ์ค์ ๋ง ESM์ผ๋ก ๋ฐ๊พธ๊ณ ์ถ๋ค | ๋ฐฉ๋ฒ 1 (.mjs ํ์ฅ์) |
| ํ๋ก์ ํธ ์ ์ฒด๋ฅผ ESM์ผ๋ก ์ ํํ๊ณ ์ถ๋ค | ๋ฐฉ๋ฒ 2 ("type": "module") |
.mjs ํ์ฅ์๋ฅผ ์ฐ๊ธฐ ์ซ๋ค |
๋ฐฉ๋ฒ 2 + import ๊ตฌ๋ฌธ ํต์ผ |
๐จ ์ค๋ฅ 3: npm ๋ฒ์ ์ถฉ๋ โ "EBADENGINE" ์ค๋ฅ
๋ฌธ์ ์ํฉ
Docker ๋น๋ ๊ณผ์ ์์ ๋ค์๊ณผ ๊ฐ์ ์ค๋ฅ๊ฐ ๋ฐ์ํ๋ค.
npm error code EBADENGINE
npm error engine Unsupported engine
npm error engine Not compatible with your version of node/npm: npm@11.1.0
npm error notsup Required: {"node":"^20.17.0 || >=22.9.0"}
npm error notsup Actual: {"npm":"10.8.2","node":"v18.20.7"}์์ธ ๋ถ์
npm@11.1.0์ Node.js 20.17.0 ์ด์ ๋๋ 22.9.0 ์ด์์ด ํ์ํ๋ค.4
๊ทธ๋ฐ๋ฐ Dockerfile์์ node:18์ ๋ฒ ์ด์ค ์ด๋ฏธ์ง๋ก ์ฌ์ฉํ๋ ๊ฒฝ์ฐ, Node.js ๋ฒ์ ์ด 18.x์ด๋ฏ๋ก npm 11.x๋ฅผ ์ค์นํ ์ ์๋ค.
์ด ์ค๋ฅ๋ ์ฃผ๋ก package.json์ postinstall ์คํฌ๋ฆฝํธ์ npm install -g npm@latest๊ฐ ํฌํจ๋์ด ์์ ๋ ๋ฐ์ํ๋ค.
{
"scripts": {
"postinstall": "npm install -g npm@latest" // โ ์ด ๋ถ๋ถ์ด ๋ฌธ์
}
}npm@latest๊ฐ 11.x์ธ๋ฐ Node.js 18๊ณผ ํธํ๋์ง ์๋ ๊ฒ์ด๋ค.5
ํด๊ฒฐ ๋ฐฉ๋ฒ
๋ฐฉ๋ฒ 1: Node.js ๋ฒ์ ์ 20 ์ด์์ผ๋ก ์ ๊ทธ๋ ์ด๋ (๊ถ์ฅ)
# ๋ณ๊ฒฝ ์
FROM node:18-alpine
# ๋ณ๊ฒฝ ํ
FROM node:20-alpine
WORKDIR /app
COPY package*.json ./
RUN npm install --legacy-peer-deps
COPY . .
EXPOSE 3000
CMD ["npm", "start"]LTS(Long Term Support) ๋ฒ์ ์ธ Node.js 20์ ์ฌ์ฉํ๋ฉด npm 10.x, 11.x ๋ชจ๋ ํธํ๋๋ค.
node:20-alpine์ Alpine Linux ๊ธฐ๋ฐ์ผ๋ก ์ด๋ฏธ์ง ํฌ๊ธฐ๊ฐ ์์ ๊ถ์ฅ๋๋ค.
๋ฐฉ๋ฒ 2: postinstall ์คํฌ๋ฆฝํธ ์์
npm์ ์ต์ ๋ฒ์ ์ผ๋ก ๊ฐ์ ์ ๋ฐ์ดํธํ์ง ์๋๋ก ํ๋ค.
{
"scripts": {
"postinstall": "node -v && npm -v"
}
}๋๋ ํน์ ๋ฒ์ ์ผ๋ก ๊ณ ์ :
{
"scripts": {
"postinstall": "npm install -g npm@10.8.2"
}
}๋ฐฉ๋ฒ 3: engines ํ๋๋ก ๋ฒ์ ์ ์ฝ ๋ช
์
package.json์ ์ง์ํ๋ Node.js ๋ฒ์ ๋ฒ์๋ฅผ ๋ช
์ํ๋ค.
{
"engines": {
"node": ">=20.0.0",
"npm": ">=10.0.0"
}
}์ด๋ ๊ฒ ํ๋ฉด ํธํ๋์ง ์๋ ํ๊ฒฝ์์ ์คํ ์๋ ์ ๋ช ํํ ์ค๋ฅ ๋ฉ์์ง๋ฅผ ๋ฐ์ ์ ์๋ค.
๐จ ์ค๋ฅ 4: process.env not defined in browser
๋ฌธ์ ์ํฉ
Vite๋ก ๋น๋ํ ์ฑ์ ๋ธ๋ผ์ฐ์ ์์ ์คํํ๋ฉด ๋ค์๊ณผ ๊ฐ์ ์ค๋ฅ๊ฐ ๋ฐ์ํ๋ค.
Uncaught ReferenceError: process is not defined
at App.jsx:5์์ธ ๋ถ์
process.env๋ Node.js ๋ฐํ์ ํ๊ฒฝ์์๋ง ์กด์ฌํ๋ ๊ฐ์ฒด๋ค.
๋ธ๋ผ์ฐ์ ์๋ process๋ผ๋ ์ ์ญ ๋ณ์๊ฐ ์๋ค.
CRA(Create React App)๋ webpack์ด process.env๋ฅผ ๋ธ๋ผ์ฐ์ ์์๋ ๋์ํ๋๋ก ํด๋ฆฌํ์ ๋ฃ์ด์คฌ์ง๋ง, Vite๋ ์ด ๋ฐฉ์์ ์ฌ์ฉํ์ง ์๋๋ค.
ํด๊ฒฐ ๋ฐฉ๋ฒ
Vite์์๋ ํ๊ฒฝ ๋ณ์์ import.meta.env๋ฅผ ์ฌ์ฉํ๋ค.
// ์๋ชป๋ ๋ฐฉ๋ฒ (process.env)
const apiUrl = process.env.REACT_APP_API_URL
// ์ฌ๋ฐ๋ฅธ ๋ฐฉ๋ฒ (import.meta.env)
const apiUrl = import.meta.env.VITE_API_URLVite์์ ํ๊ฒฝ ๋ณ์๋ VITE_ ์ ๋์ฌ๊ฐ ์์ด์ผ ํด๋ผ์ด์ธํธ ์ฝ๋์ ๋
ธ์ถ๋๋ค.
# .env ํ์ผ
VITE_API_URL=https://api.example.com
VITE_APP_NAME=MyApp
SECRET_KEY=this_will_not_be_exposed # VITE_ ์ ๋์ฌ ์์ผ๋ฉด ๋
ธ์ถ ์ ๋จ// ์ฌ์ฉ ์์
console.log(import.meta.env.VITE_API_URL) // "https://api.example.com"
console.log(import.meta.env.VITE_APP_NAME) // "MyApp"
console.log(import.meta.env.SECRET_KEY) // undefined (์์ ํ๊ฒ ๋ณดํธ๋จ)
console.log(import.meta.env.MODE) // "development" ๋๋ "production"
console.log(import.meta.env.DEV) // true (๊ฐ๋ฐ ๋ชจ๋์์)
console.log(import.meta.env.PROD) // true (ํ๋ก๋์
์์)๐จ ์ค๋ฅ 5: ์ ๋ ๊ฒฝ๋ก alias ์ค์ ์ค๋ฅ
๋ฌธ์ ์ํฉ
// ์ด๋ฐ import๊ฐ ๋์ํ์ง ์์
import Button from '@/components/Button'
// Error: Failed to resolve import "@/components/Button"์์ธ ๋ถ์
Vite๋ ๊ธฐ๋ณธ์ ์ผ๋ก @ ๊ฐ์ ๊ฒฝ๋ก ๋ณ์นญ์ ๋ชจ๋ฅธ๋ค.
Webpack์์๋ resolve.alias๋ก ์ค์ ํ๋ ๊ฒ์ฒ๋ผ, Vite๋ ๋์ผํ๊ฒ ์ค์ ํด์ค์ผ ํ๋ค.
ํด๊ฒฐ ๋ฐฉ๋ฒ
vite.config.js์์ alias ์ค์ ์ ์ถ๊ฐํ๋ค.
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
import path from 'path'
export default defineConfig({
plugins: [react()],
resolve: {
alias: {
'@': path.resolve(__dirname, './src'),
'@components': path.resolve(__dirname, './src/components'),
'@hooks': path.resolve(__dirname, './src/hooks'),
'@utils': path.resolve(__dirname, './src/utils'),
},
},
})TypeScript ํ๋ก์ ํธ๋ผ๋ฉด tsconfig.json์๋ ๋์ผํ๊ฒ ์ค์ ํด์ผ IDE ์๋์์ฑ์ด ๋์ํ๋ค.
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@/*": ["src/*"],
"@components/*": ["src/components/*"],
"@hooks/*": ["src/hooks/*"],
"@utils/*": ["src/utils/*"]
}
}
}๐จ ์ค๋ฅ 6: ๋น๋ ๊ฒฐ๊ณผ๋ฌผ ๊ฒฝ๋ก ์ค์ โ base URL ์ค๋ฅ
๋ฌธ์ ์ํฉ
GitHub Pages๋ ์๋ธ ๊ฒฝ๋ก์ ๋ฐฐํฌํ ๋ CSS/JS ํ์ผ์ ์ฐพ์ง ๋ชปํ๋ ๊ฒฝ์ฐ.
# ๋ฐฐํฌ URL: https://username.github.io/my-repo/
# ํ์ง๋ง ๋ธ๋ผ์ฐ์ ๋ ๋ค์์ ์์ฒญ:
GET https://username.github.io/assets/index-abc123.js # ์๋ชป๋ ๊ฒฝ๋ก
# ์ฌ๋ฐ๋ฅธ ๊ฒฝ๋ก:
GET https://username.github.io/my-repo/assets/index-abc123.js์์ธ ๋ถ์
Vite๋ ๊ธฐ๋ณธ์ ์ผ๋ก ๋น๋๋ ํ์ผ์ ๊ฒฝ๋ก๋ฅผ /(๋ฃจํธ)๋ก ์ค์ ํ๋ค.
์๋ธ ๊ฒฝ๋ก์ ๋ฐฐํฌํ๋ฉด ์ ์ ์์ฐ์ ์ฐพ์ง ๋ชปํ๋ค.
ํด๊ฒฐ ๋ฐฉ๋ฒ
vite.config.js์ base ์ต์
์ ์ค์ ํ๋ค.
import { defineConfig } from 'vite'
export default defineConfig({
// GitHub Pages์ ๊ฒฝ์ฐ
base: '/my-repo/',
// ํ๊ฒฝ ๋ณ์๋ก ์ ์ฐํ๊ฒ ์ค์
base: process.env.VITE_BASE_URL || '/',
build: {
outDir: 'dist', // ๋น๋ ์ถ๋ ฅ ๋๋ ํฐ๋ฆฌ
assetsDir: 'assets', // ์ ์ ์์ฐ ๋๋ ํฐ๋ฆฌ
sourcemap: false, // ํ๋ก๋์
์์ ์์ค๋งต ๋นํ์ฑํ
},
})Render.com์ ๋ฐฐํฌํ ๋๋ ๋ฃจํธ ๊ฒฝ๋ก(/)๋ฅผ ์ฌ์ฉํ๋ ๊ฒฝ์ฐ๊ฐ ๋ง์ผ๋ฏ๋ก ๊ธฐ๋ณธ๊ฐ ๊ทธ๋๋ก ๋๋ฉด ๋๋ค.
Vite ์ค์ ํ์ผ ์์ ์ ๋ฆฌ
์ค๋ฌด์์ ์์ฃผ ์ฌ์ฉํ๋ vite.config.js ์ต์
๋ค์ ์ ๋ฆฌํ๋ค.
import { defineConfig, loadEnv } from 'vite'
import react from '@vitejs/plugin-react'
import path from 'path'
export default defineConfig(({ command, mode }) => {
// ํ๊ฒฝ ๋ณ์ ๋ก๋ (๋ชจ๋ VITE_ ์ ๋์ฌ ๋ณ์)
const env = loadEnv(mode, process.cwd(), '')
return {
// ํ๋ฌ๊ทธ์ธ
plugins: [react()],
// ๊ฒฝ๋ก ๋ณ์นญ
resolve: {
alias: {
'@': path.resolve(__dirname, './src'),
},
},
// ๊ฐ๋ฐ ์๋ฒ ์ค์
server: {
host: '0.0.0.0', // ์ธ๋ถ ์ ๊ทผ ํ์ฉ (Docker, ๋คํธ์ํฌ ์ ๊ทผ)
port: 3000,
open: false, // ๋ธ๋ผ์ฐ์ ์๋ ์คํ ๋นํ์ฑํ
proxy: {
// API ์์ฒญ์ ๋ฐฑ์๋ ์๋ฒ๋ก ํ๋ก์
'/api': {
target: env.VITE_API_URL || 'http://localhost:8080',
changeOrigin: true,
rewrite: (path) => path.replace(/^\/api/, ''),
},
},
},
// ๋น๋ ์ค์
build: {
outDir: 'dist',
assetsDir: 'assets',
sourcemap: mode !== 'production',
minify: 'esbuild',
rollupOptions: {
output: {
// ์ฒญํฌ ๋ถํ ์ ๋ต
manualChunks: {
vendor: ['react', 'react-dom'],
router: ['react-router-dom'],
},
},
},
},
// ๊ธฐ๋ณธ ๊ฒฝ๋ก
base: env.VITE_BASE_URL || '/',
// ํ๊ฒฝ ๋ณ์ ์ ๋์ฌ (๊ธฐ๋ณธ: VITE_)
envPrefix: 'VITE_',
// ํ๋ฆฌ๋ทฐ ์๋ฒ (vite preview ๋ช
๋ น)
preview: {
host: '0.0.0.0',
port: 4173,
},
}
})Render ๋ฐฐํฌ ์ค์
1. ์น ์๋น์ค ์ค์ (Build & Deploy)
Render ๋์๋ณด๋์์ ์ Web Service๋ฅผ ์์ฑํ ๋:
| ํญ๋ชฉ | ๊ฐ |
|---|---|
| Runtime | Node |
| Build Command | npm ci && npm run build |
| Start Command | npm run preview -- --host 0.0.0.0 --port $PORT |
$PORT๋ Render๊ฐ ์๋์ผ๋ก ์ ๊ณตํ๋ ํฌํธ ๋ฒํธ๋ค.
Render๋ ๋ด๋ถ์ ์ผ๋ก 10000๋ฒ ํฌํธ๋ฅผ ์ฌ์ฉํ๋ฏ๋ก, vite preview๊ฐ ํด๋น ํฌํธ์ ๋ฐ์ธ๋ฉ๋๋๋ก ํด์ผ ํ๋ค.
2. ํ๊ฒฝ ๋ณ์ ์ค์
Render ๋์๋ณด๋ โ Environment ํญ:
NODE_ENV=production
BROWSER=none
VITE_API_URL=https://api.your-backend.com
VITE_BASE_URL=/3. package.json ์คํฌ๋ฆฝํธ ์ ๋ฆฌ
{
"scripts": {
"dev": "vite",
"build": "vite build",
"preview": "vite preview",
"preview:render": "vite preview --host 0.0.0.0"
}
}Docker + Vite + Render ์ ์ฒด ์ค์ ์์
Dockerfile (๋ฉํฐ์คํ ์ด์ง ๋น๋)
# === ๋น๋ ์คํ
์ด์ง ===
FROM node:20-alpine AS builder
WORKDIR /app
# ์์กด์ฑ ์ค์น (์บ์ ํ์ฉ)
COPY package*.json ./
RUN npm ci
# ์์ค ์ฝ๋ ๋ณต์ฌ ๋ฐ ๋น๋
COPY . .
RUN npm run build
# === ํ๋ก๋์
์คํ
์ด์ง ===
FROM node:20-alpine AS production
WORKDIR /app
# ๋น๋ ๊ฒฐ๊ณผ๋ฌผ๋ง ๋ณต์ฌ
COPY /app/dist ./dist
COPY /app/package*.json ./
# preview ์๋ฒ ์คํ์ ํ์ํ vite๋ง ์ค์น
RUN npm ci --only=production
# ํฌํธ ๋
ธ์ถ
EXPOSE 4173
# vite preview๋ก ์ ์ ํ์ผ ์๋น
CMD ["npx", "vite", "preview", "--host", "0.0.0.0", "--port", "4173"].dockerignore
node_modules
dist
.env
.env.local
.git
*.logdocker-compose.yml (๋ก์ปฌ ํ
์คํธ์ฉ)
version: '3.8'
services:
app:
build:
context: .
target: production
ports:
- "4173:4173"
environment:
- NODE_ENV=production
- BROWSER=none
- VITE_API_URL=http://localhost:8080๊ฐ๋ฐ/์คํ ์ด์ง/ํ๋ก๋์ ํ๊ฒฝ ๋ถ๋ฆฌ
Vite๋ .env ํ์ผ์ ์ฌ๋ฌ ๊ฐ ์ง์ํ๋ค.
.env # ๋ชจ๋ ํ๊ฒฝ์์ ๋ก๋ (๊ณตํต)
.env.local # ๋ชจ๋ ํ๊ฒฝ์์ ๋ก๋, git ๋ฌด์ (๋ก์ปฌ override)
.env.development # ๊ฐ๋ฐ ํ๊ฒฝ์์๋ง ๋ก๋ (vite dev)
.env.staging # ์คํ
์ด์ง ํ๊ฒฝ์์๋ง ๋ก๋ (์ปค์คํ
mode)
.env.production # ํ๋ก๋์
ํ๊ฒฝ์์๋ง ๋ก๋ (vite build).env (๊ณตํต)
VITE_APP_NAME=MyApp
VITE_VERSION=1.0.0.env.development
VITE_API_URL=http://localhost:8080
VITE_DEBUG=true.env.staging
VITE_API_URL=https://staging-api.example.com
VITE_DEBUG=true.env.production
VITE_API_URL=https://api.example.com
VITE_DEBUG=false๋น๋ ์ mode๋ฅผ ์ง์ ํด ํ๊ฒฝ์ ์ ํํ๋ค.
# ๊ฐ๋ฐ ์๋ฒ
npm run dev # .env.development ์ฌ์ฉ
# ์คํ
์ด์ง ๋น๋
vite build --mode staging # .env.staging ์ฌ์ฉ
# ํ๋ก๋์
๋น๋
npm run build # .env.production ์ฌ์ฉ (๊ธฐ๋ณธ)๊ฒฐ๋ก
Vite์ Render๋ฅผ ์กฐํฉํ ๋ฐฐํฌ ํ๊ฒฝ์์ ๋ฐ์ํ ์ ์๋ ์ฃผ์ ์ค๋ฅ๋ค๊ณผ ํด๊ฒฐ ๋ฐฉ๋ฒ์ ์ ๋ฆฌํ๋ค.
ํต์ฌ ์ฒดํฌ๋ฆฌ์คํธ
- xdg-open ์ค๋ฅ: Render ํ๊ฒฝ ๋ณ์์
BROWSER=none์ถ๊ฐ - CJS API ๊ฒฝ๊ณ :
package.json์"type": "module"์ถ๊ฐ ๋๋.mjsํ์ฅ์ ์ฌ์ฉ - npm ๋ฒ์ ์ถฉ๋: Dockerfile์์ Node.js 20 ์ด์ ์ฌ์ฉ
process.env์ค๋ฅ:import.meta.env.VITE_*๋ฐฉ์์ผ๋ก ์ ํ- ๊ฒฝ๋ก alias ์ค๋ฅ:
vite.config.js์resolve.alias์ค์ - base URL ์ค๋ฅ: ์๋ธ ๊ฒฝ๋ก ๋ฐฐํฌ ์
base์ต์ ์ค์ - ํ๊ฒฝ ๋ณ์:
VITE_์ ๋์ฌ ๊ท์น ์ค์ +.env.*ํ์ผ ๋ถ๋ฆฌ
Vite์ ๋น ๋ฅธ ๊ฐ๋ฐ ๊ฒฝํ๊ณผ Render์ ๊ฐํธํ ๋ฐฐํฌ๋ฅผ ์กฐํฉํ๋ฉด ํ๋ก๋์ ์์ค์ ์น ์ฑ์ ๋น ๋ฅด๊ฒ ๊ฐ๋ฐํ๊ณ ๋ฐฐํฌํ ์ ์๋ค.
