목차
💡 이것은 정말로 더 많은 노력을 기울일 가치가 있습니까?
💡 이제 모듈을 ES2015로 게시하기 시작할 때입니다.
요즘 대부분의 웹 개발자들이 최신 언어 기능인 async/await, 클래스, 화살표 함수 등을 사용하여 JavaScript를 작성하는 것을 좋아한다는 것을 알게 되었습니다. 하지만 모든 현대 브라우저가 ES2015+ 코드를 실행하고 방금 언급한 기능들을 네이티브로 지원하지만, 대부분의 개발자들은 여전히 코드를 ES5로 트랜스파일하고 폴리필과 번들링하여 오래된 브라우저를 사용하는 소수의 사용자를 수용하고 있습니다.
이런 상황은 좀 불편합니다. 이상적인 세상에서는 필요없는 코드를 배포하지 않아도 될 것입니다.
새로운 JavaScript와 DOM API로 인해 런타임에서 폴리필을 조건부로 로드할 수 있습니다. 그러나 새로운 JavaScript 구문은 알 수 없는 구문이 에러를 발생시키고 그러면 코드 전체가 실행되지 않기 때문에 이 작업이 상당히 까다로워집니다.
새로운 구문을 feature detect(지원 여부를 확인)하는 좋은 해결책은 아직 없지만, 오늘날 기본적인 ES2015 구문 지원 feature deetect할 수 있는 방법은 있습니다.
해결책은 <script type="module">입니다.
대부분의 개발자들은 <script type="module">을 ES 모듈을 로드하는 방법으로 생각하지만 (물론 이것은 맞습니다), <script type="module">은 더 즉각적이고 실용적인 용도도 있습니다.
바로 ES2015+ 기능을 포함한 일반적인 JavaScript 파일을 로드하고 브라우저가 처리할 수 있다는 것을 알 수 있는 기능입니다!
다시 말해, <script type="module">을 지원하는 모든 브라우저는 알고 있고 좋아하는 대부분의 ES2015+ 기능을 지원합니다.
예를 들어:
● <script type="module">을 지원하는 모든 브라우저는 async/await도 지원합니다.
● <script type="module">을 지원하는 모든 브라우저는 클래스도 지원합니다.
● <script type="module">을 지원하는 모든 브라우저는 화살표 함수도 지원합니다.
● <script type="module">을 지원하는 모든 브라우저는 fetch, Promise, Map, Set 등을 비롯한 다양한 기능도 지원합니다.
남은 일은 <script type="module">을 지원하지 않는 브라우저에 대한 대체 방법을 제공하는 것뿐입니다. 다행히도, 현재 ES5 버전의 코드를 생성하고 있다면 이미 해당 작업을 수행했습니다. 이제 필요한 것은 ES2015+ 버전을 생성하는 것뿐입니다.
이 문서의 나머지 부분에서는 이 기술을 구현하는 방법을 설명하고, ES2015+ 코드를 배포할 수 있는 능력이 앞으로 모듈 작성 방식을 어떻게 바꿀지에 대해 논의합니다.
💡구현
현재 webpack 또는 rollup과 같은 모듈 번들러를 사용하여 JavaScript를 생성하고 있다면, 그대로 계속 사용하시면 됩니다.
다음으로, 현재 번들과는 별개로 두 번째 번들을 생성합니다. 첫 번째 번들과 완전히 동일한데, 유일한 차이는 ES5까지 트랜스파일하지 않고 레거시 폴리필을 포함할 필요가 없다는 점입니다.
babel-preset-env를 이미 사용 중이라면 (사용하는 것이 좋습니다), 두 번째 단계는 매우 간단합니다.
브라우저 목록을 <script type="module">을 지원하는 브라우저로 변경하기만 하면 됩니다. Babel은 필요하지 않은 변환을 자동으로 적용하지 않을 것입니다.
다시 말해, Babel은 ES5 대신 ES2015+ 코드를 출력할 것입니다.
예를 들어, webpack을 사용하고 현재의 메인 스크립트 엔트리 포인트가 ./path/to/main.mjs라면, ES5 버전을 위한 설정은 다음과 같을 수 있습니다 (참고로, 이 번들은 ES5이므로 main.es5.js로 지칭합니다).
모던한 ES2015+ 버전을 만들기 위해서는 두 번째 구성 파일을 생성하고 목표 환경을 <script type="module">을 지원하는 브라우저로 설정하면 됩니다.
다음과 같이 설정할 수 있습니다 (참고로, 여기서는 모듈이기 때문에 .mjs 확장자를 사용하였습니다).
이 두 개의 구성 파일을 실행하면 두 개의 프로덕션용 JavaScript 파일이 생성됩니다.
● main.mjs (구문은 ES2015+입니다.)
● main.es5.js (구문은 ES5입니다)
다음 단계는 HTML을 업데이트하여 모듈을 지원하는 브라우저에서만 ES2015+ 번들을 조건부로 로드하는 것입니다. 이를 위해 <script type="module">과 <script nomodule>을 조합하여 사용할 수 있습니다.
참고!
이 문서의 예제를 업데이트하여 모듈로 로드하는 모든 파일에 .mjs 확장자를 사용했습니다.
이 관행은 비교적 최근에 도입된 것이므로, 사용할 때 주의해야 할 몇 가지 사항을 안내해 드립니다.
● 웹 서버는 Content-Type 헤더 text/javascript로 .mjs 파일을 제공하도록 구성되어야 합니다. 브라우저가 .mjs 파일을 로드하지 못하는 경우 이것이 그 이유일 수 있습니다.
● Webpack과 babel-loader를 사용하여 JavaScript를 번들링하고 있다면, 아마도 .js 파일에 대해서만 트랜스파일하는 일부 구성 코드를 복사/붙여넣기한 것입니다. 설정 파일의 정규식을 /.js$/에서 /.m?js$/로 변경하면 문제가 해결될 것입니다.
● 이전 버전의 webpack은 .mjs 파일에 대해 소스맵을 생성하지 않았지만, webpack 4.19.1부터 이 문제가 해결되었습니다.
💡 중요한 사항
대부분의 경우, 이 기술은 "그냥 작동"하지만, 이 전략을 구현하기 전에 알아야 할 몇 가지 모듈 로딩에 관련된 세부 사항이 있습니다.
1. 모듈은 <script defer>와 같은 방식으로 로드되므로 문서 파싱이 완료된 후에 실행됩니다. 따라서 일부 코드가 그 이전에 실행되어야 할 경우, 해당 코드를 분리하고 별도로 로드하는 것이 좋습니다.
2. 모듈은 항상 strict mode에서 코드를 실행합니다. 따라서 특정 이유로 인해 코드의 일부가 strict mode 외부에서 실행되어야 하는 경우, 별도로 로드해야 합니다.
3. 모듈은 스크립트와는 다르게 최상위 var 및 function 선언을 처리합니다. 예를 들어, 스크립트에서 var foo = 'bar' 및 function foo() {...}는 window.foo로 접근할 수 있지만, 모듈에서는 그렇지 않습니다. 코드에서 이러한 동작에 의존하지 않도록 주의하십시오.
경고!
Safari 10은 nomodule 속성을 지원하지 않지만, <script nomodule> 태그를 사용하기 전에 HTML에 JavaScript 스니펫을 인라인으로 추가함으로써 이 문제를 해결할 수 있습니다. (참고: Safari 11에서 이 문제가 해결되었습니다).
💡 작동 예시
저는 webpack-esnext-boilerplate을 만들었으며, 개발자들이 이 기술의 실제 구현을 볼 수 있도록 하였습니다.
이 보일러플레이트에서는 실제 상황에서도 제대로 작동하고 프로덕션에 사용할 수 있는 것을 보여주기 위해 의도적으로 여러 가지 고급 webpack 기능을 포함시켰습니다. 이에는 다음과 같은 잘 알려진 번들링 최적화 기법이 포함됩니다.
● 코드 분할 (Code splitting)
● 동적 로딩 (런타임에서 추가 코드를 조건부로 로드)
● 자산 지문 (효율적인 장기 캐싱을 위한 자산 버전 관리)
또한, 제가 사용하지 않을 만한 것은 절대로 추천하지 않기 때문에, 이 블로그에서도 이 기술을 사용하도록 업데이트했습니다. 더 많은 내용을 보고 싶다면 소스 코드를 확인해볼 수 있습니다.
프로덕션 번들을 생성하는데 webpack 이외의 도구를 사용하고 있다면, 프로세스는 거의 동일합니다. 저는 webpack을 사용하여 이를 데모하는 것을 선택한 이유는 현재 가장 인기 있는 번들러이며, 또한 가장 복잡하기 때문입니다. webpack에서 이 기술이 작동한다면 다른 어떤 도구에서도 작동할 수 있다고 생각했기 때문입니다.
💡 이것은 정말로 더 많은 노력을 기울일 가치가 있습니까?
이것은 확실히 가치가 있습니다! 절약되는 비용이 상당할 수 있습니다.
예를 들어, 이 블로그의 실제 생성된 코드의 두 가지 버전에 대한 총 파일 크기 비교입니다.
ES5 버전인 기존 버전은 ES2015+ 버전과 비교하여 파일 크기가 두 배 이상입니다(압축 후에도 마찬가지로)
더 큰 파일은 다운로드에 더 많은 시간이 걸리지만, 파싱과 실행에도 더 많은 시간이 소요됩니다. 이 사이트의 두 가지 버전을 비교할 때, 기존 버전의 파싱/실행 시간도 일관되게 두 배 정도 더 걸렸습니다 (이 테스트는 webpagetest.org를 사용하여 Moto G4에서 실행되었습니다).
이 절대적인 파일 크기와 파싱/실행 시간은 특별히 길지 않습니다만, 이는 블로그이며 많은 스크립트를 로드하지 않기 때문입니다. 그러나 대부분의 웹사이트에는 이와 같은 상황이 적용되지 않습니다. 스크립트가 많을수록 ES2015+ 코드를 제공함으로써 얻을 수 있는 이득이 더 커집니다.
여전히 회의적이고 파일 크기와 실행 시간의 차이가 주로 기존 환경을 지원하기 위해 많은 폴리필이 필요하다는 사실 때문이라고 생각한다면 완전히 틀리지는 않습니다. 그러나 좋거나 나쁘거나, 이것은 현재 웹에서 극히 흔한 관행입니다.
HTTPArchive 데이터셋의 간단한 쿼리를 실행하면 Alexa 순위 상위 85,181개 사이트 중 34,588개 사이트에서 babel-polyfill, core-js 또는 regenerator-runtime을 제작 번들에 포함시키고 있다는 것을 확인할 수 있습니다. 6개월 전에는 이 숫자가 34,588개였습니다!
현실은 트랜스파일링하고 폴리필을 포함하는 것이 빠르게 새로운 표준이 되고 있다는 것입니다. 유감스럽게도, 이로 인해 수십억 사용자가 불필요하게 브라우저에 전송되는 수조 바이트를 받게 되었는데, 이러한 브라우저는 트랜스파일되지 않은 코드를 기본적으로 실행할 수 있었을 것입니다.
💡 이제 모듈을 ES2015로 게시하기 시작할 때입니다
현재 이 기술을 위한 주요한 문제는 대부분의 모듈 작성자들이 소스 코드의 ES2015+ 버전을 게시하지 않고, 트랜스파일된 ES5 버전을 게시한다는 것입니다.
ES2015+ 코드를 배포할 수 있는 상황이 되었으므로, 이를 변경할 시기입니다.
즉각적인 미래에는 이로 인해 많은 도전 과제가 발생한다는 것을 완전히 이해하고 있습니다. 대부분의 빌드 도구는 현재 모든 모듈이 ES5인 것을 가정하는 구성에 대한 문서를 게시합니다. 이는 모듈 작성자들이 ES2015+ 소스 코드를 npm에 게시하면 사용자의 빌드를 깨뜨리고 일반적으로 혼란을 초래할 수 있다는 것을 의미합니다.
문제는 대부분의 Babel을 사용하는 개발자들이 node_modules에서 아무 것도 트랜스파일하지 않도록 구성한다는 것인데, 모듈이 ES2015+ 소스 코드로 게시된다면 문제가 발생합니다. 다행히 해결책은 간단합니다. 빌드 구성에서 node_modules 제외를 제거하면 됩니다.
단점은 Babel과 같은 도구가 로컬 종속성뿐만 아니라 node_modules의 종속성도 트랜스파일해야 한다면 빌드가 느려질 수 있다는 점입니다. 다행히 이는 지속적이고 로컬 캐싱을 통해 어느 정도 해결될 수 있는 문제입니다.
ES2015+가 새로운 모듈 게시 표준이 되기까지 우리가 직면할 가능성이 있는 어려움에도 불구하고, 이를 위한 싸움은 가치가 있다고 생각합니다. 모듈 작성자로서 우리가 npm에만 ES5 버전의 코드를 게시한다면 사용자에게 비효율적이고 느린 코드를 강요하는 것입니다.
ES2015+를 게시함으로써 개발자들에게 선택권을 제공하고, 그 결과로 모두에게 혜택이 되도록 합시다.
💡 결론
<script type="module">는 브라우저에서 ES 모듈(및 해당 종속성)을 로드하기 위한 메커니즘이라고 고안되었지만, 그것만을 위해 사용해야 하는 것은 아닙니다.
<script type="module">은 기껏해야 하나의 JavaScript 파일을 로드할 수 있으며, 이는 브라우저에서 현대적인 기능을 조건부로 로드하는 필요한 수단을 제공합니다.
이와 함께 nomodule 속성을 사용하면 우리는 ES2015+ 코드를 프로덕션 환경에서 사용할 수 있게 되었으며, 이제 불필요한 트랜스파일된 코드를 필요로하지 않는 브라우저로 전송하는 것을 멈출 수 있습니다.
ES2015 코드 작성은 개발자에게 이익이 되고, ES2015 코드 배포는 사용자에게 이익이 됩니다.
'E-커머스 쇼핑몰 운영' 카테고리의 다른 글
[온라인 쇼핑몰 속도 최적화] 필요한 원본에 미리 연결 (3) | 2024.10.23 |
---|---|
[온라인 쇼핑몰 속도 최적화] Facades를 사용하여 외부(Third-party) 리소스를 지연 로드 (2) | 2024.10.22 |
[온라인 쇼핑몰 속도 최적화] 웹폰트 로드 중 텍스트가 보이는지 확인 (0) | 2024.10.21 |
[온라인 쇼핑몰 속도 최적화] document.write()를 피하세요. (2) | 2024.10.19 |
[온라인 쇼핑몰 속도 최적화] Keep-Alive 활성화 (1) | 2024.10.19 |