구닥다리 공룡을 위한 오늘날의 JavaScript

in #javascript6 years ago

이 post는 아래 article을 번역한 것입니다.

Modern JavaScript Explained For Dinosaurs

  • 영문명사는 가능한 영문 그대로 썼습니다.
  • 비표준어를 다소 사용했습니다.
  • 저는 전문 번역가가 아닙니다. 오역이 의심 스러운 부분은 원문을 참고하세요!
  • 원문에 있는 링크가 빠졌다거나 오탈자가 있으면 제보 부탁드립니다. 정말 감사하겠습니다.

구닥다리 공룡을 위한 오늘날의 JavaScript

modern_dino_1.png
Images from Dinosaur Comics by Ryan North

오늘날 자바스크립트를 공부하는 것은 힘듭니다. 초창기부터 자바스크립트업계에 몸담아 오지 않았다면 더욱! 자바스크립트 생태계가 너무 빨리 성장하고 변하는 바람에 다양한 도구로 해결하는 문제 자체가 이해하기 어려워 졌습니다. 저는 1998년 부터 프로그래밍을 했지만 자바스크립트를 진지하게 배우기 시작한건 2014년 부터 였습니다. 그 당시 들여다 본, 우연히 접하게 된 Browserify의 태그라인을 전 아직도 기억합니다.

“Browserify는 브라우저에서 require(‘modules’)를 사용하여 모든 의존성을 통합할 수 있습니다.”

전 이 문장의 한 단어도 이해할 수 없었고, 이게 개발자로서 나에게 무슨 도움이 될런지 알고자 발버둥 쳤습니다.

이 article의 목표는 JavaScript 도구들이 2017년 현재까지 진화해 온 역사적 문맥을 알려드리는데에 있습니다. 먼저 구닥다리 공룡같은 예제 website-단순한 HTML, JavaScript 외에 어떤 도구도 사용되지 않는-를 만들어 볼겁니다. 그리고나서 차차 구식 frontend 개발 생태계의 문제점들을 해결하는 도구들을 하나씩 소개할 겁니다. 이 역사적 문맥을 통해 여러분들의 학습은 이전보다 더 좋아질 것이고 끊임없이 변화하고 전진하는 JavaScript 지형에 적응 할 수 있을 겁니다.

이 아티클의 목표는 자바스크립트 도구들이 현재(2017년)까지 진화해 온 역사적 맥락을 알려드리는 것입니다. 먼저 구닥다리 공룡같은 예제 웹사이트-단순한 HTML, 자바스크립트 외에 어떤 도구도 사용되지 않는-를 만들어 볼겁니다. 그리고나서 구식 프론트엔드 개발 생태계의 문제점들을 해결하는 도구들을 하나씩 소개할 겁니다. 이 역사적 맥락을 통해 여러분의 학습은 이전보다 더 편해질 것이고 끊임없이 변화하고 전진하는 자바스크립트 지형에 적응 할 수 있을 겁니다.

구식 자바스크립트 사용법

자, 수동으로 파일들을 다운받고 연결하는 구식 웹사이트로 시작해 봅시다. 이 웹사이트는 HTML과 자바스크립트를 사용합니다. 여기 하나의 자바스크립트 파일이 연결된 간단한 index.html이 있습니다.

(html comment removed:  index.html )
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>자바스크립트 Example</title>
  <script src="index.js"></script>
</head>
<body>
  <h1>Hello from HTML!</h1>
</body>
</html>
<script src="index.js"></script>

이 행은 index.html과 같은 디렉토리에 있는 별도의 자바스크립트 파일인 index.js를 참조합니다. index.js의 내용은 아래와 같습니다.

console.log("Hello from 자바스크립트!");

이게 여러분이 웹사이트를 만드는데 필요한 전부예요! 이제 다른 누군가가 작성한 외부 라이브러리를 추가한다고 쳐봅시다. moment.js 같은거요. moment.js는 날짜 형식을 인간이 읽기 쉬운 형식으로 바꿀때 유용합니다. 예를 들면 아래와 같이 moment 함수를 사용할 수 있습니다.

moment().startOf('day').fromNow();  // 20 hours ago

그치만 이건 어디까지나 moment.js를 여러분의 웹사이트에 포함시켰단 가정 하입니다. moment.js의 홈페이지를 방문해 보면 아래와 같은 지시사항을 볼 수 있습니다.

moment_instruction.png

흠, 오른편의 인스톨 섹션에 무언가 많네요. 하지만 일단 전부 무시해도 됩니다. index.html이 들어있는 디렉토리에 moment.min.js를 다운로드 하세요. 그럼 아래 코드처럼 index.html에 moment.min.js를 추가 시킬 수 있어요.

(html comment removed:  index.html )
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Example</title>
  <link rel="stylesheet" href="index.css">
  <script src="`moment.min.js`"></script>
  <script src="index.js"></script>
</head>
<body>
  <h1>Hello from HTML!</h1>
</body>
</html>

moment.min.js가 index.js보다 앞서 로드 되고 있다는걸 주의하세요. 이 말인 즉, index.js 안에서 moment 함수를 쓸 수 있게 되었다는걸 의미합니다. 아래 코드 처럼요:

// index.js
console.log("Hello from 자바스크립트!");
console.log(moment().startOf('day').fromNow());

그리고 이게 바로 우리가 웹사이트에 자바스크립트 라이브러리를 사용하는 (구닥다리)방식입니다. 이해하기 쉽다는 게 이 방식의 장점이죠. 나쁜 점은 라이브러리 제작자가 업데이트를 할 때마다 그것의 새 버전을 매번 찾아야 하고 다운로드 하기 번거롭다는 겁니다.

자바스크립트 패키지 매니저 (npm) 사용하기

2010년 즈음 하여, 중앙 레포지토리로부터 라이브러리 다운로드와 업그레이드를 자동화 해주는, 여러 경쟁적인 자바스크립트 패키지 매니저가 등장했습니다. 2013년 Bower는 거의 이견 없이 최고의 인기 제품 이었습니다만, 2015년 즈음 하여 마침내 npm이 그 인기를 따라잡았습니다. (2016년 말부터 시작 된, yarn이 npm 인터페이스의 대안으로 나타났지만 yarn도 여전히 내부적으로는 npm 패키지를 사용하고 있습니다.)

npm은 원래 node.js를 위해 특별히 만들어진 패키지 매니저라는 점을 염두해 두세요. node.js는 프론트엔드가 아닌 서버 위에서 구동되도록 설계된 자바스크립트 실행 환경입니다. 이 때문에 npm을, 브라우저에서 실행되는 JS 라이브러리들을 위한 프론트엔드 자바스크립트 패키지 매니저로 선택했다는 건 꽤 괴팍해 보입니다. 서버 환경에서 쓰던걸 프론트엔드 환경에서 쓰려는 것이니까요.

Note: 패키지 매니저를 쓴다는 것은 보통 커맨드라인 사용과 연관있습니다. 구닥다리 프론트엔드 개발 방식에는 전혀 필요 없던 부분이었죠. 만약 한번도 커맨드라인을 써본적이 없다면 이 튜토리얼을 훑어 보시길 권합니다. 좋든 싫든 커맨드라인은 오늘날의 프론트엔드 개발에 있어 중요한 부분이 되었습니다 (그리고 다른 개발 영역으로의 훌륭한 열린 문이 될겁니다).

자 이제 npm을 사용해서 어떻게 moment.js 패키지를 자동으로 설치하는지 살펴 보도록 하죠. 구닥다리 방식의 단점으로 지적되었던 번거롭게 매번 수동으로 다운 받는 것 대신에 말이죠. 만약 node.js가 설치되어 있다면 npm도 이미 설치 된 것입니다. 그러면 커맨드라인으로 index.html이 있는 디렉토리로 이동한 후 다음 명령어를 입력 할수 있습니다.

$ npm init

이 명령어를 입력하면 몇 가지 질의응답 과정이 이어집니다. 응답은 기본 값으로 충분하니 모든 질문에 엔터키를 눌러주세요. 그러면 package.json 이라는 새로운 파일 하나가 생성 됩니다. 이 녀석은 configuration(설정, 구성) 파일로 npm이 이 프로젝트에 대한 모든 정보를 저장하는데 사용됩니다. 기본적인 package.json의 내용은 아래와 같습니다.

{
  "name": "your-프로젝트-name",
  "버전": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC"
}

이제 moment.js 자바스크립트 패키지를 설치하기 위해서 moment.js의 홈페이지에 안내되어 있던 지시사항을 따라 할 수 있습니다. 아래의 명령어를 커맨드라인에 입력하세요:

$ npm install moment --save

이 명령은 두가지 일을 수행합니다. 첫째로 moment.js 패키지의 모든 코드를 내려받아 node_modules 라는 폴더에 저장합니다. 둘째로 package.json 파일을 아래와 같이 고쳐 프로젝트가 의존성을 갖는 moment.js를 지속적으로 추적하도록 합니다.

{
  "name": "modern-자바스크립트-example",
  "버전": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC",
  "dependencies": {
    "moment": "^2.19.1"
  }
}

이는 나중에 다른이와 프로젝트를 공유할때 유용합니다. 대개의 경우 용량이 매우 큰 node_modules 폴더를 직접 공유하는 대신 package.json 파일 하나만 공유하면 다른 개발자들이 필요한 패키지들을 자동으로 설치 할 수 있습니다. npm install 이라는 명령어 하나로 말이죠.

이로써 우리의 프로젝트도 더는 수동으로 moment.js를 내려받을 필요가 없어졌습니다. npm을 사용하여 자동으로 다운로드 받고 업데이트 받을 수 있습니다. node_modules 폴더 안을 살펴보면 moment.min.js 파일이 node_modules/moment/min 디렉토리 안에 있습니다. npm으로 다운로드 한 moment.min.js를 index.html에 연결 할 수 있다는 의미지요.

(html comment removed:  index.html )
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>자바스크립트 Example</title>
  <script src="`node_modules`/moment/min/`moment.min.js`"></script>
  <script src="index.js"></script>
</head>
<body>
  <h1>Hello from HTML!</h1>
</body>
</html>

그래서 정리하자면, 좋은점은 커맨드라인으로 npm을 사용해 우리의 패키지들을 다운로드하고 업데이트 할 수 있다는 겁니다. 이 상황에서 나쁜 점은 패키지가 실제로 담겨 있는 node_modules 폴더의 깊은 곳 까지 파고들어야지만 수동으로 HTML에 불러올 수 있다는 것이죠. 이건 꽤 불편합니다. 그래서 다음으로 이 과정을 자동으로 처리해 주는 방법을 살펴볼 겁니다.

modern_dino_2.png

자바스크립트 모듈 번들러 (webpack) 사용하기

대부분의 프로그래밍 언어들이 하나의 코드에서 다른 코드를 불러들이는 방법을 제공합니다. 그러나 자바스크립트는 이런 기능이 없습니다. 왜냐하면 자바스크립트는 오직 브라우저 환경에서만 구동되도록 만들어졌고 보안상의 이유로 컴퓨터의 파일 시스템에는 접근할 수 없기 때문입니다. 그래서 오랜 시간동안 다수의 파일로 자바스크립트 코드를 구성하는 일은 각 파일을 전역 변수로 할당하여 공유해야만 했습니다.

우리가 앞서 한 행위도 이겁니다. 예를들어 전체 moment.min.js 파일은 HTML로 로드 됩니다. 그 안에 정의 되어 있는 변수 moment는 전역 변수가 됩니다. 이 후에 로드 되는 모든 파일에서 이 전역 변수를 사용 할 수 있습니다. 접속 권한이 있는지 없는지는 상관 없이요.

2009년, CommonJS라는 이름의 프로젝트가 시작되었습니다. 이것의 목표는 브라우저 외의 자바스크립트 생태계를 만드는 것이었죠. CommonJS의 대부분은 모듈에 대한 명세였습니다. 이 명세로 마침내 자바스크립트가 다른 대부분의 프로그래밍 언어들 처럼 파일을 통해 코드를 들여오고(import) 내보낼(export) 수 있게 되었죠. 전역 변수에 할당하는 방법 대신 말입니다. 이 CommonJS 모듈의 구현체중 가장 유명한 것이 바로 node.js 입니다.

nodejs_logo.png

앞서 이야기 했던 것 처럼 node.js는 서버에서 구동되도록 설계된 자바스크립트 실행 환경 입니다. 아래에 초기의 node.js 모듈 사용 예시가 있습니다. moment.min.js를 HTML script tag로 불러오는 것 대신 자바스크립트 파일을 직접 자바스크립트 안에 불러올 수 있습니다:

// index.js
var moment = require('moment');
console.log("Hello from 자바스크립트!");
console.log(moment().startOf('day').fromNow());

다시 말씀드리지만 이건 node.js에서 작동하는 모듈 로딩 방식입니다. node.js가 컴퓨터의 파일 시스템에 접근 가능한 서버 사이드 언어이기에 가능한 것이죠. node.js는 또 각 npm 모듈이 어느 경로에 위치하는지를 알고 있습니다. 이 덕분에 require('./node_modules/moment/min/moment.min.js')라고 쓰는 대신 require('moment')라고 쓸 수 있죠. 달달하쥬?

node.js가 이렇게 좋습니다만, 위 코드를 브라우저 상에서 실행 하려고 하면 require가 정의되지 않았다는 에러가 뜹니다. 브라우저는 파일 시스템에 접근할 권한이 없습니다. 따라서 이 방식으로 모듈을 불러 오고자 한다면 아주 까다롭습니다. 파일들을 불러오는 것이 (실행속도를 느리게 하는)동기적인 것이든 (타이밍 문제가 있는)비동기적인 것이든 동적으로 수행되어야만 합니다. (역주: require와 같은 모듈 로딩 구문은 실행시에 그 구문이 로드한 다른 파일의 코드로 대치된다-이렇게 이해해도 큰 무리는 없다. 만약, 자바스크립트 파일이 브라우저에서 실행되기 이전에 require 구문의 대치가 동적으로 완료된다면 모듈 로딩으로써도 유의미한 것이고 브라우저 오류도 없지 않겠느냐는 말이다.)

이 부분이 바로 모듈 번들러가 필요해 지는 지점입니다. 자바스크립트 모듈 번들러는 파일 시스템에 접근 할 수있는 빌드 단계에서 위와 같은 문제를 해결하여 브라우저와 호환되는 (파일 시스템에 액세스 할 필요가 없는)최종 결과물을 만들어내는 도구입니다. 우리의 경우에는 (브라우저 자바스크립트 문법에는 맞지 않는)모든 require 구문을 찾아내어 이를 요구된(required) 파일들의 실제 내용으로 대치시켜주는 모듈 번들러가 필요합니다. 이때 최종 결과물은 하나로 묶인(bundled) (require 구문이 없는)단일 자바스크립트 파일인 것이죠.

가장 인기 있었던 모듈 번들러는 Browserify로, 2011년에 출시 되었으며 node.js 방식의 require 구문을 프론트엔드에 사용하는데 있어 선구자적 역할을 했습니다. 근본적으로 npm이 프론트엔드 패키지 매니저가 될 수 있게 해주었죠. 2015년 즘엔 webpack이 등장하여 더 보편적으로 사용되는 모듈 번들러가 됩니다(webpack의 이점을 몽땅 활용 가능한 프론트엔드 프레임워크인 React의 인기가 치솟게 됩니다). (역주: 엄밀히 말하면 React는 프레임워크가 아니라 라이브러리 입니다.)

이제 어떻게 webpack을 써야 위의 require('moment')예제를 브라우저에서 돌릴 수 있을지 살펴봅시다. 먼저 webpack을 프로젝트에 추가해야 겠지요. webpack 자체는 그저 npm 패키지 이고, 따라서 아래와 같은 커맨드라인으로 설치 할 수 있습니다:

$ npm install webpack --save-dev

--save-dev 인수로 설치하면 패키지가 개발용 의존으로 저장 된다는 점을 알아두세요. 이 말은 이 패키지가 개발 환경에서만 쓰이고 서버에 올라간 제품 상태에선 사용하지 않을 것이란 의미입니다. 이 점은 package.json에도 자동으로 반영됩니다.

{
  "name": "modern-자바스크립트-example",
  "버전": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"에러: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC",
  "dependencies": {
    "moment": "^2.19.1"
  },
  "devDependencies": {
    "webpack": "^3.7.1"
  }
}

webpack이 패키지 중 하나로써 node_modules 폴더에 설치가 되었습니다. 커맨드라인에 아래처럼 입력함으로써 webpack을 사용할 수 있습니다.

$ ./node_modules/.bin/webpack index.js bundle.js

이 명령은 node_modules에 설치되어 있는 webpack 도구를 실행킵니다. 실행된 도구는 index.js 파일을 읽기 시작하여 require구문을 찾고 이를 다른 파일의 코드로 대치시킨 최종 결과물로써 bundle.js를 출력합니다. 이 말은 우리의 예제 HTML에서 더 이상 (require 구문이 있는)index.js를 쓸 수 없게 된다는 말입니다. 대신 bundle.js를 써야합니다.

(html comment removed:  index.html )
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>자바스크립트 Example</title>
  <script src="bundle.js"></script>
</head>
<body>
  <h1>Hello from HTML!</h1>
</body>
</html>

브라우저를 새로고침 해보면 이전과 마찬가지로 모든 것이 정상 작동함을 볼 수 있습니다.

index.js가 수정 될 때마다 webpack 명령을 실행해야 함을 상기하세요. 물론 이 점은 귀찮은 데다가 webpack의 고급 기능을 사용하게 되면 더 귀찮아 집니다. 예를 들어, 변환된 코드의 오류를 원본 코드에서 고칠 때 도움을 주는 소스맵을 생성하는 고급 기능 말이지요. 이 귀찮은 점을 해결하기 위해 webpack은 config(설정) 파일로부터 옵션들을 읽을 수 있습니다. 이 config 파일은 프로젝트의 root 폴더에 위치하는 webpack.config.js입니다. 우리 예제의 경우에는 아래와 같은 내용이면 됩니다.

// webpack.config.js
module.exports = {
  entry: './index.js',
  output: {
    파일name: 'bundle.js'
  }
};

이제 매 번 index.js가 바뀔 때 마다 아래와 같은 명령어를 사용할 수 있습니다.

$ ./node_modules/.bin/webpack

index.jsbundle.js를 지정해 주지 않는 것이 보이죠? webpack.config.js에 설정한 옵션들을 webpack이 알아서 읽기 때문입니다. 이게 더 좋은 방법이긴 합니다. 그러나 명령어를 매 번 입력해야 한다는 건 여전히 귀찮습니다. 이걸 좀 더 편리하게 만들어 보도록 하죠.

전반적으로 시원찮아 보일 수도 있습니다만, 이러한 워크 플로우엔 상당한 이점이 있습니다. 더 이상 전역 변수로 외부 스크립트를 불러들일 필요가 없지요. 어느 자바스크립트 라이브러리도 HTML 태그 대신 자바스크립트의 require 구문을 통해 추가될 것입니다. 단일 자바스크립트 묶음 파일을 갖는 것은 성능면에서도 더 좋습니다. 그리고 이제 또 다른 강력한 기능들을 개발 workflow에 추가 할 수 있는 빌드 단계가 추가 되었습니다.

modern_dino_3.png

언어의 새로운 기능을 사용하기 위한 코드 transpiling (babel)

코드를 트랜스파일(transpile) 한다는 것은 어떤 한 언어로 작성 된 코드를 비슷하지만 다른 언어로 변환 시켜 준다는 것입니다. 이는 프론트엔드 개발에 있어 중요한 부분입니다. 브라우저는 언어의 새로운 기능을 추가 지원 해주는 데에 늘 늦장을 부리기 때문에 새 언어의 실험적인 기능은 브라우저에 호환 되는 언어로 트랜스파일 해야 합니다.

CSS로 말하자면 Sass, Less, 그리고 ](http://stylus-lang.com/)등을 말할 수 있습니다. 자바스크립트로 치자면 한 때 가장 인기있었던 트랜스파일러는 CoffeeScript (2010년즘 출시 됨) 이었고, 현재는 대부분의 사람들이 babel 또는 TypeScript 를 사용합니다. CoffeeScript는 임의의 괄호, 의미있는 공백등을 적용함으로써 자바스크립트를 발전시는데 초점을 맞추고 있습니다. Babel은 새로운 언어는 아닙니다만 아직 모든 브라우저에서 사용할 수는 없는 다음 세대 자바스크립트 (ES2015 이후)의 기능을 오래되고 호환 가능한 자바스크립트 (ES5)로 트랜스파일 해주는 트랜스파일러입니다. TypeScript는 기본적으로 다음 세대 자바스크립트와 같지만 임의의 정적 형지정(typing)을 추가하는 언어입니다. 많은 사람들이 babel을 선택했습니다. 바닐라 자바스크립트에 가장 가깝기 때문입니다.

babel을 어떻게 사용하는지 이미 만들어 둔 webpack 빌드 과정과 함께 그 예시를 보도록 하죠. 먼저 babel을 우리의 프로젝트에 커맨드라인으로 설치할 겁니다. babel은 npm pacakge 입니다:

$ npm install babel-core babel-preset-env babel-loader --save-dev

개발용 의존성으로 3가지 별도의 패키지를 설치하고 있는 것에 주목하세요. babel-core는 babel의 핵심부 입니다. babel-preset-env는 어떠한 자바스크립트 새 기능을 트랜스파일할지에 대한 사전정의(preset)입니다. 그리고 babel-loader는 babel이 webpack과 함께 일 할수 있게 해주는 패키지입니다. 이제 webpack.config.js를 아래와 같이 수정하여 babel-loader를 사용할 수 있습니다:

// webpack.config.js
module.exports = {
  entry: './index.js',
  output: {
    파일name: 'bundle.js'
  },
  module: {
    rules: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        use: {
          loader: 'babel-loader',
          options: {
            presets: ['env']
          }
        }
      }
    ]
  }
};

문법이 번잡스러울수도 있습니다 (다행이도 그렇게 자주 수정할것은 아닙니다). 기본적으로 이 설정을 통해 webpack에게 모든 .js 파일을 지켜보도록 시키고 있습니다 (node_modules의 항목은 제외합니다). 그리고 babel-preset-env로 사전정의 된 babel-loader를 사용하여 babel의 트랜스파일을 적용합니다. webpack 구성법에 대해선 여기에서 더 자세히 알아볼 수 있습니다.

이제 모든게 갖춰졌습니다. ES2015의 기능을 사용할 수 있다는 말입니다! 아래에 ES2015 템플릿 문자열의 예시를 index.js에 보이고 있습니다:

// index.js
var moment = require('moment');
console.log("Hello from 자바스크립트!");
console.log(moment().startOf('day').fromNow());
var name = "Bob", time = "today";
console.log(`Hello ${name}, how are you ${time}?`);

require 대신 ES2015 import 구문을 모듈 로딩에 사용할 수 있습니다. 오늘날 많은 코드 베이스에서 볼 수 있는 것이죠.

// index.js
import moment from 'moment';
console.log("Hello from 자바스크립트!");
console.log(moment().startOf('day').fromNow());
var name = "Bob", time = "today";
console.log(`Hello ${name}, how are you ${time}?`);

이 예에서 import 문법은 require 문법과 많이 다르지 않습니다. 그러나 더욱 진보한 상황에서 전자가 추가적인 유연성을 갖고 있습니다. 아무튼 index.js가 수정되었기 때문에 커맨드라인으로 webpack을 다시 구동해줘야 합니다:

$ ./node_modules/.bin/webpack

이제 브라우저에서 index.html을 새로고침 할 수 있습니다. 이 글이 작성되고 있는 시점에 대부분의 모던 브라우저들이 모든 ES2015 기능을 지원하고 있습니다. 따라서 엄밀히 말하면 babel이 이 작업을 해줬다곤 말하기 힘듭니다. IE9같은 구식 브라우저에서 시험해 보세요. 아니면 bundle.js를 열어서 트랜스파일된 코드를 살펴보세요.

// bundle.js
// ...
console.log('Hello ' + name + ', how are you ' + time + '?');
// ...

브라우저 호환성을 맞춰주기 위해 ES2015 템플릿 문자열이 일반적인 자바스크립트 문자열 연쇄로 트랜스파일 된 모습을 볼 수 있습니다. 이런 예시가 그닥 흥미롭지 않을 수도 있지만, 트랜스파일 코드의 능력은 아주 강력한 것입니다. 오늘 당장 사용하여 더 좋은 코드를 작성할 수 있게 해줄 async/await같은 언어의 재미난 기능이 곧 다가올 것입니다. 그리고 트랜스파일이 지겹고 고통스러워 보일지도 모르지만, 사람들이 내일의 기능을 오늘 시험해 봄으로써 지난 몇년간 언어의 극적인 발전을 이끌어 왔습니다.

이제 거의 다 됐습니다. 그러나 여전히 말끔하지 못한 모서리가 우리의 워크플로우 안에 남아있습니다. 만약 성능을 고려한다면, 번들 파일을 축소(minifying) 시킬 필요가 있습니다. 이건 쉬울겁니다. 우리가 이미 빌드 과정을 결합시켜 놨으니까요. 또 지금은 자바스크립트가 변경될 때마다 webpack 커맨드를 재실행 시켜줘야 합니다. 그래서 다음 단계에서는 이를 해결하기 위한 편리한 도구들을 살펴 볼 겁니다.

태스크러너 사용하기 (npm scripts)

이제 빌드 단계를 사용하여 자바스크립트 모듈로 일하고 있으므로 태스크러너를 사용 해야 할 것 같습니다. 각기 다른 부분의 빌드 프로세스를 자동화 해주는 도구입니다. 프론트엔드 개발에 있어 태스크란 코드 압축(minify), 이미지 최적화, 테스트 실행 등을 말합니다.

2013년, Grunt가 가장 인기 있는 프론트엔드 태스크러너였고, Gulp가 뒤를 이었습니다. 둘 모두 다른 커맨드라인 도구를 두르고 있는 플러그인에 기대고 있습니다. 요즘에 가장 인기 있는 선택으로 보이는 것은 npm 패키지 매니저 자체의 스크립팅 가용성을 이용하는 것으로 plugin을 사용하지 않고 다른 커맨드라인 도구와 직접 일합니다.

자 npm 스크립트를 작성해서 webpack 사용을 좀 더 쉽게 만들어 봅시다. 이 작업은 package.json을 조금 바꾸게 됩니다:

{
  "name": "modern-javascript-example",
  "버전": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"error: no test specified\" && exit 1",
    "빌드": "webpack --progress -p",
    "watch": "webpack --progress --watch"
  },
  "author": "",
  "license": "ISC",
  "dependencies": {
    "moment": "^2.19.1"
  },
  "devDependencies": {
    "babel-core": "^6.26.0",
    "babel-loader": "^7.1.2",
    "babel-preset-env": "^1.6.1",
    "webpack": "^3.7.1"
  }
}

buildwatch라는 두 새로운 스크립트가 추가되었습니다. build 스크립트를 구동하려면 커맨드라인을 아래와 같이 입력하면 됩니다:

$ npm run build

이를 통해 webpack(이전에 만들어 둔 webpack.config.js를 설정으로 사용함)이 구동되는데 --progress 옵션을 주면 진행 정도를 백분율로 보여주며 -p 옵션을 주면 제품용 코드를 압축하게 됩니다. watch 스크립트를 구동하려면 아래와 같습니다:

$ npm run watch

이것은 --watch 옵션을 사용하고 있기 때문에 자바스크립트가 수정될 때마다 자동으로 webpack을 재실행 해줍니다. 개발에 있어선 최고죠.

package.json의 스크립트에 webpack의 완전한 전체 경로 ./node_modules/.bin/webpack가 없어도 구동할 수 있다는 점을 주목하세요. node.js가 각각의 npm 모듈 경로를 알고 있기 때문입니다. 이건 정말 좋습니다! 심지어 webpack-dev-server를 설치하면 더 좋아집니다. 이 녀석은 실시간 다시 불러오기(live reloading) 기능과 함께 단순한 웹 서버를 제공하는 별도의 도구입니다. 개발 의존성으로 설치하려면 다음과 같습니다:

$ npm install webpack-dev-server --save-dev

그러면 package.json에 다음과 같이 npm 스크립트가 추가됩니다.

{
  "name": "modern-javascript-example",
  "버전": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"error: no test specified\" && exit 1",
    "빌드": "webpack --progress -p",
    "watch": "webpack --progress --watch",
    "서버": "webpack-dev-server --open"
  },
  "author": "",
  "license": "ISC",
  "dependencies": {
    "moment": "^2.19.1"
  },
  "devDependencies": {
    "babel-core": "^6.26.0",
    "babel-loader": "^7.1.2",
    "babel-preset-env": "^1.6.1",
    "webpack": "^3.7.1"
  }
}

이제 개발용 서버를 아래의 커맨드로 실행 시킬 수 있습니다:

$ npm run 서버

이걸로 index.html 웹사이트가 브라우저에 localhost:8080(기본값)으로써 자동으로 열립니다. 언제든 index.js의 자바스크립트를 수정하면, webpack-dev-server는 번들 된 자바스크립트를 다시 빌드 하고 브라우저를 자동으로 새로고침 할 것입니다. 놀라울 정도로 시간을 절약 시켜 주죠. 새로 바뀐 것을 눈으로 확인하려고 지리하게 코드와 브라우저를 왔다 갔다 하며 맥이 끊기는 대신 계속해서 코드에만 집중 할 수 있게 해줍니다.

이건 단지 겉 핥기 수준입니다. 훨씬 많은 옵션들이 webpack과 webpack-dev-server(이 녀석에 대해 더 자세히 알고 싶다면 이곳으로…)에 존재합니다. 당연히 다른 태스크를 위해 npm 스크립트를 작성할 수 있습니다. Sass를 CSS로 변환하는 일, 이미지를 압축 하는 일, 테스트를 실행하는 일-어떤 일이든 커맨드라인 tool만 있으면 됩니다. 또한 엄청난 고급 옵션과 트릭들이 npm 스크립트 자체에 있습니다-Kate Hudson의 이 담화가 좋은 출발점이 될 겁니다:

결론

네 이게 바로 모던 자바스크립트 입니다. 단순한 HTML과 JS로부터 시작해 패키지 매니저를 써서 3rd 파티 패키지들을 자동으로 다운로드하고, 모듈 번들러를 사용해서 단일 스크립트 파일을 만들어내고, 트랜스파일러를 이용해 미래의 자바스크립트 기능들을 사용했으며, 그리고 태스크러너로 다른 부분의 빌드 과정을 자동화 했습니다. 초보자에겐 버거울 정도로 많은 것들을 다루긴 했습니다. 확실히 웹 개발은 프로그래밍에 막 들어온 사람들에게 훌륭한 시작점이었습니다. 쉽게 배워서 돌려볼 수 있었으니까요; 요즈음은 이게 꽤 위축 될 수도 있겠네요. 왜냐하면, 특히 그 다양한 도구와 급변하는 성질 때문에 말입니다.

허나 보기만큼 나쁘진 않습니다. 특히 프론트엔드와 함께 작업할 실행가능한 방법으로써 node 생태계를 적용하면 상황은 꽤 안정화 됩니다. 이건 멋지고 일관된 방법입니다. npm을 패키지 매니저로 사용하는 것, node requireimport 구문을 모듈을 위해 사용하는 것, 그리고 npm 스크립트로 태스크를 수행하는 것들 말입니다. 1, 2년 전에 비하면 정말이지 엄청나게 편해진 워크플로우 입니다.

심지어 초심자들에게나 숙련자들에게나 마찬가지로 더욱 좋은 점은 요즘엔 프레임워크가 과정을 더 쉽게 시작할 수 있도록 해주는 도구를 제공한다는 것입니다. Ember는 Angular의 angular-cli로부터 영향을 받은 ember-cli를 갖고 있고, React는 create-react-app, Vue는 vue-cli등을 갖고 있습니다. 이 모든 도구들은 프로젝트를 구성해줍니다. 프로젝트에 필요한 모든것과 함께 말이죠. 우리가 해야할 일은 그저 코드를 작성하기 시작하는 것 밖에 없어요. 그러나 이런 도구들은 마법이 아닙니다. 이 도구들은 일관되고 잘 동작하는 방식으로 모든 것을 구성할 뿐입니다. 종종 별도의 webpack, babel, 기타 등등의 설정이 필요한 부분을 마주치게 될지도 모릅니다. 그래서 이 아티클에서 다룬 각 조각들이 뭘 하는지 이해하는 일은 여전이 아주 중요합니다.

모던 자바스크립트는 분명 계속되는 변화와 급격한 진화 속도로 좌절감을 줄 수도 있습니다. 그러나 지금 이 순간이 바퀴를 다시 발명하는 것 같아 보이더라도 자바스크립트의 급격한 진화는 hot-reloading, 실시간 문법 검사, time-travel debugging과 같은 혁신에 도움을 주고 있습니다. 개발자에겐 흥미로운 시간입니다. 저는 이 정보가 당신의 여행에 있어 도움이 되기를 바랍니다!

modern_dino_4.png

@ryanqnorthDinosaur Comics에 특별한 감사를 전합니다. 2003년(공룡들이 web을 지배하던 그때)부터 부조리에 대한 양질의 풍자를 제공해 줬습니다.

Coin Marketplace

STEEM 0.19
TRX 0.15
JST 0.029
BTC 63117.29
ETH 2601.03
USDT 1.00
SBD 2.76