PageSourceSearch

https://webpack.kr/1930.46b4d2a6b8e67f86.js

js webpack.kr collected 2026-09-25 23:35:21 UTC 90,782 bytes, 1 lines download raw bytes

1"use strict";(self.webpackChunk=self.webpackChunk||[]).push([[1930],{1930:function(n,e,s){s.r(e),s.d(e,{default:function(){return l}});var a=s(2540),c=s(9710);function t(n){const e={a:"a",aside:"aside",code:"code",h2:"h2",h3:"h3",li:"li",p:"p",pre:"pre",span:"span",strong:"strong",ul:"ul",...(0,c.R)(),...n.components};return(0,a.jsxs)(a.Fragment,{children:[(0,a.jsxs)(e.p,{children:["Webpack 5.107이 출시되었습니다. 이번 릴리스의 핵심은 webpack core에서 ",(0,a.jsx)(e.code,{children:".html"})," 파일을 네이티브하게 처리하기 위한 첫 단계입니다. 이제 JS에서 HTML 파일을 import하면 ê·¸ 안의 ",(0,a.jsx)(e.code,{children:"<img src>"}),", ",(0,a.jsx)(e.code,{children:"<link href>"}),", 인라인 ",(0,a.jsx)(e.code,{children:"<style>"}),", ",(0,a.jsx)(e.code,{children:"<script src>"})," 참조가 일반적인 webpack pipeline을 통해 해석되며, 오랫동안 ",(0,a.jsx)(e.code,{children:"html-loader"}),"가 맡아오던 역할을 대체하기 시작합니다. HTML entry points(",(0,a.jsx)(e.code,{children:"html-webpack-plugin"}),"이 담당하던 부분)는 아직 5.107에 포함되지 않았고, 다음 마이너 릴리스에서 도입될 예정입니다."]}),"\n",(0,a.jsxs)(e.p,{children:["이번 릴리스에는 Node.js의 내장 type-stripping 기능을 활용하는 실험적 TypeScript 지원도 포함되었습니다. 덕분에 단순한 TypeScript 프로젝트라면 ",(0,a.jsx)(e.code,{children:"ts-loader"}),"나 ",(0,a.jsx)(e.code,{children:"swc-loader"})," 없이도 컴파일할 수 있습니다."]}),"\n",(0,a.jsx)(e.p,{children:"두 기능 모두 experimental이며 opt-in flag 뒤에 숨겨져 있지만, 방향성은 분명합니다. 결국에는 HTML, CSS, 기본적인 TypeScript를 처리하기 위해 추가 loader나 plugin 없이 완전한 웹 앱을 빌드할 수 있게 하려는 것입니다."}),"\n",(0,a.jsx)(e.p,{children:"이러한 실험적 작업과 함께, 이번 릴리스에서는 내장 CSS pipeline도 계속 성숙해지고 있으며, tree shaking, deferred imports, module resolution에도 여러 개선 사항이 포함되었습니다."}),"\n",(0,a.jsx)(e.p,{children:"이번 릴리스의 새로운 기능을 살펴보세요:"}),"\n",(0,a.jsxs)(e.ul,{children:["\n",(0,a.jsxs)(e.li,{children:[(0,a.jsx)(e.a,{href:"#html-modules-experimental",children:(0,a.jsx)(e.strong,{children:"HTML Modules (Experimental)"})}),"\n",(0,a.jsxs)(e.ul,{children:["\n",(0,a.jsx)(e.li,{children:(0,a.jsxs)(e.a,{href:"#experimentshtml-flag",children:[(0,a.jsx)(e.code,{children:"experiments.html"})," 플래그"]})}),"\n",(0,a.jsx)(e.li,{children:(0,a.jsxs)(e.a,{href:"#inline-style-tags",children:["인라인 ",(0,a.jsx)(e.code,{children:"<style>"})," 태그"]})}),"\n",(0,a.jsx)(e.li,{children:(0,a.jsxs)(e.a,{href:"#inline-script-tags",children:["인라인 ",(0,a.jsx)(e.code,{children:"<script>"})," 태그"]})}),"\n",(0,a.jsx)(e.li,{children:(0,a.jsxs)(e.a,{href:"#script-src-and-link-relmodulepreload",children:[(0,a.jsx)(e.code,{children:"<script src>"}),"와 ",(0,a.jsx)(e.code,{children:'<link rel="modulepreload">'})]})}),"\n",(0,a.jsx)(e.li,{children:(0,a.jsxs)(e.a,{href:"#webpackignore-magic-comment",children:[(0,a.jsx)(e.code,{children:"webpackIgnore"})," 매직 코멘트"]})}),"\n"]}),"\n"]}),"\n",(0,a.jsx)(e.li,{children:(0,a.jsx)(e.a,{href:"#typescript-support-experimental",children:(0,a.jsx)(e.strong,{children:"TypeScript Support (Experimental)"})})}),"\n",(0,a.jsxs)(e.li,{children:[(0,a.jsx)(e.a,{href:"#css-improvements",children:(0,a.jsx)(e.strong,{children:"CSS Improvements"})}),"\n",(0,a.jsxs)(e.ul,{children:["\n",(0,a.jsx)(e.li,{children:(0,a.jsx)(e.a,{href:"#scope-hoisting-for-css-modules",children:"CSS Modules를 위한 Scope Hoisting"})}),"\n",(0,a.jsx)(e.li,{children:(0,a.jsx)(e.a,{href:"#pure-mode-for-css-modules",children:"CSS Modules를 위한 Pure Mode"})}),"\n",(0,a.jsx)(e.li,{children:(0,a.jsxs)(e.a,{href:"#value-in-urls-and-import",children:[(0,a.jsx)(e.code,{children:"@import"}),"와 URL에서의 ",(0,a.jsx)(e.code,{children:"@value"})]})}),"\n",(0,a.jsx)(e.li,{children:(0,a.jsxs)(e.a,{href:"#multiple-aliases-via-exportsconvention",children:[(0,a.jsx)(e.code,{children:"exportsConvention"}),"을 통한 여러 별칭"]})}),"\n",(0,a.jsx)(e.li,{children:(0,a.jsxs)(e.a,{href:"#linkinsert-hook",children:[(0,a.jsx)(e.code,{children:"linkInsert"})," hook"]})}),"\n",(0,a.jsx)(e.li,{children:(0,a.jsxs)(e.a,{href:"#ordermodules-hook",children:[(0,a.jsx)(e.code,{children:"orderModules"})," hook"]})}),"\n"]}),"\n"]}),"\n",(0,a.jsxs)(e.li,{children:[(0,a.jsx)(e.a,{href:"#javascript-and-esm",children:(0,a.jsx)(e.strong,{children:"JavaScript and ESM"})}),"\n",(0,a.jsxs)(e.ul,{children:["\n",(0,a.jsx)(e.li,{children:(0,a.jsx)(e.a,{href:"#anonymous-default-export-naming",children:"익명 default export 이름 지정"})}),"\n",(0,a.jsx)(e.li,{children:(0,a.jsxs)(e.a,{href:"#preserving-defer-and-source-phase-on-externals",children:["externals에서 ",(0,a.jsx)(e.code,{children:"defer"}),"와 ",(0,a.jsx)(e.code,{children:"source"})," phase 유지"]})}),"\n",(0,a.jsx)(e.li,{children:(0,a.jsxs)(e.a,{href:"#__no_side_effects__-annotation",children:[(0,a.jsx)(e.code,{children:"#__NO_SIDE_EFFECTS__"})," annotation"]})}),"\n"]}),"\n"]}),"\n",(0,a.jsx)(e.li,{children:(0,a.jsx)(e.a,{href:"#resolver-updates",children:(0,a.jsx)(e.strong,{children:"Resolver Updates"})})}),"\n",(0,a.jsx)(e.li,{children:(0,a.jsx)(e.a,{href:"#bug-fixes",children:(0,a.jsx)(e.strong,{children:"Bug Fixes"})})}),"\n"]}),"\n",(0,a.jsxs)(e.h2,{children:[(0,a.jsx)(e.span,{id:"html-modules-experimental"}),"HTML Modules (Experimental)",(0,a.jsx)(e.a,{href:"#html-modules-experimental","aria-hidden":"true",tabIndex:"-1",children:(0,a.jsx)(e.span,{className:"header-link"})})]}),"\n",(0,a.jsxs)(e.aside,{className:"warning",children:[(0,a.jsx)(e.p,{className:"warning__prefix",children:"warning"}),(0,a.jsxs)(e.p,{children:[(0,a.jsx)(e.strong,{children:"이 기능은 experimental이며 아직 일부만 구현되어 있습니다."})," Webpack 5.107은 현재 ",(0,a.jsx)(e.code,{children:"html-loader"}),"가 담당하던 부분만 구현합니다. 즉, JavaScript에서 HTML 파일ì
1„ import하면 ê·¸ 안의 태그 참조가 webpack pipeline을 통해 처리됩니다. ",(0,a.jsx)(e.strong,{children:"HTML entry points"}),"(",(0,a.jsx)(e.code,{children:".html"})," 파일을 ",(0,a.jsx)(e.code,{children:"entry"}),"로 직접 사용하는 방식, 즉 ",(0,a.jsx)(e.code,{children:"html-webpack-plugin"}),"이 맡던 부분)는 ",(0,a.jsx)(e.strong,{children:"아직 지원되지 않으며"}),", 다음 마이너 릴리스에서 도입될 예정입니다. 전체 작업은 이슈 ",(0,a.jsx)(e.a,{href:"https://github.com/webpack/webpack/issues/536",children:"#536"}),"에서 추적되고 있습니다."]})]}),"\n",(0,a.jsxs)(e.p,{children:["실제 webpack 설정에서 HTML entry point를 사용하려면 역사적으로 최소 두 개의 추가 의존성이 필요했습니다. 하나는 HTML 파일을 생성하거나 출력하고 여기에 올바른 번들 URL을 주입해 주는 ",(0,a.jsx)(e.code,{children:"html-webpack-plugin"}),"입니다. 다른 하나는 ",(0,a.jsx)(e.code,{children:"<img src>"}),", ",(0,a.jsx)(e.code,{children:"<link href>"}),", ",(0,a.jsx)(e.code,{children:"<script src>"})," 등의 참조를 webpack이 순회할 수 있게 해, 이 참조들이 일반적인 resolver 및 asset pipeline을 거치게 해 주는 ",(0,a.jsx)(e.code,{children:"html-loader"}),"입니다."]}),"\n",(0,a.jsxs)(e.p,{children:["이 두 도구는 오랫동안 커뮤니티에 큰 도움이 되었지만, core 바깥에 존재해 왔습니다. Webpack 5.107은 이제 이 작업 중 ",(0,a.jsx)(e.code,{children:"html-loader"}),"가 맡던 부분을 core 안으로 가져오기 시작합니다."]}),"\n",(0,a.jsxs)(e.h3,{children:[(0,a.jsx)(e.span,{id:"experimentshtml-flag"}),(0,a.jsx)(e.code,{children:"experiments.html"})," Flag",(0,a.jsx)(e.a,{href:"#experimentshtml-flag","aria-hidden":"true",tabIndex:"-1",children:(0,a.jsx)(e.span,{className:"header-link"})})]}),"\n",(0,a.jsxs)(e.p,{children:["이 섹션의 나머지 기능은 모두 하나의 opt-in flag 뒤에 있습니다. 새로운 ",(0,a.jsx)(e.code,{children:"experiments.html"})," 옵션은 ",(0,a.jsx)(e.code,{children:"NormalModuleFactory"}),"에 ",(0,a.jsx)(e.code,{children:"html"})," module type을 등록하고, 아래에서 설명하는 HTML 동작을 활성화합니다."]}),"\n",(0,a.jsx)(e.pre,{children:(0,a.jsxs)(e.code,{className:"hljs language-js",children:[(0,a.jsx)(e.span,{className:"token comment",children:"// webpack.config.js"}),"\nmodule",(0,a.jsx)(e.span,{className:"token punctuation",children:"."}),"exports ",(0,a.jsx)(e.span,{className:"token operator",children:"="})," ",(0,a.jsx)(e.span,{className:"token punctuation",children:"{"}),"\n  ",(0,a.jsx)(e.span,{className:"token literal-property property",children:"experiments"}),(0,a.jsx)(e.span,{className:"token operator",children:":"})," ",(0,a.jsx)(e.span,{className:"token punctuation",children:"{"}),"\n    ",(0,a.jsx)(e.span,{className:"token literal-property property",children:"html"}),(0,a.jsx)(e.span,{className:"token operator",children:":"})," ",(0,a.jsx)(e.span,{className:"token boolean",children:"true"}),(0,a.jsx)(e.span,{className:"token punctuation",children:","}),"\n  ",(0,a.jsx)(e.span,{className:"token punctuation",children:"}"}),(0,a.jsx)(e.span,{className:"token punctuation",children:","}),"\n",(0,a.jsx)(e.span,{className:"token punctuation",children:"}"}),(0,a.jsx)(e.span,{className:"token punctuation",children:";"})]})}),"\n",(0,a.jsx)(e.p,{children:"그다음 JavaScript에서 HTML 파일을 import합니다. default export는 처리된 HTML 문자열이며, 모든 asset 참조는 webpack을 통해 해석됩니다."}),"\n",(0,a.jsx)(e.pre,{children:(0,a.jsxs)(e.code,{className:"hljs language-js",children:[(0,a.jsx)(e.span,{className:"token comment",children:"// src/index.js"}),"\n",(0,a.jsx)(e.span,{className:"token keyword",children:"import"})," page ",(0,a.jsx)(e.span,{className:"token keyword",children:"from"})," ",(0,a.jsx)(e.span,{className:"token string",children:'"./page.html"'}),(0,a.jsx)(e.span,{className:"token punctuation",children:";"}),"\n\ndocument",(0,a.jsx)(e.span,{className:"token punctuation",children:"."}),"documentElement",(0,a.jsx)(e.span,{className:"token punctuation",children:"."}),"innerHTML ",(0,a.jsx)(e.span,{className:"token operator",children:"="})," page",(0,a.jsx)(e.span,{className:"token punctuation",children:";"})]})}),"\n",(0,a.jsxs)(e.p,{children:["이 결과물의 형태는 ",(0,a.jsx)(e.code,{children:"html-loader"}),"가 생성하던 것과 동일하므로, HTML을 import하던 기존 코드는 계속 동작해야 합니다. 이제 loader가 하던 일을 pipeline이 직접 수행합니다. 태그 참조는 해석되고, 해시된 파일 이름은 다시 HTML 문자열 안에 반영되며, 최종 결과는 JS 번들에 포함됩니다. ",(0,a.jsx)(e.code,{children:".html"}
1)," 파일을 webpack ",(0,a.jsx)(e.code,{children:"entry"}),"로 직접 사용하는 것은 5.107에서 ",(0,a.jsx)(e.strong,{children:"지원되지 않습니다"}),"."]}),"\n",(0,a.jsxs)(e.h3,{children:[(0,a.jsx)(e.span,{id:"inline-style-tags"}),"Inline ",(0,a.jsx)(e.code,{children:"<style>"})," Tags",(0,a.jsx)(e.a,{href:"#inline-style-tags","aria-hidden":"true",tabIndex:"-1",children:(0,a.jsx)(e.span,{className:"header-link"})})]}),"\n",(0,a.jsxs)(e.p,{children:["webpack이 HTML module 내부에서 ",(0,a.jsx)(e.code,{children:"<style>"})," 블록을 발견하면, 그 CSS 본문을 ",(0,a.jsx)(e.code,{children:".css"})," 파일에 사용하는 것과 동일한 CSS pipeline으로 전달합니다. 이 블록은 ",(0,a.jsx)(e.code,{children:'exportType: "text"'}),"를 갖는 가상 CSS module로 처리되므로, 스타일 내부의 ",(0,a.jsx)(e.code,{children:"url()"})," 참조와 ",(0,a.jsx)(e.code,{children:"@import"})," 구문은 HTML 파일을 기준으로 해석됩니다. 처리가 끝나면 변환된 CSS가 출력 HTML 문자열의 원래 ",(0,a.jsx)(e.code,{children:"<style>"})," 태그 안에 다시 기록됩니다."]}),"\n",(0,a.jsx)(e.pre,{children:(0,a.jsxs)(e.code,{className:"hljs language-html",children:[(0,a.jsx)(e.span,{className:"token comment",children:"\x3c!-- src/page.html --\x3e"}),"\n",(0,a.jsxs)(e.span,{className:"token doctype",children:[(0,a.jsx)(e.span,{className:"token punctuation",children:"<!"}),(0,a.jsx)(e.span,{className:"token doctype-tag",children:"doctype"})," ",(0,a.jsx)(e.span,{className:"token name",children:"html"}),(0,a.jsx)(e.span,{className:"token punctuation",children:">"})]}),"\n",(0,a.jsxs)(e.span,{className:"token tag",children:[(0,a.jsxs)(e.span,{className:"token tag",children:[(0,a.jsx)(e.span,{className:"token punctuation",children:"<"}),"html"]}),(0,a.jsx)(e.span,{className:"token punctuation",children:">"})]}),"\n  ",(0,a.jsxs)(e.span,{className:"token tag",children:[(0,a.jsxs)(e.span,{className:"token tag",children:[(0,a.jsx)(e.span,{className:"token punctuation",children:"<"}),"head"]}),(0,a.jsx)(e.span,{className:"token punctuation",children:">"})]}),"\n    ",(0,a.jsxs)(e.span,{className:"token tag",children:[(0,a.jsxs)(e.span,{className:"token tag",children:[(0,a.jsx)(e.span,{className:"token punctuation",children:"<"}),"style"]}),(0,a.jsx)(e.span,{className:"token punctuation",children:">"})]}),'\n      @import "./reset.css";\n\n      body {\n        background: url("./bg.png");\n      }\n    ',(0,a.jsxs)(e.span,{className:"token tag",children:[(0,a.jsxs)(e.span,{className:"token tag",children:[(0,a.jsx)(e.span,{className:"token punctuation",children:"</"}),"style"]}),(0,a.jsx)(e.span,{className:"token punctuation",children:">"})]}),"\n  ",(0,a.jsxs)(e.span,{className:"token tag",children:[(0,a.jsxs)(e.span,{className:"token tag",children:[(0,a.jsx)(e.span,{className:"token punctuation",children:"</"}),"head"]}),(0,a.jsx)(e.span,{className:"token punctuation",children:">"})]}),"\n  ",(0,a.jsxs)(e.span,{className:"token tag",children:[(0,a.jsxs)(e.span,{className:"token tag",children:[(0,a.jsx)(e.span,{className:"token punctuation",children:"<"}),"body"]}),(0,a.jsx)(e.span,{className:"token punctuation",children:">"})]}),"\n    ...\n  ",(0,a.jsxs)(e.span,{className:"token tag",children:[(0,a.jsxs)(e.span,{className:"token tag",children:[(0,a.jsx)(e.span,{className:"token punctuation",children:"</"}),"body"]}),(0,a.jsx)(e.span,{className:"token punctuation",children:">"})]}),"\n",(0,a.jsxs)(e.span,{className:"token tag",children:[(0,a.jsxs)(e.span,{className:"token tag",children:[(0,a.jsx)(e.span,{className:"token punctuation",children:"</"}),"html"]}),(0,a.jsx)(e.span,{className:"token punctuation",children:">"})]})]})}),"\n",(0,a.jsxs)(e.p,{children:[(0,a.jsx)(e.code,{children:'<style type="text/css">'}),"와 ",(0,a.jsx)(e.code,{children:"type"})," 속성이 없는 ",(0,a.jsx)(e.code,{children:"<style>"}),"은 처리됩니다. CSS가 아닌 ",(0,a.jsx)(e.code,{children:"type"}),"을 가진 경우에는 변경 없이 그대로 통과합니다. 이를 통해 pipeline에 ",(0,a.jsx)(e.code,{children:"html-loader"}),"를 넣지 않아도 인라인 스타일 관련 동작을 처리할 수 있습니다."]}),"\n",(0,a.jsxs)(e.h3,{children:[(0,a.jsx)(e.span,{id:"inline-script-tags"}),"Inline ",(0,a.jsx)(e.code,{children:"<script>"})," Tags",(0,a.jsx)(e.a,{href:"#inline-script-tags","aria-hidden":"true",tabIndex:"-1",children:(0,a.jsx)(e.span,{className:"header-link"})})]}),"\n",(0,a.jsxs)(e.p,{children:["인라인 ",(0,a.jsx)(e.code,{children:"<script>"})," 본문은 이미 ",(0,a.jsx)(e.code,{children:"<script src>"}),"를 처리하는 것과 동일한 entry pipeline으로 전달됩니다. 각 ",(0,a.jsx)(e.code,{children:"<script>"})," 본문은 각각의 webpack entry가 됩니다. 일반적인 인라인 스크립트는 CommonJS로 번들링되고, ",(0,a.jsx)(e.code,{children:'<script type="module">'})," 본문은 ESM으로 번들링됩니다. 출력된 HTML의 태그는 생성된 청크를 가리키는 ",(0,a.jsx)(e.code,{children:'<script src="...">'})," 형태로 다시 작성되며, 본문은 비워집니다."]}),"\n",(0,a.jsx)(e.pre,{children:(0,a.jsxs)(e.code,{className:"hljs language-html",children:[(0,a.jsx)(e.span,{className:"token comment",children:"\x3c!-- src/page.html --\x3e"}),"\n",(0,a.jsxs)(e.span,{className:"token doctype",children:[(0,a.jsx)(e.span,{className:"token punctuation",children:"<!"}),(0,a.jsx)(e.span,{className:"token doctype-tag",children:"doctype"})," ",(0,a.jsx)(e.span,{className:"token name",children:"html"}),(0,a.jsx)(e.span,{className:"token punctuation",children:">"})]}),"\n",(0,a.jsxs)(e.span,{className:"token tag",children:[(0,a.jsxs)(e.span,{className:"token tag",children:[(0,a.jsx)(e.span,{className:"token punctuation",children:"<"}),"html"]}),(0,a.jsx)(e.span,{className:"token punctuation",children:">"})]}),"\n  ",(0,a.jsxs)(e.span,{className:"token tag",children:[(0,a.jsxs)(e.span,{className:"token tag",children:[(0,a.jsx)(e.span,{className:"token punctuation",children:"<"}),"body"]}),(0,a.jsx)(e.span,{className:"token punctuation",children:">"})]}),"\n    ",(0,a.jsxs)(e.span,{className:"token tag",children:[(0,a.jsxs)(e.span,{className:"token tag",children:[(0,a.jsx)(e.span,{className:"token punctuation",children:"<"}),"script"]})," ",(0,a.jsx)(e.span,{className:"token attr-name",children:"type"}),(0,a.jsxs)(e.span,{className:"token attr-value",children:[(0,a.jsx)(e.span,{className:"token punctuation attr-equals",children:"="}),(0,a.jsx)(e.span,{className:"token punctuation",children:'"'}),"module",(0,a.jsx)(e.span,{className:"token punctuation",children:'"'})]}),(0,a.jsx)(e.span,{className:"token punctuation",children:">"})]}),'\n      import { greet } from "./lib.js";\n      greet("world");\n    ',(0,a.jsxs)(e.span,{className:"token tag",children:[(0,a.jsxs)(e.span,{className:"token tag",children:[(0,a.jsx)(e.span,{className:"token punctuation",children:"</"}),"script"]}),(0,a.jsx)(e.span,{className:"token punctuation",children:">"})]}),"\n\n    ",(0,a.jsxs)(e.span,{className:"token tag",children:[(0,a.jsxs)(e.span,{className:"token tag",children:[(0,a.jsx)(e.span,{className:"token punctuation",children:"<"}),"script"]}),(0,a.jsx)(e.span,{className:"token punctuation",children:">"})]}),'\n      console.log("classic inline script");\n    ',(0,a.jsxs)(e.span,{className:"token tag",children:[(0,a.jsxs)(e.span,{className:"token tag",children:[(0,a.jsx)(e.span,{className:"token punctuation",children:"</"}),"script"]}),(0,a.jsx)(e.span,{className:"token punctuation",children:">"})]}),"\n  ",(0,a.jsxs)(e.span,{className:"token tag",children:[(0,a.jsxs)(e.span,{className:"token tag",children:[(0,a.jsx)(e.span,{className:"token punctuation",children:"</"}),"body"]}),(0,a.jsx)(e.span,{className:"token punctuation",children:">"})]}),"\n",(0,a.jsxs)(e.span,{className:"token tag",children:[(0,a.jsxs)(e.span,{className:"token tag",children:[(0,a.jsx)(e.span,{className:"token punctuation",children:"</"}),"html"]}),(0,a.jsx)(e.span,{className:"token punctuation",children:">"})]})]})}),"\n",(0,a.jsxs)(e.p,{children:["외부 ",(0,a.jsx)(e.code,{children:"<script src>"}),"에 적용되는 동작은 여기에도 동일하게 적용됩니다."]}),"\n",(0,a.jsxs)(e.ul,{children:["\n",(0,a.jsxs)(e.li,{children:[(0,a.jsx)(e.code,{children:"output.module"}
1),"이 활성화되어 있으면, 일반적인 인라인 ",(0,a.jsx)(e.code,{children:"<script>"})," 태그는 ",(0,a.jsx)(e.code,{children:"<script src>"}),"에서의 동작과 마찬가지로 자동으로 ",(0,a.jsx)(e.code,{children:'type="module"'}),"로 승격됩니다."]}),"\n",(0,a.jsxs)(e.li,{children:[(0,a.jsx)(e.code,{children:"webpackIgnore"}),"는 인라인 ",(0,a.jsx)(e.code,{children:"<script>"})," 태그에서도 동작하므로, 원래 본문을 그대로 유지할 수 있습니다."]}),"\n",(0,a.jsxs)(e.li,{children:[(0,a.jsx)(e.code,{children:"application/ld+json"}),"이나 ",(0,a.jsx)(e.code,{children:"importmap"}),"처럼 JavaScript가 아닌 ",(0,a.jsx)(e.code,{children:"type"})," 값은 변경 없이 그대로 통과합니다."]}),"\n"]}),"\n",(0,a.jsxs)(e.h3,{children:[(0,a.jsx)(e.span,{id:"script-src-and-link-relmodulepreload"}),(0,a.jsx)(e.code,{children:"<script src>"})," and ",(0,a.jsx)(e.code,{children:'<link rel="modulepreload">'}),(0,a.jsx)(e.a,{href:"#script-src-and-link-relmodulepreload","aria-hidden":"true",tabIndex:"-1",children:(0,a.jsx)(e.span,{className:"header-link"})})]}),"\n",(0,a.jsxs)(e.p,{children:["HTML module 내부의 ",(0,a.jsx)(e.code,{children:"<script src>"}),"와 ",(0,a.jsx)(e.code,{children:'<link rel="modulepreload">'})," 참조는 실제 webpack entry가 되며, 출력된 청크 URL이 다시 HTML 문자열에 기록되어 해시된 파일 이름도 올바르게 유지됩니다."]}),"\n",(0,a.jsx)(e.pre,{children:(0,a.jsxs)(e.code,{className:"hljs language-html",children:[(0,a.jsx)(e.span,{className:"token comment",children:"\x3c!-- src/page.html --\x3e"}),"\n",(0,a.jsxs)(e.span,{className:"token doctype",children:[(0,a.jsx)(e.span,{className:"token punctuation",children:"<!"}),(0,a.jsx)(e.span,{className:"token doctype-tag",children:"doctype"})," ",(0,a.jsx)(e.span,{className:"token name",children:"html"}),(0,a.jsx)(e.span,{className:"token punctuation",children:">"})]}),"\n",(0,a.jsxs)(e.span,{className:"token tag",children:[(0,a.jsxs)(e.span,{className:"token tag",children:[(0,a.jsx)(e.span,{className:"token punctuation",children:"<"}),"html"]}),(0,a.jsx)(e.span,{className:"token punctuation",children:">"})]}),"\n  ",(0,a.jsxs)(e.span,{className:"token tag",children:[(0,a.jsxs)(e.span,{className:"token tag",children:[(0,a.jsx)(e.span,{className:"token punctuation",children:"<"}),"head"]}),(0,a.jsx)(e.span,{className:"token punctuation",children:">"})]}),"\n    ",(0,a.jsxs)(e.span,{className:"token tag",children:[(0,a.jsxs)(e.span,{className:"token tag",children:[(0,a.jsx)(e.span,{className:"token punctuation",children:"<"}),"link"]})," ",(0,a.jsx)(e.span,{className:"token attr-name",children:"rel"}),(0,a.jsxs)(e.span,{className:"token attr-value",children:[(0,a.jsx)(e.span,{className:"token punctuation attr-equals",children:"="}),(0,a.jsx)(e.span,{className:"token punctuation",children:'"'}),"modulepreload",(0,a.jsx)(e.span,{className:"token punctuation",children:'"'})]})," ",(0,a.jsx)(e.span,{className:"token attr-name",children:"href"}),(0,a.jsxs)(e.span,{className:"token attr-value",children:[(0,a.jsx)(e.span,{className:"token punctuation attr-equals",children:"="}),(0,a.jsx)(e.span,{className:"token punctuation",children:'"'}),"./preloaded.js",(0,a.jsx)(e.span,{className:"token punctuation",children:'"'})]})," ",(0,a.jsx)(e.span,{className:"token punctuation",children:"/>"})]}),"\n  ",(0,a.jsxs)(e.span,{className:"token tag",children:[(0,a.jsxs)(e.span,{className:"token tag",children:[(0,a.jsx)(e.span,{className:"token punctuation",children:"</"}),"head"]}),(0,a.jsx)(e.span,{className:"token punctuation",children:">"})]}),"\n  ",(0,a.jsxs)(e.span,{className:"token tag",children:[(0,a.jsxs)(e.span,{className:"token tag",children:[(0,a.jsx)(e.span,{className:"token punctuation",children:"<"}),"body"]}),(0,a.jsx)(e.span,{className:"token punctuation",children:">"})]}),"\n    ",(0,a.jsxs)(e.span,{className:"token tag",children:[(0,a.jsxs)(e.span,{className:"token tag",children:[(0,a.jsx)(e.span,{className:"token punctuation",children:"<"}),"script"]})," ",(0,a.jsx)(e.span,{className:"token attr-name",children:"src"}),(0,a.jsxs)(e.span,{className:"token attr-value",children:[(0,a.jsx)(e.span,{className:"token punctuation attr-equals",children:"="}),(0,a.jsx)(e.span,{className:"token punctuation",children:'"'}),"./entry.js",(0,a.jsx)(e.span,{className:"token punctuation",children:'"'})]}),(0,a.jsx)(e.span,{className:"token punctuation",children:">"})]}),(0,a.jsxs)(e.span,{className:"token tag",children:[(0,a.jsxs)(e.span,{className:"token tag",children:[(0,a.jsx)(e.span,{className:"token punctuation",children:"</"}),"script"]}),(0,a.jsx)(e.span,{className:"token punctuation",children:">"})]}),"\n    ",(0,a.jsxs)(e.span,{className:"token tag",children:[(0,a.jsxs)(e.span,{className:"token tag",children:[(0,a.jsx)(e.span,{className:"token punctuation",children:"<"}),"script"]})," ",(0,a.jsx)(e.span,{className:"token attr-name",children:"src"}),(0,a.jsxs)(e.span,{className:"token attr-value",children:[(0,a.jsx)(e.span,{className:"token punctuation attr-equals",children:"="}),(0,a.jsx)(e.span,{className:"token punctuation",children:'"'}),"./second.js",(0,a.jsx)(e.span,{className:"token punctuation",children:'"'})]}),(0,a.jsx)(e.span,{className:"token punctuation",children:">"})]}),(0,a.jsxs)(e.span,{className:"token tag",children:[(0,a.jsxs)(e.span,{className:"token tag",children:[(0,a.jsx)(e.span,{className:"token punctuation",children:"</"}),"script"]}),(0,a.jsx)(e.span,{className:"token punctuation",children:">"})]}),"\n  ",(0,a.jsxs)(e.span,{className:"token tag",children:[(0,a.jsxs)(e.span,{className:"token tag",children:[(0,a.jsx)(e.span,{className:"token punctuation",children:"</"}),"body"]}),(0,a.jsx)(e.span,{className:"token punctuation",children:">"})]}),"\n",(0,a.jsxs)(e.span,{className:"token tag",children:[(0,a.jsxs)(e.span,{className:"token tag",children:[(0,a.jsx)(e.span,{className:"token punctuation",children:"</"}),"html"]}),(0,a.jsx)(e.span,{className:"token punctuation",children:">"})]})]})}),"\n",(0,a.jsx)(e.p,{children:"알아두면 좋은 동작은 다음과 같습니다."}),"\n",(0,a.jsxs)(e.ul,{children:["\n",(0,a.jsxs)(e.li,{children:["같은 페이지의 여러 ",(0,a.jsx)(e.code,{children:"<script src>"})," 태그는 하나의 runtime을 공유합니다. 각 그룹(일반 스크립트 또는 ",(0,a.jsx)(e.code,{children:'type="module"'}),") 안에서 선두 항목이 runtime을 보유하고, 나머지는 여기에 ",(0,a.jsx)(e.code,{children:"dependOn"}),"을 선언합니다."]}),"\n",(0,a.jsxs)(e.li,{children:[(0,a.jsx)(e.code,{children:'<link rel="modulepreload">'})," entry는 독립적으로 유지되며 형제 script에서 import되지 않습니다. 따라서 스펙이 요구하는 대로 실행 없이 preload만 수행합니다."]}),"\n",(0,a.jsxs)(e.li,{children:[(0,a.jsx)(e.code,{children:"output.module"}
1),"이 활성화되어 있으면, 일반적인 ",(0,a.jsx)(e.code,{children:"<script src>"})," 태그는 출력되는 ES module 청크가 올바른 모드로 로드되도록 ",(0,a.jsx)(e.code,{children:'<script type="module" src>'}),"로 자동 승격됩니다."]}),"\n",(0,a.jsxs)(e.li,{children:[(0,a.jsx)(e.code,{children:"application/ld+json"}),", ",(0,a.jsx)(e.code,{children:"importmap"})," 같은 JavaScript가 아닌 script type이나 data URI는 변경 없이 그대로 통과하며 JS로 번들링되지 않습니다."]}),"\n"]}),"\n",(0,a.jsxs)(e.h3,{children:[(0,a.jsx)(e.span,{id:"webpackignore-magic-comment"}),(0,a.jsx)(e.code,{children:"webpackIgnore"})," Magic Comment",(0,a.jsx)(e.a,{href:"#webpackignore-magic-comment","aria-hidden":"true",tabIndex:"-1",children:(0,a.jsx)(e.span,{className:"header-link"})})]}),"\n",(0,a.jsxs)(e.p,{children:["익숙한 ",(0,a.jsx)(e.code,{children:"webpackIgnore: true"})," 매직 코멘트가 이제 HTML modules 내부에서도 동작합니다. 태그 바로 앞에 해당 지시어가 들어 있는 HTML comment를 두면, webpack은 출력 시 해당 태그의 URL을 건드리지 않습니다. 이는 ",(0,a.jsx)(e.code,{children:"html-loader"}),"가 동일한 경우를 처리하던 방식과 같습니다."]}),"\n",(0,a.jsx)(e.pre,{children:(0,a.jsxs)(e.code,{className:"hljs language-html",children:[(0,a.jsx)(e.span,{className:"token comment",children:"\x3c!-- webpackIgnore: true --\x3e"}),"\n",(0,a.jsxs)(e.span,{className:"token tag",children:[(0,a.jsxs)(e.span,{className:"token tag",children:[(0,a.jsx)(e.span,{className:"token punctuation",children:"<"}),"img"]})," ",(0,a.jsx)(e.span,{className:"token attr-name",children:"src"}),(0,a.jsxs)(e.span,{className:"token attr-value",children:[(0,a.jsx)(e.span,{className:"token punctuation attr-equals",children:"="}),(0,a.jsx)(e.span,{className:"token punctuation",children:'"'}),"https://cdn.example.com/logo.png",(0,a.jsx)(e.span,{className:"token punctuation",children:'"'})]})," ",(0,a.jsx)(e.span,{className:"token punctuation",children:"/>"})]}),"\n\n",(0,a.jsx)(e.span,{className:"token comment",children:"\x3c!-- webpackIgnore: true --\x3e"}),"\n",(0,a.jsxs)(e.span,{className:"token tag",children:[(0,a.jsxs)(e.span,{className:"token tag",children:[(0,a.jsx)(e.span,{className:"token punctuation",children:"<"}),"script"]})," ",(0,a.jsx)(e.span,{className:"token attr-name",children:"src"}),(0,a.jsxs)(e.span,{className:"token attr-value",children:[(0,a.jsx)(e.span,{className:"token punctuation attr-equals",children:"="}),(0,a.jsx)(e.span,{className:"token punctuation",children:'"'}),"/legacy/external.js",(0,a.jsx)(e.span,{className:"token punctuation",children:'"'})]}),(0,a.jsx)(e.span,{className:"token punctuation",children:">"})]}),(0,a.jsxs)(e.span,{className:"token tag",children:[(0,a.jsxs)(e.span,{className:"token tag",children:[(0,a.jsx)(e.span,{className:"token punctuation",children:"</"}),"script"]}),(0,a.jsx)(e.span,{className:"token punctuation",children:">"})]})]})}),"\n",(0,a.jsxs)(e.p,{children:["이 comment 값은 JS와 CSS parser가 사용하는 것과 동일한 컨텍스트에서 파싱되므로, boolean이 아닌 값을 사용하면 ",(0,a.jsx)(e.code,{children:"UnsupportedFeatureWarning"}),"이 발생합니다."]}),"\n",(0,a.jsxs)(e.h2,{children:[(0,a.jsx)(e.span,{id:"typescript-support-experimental"}),"TypeScript Support (Experimental)",(0,a.jsx)(e.a,{href:"#typescript-support-experimental","aria-hidden":"true",tabIndex:"-1",children:(0,a.jsx)(e.span,{className:"header-link"})})]}),"\n",(0,a.jsxs)(e.aside,{className:"warning",children:[(0,a.jsx)(e.p,{className:"warning__prefix",children:"warning"}),(0,a.jsxs)(e.p,{children:[(0,a.jsx)(e.strong,{children:"이 기능은 experimental이며 최신 Node.js에 의존합니다."})," 안정적인 ",(0,a.jsx)(e.code,{children:"module.stripTypeScriptTypes"})," API를 사용하려면 Node.js 22.6 이상이 필요합니다. 또한 이 변환은 지워질 수 있는 TypeScript 문법만 처리합니다(아래 제한 사항 참고). 그 외의 경우에는 계속 ",(0,a.jsx)(e.code,{children:"ts-loader"}),"나 ",(0,a.jsx)(e.code,{children:"swc-loader"}),"를 사용하세요."]})]}),"\n",(0,a.jsxs)(e.p,{children:["Webpack 5.107은 새로운 ",(0,a.jsx)(e.code,{children:"experiments.typescript"})," 플래그 뒤에서 first-class TypeScript 지원을 제공합니다. 이를 활성화하면 webpack은 Node.js의 내장 ",(0,a.jsx)(e.a,{href:"https://nodejs.org/api/module.html#modulestriptypescripttypescode-options",children:(0,a.jsx)(e.code,{children:"module.stripTypeScriptTypes"})}),"를 통해 ",(0,a.jsx)(e.code,{children:".ts"}),", ",(0,a.jsx)(e.code,{children:".cts"}),", ",(0,a.jsx)(e.code,{children:".mts"}
1)," 파일을 직접 컴파일하며, 외부 loader가 필요하지 않습니다. 이 플래그는 ",(0,a.jsx)(e.a,{href:"/configuration/experiments/#experimentsfuturedefaults",children:(0,a.jsx)(e.code,{children:"experiments.futureDefaults"})}),"를 사용하면 자동으로 활성화되기도 합니다."]}),"\n",(0,a.jsx)(e.pre,{children:(0,a.jsxs)(e.code,{className:"hljs language-js",children:[(0,a.jsx)(e.span,{className:"token comment",children:"// webpack.config.js"}),"\n",(0,a.jsx)(e.span,{className:"token keyword",children:"export"})," ",(0,a.jsx)(e.span,{className:"token keyword",children:"default"})," ",(0,a.jsx)(e.span,{className:"token punctuation",children:"{"}),"\n  ",(0,a.jsx)(e.span,{className:"token literal-property property",children:"experiments"}),(0,a.jsx)(e.span,{className:"token operator",children:":"})," ",(0,a.jsx)(e.span,{className:"token punctuation",children:"{"}),"\n    ",(0,a.jsx)(e.span,{className:"token literal-property property",children:"typescript"}),(0,a.jsx)(e.span,{className:"token operator",children:":"})," ",(0,a.jsx)(e.span,{className:"token boolean",children:"true"}),(0,a.jsx)(e.span,{className:"token punctuation",children:","}),"\n  ",(0,a.jsx)(e.span,{className:"token punctuation",children:"}"}),(0,a.jsx)(e.span,{className:"token punctuation",children:","}),"\n  ",(0,a.jsx)(e.span,{className:"token literal-property property",children:"entry"}),(0,a.jsx)(e.span,{className:"token operator",children:":"})," ",(0,a.jsx)(e.span,{className:"token string",children:'"./src/index.ts"'}),(0,a.jsx)(e.span,{className:"token punctuation",children:","}),"\n",(0,a.jsx)(e.span,{className:"token punctuation",children:"}"}),(0,a.jsx)(e.span,{className:"token punctuation",children:";"})]})}),"\n",(0,a.jsxs)(e.p,{children:["이 플래그를 활성화하면 몇 가지 합리적인 기본값도 함께 설정됩니다. ",(0,a.jsx)(e.code,{children:".ts"})," / ",(0,a.jsx)(e.code,{children:".cts"})," / ",(0,a.jsx)(e.code,{children:".mts"}),"용 rules, ",(0,a.jsx)(e.code,{children:".js"}),"보다 앞서 ",(0,a.jsx)(e.code,{children:".ts"}),"를 extension resolution에 추가하는 동작, ",(0,a.jsx)(e.code,{children:'import "./foo.js"'}),"가 ",(0,a.jsx)(e.code,{children:"./foo.ts"}),"도 시도하게 하는 ",(0,a.jsx)(e.code,{children:"extensionAlias"}),", ",(0,a.jsx)(e.code,{children:"tsconfig.json"})," 해석, 그리고 ",(0,a.jsx)(e.code,{children:".ts"})," 소스를 배포하는 monorepo를 위한 ",(0,a.jsx)(e.code,{children:'"typescript"'})," conditional exports key 지원이 포함됩니다."]}),"\n",(0,a.jsxs)(e.p,{children:["이 변환은 ",(0,a.jsx)(e.strong,{children:"타입만 제거"}),"합니다. type checking은 하지 않으며, JSX / ",(0,a.jsx)(e.code,{children:".tsx"}),", 그리고 지워질 수 없는 문법(",(0,a.jsx)(e.code,{children:"enum"}),", ",(0,a.jsx)(e.code,{children:"namespace"}),", parameter-property constructors, decorator metadata)은 지원하지 않습니다. 이는 TypeScript의 ",(0,a.jsx)(e.a,{href:"https://www.typescriptlang.org/tsconfig/#erasableSyntaxOnly",children:(0,a.jsx)(e.code,{children:"erasableSyntaxOnly"})}),"와 동일한 제약입니다. type checking이 필요하다면 ",(0,a.jsx)(e.code,{children:"tsc --noEmit"}),"이나 ",(0,a.jsx)(e.a,{href:"https://github.com/TypeStrong/fork-ts-checker-webpack-plugin",children:(0,a.jsx)(e.code,{children:"fork-ts-checker-webpack-plugin"})}),"을 함께 사용하세요. JSX나 지워질 수 없는 문법을 사용한다면 계속 ",(0,a.jsx)(e.code,{children:"ts-loader"}),"나 ",(0,a.jsx)(e.code,{children:"swc-loader"}),"를 사용해야 합니다."]}),"\n",(0,a.jsxs)(e.p,{children:["내장 설정 예제는 ",(0,a.jsx)(e.a,{href:"https://github.com/webpack/webpack/tree/main/examples/typescript",children:(0,a.jsx)(e.code,{children:"examples/typescript"})}),"에서, ",(0,a.jsx)(e.code,{children:"ts-loader"})," fallback 예제는 ",(0,a.jsx)(e.a,{href:"https://github.com/webpack/webpack/tree/main/examples/typescript-non-erasable",children:(0,a.jsx)(e.code,{children:"examples/typescript-non-erasable"})}),"에서 확인할 수 있습니다."]}),"\n",(0,a.jsxs)(e.h2,{children:[(0,a.jsx)(e.span,{id:"css-improvements"}),"CSS Improvements",(0,a.jsx)(e.a,{href:"#css-improvements","aria-hidden":"true",tabIndex:"-1",children:(0,a.jsx)(e.span,{className:"header-link"})})]}),"\n",(0,a.jsxs)(e.h3,{children:[(0,a.jsx)(e.span,{id:"scope-hoisting-for-css-modules"}),"Scope Hoisting for CSS Modules",(0,a.jsx)(e.a,{href:"#scope-hoisting-for-css-modules","aria-hidden":"true",tabIndex:"-1",children:(0,a.jsx)(e.span,{className:"header-link"})})]}),"\n",(0,a.jsxs)(e.p,{children:["Module concatenation(일반적으로 scope hoisting이라고도 부름)은 이전까지 JavaScript 전용 최적화였습니다. ",(0,a.jsx)(e.code,{children:"experiments.css"}),"를 활성화하더라도, 연결된 번들에 포함된 CSS Modules는 여전히 별도의 runtime 인스턴스를 생성했습니다. 5.107부터는 ",(0,a.jsx)(e.code,{children:"text"}),", ",(0,a.jsx)(e.code,{children:"css-style-sheet"}),", ",(0,a.jsx)(e.code,{children:"style"}),", ",(0,a.jsx)(e.code,{children:"link"}),"를 export type으로 사용하는 CSS Modules에도 동일한 최적화가 적용됩니다. ê·¸ ê²°ê³¼ CSS 비중이 큰 번들에서 runtime 오버헤드가 줄고 출력 크기도 더 작아집니다."]}),"\n",(0,a.jsx)(e.pre,{children:(0,a.jsxs)(e.code,{className:"hljs language-js",children:["module",(0,a.jsx)(e.span,{className:"token punctuation",children:"."}),"exports ",(0,a.jsx)(e.span,{className:"token operator",children:"="})," ",(0,a.jsx)(e.span,{className:"token punctuation",children:"{"}),"\n  ",(0,a.jsx)(e.span,{className:"token literal-property property",children:"experiments"}),(0,a.jsx)(e.span,{className:"token operator",children:":"})," ",(0,a.jsx)(e.span,{className:"token punctuation",children:"{"})," ",(0,a.jsx)(e.span,{className:"token literal-property property",children:"css"}),(0,a.jsx)(e.span,{className:"token operator",children:":"})," ",(0,a.jsx)(e.span,{className:"token boolean",children:"true"})," ",(0,a.jsx)(e.span,{className:"token punctuation",children:"}"}),(0,a.jsx)(e.span,{className:"token punctuation",children:","}),"\n  ",(0,a.jsx)(e.span,{className:"token literal-property property",children:"optimization"}),(0,a.jsx)(e.span,{className:"token operator",children:":"})," ",(0,a.jsx)(e.span,{className:"token punctuation",children:"{"}),"\n    ",(0,a.jsx)(e.span,{className:"token literal-property property",children:"concatenateModules"}),(0,a.jsx)(e.span,{className:"token operator",children:":"})," ",(0,a.jsx)(e.span,{className:"token boolean",children:"true"}),(0,a.jsx)(e.span,{className:"token punctuation",children:","}),"\n  ",(0,a.jsx)(e.span,{className:"token punctuation",children:"}"}),(0,a.jsx)(e.span,{className:"token punctuation",children:","}),"\n  ",(0,a.jsx)(e.span,{className:"token literal-property property",children:"module"}),(0,a.jsx)(e.span,{className:"token operator",children:":"})," ",(0,a.jsx)(e.span,{className:"token punctuation",children:"{"}),"\n    ",(0,a.jsx)(e.span,{className:"token literal-property property",children:"rules"}),(0,a.jsx)(e.span,{className:"token operator",children:":"})," ",(0,a.jsx)(e.span,{className:"token punctuation",children:"["}),"\n      ",(0,a.jsx)(e.span,{className:"token punctuation",children:"{"}),"\n        ",(0,a.jsx)(e.span,{className:"token literal-property property",children:"test"}),(0,a.jsx)(e.span,{className:"token operator",children:":"})," ",(0,a.jsxs)(e.span,{className:"token regex",children:[(0,a.jsx)(e.span,{className:"token regex-delimiter",children:"/"}),(0,a.jsx)(e.span,{className:"token regex-source language-regex",children:"\\.css$"}),(0,a.jsx)(e.span,{className:"token regex-delimiter",children:"/"})]}),(0,a.jsx)(e.span,{className:"token punctuation",children:","}),"\n        ",(0,a.jsx)(e.span,{className:"token literal-property property",children:"type"}),(0,a.jsx)(e.span,{className:"token operator",children:":"})," ",(0,a.jsx)(e.span,{className:"token string",children:'"css/module"'}),(0,a.jsx)(e.span,{className:"token punctuation",children:","}),"\n        ",(0,a.jsx)(e.span,{className:"token literal-property property",children:"parser"}),(0,a.jsx)(e.span,{className:"token operator",children:":"})," ",(0,a.jsx)(e.span,{className:"token punctuation",children:"{"}),"\n          ",(0,a.jsx)(e.span,{className:"token literal-property property",children:"exportType"}),(0,a.jsx)(e.span,{className:"token operator",children:":"})," ",(0,a.jsx)(e.span,{className:"token string",children:'"css-style-sheet"'}),(0,a.jsx)(e.span,{className:"token punctuation",children:","}),"\n        ",(0,a.jsx)(e.span,{className:"token punctuation",children:"}"}),(0,a.jsx)(e.span,{className:"token punctuation",children:","}),"\n      ",(0,a.jsx)(e.span,{className:"token punctuation",children:"}"}),(0,a.jsx)(e.span,{className:"token punctuation",children:","}),"\n    ",(0,a.jsx)(e.span,{className:"token punctuation",children:"]"}),(0,a.jsx)(e.span,{className:"token punctuation",children:","}),"\n  ",(0,a.jsx)(e.span,{className:"token punctuation",children:"}"}),(0,a.jsx)(e.span,{className:"token punctuation",children:","}),"\n",(0,a.jsx)(e.span,{className:"token punctuation",children:"}"}),(0,a.jsx)(e.span,{className:"token punctuation",children:";"})]})}),"\n",(0,a.jsxs)(e.h3,{children:[(0,a.jsx)(e.span,{id:"pure-mode-for-css-modules"}),"Pure Mode for CSS Modules",(0,a.jsx)(e.a,{href:"#pure-mode-for-css-modules","aria-hidden":"true",tabIndex:"-1",children:(0,a.jsx)(e.span,{className:"header-link"})})]}),"\n",(0,a.jsxs)(e.p,{children:[(0,a.jsx)(e.code,{children:"css/module"}),"ê³¼ ",(0,a.jsx)(e.code,{children:"css/auto"}),"에는 이제 새로운 ",(0,a.jsx)(e.code,{children:"pure"})," parser 옵션이 추가되었습니다. 이는 ",(0,a.jsx)(e.code,{children:"postcss-modules-local-by-default"}),"의 엄격한 pure mode와 동일한 개념입니다. 활성화하면 모든 selector는 최소 하ë
1‚˜ì˜ local class 또는 id를 포함해야 하며, 그렇지 않으면 webpack이 build error를 발생시킵니다. 목적은 CSS Modules 안에서 의도치 않게 전역 selector를 작성하는 실수를 프로덕션 이전에 잡아내는 것입니다."]}),"\n",(0,a.jsx)(e.pre,{children:(0,a.jsxs)(e.code,{className:"hljs language-js",children:["module",(0,a.jsx)(e.span,{className:"token punctuation",children:"."}),"exports ",(0,a.jsx)(e.span,{className:"token operator",children:"="})," ",(0,a.jsx)(e.span,{className:"token punctuation",children:"{"}),"\n  ",(0,a.jsx)(e.span,{className:"token literal-property property",children:"experiments"}),(0,a.jsx)(e.span,{className:"token operator",children:":"})," ",(0,a.jsx)(e.span,{className:"token punctuation",children:"{"})," ",(0,a.jsx)(e.span,{className:"token literal-property property",children:"css"}),(0,a.jsx)(e.span,{className:"token operator",children:":"})," ",(0,a.jsx)(e.span,{className:"token boolean",children:"true"})," ",(0,a.jsx)(e.span,{className:"token punctuation",children:"}"}),(0,a.jsx)(e.span,{className:"token punctuation",children:","}),"\n  ",(0,a.jsx)(e.span,{className:"token literal-property property",children:"module"}),(0,a.jsx)(e.span,{className:"token operator",children:":"})," ",(0,a.jsx)(e.span,{className:"token punctuation",children:"{"}),"\n    ",(0,a.jsx)(e.span,{className:"token literal-property property",children:"parser"}),(0,a.jsx)(e.span,{className:"token operator",children:":"})," ",(0,a.jsx)(e.span,{className:"token punctuation",children:"{"}),"\n      ",(0,a.jsx)(e.span,{className:"token string-property property",children:'"css/module"'}),(0,a.jsx)(e.span,{className:"token operator",children:":"})," ",(0,a.jsx)(e.span,{className:"token punctuation",children:"{"}),"\n        ",(0,a.jsx)(e.span,{className:"token literal-property property",children:"pure"}),(0,a.jsx)(e.span,{className:"token operator",children:":"})," ",(0,a.jsx)(e.span,{className:"token boolean",children:"true"}),(0,a.jsx)(e.span,{className:"token punctuation",children:","}),"\n      ",(0,a.jsx)(e.span,{className:"token punctuation",children:"}"}),(0,a.jsx)(e.span,{className:"token punctuation",children:","}),"\n    ",(0,a.jsx)(e.span,{className:"token punctuation",children:"}"}),(0,a.jsx)(e.span,{className:"token punctuation",children:","}),"\n  ",(0,a.jsx)(e.span,{className:"token punctuation",children:"}"}),(0,a.jsx)(e.span,{className:"token punctuation",children:","}),"\n",(0,a.jsx)(e.span,{className:"token punctuation",children:"}"}),(0,a.jsx)(e.span,{className:"token punctuation",children:";"})]})}),"\n",(0,a.jsx)(e.p,{children:"필요할 때는 두 가지 comment로 예외를 둘 수 있습니다. 첫 번째는 단일 rule에 대해서만 검사를 억제합니다."}),"\n",(0,a.jsx)(e.pre,{children:(0,a.jsxs)(e.code,{className:"hljs language-css",children:[(0,a.jsx)(e.span,{className:"token comment",children:"/* cssmodules-pure-ignore */"}),"\n",(0,a.jsx)(e.span,{className:"token selector",children:"a"})," ",(0,a.jsx)(e.span,{className:"token punctuation",children:"{"}),"\n  ",(0,a.jsx)(e.span,{className:"token comment",children:"/* 이 rule에 대해서만 검사 억제 */"}),"\n  ",(0,a.jsx)(e.span,{className:"token property",children:"color"}),(0,a.jsx)(e.span,{className:"token punctuation",children:":"})," blue",(0,a.jsx)(e.span,{className:"token punctuation",children:";"}),"\n",(0,a.jsx)(e.span,{className:"token punctuation",children:"}"})]})}),"\n",(0,a.jsx)(e.p,{children:"두 번째는 파일의 어떤 rule보다도 앞에 위치한 선행 comment 중에 배치했을 때, 파일 전체에 대한 검사를 비활성화합니다."}),"\n",(0,a.jsx)(e.pre,{children:(0,a.jsxs)(e.code,{className:"hljs language-css",children:[(0,a.jsx)(e.span,{className:"token comment",children:"/* cssmodules-pure-no-check */"}),"\n",(0,a.jsx)(e.span,{className:"token comment",children:"/* 이 파일에 대해 pure mode를 비활성화 */"}),"\n\n",(0,a.jsx)(e.span,{className:"token selector",children:"a"})," ",(0,a.jsx)(e.span,{className:"token punctuation",children:"{"}),"\n  ",(0,a.jsx)(e.span,{className:"token comment",children:"/* pure mode라면 보통 실패했을 selector */"}),"\n  ",(0,a.jsx)(e.span,{className:"token property",children:"color"}),(0,a.jsx)(e.span,{className:"token punctuation",children:":"})," red",(0,a.jsx)(e.span,{className:"token punctuation",children:";"}),"\n",(0,a.jsx)(e.span,{className:"token punctuation",children:"}"})]})}),"\n",(0,a.jsxs)(e.p,{children:["local selector를 포함하는 상위 규칙 안의 중첩 규칙은 pure를 만족하는 것으로 간주되고, ",(0,a.jsx)(e.code,{children:"&"}),"는 부모 규칙의 purity를 따르며, ",(0,a.jsx)(e.code,{children:"@keyframes"}),"와 ",(0,a.jsx)(e.code,{children:"@counter-style"})," 본문은 예외로 처리됩니다."]}),"\n",(0,a.jsxs)(e.h3,{children:[(0,a.jsx)(e.span,{id:"value-in-urls-and-import"}),(0,a.jsx)(e.code,{children:"@value"})," in URLs and ",(0,a.jsx)(e.code,{children:"@import"}),(0,a.jsx)(e.a,{href:"#value-in-urls-and-import","aria-hidden":"true",tabIndex:"-1",children:(0,a.jsx)(e.span,{className:"header-link"})})]}),"\n",(0,a.jsxs)(e.p,{children:["이제 CSS Modules의 ",(0,a.jsx)(e.code,{children:"@value"})," 식별자를 ",(0,a.jsx)(e.code,{children:"@import"}),"의 경로 인자나 ",(0,a.jsx)(e.code,{children:"url()"})," 참조 내부에서 사용할 수 있습니다. 덕분에 공통 경로와 asset을 한 번만 정의해 두고 여러 stylesheet에서 재사용하기 쉬워집니다."]}),"\n",(0,a.jsx)(e.pre,{children:(0,a.jsxs)(e.code,{className:"hljs language-css",children:[(0,a.jsxs)(e.span,{className:"token atrule",children:[(0,a.jsx)(e.span,{className:"token rule",children:"@value"})," ",(0,a.jsx)(e.span,{className:"token property",children:"path"}),(0,a.jsx)(e.span,{className:"token punctuation",children:":"})," ",(0,a.jsx)(e.span,{className:"token string",children:'"./other.module.css"'}),(0,a.jsx)(e.span,{className:"token punctuation",children:";"})]}),"\n",(0,a.jsxs)(e.span,{className:"token atrule",children:[(0,a.jsx)(e.span,{className:"token rule",children:"@import"})," path",(0,a.jsx)(e.span,{className:"token punctuation",children:";"})]}),"\n\n",(0,a.jsxs)(e.span,{className:"token atrule",children:[(0,a.jsx)(e.span,{className:"token rule",children:"@value"})," ",(0,a.jsx)(e.span,{className:"token property",children:"bg"}),(0,a.jsx)(e.span,{className:"token punctuation",children:":"})," ",(0,a.jsx)(e.span,{className:"token string",children:'"./image.png"'}),(0,a.jsx)(e.span,{className:"token punctuation",children:";"})]}),"\n\n",(0,a.jsx)(e.span,{className:"token selector",children:".a"})," ",(0,a.jsx)(e.span,{className:"token punctuation",children:"{"}),"\n  ",(0,a.jsx)(e.span,{className:"token property",children:"background"}),(0,a.jsx)(e.span,{className:"token punctuation",children:":"})," ",(0,a.jsxs)(e.span,{className:"token url",children:[(0,a.jsx)(e.span,{className:"token function",children:"url"}),(0,a.jsx)(e.span,{className:"token punctuation",children:"("}),"bg",(0,a.jsx)(e.span,{className:"token punctuation",children:")"})]}),(0,a.jsx)(e.span,{className:"token punctuation",children:";"}),"\n",(0,a.jsx)(e.span,{className:"token punctuation",children:"}"})]})}),"\n",(0,a.jsxs)(e.p,{children:["값은 따옴표 형태(",(0,a.jsx)(e.code,{children:'"./x"'}),", ",(0,a.jsx)(e.code,{children:"'./x'"}),")도, 따옴표 없는 형태(",(0,a.jsx)(e.code,{children:"./x"}),")도 모두 동작합니다. 어떤 형태로 작성하든 감싸고 있던 문자는 제거된 뒤 module request로 해석되므로, asset은 일반적인 webpack resolver 및 asset pipeline을 거치고 단순한 식별자로 남지 않습니다."]}),"\n",(0,a.jsxs)(e.h3,{children:[(0,a.jsx)(e.span,{id:"multiple-aliases-via-exportsconvention"}),"Multiple Aliases via ",(0,a.jsx)(e.code,{children:"exportsConvention"}),(0,a.jsx)(e.a,{href:"#multiple-aliases-via-exportsconvention","aria-hidden":"true",tabIndex:"-1",children:(0,a.jsx)(e.span,{className:"header-link"})})]}),"\n",(0,a.jsxs)(e.p,{children:["이제 CSS Modules의 ",(0,a.jsx)(e.code,{children:"generator.exportsConvention"})," 함수형은 ",(0,a.jsx)(e.code,{children:"string"}),"뿐 아니라 ",(0,a.jsx)(e.code,{children:"string[]"}),"도 반환할 수 있습니다. 배열을 반환하면 배열 안의 모든 이름으로 해당 local class가 export되며, 이는 ",(0,a.jsx)(e.code,{children:"css-loader"}),"의 동작과 동일합니다. 예를 들어 원래 이름과 대문자 버전 두 가지를 모두 노출하고 싶을 때 유용합니다."]}),"\n",(0,a.jsx)(e.pre,{children:(0,a.jsxs)(e.code,{className:"hljs language-js",children:["module",(0,a.jsx)(e.span,{className:"token punctuation",children:"."}),"exports ",(0,a.jsx)(e.span,{className:"token operator",children:"="})," ",(0,a.jsx)(e.span,{className:"token punctuation",children:"{"}),"\n  ",(0,a.jsx)(e.span,{className:"token literal-property property",children:"experiments"}),(0,a.jsx)(e.span,{className:"token operator",children:":"})," ",(0,a.jsx)(e.span,{className:"token punctuation",children:"{"})," ",(0,a.jsx)(e.span,{className:"token literal-property property",children:"css"}),(0,a.jsx)(e.span,{className:"token operator",children:":"})," ",(0,a.jsx)(e.span,{className:"token boolean",children:"true"})," ",(0,a.jsx)(e.span,{className:"token punctuation",children:"}"}),(0,a.jsx)(e.span,{className:"token punctuation",children:","}),"\n  ",(0,a.jsx)(e.span,{className:"token literal-property property",children:"module"}),(0,a.jsx)(e.span,{className:"token operator",children:":"})," ",(0,a.jsx)(e.span,{className:"token punctuation",children:"{"}),"\n    ",(0,a.jsx)(e.span,{className:"token literal-property property",children:"generator"}),(0,a.jsx)(e.span,{className:"token operator",children:":"})," ",(0,a.jsx)(e.span,{className:"token punctuation",children:"{"}),"\n      ",(0,a.jsx)(e.span,{className:"token string-property property",children:'"css/module"'}),(0,a.jsx)(e.span,{className:"token operator",children:":"})," ",(0,a.jsx)(e.span,{className:"token punctuation",children:"{"}),"\n        ",(0,a.jsx)(e.span,{className:"token function-variable function",children:"exportsConvention"}),(0,a.jsx)(e.span,{className:"token operator",children:":"})," ",(0,a.jsx)(e.span,{className:"token punctuation",children:"("}),(0,a.jsx)(e.span,{className:"token parameter",children:"name"}),(0,a.jsx)(e.span,{className:"token punctuation",children:")"})," ",(0,a.jsx)(e.span,{className:"token operator",children:"=>"})," ",(0,a.jsx)(e.span,{className:"token punctuation",children:"["}),"name",(0,a.jsx)(e.span,{className:"token punctuation",children:","})," name",(0,a.jsx)(e.span,{className:"token punctuation",children:"."}),(0,a.jsx)(e.span,{className:"token function",children:"toUpperCase"}),(0,a.jsx)(e.span,{className:"token punctuation",children:"("}),(0,a.jsx)(e.span,{className:"token punctuation",children:")"}),(0,a.jsx)(e.span,{className:"token punctuation",children:"]"}),(0,a.jsx)(e.span,{className:"token punctuation",children:","}),"\n      ",(0,a.jsx)(e.span,{className:"token punctuation",children:"}"}),(0,a.jsx)(e.span,{className:"token punctuation",children:","}),"\n    ",(0,a.jsx)(e.span,{className:"token punctuation",children:"}"}),(0,a.jsx)(e.span,{className:"token punctuation",children:","}),"\n  ",(0,a.jsx)(e.span,{className:"token punctuation",children:"}"}),(0,a.jsx)(e.span,{className:"token punctuation",children:","}),"\n",(0,a.jsx)(e.span,{className:"token punctuation",children:"}"}),(0,a.jsx)(e.span,{className:"token punctuation",children:";"})]})}),"\n",(0,a.jsx)(e.pre,{children:(0,a.jsxs)(e.code,{className:"hljs language-js",children:[(0,a.jsx)(e.span,{className:"token comment",children:"// JS에서 사용"}),"\n",(0,a.jsx)(e.span,{className:"token keyword",children:"import"})," styles ",(0,a.jsx)(e.span,{className:"token keyword",children:"from"})," ",(0,a.jsx)(e.span,{className:"token string",children:'"./button.module.css"'}),(0,a.jsx)(e.span,{className:"token punctuation",children:";"}),"\n\nconsole",(0,a.jsx)(e.span,{className:"token punctuation",children:"."}),(0,a.jsx)(e.span,{className:"token function",children:"log"}),(0,a.jsx)(e.span,{className:"token punctuation",children:"("}),"styles",(0,a.jsx)(e.span,{className:"token punctuation",children:"."}),"btn",(0,a.jsx)(e.span,{className:"token punctuation",children:")"}),(0,a.jsx)(e.span,{className:"token punctuation",children:";"})," ",(0,a.jsx)(e.span,{className:"token comment",children:"// 해시된 클래스"}),"\nconsole",(0,a.jsx)(e.span,{className:"token punctuation",children:"."}),(0,a.jsx)(e.span,{className:"token function",children:"log"}),(0,a.jsx)(e.span,{className:"token punctuation",children:"("}),"styles",(0,a.jsx)(e.span,{className:"token punctuation",children:"."}),(0,a.jsx)(e.span,{className:"token constant",children:"BTN"}),(0,a.jsx)(e.span,{className:"token punctuation",children:")"}),(0,a.jsx)(e.span,{className:"token punctuation",children:";"})," ",(0,a.jsx)(e.span,{className:"token comment",children:"// 같은 해시된 클래스, 대문자 별칭"})]})}),"\n",(0,a.jsxs)(e.h3,{children:[(0,a.jsx)(e.span,{id:"linkinsert-hook"}),(0,a.jsx)(e.code,{children:"linkInsert"})," Hook",(0,a.jsx)(e.a,{href:"#linkinsert-hook","aria-hidden":"true",tabIndex:"-1",children:(0,a.jsx)(e.span,{className:"header-link"})})]}),"\n",(0,a.jsxs)(e.p,{children:["webpack이 stylesheet ",(0,a.jsx)(e.code,{children:"<link>"}),"를 문서 어디에 삽입할지 제어하고 싶었다면, 이제 이를 위한 hook이 생겼습니다. ",(0,a.jsx)(e.code,{children:"CssLoadingRuntimeModule.getCompilationHooks(compilation)"}),"은 새로운 ",(0,a.jsx)(e.code,{children:"linkInsert"})," hook을 노출합니다. 이 hook은 기본 삽입 코드(",(0,a.jsx)(e.code,{children:"document.head.appendChild(link);"}),")와 청크를 전달받고, 링크를 연결할 때 사용할 JS를 반환합니다."]}),"\n",(0,a.jsx)(e.pre,{children:(0,a.jsxs)(e.code,{className:"hljs language-js",children:[(0,a.jsx)(e.span,{className:"token keyword",children:"const"})," webpack ",(0,a.jsx)(e.span,{className:"token operator",children:"="})," ",(0,a.jsx)(e.span,{className:"token function",children:"require"}),(0,a.jsx)(e.span,{className:"token punctuation",children:"("}),(0,a.jsx)(e.span,{className:"token string",children:'"webpack"'}),(0,a.jsx)(e.span,{className:"token punctuation",children:")"}),(0,a.jsx)(e.span,{className:"token punctuation",children:";"}),"\n\n",(0,a.jsx)(e.span,{className:"token keyword",children:"class"})," ",(0,a.jsx)(e.span,{className:"token class-name",children:"MyLinkInsertPlugin"})," ",(0,a.jsx)(e.span,{className:"token punctuation",children:"{"}),"\n  ",(0,a.jsx)(e.span,{className:"token function",children:"apply"}),(0,a.jsx)(e.span,{className:"token punctuation",children:"("}),(0,a.jsx)(e.span,{className:"token parameter",children:"compiler"}),(0,a.jsx)(e.span,{className:"token punctuation",children:")"})," ",(0,a.jsx)(e.span,{className:"token punctuation",children:"{"}),"\n    compiler",(0,a.jsx)(e.span,{className:"token punctuation",children:"."}),"hooks",(0,a.jsx)(e.span,{className:"token punctuation",children:"."}),"thisCompilation",(0,a.jsx)(e.span,{className:"token punctuation",children:"."}),(0,a.jsx)(e.span,{className:"token function",children:"tap"}),(0,a.jsx)(e.span,{className:"token punctuation",children:"("}),(0,a.jsx)(e.span,{className:"token string",children:'"MyLinkInsertPlugin"'}),(0,a.jsx)(e.span,{className:"token punctuation",children:","})," ",(0,a.jsx)(e.span,{className:"token punctuation",children:"("}),(0,a.jsx)(e.span,{className:"token parameter",children:"compilation"}),(0,a.jsx)(e.span,{className:"token punctuation",children:")"})," ",(0,a.jsx)(e.span,{className:"token operator",children:"=>"})," ",(0,a.jsx)(e.span,{className:"token punctuation",children:"{"}),"\n      ",(0,a.jsx)(e.span,{className:"token keyword",children:"const"})," hooks ",(0,a.jsx)(e.span,{className:"token operator",children:"="}),"\n        webpack",(0,a.jsx)(e.span,{className:"token punctuation",children:"."}),"web",(0,a.jsx)(e.span,{className:"token punctuation",children:"."}),"CssLoadingRuntimeModule",(0,a.jsx)(e.span,{className:"token punctuation",children:"."}),(0,a.jsx)(e.span,{className:"token function",children:"getCompilationHooks"}),(0,a.jsx)(e.span,{clas
1sName:"token punctuation",children:"("}),"compilation",(0,a.jsx)(e.span,{className:"token punctuation",children:")"}),(0,a.jsx)(e.span,{className:"token punctuation",children:";"}),"\n\n      ",(0,a.jsx)(e.span,{className:"token comment",children:"// 기본 `document.head.appendChild(link);`를 재정의합니다."}),"\n      hooks",(0,a.jsx)(e.span,{className:"token punctuation",children:"."}),"linkInsert",(0,a.jsx)(e.span,{className:"token punctuation",children:"."}),(0,a.jsx)(e.span,{className:"token function",children:"tap"}),(0,a.jsx)(e.span,{className:"token punctuation",children:"("}),"\n        ",(0,a.jsx)(e.span,{className:"token string",children:'"MyLinkInsertPlugin"'}),(0,a.jsx)(e.span,{className:"token punctuation",children:","}),"\n        ",(0,a.jsx)(e.span,{className:"token punctuation",children:"("}),(0,a.jsxs)(e.span,{className:"token parameter",children:["source",(0,a.jsx)(e.span,{className:"token punctuation",children:","})," chunk"]}),(0,a.jsx)(e.span,{className:"token punctuation",children:")"})," ",(0,a.jsx)(e.span,{className:"token operator",children:"=>"}),"\n          ",(0,a.jsx)(e.span,{className:"token string",children:'\'link.setAttribute("data-injected", "true"); document.body.appendChild(link);\''}),(0,a.jsx)(e.span,{className:"token punctuation",children:","}),"\n      ",(0,a.jsx)(e.span,{className:"token punctuation",children:")"}),(0,a.jsx)(e.span,{className:"token punctuation",children:";"}),"\n    ",(0,a.jsx)(e.span,{className:"token punctuation",children:"}"}),(0,a.jsx)(e.span,{className:"token punctuation",children:")"}),(0,a.jsx)(e.span,{className:"token punctuation",children:";"}),"\n  ",(0,a.jsx)(e.span,{className:"token punctuation",children:"}"}),"\n",(0,a.jsx)(e.span,{className:"token punctuation",children:"}"}),"\n\nmodule",(0,a.jsx)(e.span,{className:"token punctuation",children:"."}),"exports ",(0,a.jsx)(e.span,{className:"token operator",children:"="})," ",(0,a.jsx)(e.span,{className:"token punctuation",children:"{"}),"\n  ",(0,a.jsx)(e.span,{className:"token literal-property property",children:"experiments"}),(0,a.jsx)(e.span,{className:"token operator",children:":"})," ",(0,a.jsx)(e.span,{className:"token punctuation",children:"{"})," ",(0,a.jsx)(e.span,{className:"token literal-property property",children:"css"}),(0,a.jsx)(e.span,{className:"token operator",children:":"})," ",(0,a.jsx)(e.span,{className:"token boolean",children:"true"})," ",(0,a.jsx)(e.span,{className:"token punctuation",children:"}"}),(0,a.jsx)(e.span,{className:"token punctuation",children:","}),"\n  ",(0,a.jsx)(e.span,{className:"token literal-property property",children:"plugins"}),(0,a.jsx)(e.span,{className:"token operator",children:":"})," ",(0,a.jsx)(e.span,{className:"token punctuation",children:"["}),(0,a.jsx)(e.span,{className:"token keyword",children:"new"})," ",(0,a.jsx)(e.span,{className:"token class-name",children:"MyLinkInsertPlugin"}),(0,a.jsx)(e.span,{className:"token punctuation",children:"("}),(0,a.jsx)(e.span,{className:"token punctuation",children:")"}),(0,a.jsx)(e.span,{className:"token punctuation",children:"]"}),(0,a.jsx)(e.span,{className:"token punctuation",children:","}),"\n",(0,a.jsx)(e.span,{className:"token punctuation",children:"}"}),(0,a.jsx)(e.span,{className:"token punctuation",children:";"})]})}),"\n",(0,a.jsxs)(e.p,{children:["이 hook은 ",(0,a.jsx)(e.code,{children:"SyncWaterfallHook<[string, Chunk]>"}),"입니다. 원래 동작을 유지하려면 기본 ",(0,a.jsx)(e.code,{children:"source"}),"를 반환하고, 삽입 위치나 방식을 재정의하려면 사용자 정의 JS를 반환하면 됩니다."]}),"\n",(0,a.jsxs)(e.h3,{children:[(0,a.jsx)(e.span,{id:"ordermodules-hook"}),(0,a.jsx)(e.code,{children:"orderModules"})," Hook",(0,a.jsx)(e.a,{href:"#ordermodules-hook","aria-hidden":"true",tabIndex:"-1",children:(0,a.jsx)(e.span,{className:"header-link"})})]}),"\n",(0,a.jsx)(e.p,{children:'하나의 chunk가 여러 파일에서 CSS를 가져올 때, webpack의 기본 정렬은 import graph에 대한 위상 정렬(topological sort)입니다. 대부분의 경우에는 적절하지만, 실제 프로젝트에서는 import graph가 모호해서 "Conflicting order between CSS ..." 경고가 발생하고, import 구조를 재편하지 않는 이상 깔끔한 해결책이 없는 경우가 있습니다.'}),"\n",(0,a.jsxs)(e.p,{children:[(0,a.jsx)(e.code,{children:"CssModulesPlugin.getCompilationHooks(compilation)"}),"의 새로운 ",(0,a.jsx)(e.code,{children:"orderModules"})," hook은 plugin 작성자에게 결정적인 우회 수단을 제공합니다. 이 hook은 각 CSS source type(",(0,a.jsx)(e.code,{children:"CSS_IMPORT_TYPE"}),"와 ",(0,a.jsx)(e.code,{children:"CSS_TYPE"}),")마다 한 번씩 실행되며, 해당 chunk의 module 목록은 전체 module 이름 기준으로 미리 정렬된 상태로 전달됩니다. 기본 동작을 재정의하려면 정렬된 ",(0,a.jsx)(e.code,{children:"Module[]"}),"을 반환하고, 기존 webpack의 import-order 위상 정렬로 계속 진행하려면 ",(0,a.jsx)(e.code,{children:"undefined"}),"를 반환하면 됩니다."]}),"\n",(0,a.jsx)(e.pre,{children:(0,a.jsxs)(e.code,{className:"hljs language-js",children:[(0,a.jsx)(e.span,{className:"token keyword",children:"const"})," webpack ",(0,a.jsx)(e.span,{className:"token operator",children:"="})," ",(0,a.jsx)(e.span,{className:"token function",children:"require"}),(0,a.jsx)(e.span,{className:"token punctuation",children:"("}),(0,a.jsx)(e.span,{className:"token string",children:'"webpack"'}),(0,a.jsx)(e.span,{className:"token punctuation",children:")"}),(0,a.jsx)(e.span,{className:"token punctuation",children:";"}),"\n\n",(0,a.jsx)(e.span,{className:"token keyword",children:"class"})," ",(0,a.jsx)(e.span,{className:"token class-name",children:"CssOrderByPathPlugin"})," ",(0,a.jsx)(e.span,{className:"token punctuation",children:"{"}),"\n  ",(0,a.jsx)(e.span,{className:"token function",children:"apply"}),(0,a.jsx)(e.span,{className:"token punctuation",children:"("}),(0,a.jsx)(e.span,{className:"token parameter",children:"compiler"}),(0,a.jsx)(e.span,{className:"token punctuation",children:")"})," ",(0,a.jsx)(e.span,{className:"token punctuation",children:"{"}),"\n    compiler",(0,a.jsx)(e.span,{className:"token punctuation",children:"."}),"hooks",(0,a.jsx)(e.span,{className:"token punctuation",children:"."}),"thisCompilation",(0,a.jsx)(e.span,{className:"token punctuation",children:"."}),(0,a.jsx)(e.span,{className:"token function",children:"tap"}),(0,a.jsx)(e.span,{className:"token punctuation",children:"("}),"\n      ",(0,a.jsx)(e.span,{className:"token string",children:'"CssOrderByPathPlugin"'}),(0,a.jsx)(e.span,{className:"token punctuation",children:","}),"\n      ",(0,a.jsx)(e.span,{className:"token punctuation",children:"("}),(0,a.jsx)(e.span,{className:"token parameter",children:"compilation"}),(0,a.jsx)(e.span,{className:"token punctuation",children:")"})," ",(0,a.jsx)(e.span,{className:"token operator",children:"=>"})," ",(0,a.jsx)(e.span,{className:"token punctuation",children:"{"}),"\n        ",(0,a.jsx)(e.span,{className:"token keyword",children:"const"})," hooks ",(0,a.jsx)(e.span,{className:"token operator",children:"="}),"\n          webpack",(0,a.jsx)(e.span,{className:"token punctuation",children:"."}),"css",(0,a.jsx)(e.span,{className:"token punctuation",children:"."}),"CssModulesPlugin",(0,a.jsx)(e.span,{className:"token punctuation",children:"."}),(0,a.jsx)(e.span,{className:"token function",children:"getCompilationHooks"}),(0,a.jsx)(e.span,{className:"token punctuation",children:"("}),"compilation",(0,a.jsx)(e.span,{className:"token punctuation",children:")"}),(0,a.jsx)(e.span,{className:"token punctuation",children:";"}),"\n\n        ",(0,a.jsx)(e.span,{className:"token comment",children:"// Module은 전체 module 이름 기준으로 미리 정렬되어 들어옵니다."}),"\n        ",(0,a.jsx)(e.span,{className:"token comment",children:"// 그대로 반환하면 파일 경로 기준의 결정적 순서를 사용하게 되어"}),"\n        ",(0,a.jsx)(e.span,{className:"token comment",children:"// conflicting order 경고를 피할 수 있습니다."}),"\n        hooks",(0,a.jsx)(e.span,{className:"token punctuation",children:"."}),"orderModules",(0,a.jsx)(e.span,{className:"token punctuation",children:"."}),(0,a.jsx)(e.span,{className:"token function",children:"tap"}),(0,a.jsx)(e.span,{className:"token punctuation",children:"("}),"\n          ",(0,a.jsx)(e.span,{className:"token string",children:'"CssOrderByPathPlugin"'}),(0,a.jsx)(e.span,{className:"token punctuation",children:","}),"\n          ",(0,a.jsx)(e.span,{className:"token punctuation",children:"("}),(0,a.jsxs)(e.span,{className:"token parameter",children:["_chunk",(0,a.jsx)(e.span,{className:"token punctuation",children:","})," modules"]}),(0,a.jsx)(e.span,{className:"token punctuation",children:")"})," ",(0,a.jsx)(e.span,{className:"token operator",children:"=>"})," modules",(0,a.jsx)(e.span,{className:"token punctuation",children:","}),"\n        ",(0,a.jsx)(e.span,{className:"token punctuation",children:")"}),(0,a.jsx)(e.span,{className:"token punctuation",children:";"}),"\n      ",(0,a.jsx)(e.span,{className:"token punctuation",children:"}"}),(0,a.jsx)(e.span,{className:"token punctuation",children:","}),"\n    ",(0,a.jsx)(e.span,{className:"token punctuation",children:")"}),(0,a.jsx)(e.span,{className:"token punctuation",children:";"}),"\n  ",(0,a.jsx)(e.span,{className:"token punctuation",children:"}"}),"\n",(0,a.jsx)(e.span,{className:"token punctuation",children:"}"}),"\n\nmodule",(0,a.jsx)(e.span,{className:"token punctuation",children:"."}),"exports ",(0,a.jsx)(e.span,{className:"token operator",children:"="})," ",(0,a.jsx)(e.span,{className:"token punctuation",children:"{"}),"\n  ",(0,a.jsx)(e.span,{className:"token literal-property property",children:"experiments"}),(0,a.jsx)(e.span,{className:"token operator",children:":"})," ",(0,a.jsx)(e.span,{className:"token punctuation",children:"{"})," ",(0,a.jsx)(e.span,{className:"token literal-property property",children:"css"}),(0,a.jsx)(e.span,{className:"token operator",children:":"})," ",(0,a.jsx)(e.span,{className:"token boolean",children:"true"})," ",(0,a.jsx)(e.span,{className:"token punctuation",children:"}"}),(0,a.jsx)(e.span,{className:"token punctuation",children:","}),"\n  ",(0,a.jsx)(e.span,{className:"token literal-property property",children:"plugins"}),(0,a.jsx)(e.span,{className:"token operator",children:":"})," ",(0,a.jsx)(e.span,{className:"token punctuation",children:"["}),(0,a.jsx)(e.span,{className:"token keyword",children:"new"})," ",(0,a.jsx)(e.span,{className:"token class-name",children:"CssOrderByPathPlugin"}),(0,a.jsx)(e.span,{className:"token punctuation",children:"("}),(0,a.jsx)(e.span,{className:"token punctuation",children:")"}),(0,a.jsx)(e.span,{className:"token punctuation",children:"]"}),(0,a.jsx)(e.span,{className:"token punctuation",children:","}),"\n",(0,a.jsx)(e.span,{className:"token punctuation",children:"}"}),(0,a.jsx)(e.span,{className:"token punctuation",children:";"})]})}),"\n",(0,a.jsxs)(e.p,{children:["이 hook은 ",(0,a.jsx)(e.code,{children:"SyncBailHook<[Chunk, Module[], Compilation], Module[] | undefined>"}),"입니다. ",(0,a.jsx)(e.code,{children:"undefined"}),"가 아닌 값을 처음 반환한 tap의 결과가 사용됩니다."]}),"\n",(0,a.jsxs)(e.h2,{children:[(0,a.jsx)(e.span,{id:"javascript-and-esm"}),"JavaScript and ESM",(0,a.jsx)(e.a,{href:"#javascript-and-esm","aria-hidden":"true",tabIndex:"-1",children:(0,a.jsx)(e.span,{className:"header-link"})})]}),"\n",(0,a.jsxs)(e.h3,{children:[(0,a.jsx)(e.span,{id:"anonymous-default-export-naming"}),"Anonymous Default Export Naming",(0,a.jsx)(e.a,{href:"#anonymous-default-export-naming","aria-hidden":"true",tabIndex:"-1",children:(0,a.jsx)(e.span,{className:"header-link"})})]}),"\n",(0,a.jsxs)(e.p,{children:["Webpack 5.106은 익명 default export에 대해 ES spec에 맞춰 ",(0,a.jsx)(e.code,{children:".name"}),"을 ",(0,a.jsx)(e.code,{children:'"default"'}),"로 설정하는 수정 사항을 도입했습니다. 동작 자체는 올바르지만, 이 과정에서 난독화할 수 없는 ",(0,a.jsx)(e.code,{children:"Object.defineProperty"})," 호출이 주입되어 번들이 커지는 문제가 있었습니다. ",(0,a.jsx)(e.code,{children:'.name === "default"'}),"에 거의 의존하지 않는 library 소비자 입장에서는 이 추가 runtime helper가 순수한 오버헤드였습니다."]}),"\n",(0,a.jsxs)(e.p,{children:["5.107에서는 이 동작을 제어할 수 있도록 새로운 ",(0,a.jsx)(e.code,{children:"module.parser.j
1avascript.anonymousDefaultExportName"})," 옵션이 추가되었습니다. 기본값은 애플리케이션에서는 ",(0,a.jsx)(e.code,{children:"true"}),", library에서는(",(0,a.jsx)(e.code,{children:"output.library"}),"가 설정된 경우) ",(0,a.jsx)(e.code,{children:"false"}),"입니다. 애플리케이션은 기본적으로 spec 호환성을 유지하고, library 작성자는 이를 몰라도 추가 runtime helper 비용을 치르지 않게 됩니다."]}),"\n",(0,a.jsx)(e.pre,{children:(0,a.jsxs)(e.code,{className:"hljs language-js",children:[(0,a.jsx)(e.span,{className:"token comment",children:"// 입력"}),"\n",(0,a.jsx)(e.span,{className:"token keyword",children:"export"})," ",(0,a.jsx)(e.span,{className:"token keyword",children:"default"})," ",(0,a.jsx)(e.span,{className:"token keyword",children:"function"})," ",(0,a.jsx)(e.span,{className:"token punctuation",children:"("}),(0,a.jsx)(e.span,{className:"token punctuation",children:")"})," ",(0,a.jsx)(e.span,{className:"token punctuation",children:"{"}),"\n  ",(0,a.jsx)(e.span,{className:"token comment",children:"/* ... */"}),"\n",(0,a.jsx)(e.span,{className:"token punctuation",children:"}"}),"\n\n",(0,a.jsx)(e.span,{className:"token comment",children:"// `anonymousDefaultExportName: true`를 사용할 때(앱의 기본값)"}),"\n",(0,a.jsx)(e.span,{className:"token comment",children:'// runtime은 네이티브 ESM 동작에 맞춰 .name = "default"를 설정합니다.'})]})}),"\n",(0,a.jsx)(e.p,{children:"기본값은 명시적으로 덮어쓸 수도 있습니다."}),"\n",(0,a.jsx)(e.pre,{children:(0,a.jsxs)(e.code,{className:"hljs language-js",children:["module",(0,a.jsx)(e.span,{className:"token punctuation",children:"."}),"exports ",(0,a.jsx)(e.span,{className:"token operator",children:"="})," ",(0,a.jsx)(e.span,{className:"token punctuation",children:"{"}),"\n  ",(0,a.jsx)(e.span,{className:"token literal-property property",children:"module"}),(0,a.jsx)(e.span,{className:"token operator",children:":"})," ",(0,a.jsx)(e.span,{className:"token punctuation",children:"{"}),"\n    ",(0,a.jsx)(e.span,{className:"token literal-property property",children:"parser"}),(0,a.jsx)(e.span,{className:"token operator",children:":"})," ",(0,a.jsx)(e.span,{className:"token punctuation",children:"{"}),"\n      ",(0,a.jsx)(e.span,{className:"token literal-property property",children:"javascript"}),(0,a.jsx)(e.span,{className:"token operator",children:":"})," ",(0,a.jsx)(e.span,{className:"token punctuation",children:"{"}),"\n        ",(0,a.jsx)(e.span,{className:"token literal-property property",children:"anonymousDefaultExportName"}),(0,a.jsx)(e.span,{className:"token operator",children:":"})," ",(0,a.jsx)(e.span,{className:"token boolean",children:"false"}),(0,a.jsx)(e.span,{className:"token punctuation",children:","}),"\n      ",(0,a.jsx)(e.span,{className:"token punctuation",children:"}"}),(0,a.jsx)(e.span,{className:"token punctuation",children:","}),"\n    ",(0,a.jsx)(e.span,{className:"token punctuation",children:"}"}),(0,a.jsx)(e.span,{className:"token punctuation",children:","}),"\n  ",(0,a.jsx)(e.span,{className:"token punctuation",children:"}"}),(0,a.jsx)(e.span,{className:"token punctuation",children:","}),"\n",(0,a.jsx)(e.span,{className:"token punctuation",children:"}"}),(0,a.jsx)(e.span,{className:"token punctuation",children:";"})]})}),"\n",(0,a.jsxs)(e.h3,{children:[(0,a.jsx)(e.span,{id:"preserving-defer-and-source-phase-on-externals"}),"Preserving ",(0,a.jsx)(e.code,{children:"defer"})," and ",(0,a.jsx)(e.code,{children:"source"})," Phase on Externals",(0,a.jsx)(e.a,{href:"#preserving-defer-and-source-phase-on-externals","aria-hidden":"true",tabIndex:"-1",children:(0,a.jsx)(e.span,{className:"header-link"})})]}),"\n",(0,a.jsxs)(e.p,{children:["이제 webpack은 ESM 출력에서 import attributes를 유지하는 것과 같은 방식으로, external dependency에 대한 ",(0,a.jsx)(e.code,{children:"defer"}),"와 ",(0,a.jsx)(e.code,{children:"source"})," import phase 키워드도 유지합니다. 이전에는 이 phase 키워드가 출력문에서 제거되었기 때문에, external에 대한 ",(0,a.jsx)(e.code,{children:'import defer * as ns from "x"'}),"는 결과물에서 deferred semantics를 잃었습니다."]}),"\n",(0,a.jsxs)(e.p,{children:["정적 ",(0,a.jsx)(e.code,{children:"module"})," externals의 경우, namespace defer import와 단일 default source import는 이제 번들 상단에 네이티브 phase 구문으로 그대로 출력됩니다."]}),"\n",(0,a.jsx)(e.pre,{children:(0,a.jsxs)(e.code,{className:"hljs language-js",children:[(0,a.jsx)(e.span,{className:"token comment",children:"// webpack.config.js"}),"\nmodule",(0,a.jsx)(e.span,{className:"token punctuation",children:"."}),"exports ",(0,a.jsx)(e.span,{className:"token operator",children:"="})," ",(0,a.jsx)(e.span,{className:"token punctuation",children:"{"}),"\n  ",(0,a.jsx)(e.span,{className:"token literal-property property",children:"output"}),(0,a.jsx)(e.span,{className:"token operator",children:":"})," ",(0,a.jsx)(e.span,{className:"token punctuation",children:"{"})," ",(0,a.jsx)(e.span,{className:"token literal-property property",children:"module"}),(0,a.jsx)(e.span,{className:"token operator",children:":"})," ",(0,a.jsx)(e.span,{className:"token boolean",children:"true"})," ",(0,a.jsx)(e.span,{className:"token punctuation",children:"}"}),(0,a.jsx)(e.span,{className:"token punctuation",children:","}),"\n  ",(0,a.jsx)(e.span,{className:"token literal-property property",children:"externalsType"}),(0,a.jsx)(e.span,{className:"token operator",children:":"})," ",(0,a.jsx)(e.span,{className:"token string",children:'"module"'}),(0,a.jsx)(e.span,{className:"token punctuation",children:","}),"\n  ",(0,a.jsx)(e.span,{className:"token literal-property property",children:"externals"}),(0,a.jsx)(e.span,{className:"token operator",children:":"})," ",(0,a.jsx)(e.span,{className:"token punctuation",children:"{"})," ",(0,a.jsx)(e.span,{className:"token string-property property",children:'"external-mod"'}),(0,a.jsx)(e.span,{className:"token operator",children:":"})," ",(0,a.jsx)(e.span,{className:"token string",children:'"external-mod"'})," ",(0,a.jsx)(e.span,{className:"token punctuation",children:"}"}),(0,a.jsx)(e.span,{className:"token punctuation",children:","}),"\n",(0,a.jsx)(e.span,{className:"token punctuation",children:"}"}),(0,a.jsx)(e.span,{className:"token punctuation",children:";"})]})}),"\n",(0,a.jsx)(e.pre,{children:(0,a.jsx)(e.code,{className:"hljs language-text",children:'// 입력\nimport defer * as ns from "external-mod";\nimport source v from "external-mod";\n\n// 출력 결과\nimport defer * as ns from "external-mod";\nimport source v from "external-mod";'})}),"\n",(0,a.jsxs)(e.p,{children:["동적 ",(0,a.jsx)(e.code,{children:"import"})," externals의 경우에는 ",(0,a.jsx)(e.code,{children:'import.defer("x")'}),"와 ",(0,a.jsx)(e.code,{children:'import.source("x")'}),"가 직접 출력됩니다."]}),"\n",(0,a.jsx)(e.pre,{children:(0,a.jsx)(e.code,{className:"hljs language-text",children:'// 입력\nconst ns = await import.defer("external-mod");\nconst src = await import.source("external-mod");\n\n// 출력 결과\nconst ns = await import.defer("external-mod");\nconst src = await import.source("external-mod");'})}),"\n",(0,a.jsxs)(e.p,{children:["관련된 또 하나의 개선 사항도 있습니다. 동일한 external을 서로 다른 두 phase(또는 attribute 집합)로 import해도 더 이상 하나의 ",(0,a.jsx)(e.code,{children:"Exter
1nalModule"}),"로 합쳐지지 않습니다. 각 조합이 별도의 emit을 생성하므로, 어느 한쪽 phase가 조용히 누락되지 않습니다."]}),"\n",(0,a.jsxs)(e.h3,{children:[(0,a.jsx)(e.span,{id:"__no_side_effects__-annotation"}),(0,a.jsx)(e.code,{children:"#__NO_SIDE_EFFECTS__"})," Annotation",(0,a.jsx)(e.a,{href:"#__no_side_effects__-annotation","aria-hidden":"true",tabIndex:"-1",children:(0,a.jsx)(e.span,{className:"header-link"})})]}),"\n",(0,a.jsxs)(e.p,{children:["이제 webpack은 더 나은 tree shaking을 위해 함수를 pure하다고 표시하는 ",(0,a.jsx)(e.a,{href:"https://github.com/javascript-compiler-hints/compiler-notations-spec/blob/main/no-side-effects-notation-spec.md#2-const-variable-declaration",children:(0,a.jsx)(e.code,{children:"#__NO_SIDE_EFFECTS__"})})," annotation을 지원합니다. 이렇게 표시된 함수는 함수 본문을 정적으로 pure하다고 분석할 수 없더라도, 반환값이 사용되지 않으면 호출이 번들에서 제거될 수 있습니다."]}),"\n","\n",(0,a.jsx)(e.pre,{children:(0,a.jsxs)(e.code,{className:"hljs language-js",children:[(0,a.jsx)(e.span,{className:"token comment",children:"// utils.js"}),"\n",(0,a.jsx)(e.span,{className:"token comment",children:"/*#__NO_SIDE_EFFECTS__*/"}),"\n",(0,a.jsx)(e.span,{className:"token keyword",children:"export"})," ",(0,a.jsx)(e.span,{className:"token keyword",children:"function"})," ",(0,a.jsx)(e.span,{className:"token function",children:"createLogger"}),(0,a.jsx)(e.span,{className:"token punctuation",children:"("}),(0,a.jsx)(e.span,{className:"token parameter",children:"prefix"}),(0,a.jsx)(e.span,{className:"token punctuation",children:")"})," ",(0,a.jsx)(e.span,{className:"token punctuation",children:"{"}),"\n  ",(0,a.jsx)(e.span,{className:"token keyword",children:"return"})," ",(0,a.jsx)(e.span,{className:"token punctuation",children:"("}),(0,a.jsx)(e.span,{className:"token parameter",children:"msg"}),(0,a.jsx)(e.span,{className:"token punctuation",children:")"})," ",(0,a.jsx)(e.span,{className:"token operator",children:"=>"})," console",(0,a.jsx)(e.span,{className:"token punctuation",children:"."}),(0,a.jsx)(e.span,{className:"token function",children:"log"}),(0,a.jsx)(e.span,{className:"token punctuation",children:"("}),(0,a.jsxs)(e.span,{className:"token template-string",children:[(0,a.jsx)(e.span,{className:"token template-punctuation string",children:"`"}),(0,a.jsx)(e.span,{className:"token string",children:"["}),(0,a.jsxs)(e.span,{className:"token interpolation",children:[(0,a.jsx)(e.span,{className:"token interpolation-punctuation punctuation",children:"${"}),"prefix",(0,a.jsx)(e.span,{className:"token interpolation-punctuation punctuation",children:"}"})]}),(0,a.jsx)(e.span,{className:"token string",children:"] "}),(0,a.jsxs)(e.span,{className:"token interpolation",children:[(0,a.jsx)(e.span,{className:"token interpolation-punctuation punctuation",children:"${"}),"msg",(0,a.jsx)(e.span,{className:"token interpolation-punctuation punctuation",children:"}"})]}),(0,a.jsx)(e.span,{className:"token template-punctuation string",children:"`"})]}),(0,a.jsx)(e.span,{className:"token punctuation",children:")"}),(0,a.jsx)(e.span,{className:"token punctuation",children:";"}),"\n",(0,a.jsx)(e.span,{className:"token punctuation",children:"}"}),"\n\n",(0,a.jsx)(e.span,{className:"token keyword",children:"export"})," ",(0,a.jsx)(e.span,{className:"token keyword",children:"function"})," ",(0,a.jsx)(e.span,{className:"token function",children:"realWork"}),(0,a.jsx)(e.span,{className:"token punctuation",children:"("}),(0,a.jsx)(e.span,{className:"token punctuation",children:")"})," ",(0,a.jsx)(e.span,{className:"token punctuation",children:"{"}),"\n  ",(0,a.jsx)(e.span,{className:"token comment",children:"// ..."}),"\n",(0,a.jsx)(e.span,{className:"token punctuation",children:"}"})]})}),"\n","\n",(0,a.jsx)(e.pre,{children:(0,a.jsxs)(e.code,{className:"hljs language-js",children:[(0,a.jsx)(e.span,{className:"token comment",children:"// app.js"}),"\n",(0,a.jsx)(e.span,{className:"token keyword",children:"import"})," ",(0,a.jsx)(e.span,{className:"token punctuation",children:"{"})," createLogger",(0,a.jsx)(e.span,{className:"token punctuation",children:","})," realWork ",(0,a.jsx)(e.span,{className:"token punctuation",children:"}"})," ",(0,a.jsx)(e.span,{className:"token keyword",children:"from"})," ",(0,a.jsx)(e.span,{className:"token string",children:'"./utils"'}),(0,a.jsx)(e.span,{className:"token punctuation",children:";"}),"\n\n",(0,a.jsx)(e.span,{className:"token comment",children:"// `createLogger`에 annotation이 있고 결과가 사용되지 않으므로 제거됩니다."}),"\n",(0,a.jsx)(e.span,{className:"token keyword",children:"const"})," unused ",(0,a.jsx)(e.span,{className:"token operator",children:"="})," ",(0,a.jsx)(e.span,{className:"token function",children:"createLogger"}),(0,a.jsx)(e.span,{className:"token punctuation",children:"("}),(0,a.jsx)(e.span,{className:"token string",children:'"debug"'}),(0,a.jsx)(e.span,{className:"token punctuation",children:")"}),(0,a.jsx)(e.span,{className:"token punctuation",children:";"}),"\n\n",(0,a.jsx)(e.span,{className:"token function",children:"realWork"}),(0,a.jsx)(e.span,{className:"token punctuation",children:"("}),(0,a.jsx)(e.span,{className:"token punctuation",children:")"}),(0,a.jsx)(e.span,{className:"token punctuation",children:";"})]})}),"\n",(0,a.jsxs)(e.aside,{className:"warning",children:[(0,a.jsx)(e.p,{className:"warning__prefix",children:"warning"}),(0,a.jsxs)(e.p,{children:["현재 이 annotation은 ",(0,a.jsx)(e.strong,{children:"선언된 동일 module 내부에서만"})," 효과가 있습니다. module 간 전파는 향후 PR에서 지원될 예정입니다."]})]}),"\n",(0,a.jsxs)(e.h2,{children:[(0,a.jsx)(e.span,{id:"resolver-updates"}),"Resolver Updates",(0,a.jsx)(e.a,{href:"#resolver-updates","aria-hidden":"true",tabIndex:"-1",children:(0,a.jsx)(e.span,{className:"header-link"})})]}),"\n",(0,a.jsxs)(e.p,{children:["이제 webpack은 resolver defaults의 기본 ",(0,a.jsx)(e.code,{children:"conditionNames"}),"에 ",(0,a.jsx)(e.code,{children:'"module-sync"'}),"를 추가하여 Node.js와 동작을 맞춥니다. Node.js는 동기적으로 로드 가능한 ESM을 위해 ",(0,a.jsx)(e.code,{children:"module-sync"})," community condition을 제공하며, 이번 변경은 ESM, CJS, AMD, worker, wasm, build-dependency resolver에 영향을 줍니다."]}),"\n",(0,a.jsxs)(e.p,{children:["구체적으로 말하면, resolver defaults의 condition chain에는 이제 ",(0,a.jsx)(e.code,{children:"module"})," 바로 앞에 ",(0,a.jsx)(e.code,{children:"module-sync"}),"가 포함됩니다."]}),"\n",(0,a.jsx)(e.pre,{children:(0,a.jsxs)(e.code,{className:"hljs language-js",children:[(0,a.jsx)(e.span,{className:"token comment",children:"// 이전 (5.106)"}),"\n",(0,a.jsx)(e.span,{className:"token literal-property property",children:"conditionNames"}),(0,a.jsx)(e.span,{className:"token operator",children:":"})," ",(0,a.jsx)(e.span,{className:"token punctuation",children:"["}),(0,a.jsx)(e.span,{className:"token string",children:'"require"'}),(0,a.jsx)(e.span,{className:"token punctuation",children:","})," ",(0,a.jsx)(e.span,{className:"token string",children:'"module"'}),(0,a.jsx)(e.span,{className:"token punctuation",children:","})," ",(0,a.jsx)(e.span,{className:"token string",children:'"..."'}),(0,a.jsx)(e.span,{className:"token punctuation",children:"]"}),(0,a.jsx)(e.span,{className:"token punctuation",children:";"})," ",(0,a.jsx)(e.span,{className:"token comment",children:"// CJS 의존성"}),"\n",(0,a.jsx)(e.span,{className:"token literal-property property",children:"conditionNames"}),(0,a.jsx)(e.span,{className:"token operator",children:":"})," ",(0,a.jsx)(e.span,{className:"token punctuation",children:"["}),(0,a.jsx)(e.span,{className:"token string",children:'"import"'}),(0,a.jsx)(e.span,{className:"token punctuation",children:","})," ",(0,a.jsx)(e.span,{className:"token string",children:'"module"'}),(0,a.jsx)(e.span,{className:"token punctuation",children:","})," ",(0,a.jsx)(e.span,{className:"token string",children:'"..."'}),(0,a.jsx)(e.span,{className:"token punctuation",children:"]"}),(0,a.jsx)(e.span,{className:"token punctuation",children:";"})," ",(0,a.jsx)(e.span,{className:"token comment",children:"// ESM 의존성"}),"\n\n",(0,a.jsx)(e.span,{className:"token comment",children:"// 이후 (5.10
17)"}),"\n",(0,a.jsx)(e.span,{className:"token literal-property property",children:"conditionNames"}),(0,a.jsx)(e.span,{className:"token operator",children:":"})," ",(0,a.jsx)(e.span,{className:"token punctuation",children:"["}),(0,a.jsx)(e.span,{className:"token string",children:'"require"'}),(0,a.jsx)(e.span,{className:"token punctuation",children:","})," ",(0,a.jsx)(e.span,{className:"token string",children:'"module-sync"'}),(0,a.jsx)(e.span,{className:"token punctuation",children:","})," ",(0,a.jsx)(e.span,{className:"token string",children:'"module"'}),(0,a.jsx)(e.span,{className:"token punctuation",children:","})," ",(0,a.jsx)(e.span,{className:"token string",children:'"..."'}),(0,a.jsx)(e.span,{className:"token punctuation",children:"]"}),(0,a.jsx)(e.span,{className:"token punctuation",children:";"}),"\n",(0,a.jsx)(e.span,{className:"token literal-property property",children:"conditionNames"}),(0,a.jsx)(e.span,{className:"token operator",children:":"})," ",(0,a.jsx)(e.span,{className:"token punctuation",children:"["}),(0,a.jsx)(e.span,{className:"token string",children:'"import"'}),(0,a.jsx)(e.span,{className:"token punctuation",children:","})," ",(0,a.jsx)(e.span,{className:"token string",children:'"module-sync"'}),(0,a.jsx)(e.span,{className:"token punctuation",children:","})," ",(0,a.jsx)(e.span,{className:"token string",children:'"module"'}),(0,a.jsx)(e.span,{className:"token punctuation",children:","})," ",(0,a.jsx)(e.span,{className:"token string",children:'"..."'}),(0,a.jsx)(e.span,{className:"token punctuation",children:"]"}),(0,a.jsx)(e.span,{className:"token punctuation",children:";"})]})}),"\n",(0,a.jsxs)(e.p,{children:["즉, ",(0,a.jsx)(e.code,{children:"package.json"}),"에 ",(0,a.jsx)(e.code,{children:"module-sync"})," export condition을 게시하는 패키지는 추가 설정 없이 자동으로 선택됩니다."]}),"\n",(0,a.jsx)(e.pre,{children:(0,a.jsxs)(e.code,{className:"hljs language-json",children:[(0,a.jsx)(e.span,{className:"token punctuation",children:"{"}),"\n  ",(0,a.jsx)(e.span,{className:"token property",children:'"name"'}),(0,a.jsx)(e.span,{className:"token operator",children:":"})," ",(0,a.jsx)(e.span,{className:"token string",children:'"my-package"'}),(0,a.jsx)(e.span,{className:"token punctuation",children:","}),"\n  ",(0,a.jsx)(e.span,{className:"token property",children:'"exports"'}),(0,a.jsx)(e.span,{className:"token operator",children:":"})," ",(0,a.jsx)(e.span,{className:"token punctuation",children:"{"}),"\n    ",(0,a.jsx)(e.span,{className:"token property",children:'"."'}),(0,a.jsx)(e.span,{className:"token operator",children:":"})," ",(0,a.jsx)(e.span,{className:"token punctuation",children:"{"}),"\n      ",(0,a.jsx)(e.span,{className:"token property",children:'"module-sync"'}),(0,a.jsx)(e.span,{className:"token operator",children:":"})," ",(0,a.jsx)(e.span,{className:"token string",children:'"./esm/index.js"'}),(0,a.jsx)(e.span,{className:"token punctuation",children:","}),"\n      ",(0,a.jsx)(e.span,{className:"token property",children:'"default"'}),(0,a.jsx)(e.span,{className:"token operator",children:":"})," ",(0,a.jsx)(e.span,{className:"token string",children:'"./cjs/index.js"'}),"\n    ",(0,a.jsx)(e.span,{className:"token punctuation",children:"}"}),"\n  ",(0,a.jsx)(e.span,{className:"token punctuation",children:"}"}),"\n",(0,a.jsx)(e.span,{className:"token punctuation",children:"}"})]})}),"\n",(0,a.jsxs)(e.h2,{children:[(0,a.jsx)(e.span,{id:"bug-fixes"}),"Bug Fixes",(0,a.jsx)(e.a,{href:"#bug-fixes","aria-hidden":"true",tabIndex:"-1",children:(0,a.jsx)(e.span,{className:"header-link"})})]}),"\n",(0,a.jsxs)(e.p,{children:["버전 ",(0,a.jsx)(e.a,{href:"https://github.com/webpack/webpack/releases/tag/v5.106.0",children:"5.
1106"})," 이후 여러 버그가 수정되었습니다. 자세한 내용은 ",(0,a.jsx)(e.a,{href:"https://github.com/webpack/webpack/blob/main/CHANGELOG.md",children:"changelog"}),"를 확인하세요."]}),"\n",(0,a.jsxs)(e.h2,{children:[(0,a.jsx)(e.span,{id:"thanks"}),"Thanks",(0,a.jsx)(e.a,{href:"#thanks","aria-hidden":"true",tabIndex:"-1",children:(0,a.jsx)(e.span,{className:"header-link"})})]}),"\n",(0,a.jsxs)(e.p,{children:["Webpack 5.107을 가능하게 해주신 모든 기여자와 ",(0,a.jsx)(e.a,{href:"https://github.com/webpack/webpack?tab=readme-ov-file#sponsoring",children:"스폰서"}),"께 진심으로 감사드립니다.\n코드 기여, 문서 작성, 재정적 후원 등 어떤 형태의 지원이든 Webpack이 모두를 위해 계속 발전하고 개선될 수 있도록 도와줍니다."]})]})}function l(n={}){const{wrapper:e}={...(0,c.R)(),...n.components};return e?(0,a.jsx)(e,{...n,children:(0,a.jsx)(t,{...n})}):t(n)}}}]);

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.