[Next.js][공식문서] create-next-app과 SWC

Gyuwon Lee·2022년 10월 23일
1

Next.js 공식 튜토리얼을 바탕으로, 필요한 개념을 보충하여 학습한 기록입니다.

1. create-next-app (feat. TS)

npx create-next-app@latest --ts
# or
yarn create next-app --typescript
# or
pnpm create next-app --ts

create-react-app 과 같이, create-next-app 은 Next.js 어플리케이션을 빠르게 생성하기 위한 CLI 툴이다.

별다른 플래그 없이 사용하면 Next.js의 기본 템플릿을 사용하게 되지만, --example 플래그를 사용하면 약 300개 안팎의 스택 별, 유형 별 예제 템플릿들 중 선택하여 세팅할 수 있다.

이외에도 플래그들은 아래와 같이 붙일 수 있다:

  • --ts, --typescript : Next.js 어플리케이션을 타입스크립트 기반으로 초기화해준다.

  • -e, --example [name]|[github-url] : Next.js 어플리케이션을 특정 예제 템플릿 바탕으로 초기화해준다. 이 때의 예제는 Next.js 레포지토리의 예제명 또는 원하는 깃허브 URL이 될 수 있다. 단 / 기호가 들어가는 경우에는 아래의 --example-path 플래그를 추가로 사용한다.

  • --example-path [path-to-example] : 예제 템플릿을 깃허브 URL로부터 가져오는 경우, 경로명에 / 기호가 사용된다면 이 플래그를 사용해야 한다. 브랜치 명에 / 기호가 들어갈 수도 있고, 하위 경로를 명시하느라 / 기호를 사용해야 할 수도 있다. 이러한 경우 반드시 경로를 따로 명시해 주어야 한다: --example-path foo/bar

🤔 직접 세팅하지 않고, CLI를 사용해도 될까?

Next.js는 공식 API Reference를 통해 Create Next App 사용 시의 여러 장점을 명시하고 있다.

대화형 설치 경험

"(기타 플래그 및 인자 없이) npx create-next-app@latest 명령어를 실행하면, 프로젝트를 설치하는 과정 동안 대화형 경험을 제공합니다"

한 마디로, 내가 하나하나 설정파일을 세팅하고 필요한 라이브러리들을 설치하고... 할 필요 없이 대화형(Y/N)으로 설치 시작부터 완료까지 마칠 수 있다는 이야기다.

오프라인 및 '의존 모듈 없는' 설치

여타 라이브러리 및 모듈을 사전(사후)에 설치할 필요 없이 Create Next App 명령어 하나면 프로젝트 초기화가 완료된다. 또한 설치를 시도하는 사용자가 오프라인인지 여부를 자동으로 탐지한다. npm 등을 사용할 수 없는 오프라인 상황에는 사용자의 로컬 패키지 캐시를 사용하여 프로젝트를 초기화시켜준다.

다양한 예제

프로젝트 목적에 맞추어 사용할 수 있는 다양한 예제 템플릿들을 제공해서, 프로젝트를 보다 빠르게 시작할 수 있도록 돕는다.

Next.js 측에서 검증한 패키지

Create Next App 은 Next.js 레포의 일부이기 때문에, Next.js 프레임워크와 동일한 모듈 통합 테스트(integration test suite)를 거친다. 즉, 매 배포마다 정상적인 작동이 보장된다.

📌 create-react-app 과 비교해보자

Next: 간단한 라우팅 방식과 pages/

Next.js는 번들 로 합쳐진 전체 코드를 각 페이지 별 chunk 로 다시 나눈다(code splitting). 기본적으로 이 기능을 지원하고 있으며, pages/ 디렉토리에 있는 파일들이 각각의 JS 번들 로 묶이게 된다. 이 때 두 개 이상의 페이지가 공유하고 있는 코드는 별도의 번들로 묶여, 불필요한 재다운로드를 방지한다.

따라서 create-next-app 로 생성된 프로젝트 폴더에는 기본적으로 pages/ 안에 index.js 가 들어 있고, 동일한 위치에 각 페이지 단위로 파일을 만들어 관리하게 된다.

React: 높은 자유도와 src/

(create-react-appnpx 로 실행해서 yarn.lock 대신 package-lock.json 이 들어 있다)

프레임워크인 Next.js와 달리 리액트는 라이브러리로서 정해진 틀 없이 개발자에게 높은 자유도를 부여한다. create-react-app 으로 생성된 프로젝트 폴더에는 App.tsx 파일을 포함한 모든 컴포넌트 파일들이 들어가게 된다.
이 때 src/ 경로에서 페이지 단위로 파일을 나눌지, 도메인 기준 혹은 컴포넌트 단위로 파일을 나눌지 결정하는 것은 순전히 개발자의 몫이다.

프로젝트 실행

초기화가 완료된 프로젝트는 npm run dev 로 웹 상에서 확인해볼 수 있다. 기본적으로 localhost 3000번 포트를 사용한다.

"scripts": {
  "dev": "next dev",
  "build": "next build",
  "start": "next start",
  "lint": "next lint"
},

여기서 next 명령어는 내부적으로 어떤 코드를 실행시키는 것일까?

create-react-app : npm run eject

잠깐 create-react-app 으로 돌아와 보자.

"scripts": {
  "start": "react-scripts start",
  "build": "react-scripts build",
  "test": "react-scripts test",
  "eject": "react-scripts eject",
},

여기서는 react-scripts 를 사용해서 프로그램을 빌드하는 듯 하다. 기본적으로 CRA는 프로젝트 디렉토리를 간결하게 유지하기 위해서 웹팩 설정이나 script들의 자세한 동작을 명시한 script 폴더를 숨겨놓는다. 하지만 숨겨진 세부 설정을 커스텀해야 할 필요가 있다면 npm run eject 를 입력해 숨겨놓은 설정 파일들을 프로젝트 디렉토리에 표시되게끔 만들 수 있다.

위 명령어로 생겨난 scripts/ 폴더의 build.js 파일을 확인하면 아래와 같은 몇몇 코드들을 확인할 수 있다:

// build.js

// Do this as the first thing so that any code reading it knows the right env.
process.env.BABEL_ENV = 'production';
...
const webpack = require('webpack');
...
// Start the webpack build
return build(previousFileSizes);
...

babelwebpack 이 사용되고 있는 것을 알 수 있다. 이미 대부분의 리액트 프로젝트에서 널리 사용되어 온 툴이기에 놀라운 사실은 아니지만, 파일을 뜯어 한 번 확인해보았다. Next.js는 다른 빌드 툴을 사용하기 때문이다.

create-next-app : SWC

리액트로 웹 앱을 완성하는 데는 결국 아래와 같은 과정을 거치게 된다:

  • 웹팩이나 바벨 같은 번들러 및 트랜스파일러를 거쳐야만 한다.
  • 제품(프로그램) 최적화를 위해 코드 쪼개기가 필요하다.
  • 성능과 SEO를 위해 몇몇 페이지를 정적으로 미리 렌더링하고 싶을 수 있다. 혹은 SSR이나 CSR을 선택적으로 사용해야 할 수도 있다.
  • 리액트 프로그램을 데이터 저장소와 연결하기 위해 일부 server-side 코드를 작성해야 할 수 있다.

위에서 create-react-app 역시 react-scripts 로 추상화시킴으로써 간편한 빌드 과정을 제공하려 했음을 알 수 있었지만, SEO 및 여러 부분에서 불완전한 부분이 남아있다.

Next.js는 프레임워크로서 내부적으로 코드 컴파일, 번들링, 경량화(minifying) 및 코드 쪼개기(code splitting)를 수행해 주는데, 이를 위해 12 버전부터 Rust 기반의 SWC 라는 빌드 툴을 도입했다.

2. Speedy Web Compiler

Next.js 의 공식 웹사이트에서는 SWC로 구축된 새로운 컴파일러를 이용해 Next.js 프로젝트를 빌드하면, 기존과 비교했을 때 빌드 타임이 최대 5배까지 빨라질 수 있다고 소개하고 있다. 따라서 바벨이나 terser 등 기존 리액트 프로젝트에서 사용되던 빌드 툴보다 향상된 성능을 제공한다.

SWC는 자바스크립트 프로젝트의 컴파일과 번들링 모두에 사용될 수 있는 빌드 툴이다.

Next.js 12 버전 이전까지는 트랜스파일링에 바벨, 코드 경량화에 Terser가 사용되었지만, 12 버전부터 전부 SWC로 대체되었다. SWC로 교체함으로써 트랜스파일링은 무려 17배나 빨라졌다고 하며, 코드 경량화 작업은 7배가 빨라졌다고 한다. 어떻게 이렇게 빨라질 수 있었을까?

이는 SWC가 기반으로 하는 Rust가 이벤트 루프 기반의 싱글 스레드 언어인 자바스크립트와는 다르게 병렬 처리를 고려해서 설계된 언어라는 점에서 이유를 찾을 수 있다.

컴퓨터는 원래 여러 가지 일을 동시에 진행할 수 있다. 이러한 컴퓨터의 특성을 활용한다면, 우리가 바벨이나 Terser로 프로젝트를 빌드할 때 의존성이 없는 파일들은 동시에 변환할 수 있어야 한다. 하지만 자바스크립트는 한 개의 스레드만을 사용하는 싱글 스레드 언어이기 때문에, 자바스크립트 언어로 구현된 바벨과 Terser는 한 번에 한 개의 파일만을 변환할 수 있습니다.

자바스크립트와는 달리 병렬 처리가 가능하도록 설계된 Rust 언어로 작성된 SWC는 의존성이 없는 파일들을 동시에 변환할 수 있다. 따라서, 만약 현재 컴퓨터가 최대 4개의 작업을 동시에 할 수 있다면 SWC를 사용한 빌드 속도는 바벨이나 Terser를 통해 빌드했을 때 보다 최대 4배까지 더 빨라질 수 있을 것이다.

물론 SWC가 바벨이나 Terser보다 빠른 이유는 이외에도 여러 가지(Rust가 LLVM 도구를 사용한다던가, 가비지 컬렉션을 하지 않는다던가…)가 있지만, 핵심적으로 동시에 여러 파일을 처리할 수 있어서 빠르다라 는 점을 강조하는 것으로 충분할 것 같다.

빌드 툴도 변한다

현재 많은 프로젝트에서 쓰이는 몇몇 바벨 플러그인들은 아직 Next.js의 SWC 컴파일러와 호환되지 않는다. CSS-in-JS 라이브러리인 emotion 을 지원하기 위한 @emotion/babel-plugin 같은 것들이 이에 해당한다. 공식문서에 따르면 현재 포팅 중에 있으며, 일단 아래와 같은 방식으로 사용할 수는 있다.

// next.config.js

module.exports = {
  compiler: {
    emotion: boolean | {
      // default is true. It will be disabled when build type is production.
      sourceMap?: boolean,
      // default is 'dev-only'.
      autoLabel?: 'never' | 'dev-only' | 'always',
      // default is '[local]'.
      // Allowed values: `[local]` `[filename]` and `[dirname]`
      // This option only works when autoLabel is set to 'dev-only' or 'always'.
      // It allows you to define the format of the resulting label.
      // The format is defined via string where variable parts are enclosed in square brackets [].
      // For example labelFormat: "my-classname--[local]", where [local] will be replaced with the name of the variable the result is assigned to.
      labelFormat?: string,
    },
  },
}

하지만 Next.js 팀에서는 깃헙 페이지에서 개발자들이 필요로 하는 바벨 플러그인들의 수요를 조사하고, 주요 바벨 플러그인들에 대한 지원을 위해 꾸준히 작업을 이어나가고 있다고 한다. 이미 styled-componentsjest 와 같은 주요 라이브러리들을 위한 바벨 플러그인들은 지원되고 있다.

웹 생태계는 하루가 다르게 변하고 있고, 빌드 툴도 예외는 아니다. 이 글에서 소개한 SWC는 물론이고, 번들러인 웹팩을 대체하기 위한 parcel 같은 빌드 툴들도 쏟아져 나오고 있다. 어떤 빌드 툴이 자바스크립트 생태계에서 주류가 될지는 아직 알 수 없지만, 적어도 Next.js를 사용한다면 SWC를 활용하는 법을 반드시 숙지해야 할 것이다.


참고:

profile
하루가 모여 역사가 된다

0개의 댓글