프록시 서버(Proxy Server)는 클라이언트와 서버 사이에서 중개자 역할을 하는 서버이다.
클라이언트가 인터넷 상의 다른 서버에 데이터를 요청할 때, 그 요청이 직접 서버로 가는 것이 아니라 프록시 서버를 거치게 되는데 프록시 서버는 이 요청을 받아 실제 목적지 서버로 전달하고, 그 응답을 다시 클라이언트에게 전달하는 역할을 한다.
프록시 서버는 자주 요청되는 데이터를 로컬에 저장할 수 있다.
이러한 캐싱 기능으로 인해 동일한 요청에 대해서는 프록시 서버가 직접 응답을 제공함으로써 네트워크 대역폭을 절약하고, 응답 시간을 단축할 수 있다.
프록시 서버는 외부와의 중간 지점으로 작용하여 클라이언트의 실제 IP 주소를 숨길 수 있다.
이로 인해 네트워크 보안을 강화하고, 내부 네트워크에 대한 무단 접근을 방지할 수 있다.
특정 웹사이트나 데이터에 대한 접근을 제어할 수 있다.
예를 들어, 기업이나 학교에서는 부적절한 콘텐츠의 접근을 차단하기 위해 프록시 서버를 사용하기도 한다.
프록시 서버를 통해 사용자의 인터넷 사용 내역을 모니터링하고 기록할 수 있다.
이는 IT 정책의 준수 여부를 확인하고, 비정상적인 활동을 감지하는 데 도움이 된다.
프록시 서버는 다른 지역에 위치할 수 있기 때문에, 특정 지역에서만 제공되는 콘텐츠에 접근할 수 있게 해주는 역할을 한다.
여러 프록시 서버를 사용하여 네트워크 트래픽을 분산시킴으로써 서버에 대한 부하를 줄일 수 있다.
개발 환경에서 프론트엔드와 백엔드 서버 간의 교차 출처 리소스 공유(CORS) 문제를 해결하기 위해 프록시 서버를 사용할 수 있다.
클라이언트나 서버 양쪽으로부터 프록시의 존재를 숨기지 않는다.
이를 통해 사용자의 인터넷 사용을 감시하거나 캐싱을 위해 주로 사용된다.
클라이언트의 IP 주소를 숨긴다.
이는 사용자의 프라이버시 보호와 보안 강화를 위해 사용된다.
익명 프록시와 유사하지만, 의도적으로 잘못된 IP 주소를 전송하여 클라이언트의 실제 위치를 숨긴다.
이 종류의 프록시는 클라이언트의 IP 주소를 숨길 뿐만 아니라, 프록시 서버를 사용하고 있다는 사실 자체도 숨긴다.
이를 통해 사용자는 완전한 익명성을 유지할 수 있다.
이 프록시는 일반적인 프록시와 반대로 클라이언트가 아닌 서버 측에 있다.
클라이언트로부터의 요청을 받아 서버로 전달하고, 서버의 응답을 클라이언트에게 다시 전달한다.
로드 밸런싱, SSL 암호화, 캐시 정적 컨텐츠, 내부 서버 보안 강화 등의 목적으로 사용된다.
프록시 서버를 경유하면 추가적인 네트워크 홉이 발생하기 때문에, 네트워크 지연이 증가할 수 있다.
프록시 서버 자체가 해킹의 대상이 될 수 있으므로, 보안 설정과 관리에 주의를 기울여야 한다.
프록시 서버는 사용자의 인터넷 사용 데이터를 로그로 기록할 수 있으며, 이는 개인정보 보호와 관련된 이슈를 일으킬 수 있다.
앞서 개발환경에서 프록시 서버를 사용하는데 주로 CORS 를 해결할 때 사용한다고 하였다. 그럼 이 Proxy 설정을 무엇으로 할까?
보통 vite 로 한다. vite 에서 제공하는 proxy 기능을 사용한다.
Vite(발음: /vit/, "빠르다"는 뜻의 프랑스어)는 현대적인 프론트엔드 개발을 위한 빌드 도구이다.
사실 이 vite를 더 자세히 알려면 이게 왜 나왔는지를 알아야하는데 이는 바로 밑에서 설명하겠다.
Vite는 개발 중에 필요한 모듈만을 빠르게 변환하여 브라우저에 제공한다.
이는 전체 애플리케이션을 번들링하는 대신, 모듈 단위로 필요할 때마다 요청하고 처리하는 방식으로, 개발 서버의 시작 시간을 크게 단축시킨다.
Vite는 변경 사항을 모듈 단위로 빠르게 교체할 수 있는 핫 모듈 교체(Hot Module Replacement
)를 지원한다.
이를 통해 개발자는 수정한 부분이 실시간으로 반영되는 것을 볼 수 있으며, 애플리케이션의 상태를 유지하면서 개발할 수 있다.
Vite는 브라우저가 지원하는 ES 모듈(EcmaScript Modules)을 사용하여, 브라우저가 모듈을 자연스럽게 해석하고 캐싱할 수 있도록 한다. 이는 추가적인 번들링 과정 없이도 모듈을 로드할 수 있게 하여 개발 속도를 높인다.
Vite는 Rollup 플러그인
과 호환되는 플러그인 시스템을 가지고 있다. 이를 통해 다양한 기능을 애플리케이션에 쉽게 추가할 수 있으며, 커뮤니티에서 제공하는 수많은 플러그인을 활용할 수 있다.
Vite는 개발 모드와 별개로 프로덕션을 위한 최적화된 빌드를 지원한다.
프로덕션 빌드는 Rollup
을 기반으로 하며, 코드 분할(code splitting), 자산 압축(asset minification), 트리 쉐이킹(tree shaking) 등의 최적화 기능을 제공한다.
Vite는 Vue, React, Preact, Svelte 등 다양한 자바스크립트 프레임워크 및 라이브러리를 공식적으로 지원한다. 각 프레임워크에 맞는 템플릿을 제공하여 쉽게 프로젝트를 시작할 수 있다.
vite.config.js 또는 vite.config.ts 파일을 통해 Vite 프로젝트를 설정할 수 있다.
설정 파일은 매우 간결하며, 대부분의 경우에 기본 설정만으로도 충분한다. 필요에 따라 개발 서버 옵션, CSS 전처리기 설정, 플러그인 등을 쉽게 추가할 수 있다.
별도의 플러그인이나 복잡한 설정 없이 타입스크립트를 사용할 수 있으며, 개발 중에 바로 타입 체크를 수행할 수 있다.
Vite는 PostCSS, CSS 모듈, Pre-processor와 같은 다양한 CSS 관련 기능을 자연스럽게 지원한다.
이를 통해 개발자는 프로젝트에서 현대적인 CSS 작성 패턴을 쉽게 적용할 수 있다.
Vite는 개발 환경을 개선하기 위해 노력한다. 예를 들어, 브라우저 캐시를 적극적으로 활용하여 개발 서버의 응답 속도를 향상시키고, 에러 메시지를 보다 명확하게 표시하여 디버깅을 용이하게 한다.
Vite는 환경 변수(.env 파일)와 개발 모드를 지원하여, 다양한 환경에 맞게 프로젝트를 구성할 수 있게 해준다.
이를 통해 개발, 스테이징, 프로덕션 등의 다양한 환경에서 애플리케이션의 동작을 쉽게 전환할 수 있다.
Vite는 SSR(Server-Side Rendering)과 정적 사이트 생성(Static Site Generation)을 위한 플러그인과 구성을 지원한다. 이를 통해 SEO 최적화나 빠른 로딩 시간이 필요한 프로젝트에도 Vite를 사용할 수 있다.
앞선 포스팅에서 번들러, webpack 이 나오게 된 이유에 대해 간략히 설명하였다. 이도 그 연장선에 있다.
자바스크립트의 사용성이 넓어짐에 따라 별도의 Module로 분할하기 위한 메커니즘 제공을 위해 생각하기 시작했다.
Node.js가 만들어짐으로써 require 함수와 module.export를 사용하는 CommonJS라는 방식의 모듈 방식이 만들어졌다.
// CommonJS 방식
const test = require("test")
module.export = function () {}
CommonJS는 브라우저 외의 환경에서도 동작하는 범용적인 JavaScript를 위한 모듈 시스템이기 때문에 모든 디펜던시가 로컬 디스크에 존재해서 필요한 모듈을 바로 사용할 수 있는 환경을 전제로 한다.
따라서 동기적(synchronously)으로 모듈을 호출하는 방식을 선택했다.
CommonJS의 모듈 시스템 사용 빈도는 높아졌지만, 처음부터 비동기 로드를 고려하지 않은 설계 때문에 브라우저에서는 CommonJS를 사용할 수 없다는 문제가 있었다.
즉, CommonJS 모듈 시스템은 Node.js 프로젝트에는 훌륭한 해결책이였지만 브라우저에게는 그렇지 않았다는 의미다.
AMD(Asynchronous Module Definition)는 비동기 상황에서도 JavaScript 모듈을 쓰기 위해 CommonJS에서 함께 논의하다 합의점을 이루지 못하고 독립한 별도의 그룹이다.
비동기적으로 모듈을 호출하는 특성 때문에 CommonJS보다 나은 성능을 보였고 또한 브라우저와 서버 사이드에서 모두 호환되는 방식이었으나 굉장히 복잡하다.
UMD(Universal Module Definition) 패턴, Common JS 와 AMD 를 모두 포용할 수 있도록 조건문으로 분기를 하고 이를 팩토리 패턴으로 구현한 방식이다.
CommonJS, AMD, UMD 이렇게 모듈 시스템이 개판일 때 JS 차원에서 지원해줘야한다고 하여 나온 시스템이다.
// ES6
import foo from "foo";
export default foo;
동기/비동기 로드를 모두 지원하고 문법역시 간단하다. 또한 실체 객체/함수를 바인딩하기에 순환 참조 관리도 편하고 정적 분석(static analyze, 코드를 실행하지 않더라도 분석이 가능)이 가능하기 때문에 트리 쉐이킹(Tree Shaking)역시 쉽게 가능했다.
하지만 ES6 문법을 공부하다보면 알 수 있듯 "최신 문법" 이기에 IE 같은 구형 브라우저에서는 제대로 동작하지 않는다는 문제점이 있다.
그러다보니 SystemJS처럼 CommonJS, AMD, ES Module 모든 모듈 시스템을 지원하는 또 따른 형태의 모듈 로더가 나오는 헤프닝도 생겼다.
이 번들러가 나온 배경은 앞선 포스팅에 설명하였으니 넘어가고
결국 이 번들러는 대규모 협업 개발에 유리하게 module과 같은 방식으로 여러개의 파일을 나눠서 개발을 하고 모든 파일을 하나로 합쳐서 하나의 번들(bundle)로 만들어내는 번들러라는 개념이다.
webpack은 모던 JavaScript 애플리케이션을 위한 정적 모듈 번들러이다.
webpack이 애플리케이션을 처리할 때, 내부적으로는 프로젝트에 필요한 모든 모듈을 매핑하고 하나 이상의 번들을 생성하는 디펜던시 그래프를 만든다.
앞서 언급한 vite 의 근간이 되는 툴이다.
Rollup은 작은 코드 조각을 라이브러리나 애플리케이션과 같이 더 크고 복잡한 것으로 컴파일하는 JavaScript용 모듈 번들러이다. CommonJS 및 AMD와 같은 이전의 특이한 솔루션 대신 JavaScript의 ES6 개정판에 포함된 코드 모듈에 대해 새로운 표준화된 형식을 사용한다.
Rollup은 webpack과 유사한 모듈 번들러이지만 가장 큰 차이점으로 ES6 모듈 형식으로 빌드 결과물을 출력할 수 있어서 라이브러리나 패키지 개발에 활용할 수 있다는 점이 있다.
Parcel은 별도의 설정 파일 없이도 동작한다. 설치하면 하면 설정 파일 없이 빌드 명령어를 입력해 바로 사용할 수 있다. webpack과 달리 JavaScript 엔트리포인트를 지정해주는 것이 아니라 애플리케이션 진입을 위한 HTML 파일 자체를 읽기 때문이다.
그러다 기존의 빌드 속도보다 100가 빠른 빌드도구인 esbuild가 등장한다. 하지만 esbuild가 나왔는데도 다들 webpack을 사용하였는데, 그 이유는 esbuild가 나온 당시 webpack은 DevServer, 트랜스파일링, 코드 스플리팅, 트리 쉐이킹, HMR, CSS, HTML, asset 지원 등 그저 빌드 도구가 아닌 개발을 도와주는 통합 툴이였지만 esbuild는 빌드 도구에 불과했기 때문이다.
또한 esbuild를 이용하여 가능한 개발은 Vanilla JS 형태의 라이브러리만 가능했으며 프레임워크를 기반으로 하는 웹 개발은 타 번들러들을 사용해야 했다.
그래서 등장한 또 다른 툴이 바로 Snowpack 이다.
Snowpack은 기존에 파일을 하나 수정 할 때마다 전체를 빌드해서 결과를 만들어내는 방식이 아니라 각각의 모듈을 별도로 빌드하고 수정이 발생하면 해당 파일만 다시 빌드를 해서 업데이트하는 방식을 채택하고 빌드는 esbuild를 사용하였다.
최초에 Rollup 을 공식 번들로 사용하다가 HMR 이슈로 snowpack 으로 넘어갔다.
이데 라ㅏ esbuild + 브라우저 표준 모듈로 개발을 진행하고 실제 릴리즈는 기존 번들 툴로 진행하면서 HMR, DevServer 등을 제공하게 되었지만 snowpack이 그다지 안정적이지는 않았다.
Vite라는 esbuild와 브라우저 모듈을 이용한 DevServer, ProxyServer, 번들 툴, 코드 스플리팅, HMR 등 앞에 나왔던 모든 기능들을 모은 프론트엔트 번들 도구가 탄생하게 된다.
Vite는 최종 번들 도구로 Rollup을 선택했고 이로 인해 Svelte는 webpack이 최종 번들 도구인 snowpack보다는 기존에 사용하던 rollup을 최종 번들 도구로 쓰는 Vite가 더 낫다고 판단 Vite와 통합을 하게 된다.
이로서 현재까지는 vite 가 빌드 툴을 제패하지 않았나 싶다.
vite.config.ts는 Vite라는 프론트엔드 빌드 도구를 위한 설정 파일이다.
Vite를 사용하는 프로젝트에서 프록시 설정을 vite.config.ts 파일에 추가하는 것은 개발 중인 로컬 환경에서 API 요청을 다루기 위해 필요하다. 특히, 앞서도 언급했듯 개발 서버가 다른 도메인이나 포트에서 실행 중인 백엔드 서버에 요청을 보낼 때 CORS(Cross-Origin Resource Sharing) 정책으로 인해 발생할 수 있는 제약을 해결하기 위해 사용된다.
vite.config.ts 파일에서 프록시 설정을 추가하면 Vite 개발 서버는 해당 설정에 맞춰 들어오는 HTTP 요청을 지정된 대상 서버로 전달하게 된다.
import { defineConfig } from 'vite';
import vue from '@vitejs/plugin-vue';
// https://vitejs.dev/config/
export default defineConfig({
plugins: [vue()],
server: {
proxy: {
// 프록시 설정
'/api': {
// 실제 백엔드 서버의 주소
target: 'http://localhost:3000',
// 호스트 헤더를 target URL로 변경
changeOrigin: true,
// 요청 주소에서 /api를 제거
rewrite: (path) => path.replace(/^\/api/, '')
},
// 다른 프록시 규칙을 추가
}
}
});
위 코드에서 /api로 시작하는 모든 요청은 http://localhost:3000으로 프록시된다.
changeOrigin 옵션은 프록시 요청이 원본 호스트를 대신하여 프록시 서버의 호스트를 사용하도록 설정한다.
rewrite 옵션은 요청 URL에서 특정 패턴을 제거하거나 변경할 때 사용된다.
인지해야할 점은 프로덕션 환경에서는 이러한 프록시 설정을 사용하지 않으며, 대신 적절한 백엔드 구성이나 서버사이드 프록시를 설정하든지 아니면 직접 back-end url을 다 적어주면 된다.