Lambda
article thumbnail

"next-sitemap이 TypeScript 파일을 못 읽는다고요?"

 

제가 Poromy 프로젝트의 SEO를 개선하던 중 만난 당황스러운 순간이었습니다. 기업 상세 페이지들을 sitemap에 포함시켜야 했는데, next-sitemap이 제 TypeScript 데이터 파일들을 읽지 못하는 문제가 발생했죠. 단순히 ID들을 하드코딩하면 끝날 일이었지만, 그건 제 개발자 자존심이 허락하지 않았습니다.

 

이번 포스팅에서는 Next.js 15 환경에서 TypeScript 파일을 next-sitemap과 통합하는 과정에서 겪은 시행착오와 최종 해결 방법을 공유하고자 합니다. 특히 동적 데이터 기반의 sitemap을 자동으로 생성하는 확장 가능한 시스템을 구축한 경험을 나누겠습니다.

 

문제 상황

저는 Poromy라는 서비스의 프론트엔드를 개발하고 있었습니다. 이 서비스는 여러 기업 정보를 제공하는데, 각 기업마다 고유한 상세 페이지가 있었죠. SEO 최적화를 위해 이 모든 페이지들을 sitemap에 포함시켜야 했습니다.

// src/constants/company.data.ts
export const companies = [
  { id: 1, name: '토스', slug: 'toss' },
  { id: 2, name: '카카오', slug: 'kakao' },
  // ... 더 많은 기업들
];

// src/utils/crypto.ts
export function encrypt(id: number): string {
  // ID 암호화 로직
}

 

sitemap을 빌드 시에 자동 생성하기 위해 next-sitemap 라이브러리를 설치하고,  next-sitemap.config.js 파일에서 위 파일들을 import하려고 하니 다음과 같은 오류가 발생했습니다:

 

Error: Cannot find module './src/constants/company.data'
Require stack:
- /Users/lamue/poromy-front/next-sitemap.config.js

 

 

Node.js 환경에서 실행되는 next-sitemap이 TypeScript 파일을 직접 읽을 수 없기 때문에 위와 같은 에러가 발생하였습니다. 문제를 해결하기 위해선 TypeScript 파일을 JavaScript로 변환하여 import하여야 했습니다. 하지만 구체적으로 어떤 프로세스로 적용하면 좋을지 고민해봤습니다.

 

해결과정

첫 번째 시도: ts-node 사용하기

처음에는 "그냥 ts-node로 실행하면 되겠지?"라고 생각했습니다.

{
  "scripts": {
    "postbuild": "ts-node --project tsconfig.json next-sitemap.config.ts"
  }
}

 

하지만 이 방법은 ES modules와 CommonJS 간의 호환성 문제로 실패했습니다.

 

두 번째 시도: 하드코딩

그 다음에는 자연스럽게 하드코딩을 떠올렸습니다. 실제로 코드로 구현하지 않고 고민 단계에서 접긴했지만, 실제로 구현하면 아래와 같이 작업을 진행했을 거 같습니다.

// next-sitemap.config.js
const companyIds = [1, 2, 3, 4, 5]; // 이렇게는 하드 코딩하면 되긴 하지만..

... 기존의 로직

 

하지만 이건 제가 추구하는 해결책이 아니었습니다. 특히 새로운 기업이 추가될 때마다 이 파일을 수동으로 업데이트해야 한다니, 정말 끔찍했습니다. 바로 고민 단계에서 포기했습니다.

최종 해결책: TypeScript → JavaScript 변환 시스템

최종적으로 빌드 시점에 TypeScript를 JavaScript로 변환하여 적용하는 방법을 선택하였습니다.

이를 매 빌드 마다 자동으로 적용하기 위해 scripts/generate-company-data.js라는 변환 스크립트를 만들었습니다:

// scripts/generate-company-data.js
const fs = require('fs');
const path = require('path');
const { execSync } = require('child_process');

// 1. 임시 TypeScript 설정 생성
const tsConfig = {
  compilerOptions: {
    target: 'es5',
    module: 'commonjs',
    esModuleInterop: true,
    skipLibCheck: true,
    outDir: 'temp',
    baseUrl: '.',
    paths: {
      '@/*': ['src/*'],
    },
  },
  include: [
    'src/constants/company.data.ts',
    'src/utils/crypto.ts',
    'src/types/company.ts',
  ],
};

// 2. 임시 tsconfig 파일 생성
fs.writeFileSync(
  'tsconfig.temp.json',
  JSON.stringify(tsConfig, null, 2)
);

// 3. TypeScript 컴파일 실행
console.log('🔄 Compiling TypeScript files for sitemap...');
execSync('npx tsc --project tsconfig.temp.json', { stdio: 'inherit' });

// 4. 컴파일된 JavaScript 파일 읽기
const jsPath = path.join(__dirname, '../temp/constants/company.data.js');
const jsContent = fs.readFileSync(jsPath, 'utf8');

// 5. CommonJS 형태로 재구성
const companiesMatch = jsContent.match(/exports\.companies = (\[[\s\S]*?\]);/);
if (!companiesMatch) {
  throw new Error('Could not find companies data');
}

const modifiedContent = `
const companies = ${companiesMatch[1]};
module.exports = { companies };
`;

// 6. 수정된 파일 저장
fs.writeFileSync('./temp/company.data.js', modifiedContent);

// 7. 정리 작업
fs.unlinkSync('tsconfig.temp.json');
console.log('✅ Company data generated successfully!');

 

그리고 최종적으로 아래와 같은 형태로 next-sitemap.config.js 파일에 적용할 수 있었습니다.

// next-sitemap.config.js
const { companies } = require('./temp/company.data');
const { encrypt } = require('./temp/crypto');

module.exports = {
  siteUrl: 'https://poromy.com',
  generateRobotsTxt: true,
  additionalPaths: async (config) => {
    // 기업 상세 페이지 동적 생성
    const companyPaths = companies.map(company => ({
      loc: `/company/details/${encrypt(company.id)}`,
      changefreq: 'daily',
      priority: 0.7,
      lastmod: new Date().toISOString(),
    }));

    return companyPaths;
  },
};

 

 

이제 매 빌드 마다 동적 데이터를 반영한 sitemap 생성을 자동화하기 pakage.json의 스크립트를 아래와 같이 수정하였습니다. 

 

{
  "scripts": {
    "build": "next build",
    "postbuild": "pnpm run generate-company-data && next-sitemap",
    "generate-company-data": "node scripts/generate-company-data.js"
  }
}

 

마치며

지금까지 Next.js 15 환경에서 TypeScript 파일을 next-sitemap과 통합하는 과정에서 겪은 시행착오와 해결 방법을 공유했습니다. 이번 문제를 해결하면서 "빌드 파이프라인 설계의 중요성"을 다시 한번 깨달았습니다. 단순히 하드코딩으로 때우는 것이 아닌 시스템적으로 접근하여 확장 가능한 해결책을 만드는 것이 처음에는 번거로울 수 있지만, 이러한 자동화가 쌓이면 쌓일 수록 개발 효율성이 늘어나는 것 같습니다.

여러분도 비슷한 문제를 겪고 계신가요? TypeScript와 JavaScript 런타임 간의 차이로 고민하고 계신다면, 이런 변환 시스템을 구축해보는 것은 어떨까요? 코드는 난해하지만, 클로드나 GPT와 같이 작업을 한다면 생각보다 금방 적용할 수 있을 겁니다 🙂 (물론 LLM을 통해 작성한 코드를 이해하고 적용해야 하지만요 !)

혹시 더 좋은 방법을 알고 계시거나, 비슷한 경험이 있으시다면 댓글로 공유해주세요. 함께 더 나은 해결책을 찾아가면 좋겠습니다! 🚀

 

읽어주셔서 감사합니다. 

 

참고

https://poromy.ai.kr/

 

Poromy - GPT/Claude AI 자소서 프롬프트 아카이브

ChatGPT, Claude 등 AI 모델을 활용한 자소서 작성, 기업 분석, 채용 공고 분석을 위한 최고의 AI 프롬프트 아카이브

poromy.ai.kr

 

 

profile

Lambda

@Lamue

포스팅이 좋았다면 "공감❤️" 또는 "구독👍🏻" 해주세요!