HEROPY
Tech
Snowpack, 더 빠른 웹 개발을 위한 새로운 방식의 프론트엔드 빌드 도구
{{ scrollPercentage }}%

Snowpack, 더 빠른 웹 개발을 위한 새로운 방식의 프론트엔드 빌드 도구

webpackparcelsnowpackrollup

변경사항

2020년 11월

  • Pika.dev를 Skypack.dev로 수정했습니다.
  • 다음 파트를 추가했습니다.
    • 구성 옵션
    • devOptions <구성 옵션>
    • buildOptions <구성 옵션>
    • installOptions <구성 옵션>
    • Svelte template <템플릿>

개요

Snowpack은 더 빠른 웹 개발을 위한 최신의 프론트엔드 빌드 도구입니다.
기존의 Webpack, Rollup 그리고 Parcel 같은 무겁고 복잡한 번들러의 번들 소요 시간을 획기적으로 절약할 수 있습니다.
Snowpack은 번들러가 아닙니다! 단순히 더 빨리 번들하는 것이 아니라 웹 빌드 시스템에 대한 새로운 접근 방식을 제공합니다.
JavaScript의 ESM(ES Modules)을 활용하여 동일 파일을 다시 빌드하지 않는 최초의 빌드 시스템을 생성해 변경사항을 브라우저에 즉시 적용할 수 있습니다.

Snowpack Benchmarks

Benchmarks by Pika
  • 개발 서버를 50ms 이내에 시작할 수 있습니다.
  • 변경 사항이 브라우저에 즉시 반영됩니다.
  • 선호하는 번들러(Webpack, Rollup..)와 통합할 수 있습니다.
  • TypeScript, JSX, CSS 모듈 등을 기본적으로 지원합니다.
  • React, Vue, Svelte 같은 다양한 프레임워크(라이브러리)를 지원합니다.

주요 개념

번들 없는 개발(Unbundled Development)

번들 없는 개발(Unbundled Development)은 개별 파일을 브라우저에 전달하는 아이디어입니다.
Babel, TypeScript, Sass 같은 자주 사용하는 라이브러리로 파일을 빌드하고,
ESM import/export 구문으로 브라우저에서 개별적으로 로드합니다.
Snowpack은 파일이 변경되면 해당 단일 파일만 다시 빌드합니다.

반면에 Webpack, Rollup 같은 번들러들은 번들 개발(Bundled Development)에 중점을 둡니다.
번들러로 애플리케이션을 실행하면 개발에 추가 작업과 복잡성이 발생합니다.
저장할 때마다 모든 변경사항을 나머지 애플리케이션과 함께 다시 번들해야만 변경사항이 브라우저에 반영됩니다.
이제 ESM이 널리 지원되므로 이런 방식은 불필요합니다.

Webpack vs Snowpack

‘번들 없는 개발’은 기존 방식에 비해 몇 가지 장점이 있습니다.

  • 빠릅니다.
  • 예측한 대로 동작합니다.
  • 디버깅이 더 쉽습니다.
  • 개별 파일 캐시가 더 좋습니다.
  • 프로젝트 크기가 개발 속도에 영향을 주지 않습니다.

모든 파일은 개별적으로 빌드되고 지속해서 캐시됩니다.
파일에 변경사항이 없으면 파일을 다시 빌드하지 않고 브라우저에서 다시 다운로드하지 않습니다.
이것이 번들 없는 개발의 핵심입니다.

또한 Snowpack은 즉시(50ms 미만) 시작하여 속도 저하 없이 무한히 큰 프로젝트로 확장할 수 있습니다.
반대로 기존 번들러로 대규모 앱을 빌드할 때는 개발 시작 시간이 30초 이상 걸리는 것이 일반적입니다.

회사에서 관리하는 Webpack 기반의 일부 프론트엔드 개발은 최초 빌드가 4분 정도 걸립니다.

의존성 모듈(Using NPM Dependencies)

NPM 패키지는 대부분 웹에서 직접 실행할 수 없는 CommonJS를 사용합니다.
브라우저에서 직접 실행할 수 있는 ESM import/export 구문을 사용하여 애플리케이션을 작성하더라도,
NPM 패키지를 가져올 때 번들러가 동작해야 합니다.

Snowpack은 다른 접근 방식을 취합니다.
전체 애플리케이션을 번들로 묶는 대신 Snowpack은 의존성을 별도로 처리합니다.
작동 방식은 다음과 같습니다.

  1. Snowpack이 애플리케이션을 스캔합니다.
  2. node_modules 디렉토리에 설치된 의존성 모듈을 확인합니다.
  3. 모든 의존성 모듈을 개별 JavaScript 파일로 변환합니다.(E.g. react => react.js)
  4. 변환된 각 파일은 브라우저에서 직접 실행하고 ESM import 구문을 통해 가져옵니다.
  5. 의존성 모듈은 따로 변경하지 않는 이상 변경사항이 없으니 다시 빌드할 필요가 없습니다.
node_modules/react  =>  http://localhost:8080/web_modules/react.js
node_modules/vue    =>  http://localhost:8080/web_modules/vue.js
<body>
  <script type="module">
    import React from 'react'
    import Vue from 'vue'

    console.log(React)
    console.log(Vue)
  </script>
</body>

Skypack.dev

Skypack를 통해 Snowpack에서 사용할 ESM 지원 패키지를 쉽게 검색하고 테스트할 수 있습니다.

Skypack.dev

기본 구조 이해

Snowpack의 기본 구조를 이해하기 위해서,
Vue.js 템플릿(@snowpack/app-template-vue)을 최대한 간소화하고 핵심 내용만 정리했습니다.

Snowpack vue example

snowpack.config.js

  • mount: Snowpack 빌드에 사용할 ‘현재 경로‘와 빌드 결과로 연결할 ‘빌드 경로‘를 지정합니다.
  • plugins: Snowpack에서 사용할 플러그인 목록을 지정합니다.

연결 옵션은 CONFIG.MOUNT 파트에서 확인할 수 있습니다.
기타 모든 옵션은 CONFIG 파트에서 확인할 수 있습니다.

mount: {
  현재_경로: 빌드_경로
}

현재 프로젝트 구조에서 public/(디렉토리)을 루트 경로로 사용하고,
src/를 지정한(/_dist_) 경로로 사용하도록 지정합니다.

module.exports = {
  mount: { 
    public: '/',
    src: '/_dist_'
  },
  plugins: [
    '@snowpack/plugin-vue'
  ]
};

package.json

snowpack dev 명령으로 개발 서버를 준비하고,
snowpack build 명령으로 제품을 빌드를 할 수 있습니다.
설치할 개발 의존성은 snowpack과 Vue 구성을 위한 @snowpack/plugin-vue입니다.
설치할 일반 의존성으론 실제 사용할 vue만 있으면 충분합니다.

{
  "scripts": {
    "dev": "snowpack dev",
    "build": "snowpack build"
  },
  "devDependencies": {
    "@snowpack/plugin-vue": "^2.2.4",
    "snowpack": "^2.15.1"
  },
  "dependencies": {
    "vue": "^3.0.2"
  }
}

public/index.html

snowpack.config.js에서 src: '/_dist_'을 통해 어느 경로에 빌드 결과가 저장되는지 지정했습니다.
이 Vue 프로젝트의 진입점은 src/main.js입니다.

<body>
  <script type="module" src="/_dist_/main.js"></script>
</body>

만약 진입점이 src/index.js인 경우, 경로를 다음과 같이 수정해야 합니다.

<script type="module" src="/_dist_/index.js"></script>

build/

프로젝트를 다음과 같이 빌드하면, build/ 디렉토리가 생성됩니다.

$ npm run build
## or
$ snowpack build

Snowpack vue example

  • __snowpack__: Snowpack의 메타 데이터(HMR, ENV..)가 출력되는 디렉토리입니다. buildOptions.metaDir 옵션으로 이름을 수정할 수 있습니다.
  • _dist_: src/의 파일이 빌드 후 출력되는 디렉토리입니다.
  • web_modules: 사용할 웹 모듈의 디렉토리입니다. 이 프로젝트에서는 vue가 웹 모듈로 사용됩니다. buildOptions.webModulesUrl 옵션으로 이름을 수정할 수 있습니다.

빌드 옵션은 CONFIG.BUILDOPTIONS 파트에서 확인할 수 있습니다.

구성 옵션

옵션설명타입
mount빌드에 포함될 디렉토리와 연결될 URL을 지정object
plugins기능을 확장할 플러그인을 연결string[] | [string, object][]
alias앱에서 사용할 경로 별칭 지정object
devOptions개발 서버의 작동 방식을 지정object
buildOptions최종 빌드를 처리하는 방법을 지정object
installOptions외부 모듈을 처리하는 방법을 지정object
testOptions테스트 환경의 작동 방식을 지정object
proxy개발 서버의 프록시 동작을 지정object
exclude지정된 파일을 빌드에서 제외string[]
install자동으로 감지되지 않는 설치할 모듈을 지정string[]
extends지정된 별도의 기본 구성 옵션을 상속해 병합string

devOptions

snowpack dev를 통한 개발 서버의 작동 방식을 지정합니다.

snowpack.config.js
module.exports = {
  devOptions: {
    port: 8080, // 개발 서버를 실행할 포트 번호
    fallback: 'index.html', // SPA인 경우 제공할 모든 사용자 경로
    open: 'default', // 새 브라우저 탭에 개발 서버를 열기, "default" | "none" | "BROWSER_NAME"
    output: 'dashboard', // 콘솔의 출력 모드를 지정, "stream" | "dashbaord"
    hostname: 'localhost', // 브라우저가 열리는 호스트 이름
    hmr: true, // Hot Module Replacement(HMR, 수정사항을 즉시 반영) 활성화
    hmrErrorOverlay: true, // HMR 활성화시 자바스크립트 오류 표시 여부
    secure: false, // HTTP2 활성화 상태에서 HTTPS 사용 여부
    // out: 'build' // Deprecated! 
  }
}

buildOptions

snowpack build를 통해 최종 빌드를 처리하는 방법을 지정합니다.

snowpack.config.js
module.exports = {
  buildOptions: {
    out: 'build', // 최종 빌드를 출력하는 로컬 디렉토리 이름
    baseUrl: '/', // 제품 모드의 기본 URL 지정, 현재 앱이 하위 디렉토리로 배포되는 경우 유용
    clean: false, // 빌드 전 기존 데이터 제거
    metaDir: '__snowpack__', // HMR 및 ENV 등의 정보를 출력할 디렉토리 이름
    sourceMap: false, // 소스 맵 사용 여부
    webModulesUrl: 'web_modules' // 사용하는 웹 모듈이 저장될 디렉토리 이름
  }
}

installOptions

설치하는 외부 모듈을 처리하는 방법을 지정합니다.

snowpack.config.js
module.exports = {
  installOptions: {
    dest: 'web_modules', // 사용하는 웹 모듈이 저장될 디렉토리 이름
    sourceMap: false, // 설치된 모듈의 소스맵 사용
    env: {}, // 환경 변수 지정
    treeshake: false, // 의존성 모듈의 트리쉐이킹 여부(제품 모드만 동작)
    installType: false, // 모듈 설치 시 타입 정의를 함께 설치(타입스크립트)
    namedExports: [], // `Uncaught SyntaxError: The requested module '/web_modules/XX.js' does not provide an export named 'YY'` 에러가 발생하는 경우, `namedExports: ['XX']`
    externalPackage: [], // 무시할 외부 모듈의 목록, E.g. 'fs'
    packageLookupFields: [], // ??
    rollup: { // Snowpack이 내부적으로 사용하는 Rollup을 더욱 세부적으로 제어하기 위한 옵션
      plugins: [], // Rollup 플러그인을 지정
      dedupe: [], // 중복 번들을 방지하기 위한 외부 모듈 이름을 지정(rollup-plugin-node-resolve)
      context: [] // 최상위 `this`를 지정, 최상위 변수를 참조하는 레거시 CJS 모듈의 오류 해결에 유용 
    },
  }
}

템플릿

공식 템플릿

주요 프레임워크의 공식 템플릿을 지원합니다.
Snowpack을 이해하는 데 많은 도움이 됩니다.
더 많은 템플릿을 확인하세요!

Svelte template

Snowpack 기반의 Svelte 템플릿을 만들었습니다.
별도의 구성 없이 바로 프로젝트를 시작할 수 있습니다.
템플릿에서 지원하는 내용은 크게 다음과 같습니다.

  • Svelte
  • TypeScript
  • SCSS
  • Autoprefixer/PostCSS
  • Web test runner
  • Chai
  • Reset.css

다음과 같이 설치합니다.

## Install template
$ npx degit ParkYoungWoong/svelte-snowpack-template DIR_NAME
## Change directory
$ cd DIR_NAME
## Install dependencies
$ npm i
## Start dev server
$ npm run dev

타입스크립트를 사용하는 경우 다음과 같이 작성할 수 있습니다.

<script lang="ts">
  let count: number = 0
</script>

SCSS를 사용하는 경우 다음과 같이 작성할 수 있습니다.

<style lang="scss">
  $color--primary: royalblue;
  h1 {
    color: $color--primary;
  }
</style>

참고자료

https://www.snowpack.dev/

공지 이미지
이 내용을 72시간 동안 안 보고 싶어요!?