소스맵 업로드

Vite 플러그인을 사용해 빌드 후 소스맵을 Sophonz 서버에 자동 업로드하고 프로덕션 에러의 원본 소스 위치를 추적합니다.

@sophonz/vite-sourcemap 플러그인을 사용하면 Vite 빌드 완료 후 소스맵을 자동으로 Sophonz 서버에 업로드할 수 있습니다. 이를 통해 프로덕션 환경에서 발생한 에러의 원본 소스코드 위치를 정확하게 추적할 수 있습니다.

@sophonz/vite-sourcemap 플러그인

NPM Version

주요 기능

  • Vite 빌드 완료 후 소스맵 자동 업로드
  • 멀티파트 폼 데이터로 파일 업로드
  • 포함/제외 패턴으로 파일 필터링
  • gzip 압축 지원
  • 동시 업로드 제한 및 재시도 로직
  • CI 환경 감지
  • 업로드 후 로컬 소스맵 파일 삭제 옵션
  • 커스텀 경로 변환 및 URL 접두사 지원

설치

npm install @sophonz/vite-sourcemap --save-dev

기본 설정

// vite.config.ts
import { defineConfig } from 'vite'
import sourcemapUpload from '@sophonz/vite-sourcemap'
 
export default defineConfig({
  build: {
    sourcemap: true, // 중요: 소스맵 생성을 활성화해야 합니다
  },
  plugins: [
    sourcemapUpload({
      endpoint: 'https://{{sophonz-service}}/api/v1/web-sourcemaps',
      apiKey: process.env.SOPHONZ_ACCESS_TOKEN,
      release: process.env.GIT_SHA,
      appVersion: process.env.npm_package_version,
    }),
  ],
})

고급 설정

// vite.config.ts
import { defineConfig } from 'vite'
import sourcemapUpload from '@sophonz/vite-sourcemap'
 
export default defineConfig({
  build: {
    sourcemap: true,
  },
  plugins: [
    sourcemapUpload({
      // 필수: 업로드 엔드포인트
      endpoint: 'https://{{sophonz-service}}/api/v1/web-sourcemaps',
 
      // 인증
      apiKey: process.env.SOPHONZ_ACCESS_TOKEN,
 
      // 릴리즈 정보
      release: process.env.GIT_SHA,
      appVersion: process.env.npm_package_version,
      build: process.env.BUILD_NUMBER,
 
      // 앱 타입 (플랫폼별 소스맵 구분)
      appType: 'ALL', // 'ANDROID' | 'IOS' | 'WEB' | 'ALL' | null
 
      // 파일 필터링
      include: [/assets\/.+\.js\.map$/],
      exclude: [/node_modules/],
 
      // CDN 경로 설정
      urlPrefix: '~/static/js',
 
      // 커스텀 경로 변환
      transformPath: (path) => `build/${path}`,
 
      // 업로드 설정
      concurrency: 3,
      retries: 5,
      gzip: true,
      deleteAfterUpload: true,
 
      // CI에서만 실행
      ciOnly: true,
 
      // 추가 헤더
      headers: {
        'X-Custom-Header': 'value',
      },
 
      // 추가 폼 필드
      fields: {
        environment: 'production',
        team: 'frontend',
      },
    }),
  ],
})

설정 옵션

필수 옵션

옵션타입설명
endpointstring소스맵을 업로드할 API 엔드포인트

선택 옵션

옵션타입기본값설명
method'POST' | 'PUT''POST'HTTP 메서드
headersRecord<string, string>{}추가 HTTP 헤더
apiKeystring-Bearer 토큰 또는 API 키
releasestring-릴리즈 식별자 (예: git SHA)
appVersionstring-앱 버전 (semver)
buildstring-빌드 번호 또는 CI 빌드 ID
appType'ANDROID' | 'IOS' | 'WEB' | 'ALL' | nullnull앱 타입 (플랫폼별 소스맵 구분)
fileFieldNamestring'file'파일 업로드용 폼 필드명
fieldsRecord<string, string | number | boolean>{}추가 폼 필드
include(string | RegExp)[]-포함할 파일 패턴
exclude(string | RegExp)[]-제외할 파일 패턴
urlPrefixstring-업로드 파일명에 추가할 접두사
transformPath(path: string) => string-경로 변환 함수
concurrencynumber6동시 업로드 수
retriesnumber3재시도 횟수
gzipbooleantruegzip 압축 사용 여부
deleteAfterUploadbooleanfalse업로드 후 로컬 파일 삭제
ciOnlybooleanfalseCI 환경에서만 실행
verbosebooleanCI에서 true, 로컬에서 false상세 로그 출력

플랫폼별 소스맵 (appType)

ServiceNamespace 또는 Service 레벨에서 플랫폼별로 소스맵을 구분하여 관리할 수 있습니다.

공통 WebView (모든 플랫폼)

Android/iOS/Web에서 공통으로 사용하는 WebView 소스맵:

sourcemapUpload({
  endpoint: 'https://api.sophonz.com/v1/web-sourcemaps',
  apiKey: process.env.SOPHONZ_ACCESS_TOKEN,
  appVersion: '1.0.0',
  appType: 'ALL', // 모든 플랫폼에서 사용
})

Android WebView 전용

sourcemapUpload({
  endpoint: 'https://api.sophonz.com/v1/web-sourcemaps',
  apiKey: process.env.SOPHONZ_ACCESS_TOKEN,
  appVersion: '1.0.0',
  appType: 'ANDROID',
})

iOS WebView 전용

sourcemapUpload({
  endpoint: 'https://api.sophonz.com/v1/web-sourcemaps',
  apiKey: process.env.SOPHONZ_ACCESS_TOKEN,
  appVersion: '1.0.0',
  appType: 'IOS',
})

Web 브라우저 전용

sourcemapUpload({
  endpoint: 'https://api.sophonz.com/v1/web-sourcemaps',
  apiKey: process.env.SOPHONZ_ACCESS_TOKEN,
  appVersion: '1.0.0',
  appType: 'WEB',
})

레거시 (appType 미지정)

기존 방식과의 호환성을 위해 appType을 지정하지 않으면 모든 플랫폼에서 fallback으로 사용됩니다:

sourcemapUpload({
  endpoint: 'https://api.sophonz.com/v1/web-sourcemaps',
  apiKey: process.env.SOPHONZ_ACCESS_TOKEN,
  appVersion: '1.0.0',
  // appType 미지정 = null (레거시 호환)
})

appType Fallback 로직

소스맵 조회 시 다음 우선순위로 검색합니다:

  1. 정확한 appType 매칭: 요청된 appType과 정확히 일치하는 소스맵
  2. ALL 타입: appType이 ALL로 지정된 소스맵 (모든 플랫폼 공용)
  3. null 타입: appType이 지정되지 않은 레거시 소스맵

예를 들어, Android 앱에서 에러가 발생하면:

  1. appType: 'ANDROID'인 소스맵을 먼저 찾음
  2. 없으면 appType: 'ALL'인 소스맵을 찾음
  3. 없으면 appType: null인 소스맵을 fallback으로 사용

TIP — 플랫폼별 소스맵 관리

Android/iOS 네이티브 앱 내 WebView와 웹 브라우저에서 동일한 웹 애플리케이션을 사용하지만 소스맵이 다른 경우, appType을 지정하여 각 플랫폼별로 정확한 소스맵을 매칭할 수 있습니다.

액세스 토큰 발급

소스맵 업로드를 위해서는 Sophonz 액세스 토큰이 필요합니다. 토큰은 ServiceNamespace 또는 Service 레벨에서 발급할 수 있습니다.

Sophonz 콘솔에서 발급

  1. Sophonz 대시보드 로그인
  2. 글로벌 관리 > 서비스 관리로 이동
  3. 대상 서비스 또는 서비스 네임스페이스 선택
  4. 액세스 토큰 탭에서 토큰 생성 클릭
  5. 토큰 이름과 만료일(선택) 설정 후 생성
  6. 생성된 토큰을 복사하여 안전하게 보관

CAUTION — 토큰 보안

액세스 토큰은 생성 시 한 번만 표시됩니다. 토큰을 분실한 경우 새로운 토큰을 발급받아야 합니다. CI/CD 환경에서는 시크릿으로 관리하세요.

API를 통한 발급

# ServiceNamespace 레벨 토큰 발급
curl -X POST https://api.sophonz.com/v1/access-tokens \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer {{SESSION_TOKEN}}" \
  -d '{
    "serviceNamespaceId": 1,
    "name": "CI/CD Sourcemap Upload",
    "expiresAt": "2025-12-31T23:59:59Z"
  }'
 
# Service 레벨 토큰 발급
curl -X POST https://api.sophonz.com/v1/access-tokens \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer {{SESSION_TOKEN}}" \
  -d '{
    "serviceId": 1,
    "name": "CI/CD Sourcemap Upload",
    "expiresAt": "2025-12-31T23:59:59Z"
  }'

응답:

{
  "id": 1,
  "name": "CI/CD Sourcemap Upload",
  "token": "generated-token-value",
  "tokenHint": "****abcd",
  "createdAt": "2024-01-15T10:00:00Z",
  "expiresAt": "2025-12-31T23:59:59Z"
}

GitHub Actions와 함께 사용

# .github/workflows/deploy.yml
- name: Build and upload sourcemaps
  env:
    SOPHONZ_ACCESS_TOKEN: ${{ secrets.SOPHONZ_ACCESS_TOKEN }}
    GIT_SHA: ${{ github.sha }}
  run: npm run build

CI 환경 감지

플러그인은 다음 환경 변수를 통해 CI 환경을 자동으로 감지합니다:

  • CI
  • GITHUB_ACTIONS
  • GITLAB_CI
  • BUILDKITE
  • CIRCLECI
  • TRAVIS
  • BITBUCKET_BUILD_NUMBER

TIP — 소스맵 업로드 확인

verbose: true 옵션을 사용하면 업로드 과정을 상세하게 확인할 수 있습니다. 소스맵이 성공적으로 업로드되면 프로덕션 환경에서 발생한 에러의 정확한 소스 코드 위치를 확인할 수 있습니다.