리액트 모던 딥 다이브 책을 읽는 중에 타사 자바스크립트 실행의 지연이라는 대목이 눈에 들어왔고
script
태그를 통해 타사 스크립트를 적용 시킬 때 대부분 defer를 통해 로드하는 것이 좋다는 것에 의문을 가지고 다시 공부하기 시작했습니다.
<script>
태그의 사용 방법<script>
태그는 HTML 클라이언트 스크립트를 추가할 때 사용합니다. 또한 src 속성을 사용해 외부 스크립트 파일을 로드할 수 있습니다.
<script src="lodash.js"></script>
그렇다면 <script>
태그는 어디에 위치하는 것이 좋을까요? 이를 설명하기 전에 <script>
태그의 load와 브라우저 렌더링 과정을 먼저 이해해야 합니다. 브라우저 렌더링은 아래와 같은 순서로 이뤄집니다.
이 때 렌더링 엔진은 사용자의 편의성을 위해 모든 HTML이 파싱하는 것을 기다리지 않고 빠르게 브라우저의 렌더링 된 요소들을 화면에 그리려고 합니다. 이 때 <script>
태그를 만나면 메인 쓰레드는 <script>
태그의 다운로드와 실행을 우선순위로 가져갑니다. 이를 통해 다른 작업들은 다운로드와 실행이 끝날 때까지 미뤄집니다.
이런 이유로 <script>
태그는 body에 마지막에 작성하는 것이 좋습니다. 그렇다면 이런 blocking 문제를 해결하는 방법이 없을까요? 다행히 <script>
태그를 로드하는 다른 방법들이 있습니다.
<head>
에 <script>
를 작성하지만 </body>
태그 앞에 <script>
를 작성하는 것과 같은 효과를 낼 수 있습니다.<script src="lodash.js" defer></script>
<script src="lodash.js" async></script>
<script src="lodash.js"></script>
<script src="...">
태그의 선택적 속성입니다.<head>
섹션에 <script>
참조를 배치하여 로딩 프로세스에서 가능한 한 빨리 다운로드를 트리거 하는 동시에 JavaScript 리소스의 렌더링 차단 효과를 제거하는 간단한 방법입니다.<script>
참조보다 낮은 우선순위로 다운로드하여 페이지의 초기 렌더링에 더 중요한 다른 리소스를 빠르게 렌더링 가능합니다. ⇒ fetchpriority="high"
를 통해 우선순위를 높일 수도 있습니다.하지만 이러한 방법은 한 가지 큰 단점이 존재합니다. 외부 자바스크립트 코드를 특정한 페이지 또는 컴포넌트에서만 불러올 수 없다는 것입니다. 그렇기 때문에 google analyrics와 같이 통계 및 모니터링이 필요하지 않은 외부 스크립트라면 부적절한 방법입니다.
찾아봤더니 이미 많이들 사용하고 계신 방법이 있었습니다. 다른 분들의 회사에서도 사이즈가 큰 외부 코드를 이러한 방식으로 가져와 사용하고 있다고 하시더라고요.
const script = document.createElement("script");
script.src = "https://unpkg.com/lodash";
script.async = true;
document.body.appendChild(script);
이 4줄만 사용하면 script 태그를 언제든지 동적으로 삽입하고 제거할 수 있습니다. 그럼 간단하게 react에서 직접 만들어 추가할 수 있지만... 사람들이 많이 사용하고 있는 useScript 오픈소스 오픈소스 코드를 공유해 드리겠습니다. 직접 만들어 보는 것도 좋을 것 같습니다.
import React from 'react';
import { StripeProvider } from 'react-stripe-elements';
import useScript from 'react-script-hook';
import MyCheckout from './my-checkout';
function App() {
const [loading, error] = useScript({ src: 'https://js.stripe.com/v3/' });
if (loading) return <h3>Loading Stripe API...</h3>;
if (error) return <h3>Failed to load Stripe API: {error.message}</h3>;
return (
<StripeProvider apiKey="pk_test_6pRNASCoBOKtIshFeQd4XMUh">
<MyCheckout />
</StripeProvider>
);
}
export default App;
위와 같이 사용한다면 언제든지 특정 컴포넌트나 페이지에서 외부 스크립트를 동적으로 사용 가능합니다.