본문으로 건너뛰기

TypeScript 프로젝트

Crawlee는 TypeScript로 작성되어 패키지에서 직접 타입 정의를 제공합니다. 이를 통해 TypeScript와 JavaScript 코드 모두에서 자동 완성 기능을 활용할 수 있습니다. 또한 TypeScript로 작성된 프로젝트는 컴파일 시점의 타입 체크를 통해 많은 코딩 실수를 방지할 수 있으며, 함수, 매개변수, 반환 값에 대한 문서화도 제공합니다. 리팩토링이 훨씬 수월해지고 버그 발생 가능성도 최소화할 수 있습니다.

TypeScript 프로젝트 설정하기

TypeScript 프로젝트를 시작하기 위해 다음과 같은 준비가 필요합니다:

  1. TypeScript 컴파일러 tsc 설치:

    npm install --save-dev typescript

    위와 같이 TypeScript는 프로젝트의 개발 의존성으로 설치하면 됩니다. 프로덕션 환경이나 시스템의 전역 저장소를 TypeScript로 오염시킬 필요가 없습니다.

  2. tsc를 실행하는 빌드 스크립트와 package.json에 올바르게 지정된 main 진입점 (빌드된 코드를 가리키도록):

    {
    "scripts": {
    "build": "tsc"
    },
    "main": "dist/main.js"
    }
  3. 사용할 모든 기능에서 타입 체크를 활용할 수 있도록 NodeJS용 타입 선언:

    npm install --save-dev @types/node
  4. 프로젝트 구조와 사용되는 기능을 tsc가 이해할 수 있도록 하는 TypeScript 설정 파일:

    우리는 @apify/tsconfig를 확장하여 사용합니다. 이는 우리가 따르기 좋다고 생각하는 규칙들을 포함하고 있습니다.

    Top level await 기능을 사용하기 위해서는 moduletarget 컴파일러 옵션을 ES2022 이상으로 설정해야 합니다. 이렇게 하면 프로젝트가 ECMAScript 모듈로 컴파일됩니다.

    tsconfig.json
    {
    "extends": "@apify/tsconfig",
    "compilerOptions": {
    "module": "ES2022",
    "target": "ES2022",
    "outDir": "dist"
    },
    "include": [
    "./src/**/*"
    ]
    }

    위 내용을 루트 폴더의 tsconfig.json 파일에 저장하세요.

    JavaScript를 사용하는 VSCode 사용자의 경우, .js 소스 파일에서도 타입을 활용하려면 동일한 내용의 jsconfig.json을 만들고 "compilerOptions""checkJs": true를 추가하세요.

    브라우저 크롤러를 사용하려면 컴파일러 옵션에 "lib": ["DOM"]도 추가해야 합니다.

    @apify/tsconfig 설치를 잊지 마세요:

    npm install --save-dev @apify/tsconfig

ts-node로 프로젝트 실행하기

개발 중에는 TypeScript 코드를 매번 JavaScript로 컴파일하지 않고 직접 실행하는 것이 편리합니다. ts-node를 사용하면 됩니다. 개발 의존성으로 설치하고 새로운 NPM 스크립트를 추가하세요:

npm install --save-dev ts-node

앞서 언급했듯이 우리 프로젝트는 ES 모듈을 사용하도록 컴파일됩니다. 따라서 ts-node-esm 바이너리를 사용해야 합니다.

-T 또는 --transpileOnly 플래그를 사용하면 코드가 타입 체크를 하지 않고 더 빠르게 컴파일됩니다. 시간이 더 걸리더라도 타입 체크를 하고 싶다면 이 플래그를 제거하세요.

package.json
{
"scripts": {
"start:dev": "ts-node-esm -T src/main.ts"
}
}

프로덕션 환경에서 실행하기

프로덕션 환경에서 프로젝트를 실행하려면 먼저 빌드 스크립트로 컴파일해야 합니다. 컴파일된 JavaScript 코드가 dist 폴더에 생성되면 node dist/main.js로 실행할 수 있습니다.

package.json
{
"scripts": {
"start:prod": "node dist/main.js"
}
}

Docker 빌드

Dockerfile에서는 최종 이미지에 TypeScript와 같은 개발 의존성이 포함되지 않도록 멀티 스테이지 빌드를 권장합니다:

Dockerfile
# TypeScript 소스 코드를 빌드하기 위해 개발 의존성이 필요하므로 멀티 스테이지 빌드 사용
FROM apify/actor-node:20 AS builder

# 모든 파일을 복사하고, 모든 의존성(개발 의존성 포함)을 설치한 후 프로젝트 빌드
COPY . ./
RUN npm install --include=dev \
&& npm run build

# 최종 이미지 생성
FROM apify/actor-node:20
# 필요한 파일만 복사
COPY --from=builder /usr/src/app/package*.json ./
COPY --from=builder /usr/src/app/dist ./dist

# 프로덕션 의존성만 설치
RUN npm --quiet set progress=false \
&& npm install --only=prod --no-optional

# 컴파일된 코드 실행
CMD npm run start:prod

모든 것을 종합하기

지금까지 설명한 내용을 정리해보겠습니다. 위에서 설명한 스크립트 외에도 Top level await를 사용하기 위해 package.jsontype: 'module'을 설정해야 합니다. 편의를 위해 3개의 start 스크립트를 만들겠습니다. 기본 스크립트는 컴파일이나 타입 체크가 필요 없는 ts-node 스크립트인 start:dev의 별칭이 됩니다. 프로덕션 스크립트(start:prod)는 Dockerfile에서 명시적인 npm run build 호출 후에 사용됩니다.

package.json
{
"name": "my-crawlee-project",
"type": "module",
"main": "dist/main.js",
"dependencies": {
"crawlee": "3.0.0"
},
"devDependencies": {
"@apify/tsconfig": "^0.1.0",
"@types/node": "^18.14.0",
"ts-node": "^10.8.0",
"typescript": "^4.7.4"
},
"scripts": {
"start": "npm run start:dev",
"start:prod": "node dist/main.js",
"start:dev": "ts-node-esm -T src/main.ts",
"build": "tsc"
}
}