๋‚ด์žฅ ๋ธŒ๋ผ์šฐ์ € <script> ์ปดํฌ๋„ŒํŠธ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋ฌธ์„œ์— ์Šคํฌ๋ฆฝํŠธ๋ฅผ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

<script> alert("hi!") </script>

๋ ˆํผ๋Ÿฐ์Šค

<script>

๋ฌธ์„œ์— ์ธ๋ผ์ธ ๋˜๋Š” ์™ธ๋ถ€ ์Šคํฌ๋ฆฝํŠธ๋ฅผ ์ถ”๊ฐ€ํ•˜๋ ค๋ฉด ๋‚ด์žฅ ๋ธŒ๋ผ์šฐ์ € <script> ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋ Œ๋”๋งํ•˜์„ธ์š”. <script>๋Š” ์–ด๋–ค ์ปดํฌ๋„ŒํŠธ์—์„œ๋“  ๋ Œ๋”๋งํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, React๋Š” ํŠน์ • ๊ฒฝ์šฐ์— ํ•ด๋‹น DOM ์š”์†Œ๋ฅผ ๋ฌธ์„œ์˜ <head>์— ๋ฐฐ์น˜ํ•˜๊ณ  ์ค‘๋ณต๋œ ๋™์ผ ์Šคํฌ๋ฆฝํŠธ๋ฅผ ์ œ๊ฑฐํ•ฉ๋‹ˆ๋‹ค.

<script> alert("hi!") </script>
<script src="script.js" />

์•„๋ž˜ ์˜ˆ์‹œ๋ฅผ ์ฐธ๊ณ ํ•˜์„ธ์š”.

Props

<script>๋Š” ๋ชจ๋“  ๊ณตํ†ต ์ปดํฌ๋„ŒํŠธ ์†์„ฑ์„ ์ง€์›ํ•ฉ๋‹ˆ๋‹ค.

children ๋˜๋Š” src ์†์„ฑ์„ ๊ฐ€์ ธ์•ผ ํ•ฉ๋‹ˆ๋‹ค.

  • children: ๋ฌธ์ž์—ด. ์ธ๋ผ์ธ ์Šคํฌ๋ฆฝํŠธ์˜ ์†Œ์Šค ์ฝ”๋“œ.
  • src: ๋ฌธ์ž์—ด. ์™ธ๋ถ€ ์Šคํฌ๋ฆฝํŠธ์˜ URL.

์ง€์›ํ•˜๋Š” ๋‹ค๋ฅธ ์†์„ฑ๋“ค:

  • async: ๋ถˆ๋ฆฌ์–ธ ๊ฐ’. ๋ธŒ๋ผ์šฐ์ €๊ฐ€ ๋ฌธ์„œ์˜ ๋‚จ์€ ๋ถ€๋ถ„์„ ์ฒ˜๋ฆฌํ•  ๋•Œ๊นŒ์ง€ ์Šคํฌ๋ฆฝํŠธ ์‹คํ–‰์„ ์—ฐ๊ธฐํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•ฉ๋‹ˆ๋‹ค. ์ด๋Š” ์„ฑ๋Šฅ์„ ์œ„ํ•œ ์šฐ์„ ์ ์ธ ๋™์ž‘ ๋ฐฉ์‹์ž…๋‹ˆ๋‹ค.
  • crossOrigin: ๋ฌธ์ž์—ด. ์‚ฌ์šฉํ•  CORS ์ •์ฑ…์ž…๋‹ˆ๋‹ค. ๊ฐ€๋Šฅํ•œ ๊ฐ’์€ anonymous์™€ use-credentials์ž…๋‹ˆ๋‹ค.
  • fetchPriority: ๋ฌธ์ž์—ด. ์—ฌ๋Ÿฌ ์Šคํฌ๋ฆฝํŠธ๋ฅผ ๋™์‹œ์— ๊ฐ€์ ธ์˜ฌ ๋•Œ ๋ธŒ๋ผ์šฐ์ €๊ฐ€ ์Šคํฌ๋ฆฝํŠธ๋ฅผ ์šฐ์„ ์ˆœ์œ„๋กœ ์ˆœ์œ„ ์ง€์ •ํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•ฉ๋‹ˆ๋‹ค. "high", "low", ๋˜๋Š” "auto" (๊ธฐ๋ณธ๊ฐ’)์ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • integrity: ๋ฌธ์ž์—ด. ์Šคํฌ๋ฆฝํŠธ์˜ ์•”ํ˜ธํ™” ํ•ด์‹œ๋กœ, ์ง„์œ„์„ฑ์„ ๊ฒ€์ฆํ•ฉ๋‹ˆ๋‹ค.
  • noModule: ๋ถˆ๋ฆฌ์–ธ ๊ฐ’. ES ๋ชจ๋“ˆ์„ ์ง€์›ํ•˜๋Š” ๋ธŒ๋ผ์šฐ์ €์—์„œ ์Šคํฌ๋ฆฝํŠธ๋ฅผ ๋น„ํ™œ์„ฑํ™”ํ•ฉ๋‹ˆ๋‹ค. ES ๋ชจ๋“ˆ์„ ์ง€์›ํ•˜์ง€ ์•Š๋Š” ๋ธŒ๋ผ์šฐ์ €์— ๋Œ€ํ•œ ๋Œ€์ฒด ์Šคํฌ๋ฆฝํŠธ๋ฅผ ํ—ˆ์šฉํ•ฉ๋‹ˆ๋‹ค.
  • nonce: ๋ฌธ์ž์—ด. ์—„๊ฒฉํ•œ ์ฝ˜ํ…์ธ  ๋ณด์•ˆ ์ •์ฑ…์„ ์‚ฌ์šฉํ•  ๋•Œ ๋ฆฌ์†Œ์Šค๋ฅผ ํ—ˆ์šฉํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉํ•˜๋Š” ์•”ํ˜ธํ™”๋œ nonce์ž…๋‹ˆ๋‹ค.
  • referrer: ๋ฌธ์ž์—ด. ์Šคํฌ๋ฆฝํŠธ๋ฅผ ๊ฐ€์ ธ์˜ค๊ณ  ์Šคํฌ๋ฆฝํŠธ๊ฐ€ ๋‹ค์‹œ ๊ฐ€์ ธ์˜จ ๋ฆฌ์†Œ์Šค๋ฅผ ๊ฐ€์ ธ์˜ฌ ๋•Œ ๋ณด๋‚ผ Referer ํ—ค๋”๋ฅผ ์ง€์ •ํ•ฉ๋‹ˆ๋‹ค.
  • type: ๋ฌธ์ž์—ด. ์Šคํฌ๋ฆฝํŠธ๊ฐ€ ์ „ํ†ต์ ์ธ ์Šคํฌ๋ฆฝํŠธ, ES ๋ชจ๋“ˆ ๋˜๋Š” import ๋งต์ธ์ง€๋ฅผ ๋‚˜ํƒ€๋ƒ…๋‹ˆ๋‹ค.

React์˜ ์Šคํฌ๋ฆฝํŠธ ํŠน์ˆ˜ ์ฒ˜๋ฆฌ๋ฅผ ๋น„ํ™œ์„ฑํ™”ํ•˜๋Š” ์†์„ฑ๋“ค:

  • onError: ํ•จ์ˆ˜. ์Šคํฌ๋ฆฝํŠธ์˜ ๋กœ๋”ฉ์„ ์‹คํŒจํ•˜์˜€์„ ๋•Œ ํ˜ธ์ถœ๋ฉ๋‹ˆ๋‹ค.
  • onLoad: ํ•จ์ˆ˜. ์Šคํฌ๋ฆฝํŠธ์˜ ๋กœ๋”ฉ์„ ์™„๋ฃŒํ•˜์˜€์„ ๋•Œ ํ˜ธ์ถœ๋ฉ๋‹ˆ๋‹ค.

React์—์„œ ๊ถŒ์žฅํ•˜์ง€ ์•Š๋Š” ์†์„ฑ๋“ค:

  • blocking: ๋ฌธ์ž์—ด. "render"๋กœ ์„ค์ •ํ•˜๋ฉด ํŽ˜์ด์ง€๊ฐ€ ์Šคํฌ๋ฆฝํŠธ์‹œํŠธ๋ฅผ ๋กœ๋“œํ•  ๋•Œ๊นŒ์ง€ ๋ธŒ๋ผ์šฐ์ €์—๊ฒŒ ํŽ˜์ด์ง€๋ฅผ ๋ Œ๋”๋งํ•˜์ง€ ์•Š๋„๋ก ์ง€์‹œํ•ฉ๋‹ˆ๋‹ค. React๋Š” Suspense๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋” ์„ธ๋ฐ€ํ•œ ์ œ์–ด๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.
  • defer: ๋ฌธ์ž์—ด. ๋ฌธ์„œ๊ฐ€ ๋กœ๋”ฉ๋  ๋•Œ๊นŒ์ง€ ๋ธŒ๋ผ์šฐ์ €๊ฐ€ ์Šคํฌ๋ฆฝํŠธ๋ฅผ ์‹คํ–‰ํ•˜์ง€ ๋ชปํ•˜๋„๋ก ํ•ฉ๋‹ˆ๋‹ค. ์ŠคํŠธ๋ฆฌ๋ฐ ์„œ๋ฒ„์— ๋ Œ๋”๋ง๋œ ์ปดํฌ๋„ŒํŠธ์™€ ํ˜ธํ™˜๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๋Œ€์‹  async ์†์„ฑ์„ ์‚ฌ์šฉํ•˜์„ธ์š”.

ํŠน๋ณ„ํ•œ ๋ Œ๋”๋ง ๋™์ž‘

React๋Š” <script> ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋ฌธ์„œ์˜ <head>๋กœ ์ด๋™์‹œํ‚ค๊ณ , ์ค‘๋ณต๋œ ๋™์ผ ์Šคํฌ๋ฆฝํŠธ๋ฅผ ์ œ๊ฑฐํ•ฉ๋‹ˆ๋‹ค.

์ด ๋™์ž‘์„ ์‚ฌ์šฉํ•˜๋ ค๋ฉด src์™€ async={true} ์†์„ฑ์„ ์ œ๊ณตํ•˜์„ธ์š”. React๋Š” src๊ฐ€ ๋™์ผํ•œ ๊ฒฝ์šฐ์—๋งŒ ์ค‘๋ณต๋œ ์Šคํฌ๋ฆฝํŠธ๋ฅผ ์ œ๊ฑฐํ•ฉ๋‹ˆ๋‹ค. ์Šคํฌ๋ฆฝํŠธ๋ฅผ ์•ˆ์ „ํ•˜๊ฒŒ ์ด๋™ํ•˜๋ ค๋ฉด async ์†์„ฑ์ด ๋ฐ˜๋“œ์‹œ true์—ฌ์•ผ ํ•ฉ๋‹ˆ๋‹ค.

์ด ํŠน๋ณ„ํ•œ ์ฒ˜๋ฆฌ์—๋Š” ๋‘ ๊ฐ€์ง€ ์ฃผ์˜ ์‚ฌํ•ญ์ด ์žˆ์Šต๋‹ˆ๋‹ค.

  • React๋Š” ์Šคํฌ๋ฆฝํŠธ๋ฅผ ๋ Œ๋”๋งํ•œ ํ›„์— ์†์„ฑ ๋ณ€๊ฒฝ์„ ๋ฌด์‹œํ•ฉ๋‹ˆ๋‹ค. (๊ฐœ๋ฐœ ํ™˜๊ฒฝ์—์„œ๋Š” ์ด๋Ÿฌํ•œ ๊ฒฝ์šฐ์— ๊ฒฝ๊ณ ๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.)
  • React๋Š” ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋งˆ์šดํŠธ ํ•ด์ œํ•œ ํ›„์—๋„ DOM์— ์Šคํฌ๋ฆฝํŠธ๋ฅผ ๋‚จ๊ธธ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. (์Šคํฌ๋ฆฝํŠธ๋Š” DOM์— ์‚ฝ์ž…๋  ๋•Œ ํ•œ ๋ฒˆ๋งŒ ์‹คํ–‰๋˜๋ฏ€๋กœ ์ด๊ฒƒ์€ ์˜ํ–ฅ์„ ๋ฏธ์น˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.)

์‚ฌ์šฉ๋ฒ•

์™ธ๋ถ€ ์Šคํฌ๋ฆฝํŠธ ๋ Œ๋”๋ง

ํŠน์ • ์Šคํฌ๋ฆฝํŠธ์— ์˜์กดํ•˜์—ฌ ์ปดํฌ๋„ŒํŠธ๋ฅผ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ํ‘œ์‹œํ•ด์•ผ ํ•œ๋‹ค๋ฉด, ์ปดํฌ๋„ŒํŠธ ๋‚ด์—์„œ <script>๋ฅผ ๋ Œ๋”๋งํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์Šคํฌ๋ฆฝํŠธ ๋กœ๋”ฉ์ด ์™„๋ฃŒ๋˜๊ธฐ ์ „์— ์ปดํฌ๋„ŒํŠธ๊ฐ€ ์ปค๋ฐ‹๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. load ์ด๋ฒคํŠธ๊ฐ€ ๋ฐœ์ƒํ•˜๋ฉด ์Šคํฌ๋ฆฝํŠธ ๋‚ด์šฉ์— ๋”ฐ๋ผ ์‹œ์ž‘ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด onLoad prop ์„ ์ด์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

React๋Š” ๋™์ผํ•œ src๋ฅผ ๊ฐ€์ง„ ์ค‘๋ณต๋œ ์Šคํฌ๋ฆฝํŠธ๋ฅผ ์ œ๊ฑฐํ•˜์—ฌ ์—ฌ๋Ÿฌ ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋ Œ๋”๋งํ•˜๋”๋ผ๋„ ๊ทธ ์ค‘ ํ•˜๋‚˜๋งŒ DOM์— ์‚ฝ์ž…ํ•ฉ๋‹ˆ๋‹ค.

import ShowRenderedHTML from './ShowRenderedHTML.js';

function Map({lat, long}) {
  return (
    <>
      <script async src="map-api.js" onLoad={() => console.log('script loaded')} />
      <div id="map" data-lat={lat} data-long={long} />
    </>
  );
}

export default function Page() {
  return (
    <ShowRenderedHTML>
      <Map />
    </ShowRenderedHTML>
  );
}

์ค‘์š”ํ•ฉ๋‹ˆ๋‹ค!

์Šคํฌ๋ฆฝํŠธ๋ฅผ ์‚ฌ์šฉํ•˜๋ ค๋Š” ๊ฒฝ์šฐ, preinit ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•˜๋Š” ๊ฒƒ์ด ์œ ๋ฆฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•˜๋ฉด <script> ์ปดํฌ๋„ŒํŠธ๋ฅผ ๊ทธ๋ƒฅ ๋ Œ๋”๋งํ•˜๋Š” ๊ฒƒ๋ณด๋‹ค ๋ธŒ๋ผ์šฐ์ €๊ฐ€ ์Šคํฌ๋ฆฝํŠธ๋ฅผ ๋” ๋นจ๋ฆฌ ๊ฐ€์ ธ์˜ค๋„๋ก ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด HTTP Early Hints ์‘๋‹ต์„ ํ†ตํ•ด ์Šคํฌ๋ฆฝํŠธ๋ฅผ ๋” ๋นจ๋ฆฌ ๊ฐ€์ ธ์˜ฌ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ธ๋ผ์ธ ์Šคํฌ๋ฆฝํŠธ ๋ Œ๋”๋ง

์ธ๋ผ์ธ ์Šคํฌ๋ฆฝํŠธ๋ฅผ ํฌํ•จํ•˜๋ ค๋ฉด <script> ์ปดํฌ๋„ŒํŠธ๋ฅผ ์ž์‹์œผ๋กœ ์Šคํฌ๋ฆฝํŠธ ์†Œ์Šค ์ฝ”๋“œ์™€ ํ•จ๊ป˜ ๋ Œ๋”๋งํ•˜์„ธ์š”. ์ธ๋ผ์ธ ์Šคํฌ๋ฆฝํŠธ๋Š” ์ค‘๋ณต ์ œ๊ฑฐ๋˜๊ฑฐ๋‚˜ ๋ฌธ์„œ์˜ <head>๋กœ ์ด๋™ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

import ShowRenderedHTML from './ShowRenderedHTML.js';

function Tracking() {
  return (
    <script>
      ga('send', 'pageview');
    </script>
  );
}

export default function Page() {
  return (
    <ShowRenderedHTML>
      <h1>My Website</h1>
      <Tracking />
      <p>Welcome</p>
    </ShowRenderedHTML>
  );
}