Home

읽기 설정

최근에 프론트엔드 툴링에 대한 관심이 정말 많아졌어요. 다들 뭔가 새로운 걸 만들고 있는 것 같아요. 스노우팩은 작년에 발표됐는데, 방금 V2가 나왔네요.00:00

Vue.js 개발자인 에반 유가 비테라는 툴을 만들고 있는데, 심지어 Preact를 작성한 제이슨 밀러도 며칠 전에 비슷한 툴을 만들고 있다고 트윗했어.00:10

이 모든 도구들이 공통적으로 가지고 있는 한 가지는 로컬 개발 환경에서 번들링 단계를 없애고 있다는 점이에요. 그러면, 도대체 무슨 뜻이고 왜 지금 이 모든 일들이 벌어지고 있는 걸까요?00:20

자, 그 질문에 답하려면 왜 처음부터 앱 번들링을 시작했는지 이해해야 합니다. 앱을 번들링하는 이유 중 하나는 성능 때문입니다.00:32

브라우저처럼 지연 시간이 긴 환경에서는 네트워크로 여러 개의 작은 파일을 보내는 것보다 하나의 큰 파일을 보내는 것이 실제로는 더 빠릅니다.00:41

하지만 우리들이 계속해서 번들링을 하는 데에는 또 다른 훨씬 더 중요한 이유가 있습니다. 그것은 개별 모듈을 사용하여 애플리케이션 코드를 작성할 수 있게 해주는 기능 때문입니다.00:50

보시다시피, 웹이 존재하는 대부분의 기간 동안에는 스크립트 파일을 로드하는 방법이 딱 한 가지였어요. 그냥 평범한 스크립트 태그로요. 그래서 만약 여러 개의 JavaScript 파일을 로드하고 싶었다면, 페이지에 여러 개의 스크립트 태그를 추가하는 수밖에 없었죠.00:59

저희 진짜 잠깐 그렇게 했었는데, 진짜 힘들었어.01:13

가장 큰 문제는 스크립트 태그들 간에 명시적인 연결 고리가 없다는 거예요. 즉, 특정 스크립트가 실행되기 전에 다른 스크립트가 로드되어야 할 때, 이제는 그걸 우리가 직접, 매우 구체적인 순서대로 정해줘야 한다는 거죠.01:17

말할 것도 없이, 정말 빨리 엄청 어려워지죠.01:34

하지만 우리는 그래도 잠시 동안 계속했죠. 그래서 명시적인 모듈 시스템이 등장하는 겁니다. 모듈을 사용하면 import나 require 같은 키워드를 이용해서 다른 자바스크립트 파일에 명시적으로 의존하는 코드를 하나의 자바스크립트 파일에 작성할 수 있고, 모든 모듈이…01:37

저희 앱들은 이 키워드들을 사용하고 있고, 이 키워드를 기반으로 최종 모듈 순서를 자동으로 생성해주는 툴링 레이어가 존재합니다. 이렇게 하면 저희 프로그램이 실행될 때, 의존하는 파일들은 항상 그 파일이 실행되기 전에 로드되도록 보장할 수 있습니다.01:55

이 과정을 의존성 분석이라고 하는데, 이 결과로 각 의존성이 정확한 방향으로 향하는 모듈 그래프가 만들어집니다. 그리고 이게 바로 프로그래머로서 다른 모듈에 의존하는 코드를 그냥 작성할 수 있게 해주는 것입니다.02:10

라이브러리를 전혀 생각하지 않고 그냥 가져다 쓸 수 있게 해주는 거죠. 그래서 앱 번들러들이 하는 가장 중요한 기능 중 하나가 의존성 그래프를 해결하는 거예요. RequireJS나 Browserify 같은 도구들, 그리고 최근에는 Webpack 같은 것들이 있죠.02:26

프론트엔드 자바스크립트 모듈은 꽤 흥미로운 역사를 가지고 있습니다. 앞서 말씀드린 것처럼, 웹의 대부분의 기간 동안에는 자바스크립트 파일을 로드하는 방법이 스크립트 태그 하나밖에 없었습니다. 하지만 Node가 나오면서 자체 모듈 시스템을 만들었죠.02:39

이것을 CommonJS라고 부릅니다. CommonJS는 require와 module.exports라는 키워드를 사용하는데, 아마 익숙하실 겁니다. 그리고 Node가 서버에서 실행되기 때문에, 이 키워드들이 작동하는 방식은 다른 서버 측 환경에서의 모듈 로딩 방식과 유사합니다.02:55

루비, PHP, 또는 파이썬과 같은 언어의 경우, 실행되는 코드가 다른 의존성 코드가 있는 서버와 동일한 서버에 있기 때문에, 앱이 다른 모듈을 로드해야 하는 지점에 도달하면 런타임은 현재 작업을 중단하고 로드할 수 있습니다.03:10

다른 모듈을 디스크에서 직접 읽어와서, 중단했던 부분부터 바로 이어서 작업을 진행할 수 있습니다. 이를 동기화된 모듈 로딩이라고 하는데, 실행 중인 코드와 의존성 코드가 같은 물리적 위치에 존재하고, 디스크 읽기 속도가 매우 빠르기 때문에 가능합니다.03:26

하지만 브라우저는 좀 달라요. 굉장히 독특한 런타임 환경이고, 저희 애플리케이션 코드를 실행할 때 사실은 사용자 기기에서 실행하는 거거든요.03:45

이제 사용자들의 기기가 저희 코드들이 저장된 서버와는 상당히 멀리 떨어져 있습니다. 그래서 앱이 실행 중이고 새로운 모듈을 로드해야 할 때, 브라우저는 현재 하고 있는 작업을 멈추고 다른 모듈을 가져올 수 없죠.03:55

네트워크를 통해 데이터를 가져오는 건 디스크에서 파일을 읽는 것보다 훨씬 느리기 때문에, 끊겼다가 다시 바로 그만두었던 지점부터 이어서 진행할 수 있습니다.04:10

바로 이 때문입니다. Node와 브라우저는 둘 다 JavaScript를 실행하지만, Node의 일반적인 JS 시스템은 브라우저에서 작동할 수 없을 겁니다.04:18

비동기 방식과는 잘 맞지 않아서 그래요. 그래서 브라우저는 자체적인 모듈 시스템이 필요했고, 바로 이 부분에서 ES 모듈 사양의 디자인이 적용된 거죠.04:27

JavaScript 프로그래밍 언어의 개발을 담당하는 TC39 위원회는 언어 레벨에서 모듈을 다루는 표준화된 방법을 도입하고자 했습니다.04:38

모든 ECMAScript 구현에서 작동할 수 있는, 환경에 관계없이 사용할 수 있는 방식이었죠. 그리고 그게 오늘날 우리가 모두 사용하는 ES 모듈 사양이라는 긴 여정으로 이어졌습니다.04:48

수입, 내보내기 문, 기본 임포트, 명명된 임포트처럼, Webpack 같은 도구들이 이해하고, 우리 모두 앱을 개발할 때 사용하는 언어들을 말이죠.04:59

이게 바로 문제의 핵심입니다. 브라우저가 import와 export 구문을 이해하게 되면, 애플리케이션 코드를 직접 분석하고, import 문을 따라가면서 의존성 그래프를 해결하고, 이 모든 작업을 대신 해 줄 수 있습니다. 덕분에 Webpack 같은 도구는 이런 작업에 신경 쓸 필요조차 없게 되는 거죠.05:09

알고 보니, 의존성 해결 및 모듈 그래프 생성 과정이 생각보다 꽤 복잡하고, 앱이 커질수록 Webpack 빌드 속도가 느려지는 이유가 바로 이것 때문인 것 같습니다.05:27

NPM 설치가 복잡하고 오래 걸리는 이유가 바로 이거예요. 브라우저로 이 작업을 최대한 옮길수록, 로컬 개발 환경이 훨씬 빨라질 수 있답니다.05:39

그래서 현대 브라우저는 ES 모듈 구문과 어떻게 상호작용하는 걸까요? 물어봐주셨다니 기쁘네요. 제 노트북이 여기 있습니다. 간단히 살펴볼까요.05:49

여기 간단한 index.html 파일이 있는데, 하나의 p 태그만 있고 지금은 아무것도 실행되고 있지 않아요.05:58

여기 제가 가진 이 S 명령어에 보시면, 그냥 파이썬의 간단한 HTTP 서버를 실행하는 걸 알 수 있어요. 그래서 이 디렉터리에 있는 파일들을 전부 보여주는 역할을 합니다.06:08

그래서 실행하면 일반 웹 서버처럼 파일을 요청할 수 있습니다. 빌드 도구도 없고, Node나 Webpack 같은 것도 실행하지 않아요.06:18

이것은 단순히 파일을 제공하는 웹 서버일 뿐입니다.06:30

자, 이제 스크립트 태그를 추가하고 콘솔에 'hello world'를 출력해 봅시다. 브라우저로 와서 콘솔을 열고 새로고침하면 'hello world'가 보이는 것을 확인할 수 있을 거예요. 이건 기본적인 자바스크립트입니다. 이걸 클래식 스크립트라고 부르죠.06:33

지금은 자바스크립트 로딩의 표준적인 방식이라고 할 수 있습니다. 클래식 스크립트에서 흥미로운 점은 'this'를 로그아웃해서 확인해보면, 'this'가 window 객체를 가리킨다는 것입니다.06:53

사실 그건 고전 스크립트들이 동일한 스코프를 공유하기 때문입니다.07:09

만약 여기 또 다른 스크립트를 쓴다면, 첫 번째 스크립트에서는 let x equals one이라고 하고, 두 번째 스크립트에서는 그냥 x를 출력해 볼게요.07:14

여기서 하나 보게 될 거예요. 이건 두 번째 대본에서 나온 부분이에요.07:25

여기서 클래식 스크립트들은 하나의 컨텍스트를 공유하고, 또한 윈도우를 가리키는 속성도 가지고 있는 것을 알 수 있습니다.07:34

그리고 마지막으로, 음, 여기 export default 어떤 문자열을 써서 다시 로드해본다면, JavaScript 엔진에서 'unexpected token export'라는 에러를 볼 수 있을 거예요.07:43

자, 그럼 고전적인 시나리오의 몇 가지 특징들을 살펴보셨죠.07:57

한번 새로고침 해보고 다시 작동하는지 확인해 봅시다. 이제 ES 모듈에 대해 이야기해 보겠습니다. 브라우저에게 ES 모듈과 함께 작동하도록 지시하는 방법은 'module'이라고 하는 type 속성을 추가하는 것뿐입니다.08:01

그거 저장해두고 나중에 다시 확인해 봐. 두 번째 스크립트에서 x가 정의되지 않았다는 에러가 발생하고 있어.08:13

자, 모듈과 클래식 스크립트의 가장 처음 눈에 띄는 차이점은 모듈이 자체 스코프를 가지고 있다는 거예요. 이게 꽤 괜찮은데, 왜냐하면 자바스크립트에서 모듈이 나오기 전에는 함수 스코프만 있었고, 그 다음에 블록 레벨 스코핑이 도입되었지만, 이렇게 로드되는 스크립트는 항상 공유해 왔거든요.08:21

스코프를 가지고 있었는데, 모듈은 이제 자체적으로 격리된 스코프를 가지고 있습니다. 이건 실제로 자바스크립트에서 새로운 스코프를 제공하는 방식이라 꽤 흥미로운 일이죠.08:41

여기서 x가 이 두 모듈에서 공유되지 않는다는 것을 볼 수 있습니다. 또 다른 차이점은 이 값을 로그로 찍어보면 undefined가 뜬다는 것입니다. 이제 모듈 내에서는 this 키워드가 정의되지 않습니다. 물론, 모듈 내에서 window 전역 객체에는 접근할 수 있지만, 이 값은 undefined이고, 모듈은 스코프가 제한됩니다. 마지막으로 export default '문자열'을 작성하고 다시 로드한다면...08:48

009:05

저기 봐, 오류는 안 보이네. 하지만 당연히 내보내고 가져오는 기능은 별도의 모듈 파일이 있을 때 정말 유용하지.09:21

자, 그럼 이걸 실제 파일로 만들어 볼까요. 여기 앱.js 파일 하나만 만들면 돼요.09:30

이걸 여기로 복사해 줘요. 여기 아래에 놔둘게요.09:36

그리고 여기서는 항상 하듯이 source 속성을 사용해서 파일 시스템 상의 파일에 참조하도록 할 겁니다. 자, 우리 앱에 console.log hi from app을 추가해볼까요.09:43

이제 새로고침을 하면 브라우저가 app.js를 가져와서 실행하고 있습니다.09:56

이걸 보면 다 잘 작동하는 것을 알 수 있죠. 만약 내보내기 기능을 빼고 타입 모듈도 제거해서 이걸 클래식 스크립트로 실행한다면, 똑같이 잘 작동할 겁니다. 이런 식으로 항상 그래왔으니까요.10:04

하지만 이러한 모듈 스크립트 덕분에 import와 export 구문이 실제로 작동하게 됩니다.10:16

자, 그럼 source favorites.js라는 파일을 하나 더 만들고, 터미널은 닫아주세요.10:23

좋아하는 곳에 파란색에 해당하는 const를 내보내고, 앱에서는 ./source/좋아하는 곳에서 color를 가져오자.10:34

그럼 콘솔에 '제 제일 좋아하는 색깔은 색깔입니다'라고 출력하고 저장한 다음에 브라우저를 새로고침해서 확인해 볼게요. 브라우저가 app.js 파일을 로딩하고 있는 걸 볼 수 있네요. 이전과 똑같이.10:51

소스/페이버릿을 요청했는데 404 오류가 발생하고 있습니다. 터미널을 확인해보면, 소스/페이버릿 파일이 없어서 404 오류가 났다는 것을 알 수 있습니다.11:09

이게 브라우저에서 ES 모듈을 사용할 때 가장 먼저 알아차릴 수 있는 부분인데, 브라우저는 이 import 경로를 실제 URL로 취급합니다. 그러니까 여기 있는 경로를 그대로 URL로 변환하는 거죠. 그리고 '좋아하는 항목' 같은 게 없기 때문에...11:24

자, 폼 형태로 되어 있는데 이걸 favorites.js로 바꿔서 다시 로드해 봅시다. 다시 로드했더니, app.js가 로딩되고 있습니다. app.js가 로딩되면서 favorites 모듈이 가져와지고, export도 잘 작동하는 걸 확인할 수 있습니다. 그리고 '제 좋아하는 색깔은 파란색입니다'라는 이 문자열은 ES 모듈 규격에서… (이하 생략)11:43

일반적으로 코드를 작성할 때 모듈 식별자를 확장자 없이 쓰는 게 익숙하죠. 저희 애플리케이션에서 모듈을 가져올 때도 그렇게 쓰는 경우가 많습니다. 하지만 브라우저는 이 모듈 식별자를 URL로 취급한다는 점이 주요 차이점 중 하나입니다.12:01

ES 모듈을 처리하는 것도 이러한 새로운 빌드 도구들이 하는 일 중 하나인데, 기존의 import 문을 브라우저가 이해할 수 있는 URL로 다시 작성해 줍니다. 덕분에 기존 코드를 다시 작성할 필요가 없고 기존 도구들도 잘 작동합니다.12:21

하지만 이렇게 URL을 사용하는 것은 꽤 멋지네요. 브라우저가 이걸 따라갈 수 있다는 것이 아주 멋진 기능이죠.12:37

기본적으로 브라우저는 모듈을 로드하는 두 가지 방법이 있습니다.12:45

하나는 타입 모듈이 있는 스크립트이고, 다른 하나는 import 문을 사용하는 방식입니다.12:48

그리고 import 문은 클래식 스크립트를 로드할 수 없기 때문에, 브라우저는 항상 이 include들을 모듈로 파싱합니다. 즉, 만약 favorites 파일에서 무언가를 로깅하려고 하면, 'undefined'가 표시될 것입니다.12:53

그래요, 그럼 다시 해봐요. 여기 모여서 유틸리티(utils) 슬래시 add.js 같은 파일을 만들어서, a와 b를 입력받아서 반환하는 기본 함수를 내보내 볼까요?13:11

a 더하기 b 그리고 즐겨찾기에 추가하려면, 점 점 슬래시 유틸리티 슬래시 add.js에서 가져와서 추가할 수 있습니다. 그리고 합계는 2 더하기 2라고 콘솔에 출력해 봅시다.13:26

합계가 4로 표시되는 것을 확인할 수 있고, 실제로 브라우저에서 add 모듈이 로드되는 것도 보입니다. 이제 이 모듈 식별자가 URL이기 때문에 절대 URL로도 사용할 수 있습니다.13:45

그래서 점 점을 생략하고 그냥 앞에 슬래시를 붙여서 웹 서버의 루트, 즉 이 디렉토리의 루트에 접속할 수 있습니다. 왜냐하면 루트에서 서비스를 제공하고 있으니까요.13:59

그리고 그걸 저장하고 다시 불러오면 모든 것이 정상적으로 작동하는 것을 확인할 수 있을 겁니다. 그리고 실제로 그렇네요.14:10

이것이 의미하는 바는, 이 URL들이 상대 URL이거나 절대 URL이 될 수 있기 때문에, 실제로 다른 도메인의 URL도 될 수 있다는 것입니다. 그리고 이것이 바로 Pika 도구가 들어맞는 곳 중 하나입니다.14:15

Pika.dev에 가시면 패키지들을 위한 CDN이 있다는 걸 보실 수 있습니다.14:27

만약 Lodash를 입력해서 확인해 본다면, Lodash ES라는 패키지가 있는데, Lodash를 ES 모듈로 내보냈고, 여기 Pika에서 이 임포트 경로를 제공해주니까 그냥 복사하면 됩니다.14:32

앱으로 다시 돌아오세요.14:49

그리고 이 부분은 그냥 주석 처리하고 안에 붙여넣어 볼게요. 그러면 이게 cdn.pika.dev라는 걸 알 수 있고, 완전한 URL이기도 하고 버전 번호까지 있네요. 그리고 이건 Lodash니까 Lodash에서 add를 import할 수 있을 거예요. 그리고 이걸 3과 4로 바꿔서 저장해 봅시다.14:53

음, 새로고침해서 한번 확인해 보세요. 합이 7이 나옵니다. 브라우저가 lodash의 특정 버전을 가져오고 있고, 그리고 pika에서 제공하는 다른 파일도 있죠. 하지만 요청하는 게 브라우저에게 es 모듈이면, 브라우저가 처리할 수 있다는 걸 알 수 있을 거예요.15:13

이 모든 의존성을 파악하고 가져와서 로드하고, абсолютно 절대로 빌드 도구 없이 올바른 순서대로 실행해야 해.15:32

여기 와서 이 import를 복사하고, 우리 앱에서 추가 로그를 넣어서 '앱에서 추가'라고 쓰고, 그리고 add five, add five를 호출하면 돼.15:41

브라우저를 새로 고침하면, 캐시가 비활성화되어 있음에도 불구하고 Lodash가 딱 한 번만 로드되는 것을 확인할 수 있습니다.15:56

그것은 브라우저가 이 모든 import 문들을 순회하면서 모듈 그래프를 만들 때, 캐시를 사용하기 때문입니다. 그래서 같은 모듈을 여러 번 요청하지 않도록 효율적이고, 저희 모듈을 직접 사용하더라도 잘 작동합니다. 따라서 이걸 지우고 utils에서 광고 모듈을 바로 두 곳에서 import하도록 다시 해봅시다.16:06

그거 저장해두고 다시 로드해 봐. 광고는 딱 한 번만 요청되니까, 아마 멋있는 거 보여줄 수 있을 거야. 그리고 이 새로운 빌드 도구 세대는 브라우저에서 제공하는 모듈 그래프를 통해 모든 정보를 활용할 수 있다는 점이 멋있는 거지.16:26

다시 말해, 의존성 문제를 해결하는 많은 작업을 브라우저로 넘겨주고, 저희가 로컬 컴퓨터에서 빌드 타임에 그 작업을 수행할 필요가 없도록 하기 위해서입니다.16:44

게다가 브라우저가 게으르게 처리하다 보니, 스크립트 태그를 통해 모듈을 로드하는 페이지를 방문하기 전까지는 이런 작업이 전혀 일어나지 않아요. 페이지 방문 후에야 브라우저가 전체 그래프를 요청하기 시작하는 거죠.16:54

그러다 보면 '좋아, 이 세 개의 모듈에서는 잘 돌아가네'라고 생각하실 수도 있을 거예요. 제 프로젝트에는 수백 개의 모듈이 있는데, 실용적인 걸까요?'17:06

특히 프로덕션 환경에서는, 사용자분들이 다시 한번 높은 지연 시간 환경에 계시기 때문에 600개의 작은 파일을 개별적으로 로드해야 하는 상황은 원치 않습니다. 하지만 로컬에서 개발할 때는 지연 시간이 병목 현상이 되는 경우는 보통 없습니다.17:14

사실상, 거의 그런 경우는 없죠. 파일 수정 후 디스크에서 변경 사항을 기다리는 동안 컴파일과 리빌드에 얼마나 오래 걸리는지가 항상 문제예요.17:28

그런데 로컬 개발 환경처럼 지연 시간이 문제가 안 되는 곳에서는 대부분 인터넷 연결이 정말 빠를 때가 많아요.17:37

이 모든 작업을 브라우저가 알아서 늦게 처리하도록 위임하면 초기 시간을 상당히 절약할 수 있습니다. 그래서 일부 빌드 도구의 콜드 스타트 시간이 거의 즉각적으로 되는 것이죠.17:44

그리고 그들은 변경 사항이 있을 때마다 브라우저의 모듈 그래프 슬롯에 새로운 모듈을 즉시 교체하는 핫 모듈 교체를 바로 지원합니다.17:54

이 아키텍처가 가능하게 하는 최적화들을 조금씩 보이기 시작하고, 브라우저에 이 모든 작업을 위임함으로써 로컬 개발 환경을 얼마나 단순화하고 빠르게 만들 수 있는지 이해할 수 있기를 바랍니다.18:06

npm에 있는 방대한 양의 코드를 모듈 로딩을 지원하는 최신 브라우저에서 사용할 수 있도록 아직 많은 작업이 진행 중이지만, 앞으로의 전망은 매우 밝습니다.18:18

브라우저들은 의존성 가져오고 캐싱하는 데 정말 능숙하잖아요. 그러니까 오늘부터라도, 특히 앞으로 몇 년 안에, 이런 패턴이 로컬 개발 환경에서 아주 흔하게 나타날 거라고 생각해요. 이 정보가 도움이 되셨기를 바라며, 이 이야기는 여러 조각들이 맞춰져 나가는 과정이고, 꽤…18:30

복잡해서 혹시 질문 있으시면 댓글 남겨주세요. 시청해주셔서 감사합니다! 다음 영상에서 또 만나요.18:50

AI Summary

이 영상은 ES 모듈의 작동 원리와 브라우저가 이를 처리하는 과정을 상세히 설명하고, 이를 통해 로컬 개발 환경을 개선하는 방법을 제시합니다. ES 모듈은 URL 기반 import를 통해 유연성을 높이고, 브라우저는 모듈 그래프를 생성하고 캐싱하며, 지연 로딩을 지원하여 초기 로딩 속도를 향상시킵니다. 빌드 도구의 역할이 줄어들고 핫 모듈 교체가 가능해지면서, 개발자는 더 빠르고 효율적으로 코드를 수정하고 결과를 확인할 수 있게 됩니다. Pika CDN과 같은 도구를 활용하여 외부 라이브러리를 쉽게 가져와 사용할 수 있으며, 앞으로 ES 모듈과 브라우저의 통합은 더욱 발전할 것으로 예상됩니다.

Key Highlights

  • ES 모듈은 JavaScript 코드의 모듈화를 가능하게 하며, URL 기반 import를 지원합니다.
  • 브라우저는 모듈 그래프를 생성하고 캐싱하여 초기 로딩 속도를 향상시킵니다.
  • 지연 로딩을 통해 초기 페이지 로딩 시간을 단축할 수 있습니다.
  • 브라우저의 모듈 처리 기능으로 인해 로컬 개발 환경에서 빌드 도구의 역할이 줄어듭니다.
  • 핫 모듈 교체(HMR)를 통해 전체 페이지를 다시 로드하지 않고 코드 변경 사항을 즉시 반영할 수 있습니다.

Related Videos