ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • TypeScript에서 webpack과 Babel의 필요성을 역사적 관점에서 본다
    Javascript 2024. 2. 13. 20:47

     

    이번에는 webpack과 Babel에 대해 배운 것을 글로 정리해 보려고 합니다.

     

    왜 처음에 webpack과 Babel에 대해 배우려고 했는지는, 지금까지 TypeScript, React 등을 사용하여 다양한 애플리케이션을 개발해 왔지만, webpack과 babel에 대한 지식이 모호한 상태에서 개발만을 계속하고 있었습니다.

     

    어쩐지 “그냥 변환해 주는 것” 정도의 지식밖에 없었기 때문에, 제대로 이해하려고 생각했습니다.

     

    그런 상황에서 webpack과 babel의 필요성을 배우면서 JavaScript의 역사를 이해하면 더 쉽게 이해할 수 있을 것 같아서, JavaScript의 역사에 대해서도 다루어 보려고 생각했습니다.


    JavaScript의 탄생

    JavaScript는 1995년에 Netscape의 기술자인 Brendan Eich가 개발하였고, Netscape Navigator 2.0에 구현되었습니다.

     

    원래는 JavaScript가 아니라 LiveScript라는 이름으로 불렸지만, Sun Microsystems(현재: Oracle)의 프로그래밍 언어인 Java가 주목받고 있었고, Netscape가 사업 제휴를 맺고 있었기 때문에, 그 주목도를 이용하여 JavaScript로 변경되었다는 배경이 있습니다.

     

    자주 JavaScript와 Java를 혼동하는 분들도 계십니다만, 그것은 이런 배경이 있고, 이름이 비슷하기 때문입니다.

     

    또한, 1996년에 Microsoft의 Internet Explorer 3.0에 탑재되어, JavaScript가 점점 보급되었습니다.

     

    그러나, Netscape Navigator와 Internet Explorer는 각각 독자적인 기능 추가를 하고 있어, 개발자들은 각각에 맞추어 사이트를 만들어야 했고, 그것은 매우 힘들었습니다.

     

    그래서 사양을 하나로 통합하려는 움직임이 있었습니다.


    ECMAScript의 공개

    Netscape는 JavaScript를 국제 표준화 기구인 Ecma International에 제출하였고, 그 결과, 1997년 6월에 ECMAScript라는 표준의 제1판이 공개되었습니다.

     

    그 후, 1998년에 제2판, 1999년에 제3판이 공개되었습니다.

     

    당시의 명칭은 ES5와 같이 ES 뒤에 판의 번호를 붙여 부르고 있었지만, 2015년의 제6판부터는 연도를 뒤에 붙이게 되어, ES2015와 같이 부르게 되었습니다.

     

    그곳에서 매년 릴리스하는 형태가 되었습니다.

    ECMAScript란?
    JavaScript의 핵심이 되는 언어 사양으로, 어떤 실행 환경에서도 공통된 동작만이 정의되어 있는 것입니다. JavaScript에는 여러 가지 실행 환경이 있고, 예를 들면 서버 측에서 동작하는 JavaScript인 Node.js가 있습니다. 여기에는 브라우저 상의 JavaScript에 존재했던 UI를 조작하는 기능이 없을 수 있습니다. 이런 Node.js나 브라우저의 차이 등을 의식하지 않고 ECMAScript로 개발을 할 수 있습니다.


    첫 번째 브라우저 전쟁

    1990년대 후반에 Netscape Navigator와 Internet Explorer 사이의 치열한 점유율 경쟁이 일어났고, Internet Explorer가 승리했습니다.

     

    이로 인해 1998년에 Windows98에 기본적으로 Internet Explorer가 탑재되어 많은 사람이 사용하게 되었습니다.

     

    그러나 이때 JavaScript로 인한 충돌이나 악용 바이러스가 많이 발생하였고, 불쾌한 애니메이션도 많아서 JavaScript 기능을 끄는 사람들도 있었습니다...

     

    동 시기에 Flash라는, 가벼운 애니메이션이 등장하였고, 재미있는 플래시 창고도 화제가 되었습니다.


    JavaScript의 부활

    한때 JavaScript에 대한 실망이 많았지만, JavaScript가 다시 주목받을 때가 왔습니다.

     

    그것은 Ajax(비동기 통신)의 등장입니다.

     

    이것은 고기능 웹 애플리케이션 개발 언어로 주목을 받았고, 특히 Google Maps가 매우 화제가 되었습니다.

     

    그곳에서 사용되었던 것이 바로 JavaScript였습니다.

     

    또한, JavaScript를 위한 라이브러리인 JQuery도 탄생하였고, 슬로건인 'write less, do more'에서 알 수 있듯이, 적은 기술로 많은 구현을 할 수 있게 되었고, 브라우저 간의 차이도 흡수할 수 있게 되었습니다.


    Ajax란

    Asynchronous JavaScript + XML의 약자로, 특정 웹 페이지를 표시한 상태에서 다른 페이지나 재로드 등을 동반하지 않고 웹 서버와 통신을 하여 동적으로 표시 내용을 변경하는 방법입니다.


    두 번째 브라우저 전쟁

    2000년대 후반부터 Internet Explorer, Google Chrome, Firefox, Safari, Opera의 5개 브라우저에서 경쟁이 시작되었습니다.

    2012년에 Chrome이 Firefox를 추월하고, 2014년에 Chrome의 점유율이 50%에 도달하여 이 경쟁이 종결되었습니다.


    서버 사이드 JavaScript

    여기서부터 JavaScript는 점점 진화하려고 합니다.

     

    당시에는 브라우저 상에서는 JavaScript로 작성되었고, 서버 사이드는 PHP나 Java와 같은 다른 언어로 작성되었는데, 어차피 둘 다 JavaScript로 작성하고 싶다는 의견이 많았습니다.

     

    그래서 2009년 1월에 Mozilla의 엔지니어 Kevin Dangoor가 ServerJS라는 프로젝트를 시작하였습니다.

     

    그러나 실제로 서버 사이드에서 JavaScript를 사용하려면 API(여기서는 JavaScript의 기능)가 부족하여 API를 만들 필요가 있었고, 만들기로 하였습니다.

     

    여기서, 만들어야 한다면 공통의 API를 만들자는 움직임이 되었고, 2009년 8월에 ServerJS에서 CommonJS로 프로젝트 이름을 변경하였습니다.

     

    여기서 여러 가지 API가 개발되었고, 대표적인 것으로 모듈 API가 개발되었습니다.


    JavaScript의 문제점

    위에서 언급한 모듈 API가 개발된 배경에는 JavaScript의 문제점이 있습니다.

     

    그것은 다음 두 가지입니다.

    • namespace가 하나뿐이다
      (여러 파일에서 같은 변수 이름을 사용하면 영향을 미친다)
    • 의존 관계로 인해 버그가 발생한다
      (다른 파일에 의존하고 있기 때문에, 어떤 파일에서 변경이 생기면 다른 파일에도 영향을 미친다)

    이 두 가지 문제점 중, 첫 번째는 위에서 언급한 모듈이 해결하고, 두 번째는 패키지 관리(npm)가 해결하게 됩니다.


    모듈 개념인 스코프

    JavaScript의 모듈은 파일 단위로, 파일 내의 변수나 함수는 다른 파일에 영향을 미치지 않습니다

     

    이러한 문제들에 대해, 모듈과 패키지 관리를 통해 문제가 해결된 것처럼 보이지만, 이것은 CommonJS에 대한 이야기이므로, 서버 사이드에서만 사용할 수 있는 것입니다.

     

    여전히 프론트엔드의 JavaScript에서는 namespace의 문제가 남아 있습니다.

     

    그래서 브라우저에서도 어떻게든 모듈을 사용하려는 흐름이 생깁니다.

     

    여기서 좀 더 서버 사이드의 흐름을 파고들어 보겠습니다.


    Node.js의 탄생

    2009년에 Ryan Dahl에 의해 만들어졌고, 처음에는 CommonJS의 모듈 API를 준수하여 만들어졌습니다.

     

    그러나 CommonJS 커뮤니티가 잘 작동하지 않았던 것도 있고, Node.js는 독자적인 진화를 이루어 나가면서 CommonJS 프로젝트는 움직임을 멈추게 되었습니다.

     

    모듈 API를 준수하였기 때문에, 이 Node.js에 의해 서버 사이드에서의 모듈 문제는 해결할 수 있었습니다.

     

    모듈 덕분에 기능이 세분되어, 다양한 기능을 조합하여 유용한 것을 할 수 있게 되었습니다.

     

    또한, 기능의 세분화로 인해, 그것들을 공유하고 싶은 요구(다른 서버 사이드 언어에서는 이미 구현됨)가 생겨났습니다.

     

    그래서 등장하는 것이 패키지 버전을 관리하거나 공유할 수 있는 패키지 관리 시스템입니다.

    패키지란
    package.json에서 기술된 파일이나 디렉토리를 말하며, 공유하고 싶은 기능의 단위입니다


    패키지 관리 시스템

    다음의 4가지 기능이 있습니다

    • 리포지토리 구독
    • 패키지 설치/삭제
    • 의존 관계 해결
    • 설정 관리

    리포지토리 구독: 로컬 환경에 설치된 패키지를 업데이트할 수 있거나, 패키지를 검색할 수 있는 것

     

    패키지 설치/삭제: 패키지를 지정하여 설치하거나 삭제할 수 있는 것

     

    의존 관계 해결: 패키지에 필요한 다른 패키지를 자동으로 설치하거나 업데이트할 수 있는 것

     

    설정 관리: 설정을 작성함으로써 1,2,3의 기능을 자동으로 수행할 수 있으며, 매번 수동으로 패키지를 넣을 필요가 없게 되는 것이며, 팀의 환경을 쉽게 맞출 수 있습니다

     

    패키지를 검색할 수 있고, 의존 관계를 시각화하는 사이트
    예: "Express"를 검색하면 매우 많은 의존 관계가 있는 것을 알 수 있습니다

     

    이러한 패키지 관리 시스템이 Node.js에서도 요구되었고, 그래서 등장하는 것이 npm입니다.


    npm의 탄생

    Node package manager의 약자로, 2010년에 Isaac Z. Schlueter에 의해 만들어진 Node.js의 패키지 관리 시스템입니다.

     

    npm을 사용하면 의존 관계가 있는 패키지를 자동으로 설치하거나 관리할 수 있게 되었습니다.

     

    이로 인해, 서버 사이드 JS의 준비가 마무리되고, Node.js 제품의 도구가 많이 개발되게 되었습니다.

     

    점점 보급되면서, Yahoo!나 Netflix, Uber 등에서 Node.js가 채택되게 되었습니다.

     

    그러나, npm은 대부분 CommonJS 형식으로 작성되었기 때문에, 이것도 프론트엔드에서는 사용할 수 없는 상태였습니다...

     

    여기서부터 브라우저 측에서도 모듈과 패키지 관리를 시도하려는 것이 시작됩니다.


    브라우저의 모듈 패턴

    사실 서버 사이드에서 모듈을 사용할 수 있게 되기 전에도 브라우저 측에서는 모듈과 같은 구조가 존재했습니다.

     

    그것은 다음 네 가지입니다.

    • 익명 클로저
    • 글로벌 임포트
    • 객체 인터페이스
    • 공개 모듈 패턴

    이러한 패턴들은 IIFE(즉시 실행 함수 표현식)를 사용하여 모듈을 흉내 내고 있었습니다.

     

    아래는 IIFE의 예시로, 함수를 해킹하여 가상의 프라이빗 공간을 만들고 있습니다.

    (function () {
      var foo = "foo";
    })();
    
    foo; //foo is not defined

    그러나 위의 것만으로는 부족하며, 완전히 namespace의 이름을 해결한 것은 아닙니다.

     

    그래서 만들어진 것이 AMD와 RequireJS입니다.


    AMD와 RequireJS의 탄생

    AMD는 브라우저에서 모듈 처리를 개선하기 위한 사양이며, RequireJS는 그 사양을 구현한 것으로, 브라우저 환경에서의 실행을 고려하고, 의존성 해결 및 지연 로드를 지원하는 사양입니다.

    define(["moduleA", "moduleB"], function (fnA, fnB) {
      //return한 것이 public
      return function () {};
    });

     

    이를 통해 브라우저에서도 모듈이 실현되고, 의존성도 해결할 수 있었습니다.


    Bower의 탄생

    더 나아가 클라이언트 사이드 개발을 위한 패키지 관리 시스템으로 2012년에 Bower가 탄생했습니다.

     

    이것은 간단히 말하면 npm과 비슷한 일을 할 수 있으며, IIFE 모듈이나 AMD 모듈을 사용할 수 있는 것입니다.

     

    그러나 AMD 형식은 서버 측 기능과 호환성이 없으며, 구문도 CommonJS와 비교하면 장황하며, 의존성이 많으면 유지 관리가 어렵고 성능 면에서도 문제가 되었습니다.

     

    더욱이, Bower도 어떤 패키지가 어떻게 의존하고 있는지를 사용자가 수동으로 정의해야 하며, 동일한 페이지 내에서 같은 패키지의 다른 버전을 지원하지 않았습니다...


    패러다임 시프트가 일어난다

    그래서 생각의 전환점이 찾아왔습니다.

     

    이전까지는 실제로 작성한 코드가 그대로 브라우저에서 작동했지만, 이제부터는 CommonJS 형식으로 작성된 것을 사전에 브라우저용으로 변환하여 표시하려는 생각으로 바뀌었습니다.

     

    이것은 실제로 작성한 코드와 화면에서 작동하는 코드가 다르다는 것입니다.

     

    이를 통해, 사전에 브라우저용으로 JavaScript를 변환하기 위해 번들과 컴파일이라는 개념이 생겼습니다.


    번들이란

    모듈의 의존 관계를 해결하고, 작성한 코드를 JS로 변환하여 한 파일로 만드는 개념으로, 개발 시에는 CommonJS 모듈로 개발할 수 있습니다.

    변환한 코드를 평소처럼 script 태그로 읽어 들일 수 있으며, CSS나 이미지 등도 번들할 수 있습니다.


    Browserify의 탄생

    2011년에 CommonJS 형식으로 작성된 것을 브라우저용으로 번들하는 도구인 Browserify가 탄생했습니다.

     

    Browserify는 모든 의존성을 묶어 브라우저에서 require('modules')를 사용할 수 있게 했습니다.

     

    이로 인해, 브라우저에서는 require 메소드가 정의되어 있지 않지만, Node.js에서는 정의되어 있으므로, Node.js와 같은 require를 사용하는 코드를 사용할 수 있게 되었고, 브라우저에서도 require 구문을 사용하여 모듈을 작성할 수 있게 되었습니다.

     

    또한, Node.js의 패키지가 브라우저용으로 이식되어, Node.js의 편리한 패키지가 브라우저에서도 사용 가능으로 되었고, 브라우저에서도 npm이 주류가 되었습니다.

     

    원래는 CommonJS 형식으로 작성된 패키지가 많아 브라우저에서 사용할 수 없었지만 Browserify 덕분에 브라우저용으로 변환할 수 있게 되어, 브라우저 측에서도 npm이 사용되게 되었습니다.

     

    여기서 더욱 등장한 것이 webpack입니다.


    webpack의 탄생

    Browserify보다 고기능인 새로운 번들 도구로서 2012년에 webpack이 탄생하였고, 현재도 주류 도구입니다.

     

    webpack은 주로 JavaScript를 대상으로 하지만, 해당 로더가 있으면, HTML, CSS, 이미지 등도 번들(변환)할 수 있는 것입니다.

     

    대략적으로 Browserify와의 비교는 Browserify는 CJS를 번들하고, webpack은 JS에 한정되지 않고 무엇이든 번들할 수 있는 것입니다.

     

    또한 webpack이 뛰어난 점으로는, Code Splitting이 있습니다.

     

    이것은 webpack을 사용함으로써 코드를 여러 개의 chunk로 분할할 수 있었던 점입니다.

     

    chunk는 실행 시에 비동기적으로 로드가 발생하기 때문에, 처음 로드 시간을 단축할 수 있는 것입니다.

     

    개발한 코드를 번들하여 하나의 파일로 만들면 상당히 많은 양의 파일이 되므로, 이 Code Splitting은 혁신적인 기능이었습니다.

    로더란
    JavaScript는 기본적으로 JS만 읽을 수 있지만, HTML, CSS, 이미지 등도 읽을 수 있게 하는 것입니다.


    ES Modules의 탄생

    webpack의 탄생으로 모듈 및 패키지 관리 문제가 해결되었습니다.

     

    그러나 이들은 JavaScript의 사양이 아니라, JavaScript를 잘 사용하기 위한 도구였습니다.

     

    그래서 JavaScript 자체에 모듈이라는 사양을 추가하려고 ECMAScript가 움직이고, ES Modules라는 모듈의 메커니즘이 ES2015에서 도입되었습니다.

     

    이로 인해 import 구문의 사용이 가능해졌습니다.

     

    그러나, 이 메커니즘은 대부분의 브라우저에서 지원되지 않았기 때문에, 번들 도구가 필요한 흐름은 변하지 않았습니다...

     

    그래서 webpack도 ES Modules에 대응하였고, 더욱이 V2에서는 로더가 없어도 사용할 수 있는 네이티브 지원되었습니다.

     

    이로 인해, import 구문으로 개발이 가능해지고, 그것을 번들하여 브라우저에서 동작하게 되었습니다.

     

    현재는 webpack을 통하지 않아도, Inernet Explorer를 제외한 모던 브라우저와 Node.js의 Version12 이상에서는 표준으로 사용이 가능하게 되었지만, 현재는 프론트엔드 프레임워크인 React나 Vue 등을 사용할 때 webpack을 통하는 것이 당연한 것처럼 되어 있으므로, 아직도 필요성은 높은 것입니다.

     

    이들에 의해, 브라우저 측에서도 모듈 및 패키지 관리 문제를 해결할 수 있게 되었습니다.


    컴파일이라는 개념

    여기서 더욱 개발을 편리하게 하기 위한 개념으로 컴파일이 있습니다.

     

    이것은 개발 시에는 브라우저에서 동작하지 않지만, 개발에 편리한 기능을 사용하여 코드를 작성할 수 있고, 작성한 코드를 브라우저에서 동작하도록 원래의 JavaScript로 변환하는 것입니다.

     

    이것은 번들하기 전의 JavaScript 앞에, 더욱 개발에 편리한 작성 방법을 하는 것입니다.

     

    컴파일을 사용하는 예로 TypeScript를 들어 흐름을 설명하면, 개발 시에는 TypeScript로 작성하고, 컴파일하여 JavaScript로 변환하고, 그것을 번들하여 JS로 변환하여 브라우저에 표시하는 흐름입니다.


    Babel의 탄생

    ES2015에서는 모듈 외에도 let, const, class, Promise, 화살표 함수, 분할 대입, 스프레드 구문 등 다양한 기능이 추가되었지만, 이들도 브라우저에서 사용할 수 없었습니다.

     

    그래서 ES2015 이후 등에서 작성된 코드를 기존의 환경에서도 동작하도록 오래된 JavaScript로 변환하는 컴파일러가 2014년에 탄생하였습니다.

     

    그것이 Babel입니다. 원래의 명칭은 6to5였고, 사람에 따라서는 ES2015를 ES6라고 부르는 사람도 적지 않아, 그 ES6의 구문을 ES5로 돌리는 컴파일러라는 것으로 6to5라고 불렸습니다.

     

    이 Babel은 webpack과 함께 사용할 수 있었기 때문에, 모듈 및 패키지 관리 문제에 ES2015의 새로운 기능도 함께 사용할 수 있게 되어, JavaScript가 편리해졌습니다.

    컴파일의 가능성

    컴파일이 당연해지면서 편리한 패키지가 계속해서 유행하게 되었고, React, Vue, TypeScript가 유행하게 되었습니다.

     

    이들은 사전에 변환함으로써 브라우저에서도 사용 가능하며, 현재는 당연하게 사용하는 사람도 많아졌습니다.


    마지막으로

    이런 JavaScript의 역사적인 흐름이 있고, webpack이나 Babel이 있는 것으로 인해, 현재는 당연하게 되어 있는 TypeScript이거나, 프론트엔드 프레임워크인 React나 Vue가 사용 가능해진 경위가 있음을 다시 이해할 수 있었습니다.

     

    그래서, webpack이나 Babel의 필요성에 대해 깊게 생각한 적이 없었기 때문에 오늘 글은 많은 생각이 나게 하네요.

     

    그럼.

Designed by Tistory.