<script type="module"></script>
1. HTML 파서와 JavaScript 엔진의 협력 관계
브라우저는 HTML 파서(HTML parser)와 JavaScript 엔진(JS engine)이 협력해서 HTML 문서와 JavaScript 코드를 각각 해석하고 실행합니다.
- HTML 파서가 HTML을 읽는 과정에서 <script> 태그를 만나게 되면, HTML 파서는 JavaScript 코드의 해석을 위해 잠시 작업을 멈춥니다.
- 그런 다음 JavaScript 엔진을 불러와서 해당 <script> 태그의 내용을 실행합니다.
- JavaScript 코드가 실행된 이후에야 HTML 파서가 다시 이어서 HTML 문서를 읽어가며 작업을 진행합니다.
만약 <script> 태그 내부의 코드가 실행하는 데 오랜 시간이 걸린다면, 그동안 HTML 파서는 멈추게 되어 웹 페이지의 나머지 부분이 늦게 로드될 수 있습니다.
2. defer와 async 속성의 역할
이 문제를 해결하기 위해 <script> 태그에 defer나 async 속성을 추가할 수 있습니다.
- defer 속성: HTML 파서가 HTML 문서를 쭉 해석하면서 <script defer> 태그를 만나도 멈추지 않고 계속해서 HTML을 해석합니다. HTML 문서의 해석이 모두 끝난 후에야 JavaScript 코드가 실행됩니다. 따라서 HTML 문서가 완전히 로드된 후에 JavaScript가 실행되므로 HTML 요소와의 연동이 원활하고, 페이지 로드가 빨라집니다.
👉 HTML이 모두 로드된 후에 JavaScript가 실행되므로, JavaScript가 HTML 요소에 안전하게 접근할 수 있습니다.
HTML 해석 -> 모든 HTML 해석 완료 후 Javascript 실행
- async 속성: HTML 파서가 HTML을 해석하면서 <script async> 태그를 만나면, JavaScript 파일을 비동기적으로 로드하기 시작합니다. JavaScript 파일이 로드되는 동안 HTML 파서는 계속 해석합니다. 하지만 JavaScript 파일이 다 로드되면 HTML 파서가 멈추고, JavaScript를 바로 실행합니다. JavaScript 실행이 끝나면 다시 HTML 해석을 이어갑니다.
HTML 해석 시작 → JavaScript 파일이 로드 완료되면 HTML 해석 중단 → JavaScript 실행 → 남은 HTML 해석 재개.
3. type="module" 속성의 특징
type="module" 속성을 <script> 태그에 추가하면 모듈 방식으로 JavaScript를 불러올 수 있습니다.
- type="module"을 사용하면 자동으로 defer 속성과 비슷한 효과를 얻을 수 있습니다. 즉, HTML 문서의 파싱이 끝난 후에 실행되어, DOM이 준비되기 전에 스크립트가 로드되는 것을 방지합니다.
- JavaScript 코드가 페이지 로딩을 막지 않고 비동기적으로 로드되고 실행됩니다. 덕분에 페이지 로딩 성능이 개선되고, HTML 문서가 파싱될 때 필요한 스크립트가 준비되지 않은 상태에서 호출되는 문제도 해결됩니다.
- 즉, defer 속성을 추가하지 않아도 마치 defer처럼 HTML 파서가 HTML을 모두 해석한 뒤에 JavaScript 코드를 실행합니다.
4. 모듈(module)을 사용하는 이유: 코드 충돌 방지 -> 5. 장점과 이어짐. 장점때문에 모듈을 사용하는 것.
기존 방식(ES6 이전)에서는 여러 외부 JavaScript 파일을 <script src="..."></script> 방식으로 가져왔습니다.
그러나 이 방식은 여러 라이브러리나 코드가 서로 전역 변수나 함수 이름이 충돌할 가능성이 있습니다.
> 전역 변수 충돌 방지:
- 모듈은 자체적인 스코프(scope)를 가지므로, 기본적으로 전역 범위(global scope)에서 다른 스크립트와 변수가 충돌할 위험이 없습니다.
- module 속성이 없을 때, 일반적으로 HTML에서 <script>로 불러오는 스크립트는 모두 같은 전역 스코프를 공유하게 되는데, 이는 변수 이름 충돌을 유발할 수 있습니다.
- type="module"을 지정하면, 해당 스크립트 파일의 모든 변수와 함수는 모듈 자체의 스코프 안에서만 유효하게 됩니다.
예시: 내가 사용하는 코드에서 이미 h1이라는 변수가 전역으로 정의되어 있는데, 외부 라이브러리에도 동일한 h1 변수가 정의되어 있을 경우 충돌이 발생할 수 있습니다.
5. ES6 모듈의 장점: 안전한 네임스페이스 제공
- ES6에서는 type="module"을 통해 모듈 단위로 import와 export를 사용해 JavaScript를 불러올 수 있게 되었습니다.
- 모듈은 독립적인 네임스페이스를 제공하므로, 각 모듈 내부의 변수나 함수가 전역으로 퍼지지 않고 모듈 내에서만 사용됩니다. 따라서 여러 라이브러리를 가져와도 코드 충돌이 발생하지 않습니다.
- 또한 이는 라이브러리나 외부 기능을 쉽게 재사용할 수 있게 하고, 코드 구조를 모듈 단위로 분리할 수 있어 유지 보수성과 가독성이 좋아집니다.
결론적으로 type="module" 속성을 통해 JavaScript 모듈을 사용하면, 코드를 안전하게 분리하고 유지보수에 유리한 환경을 만들 수 있습니다.