현재 프로젝트는 반복해서 사용되는 header, footer.html를 분리하고 나서 jquery로 각 페이지에 추가하도록 구성되어 있다. 분리된 html 중 header_nav.html에 mouseover시 drop down menu가 나오거나 버튼 클릭 이벤트 등 모든 페이지에서 사용해야될 로직은 common.js에 담겨 있다.
sub2, sub3, sub6.html은 각각 하위메뉴를 가지고 있어 해당 페이지를 클릭할 때마다 해당 하위메뉴가 활성화되고 나머지 하위메뉴들은 감추어져야한다.
예를 들어 sub2.html로 들어가면 sub2_menu에 active 클래스 이름 추가되고 sub6_menu에서는 active 클래스 이름 제거되어야 한다.
- load_HTML.js - jquery로 header_nav.html, - footer_float_menu.html 등을 원하는 html 위치에 추가하는 로직 실행
- common.js - header nav 관련 event 로직 실행
- sub2.js - sub2_menu에 active 클래스 이름 추가, sub3_menu, sub6_menu에서는 active 클래스 이름 제거하기
이때 /src/js/sub2.js에서 세 js 파일 순서를 조절하려고 하니 로드할 때마다 달라져 sub2_menu가 보이지 않는 문제가 발생했다.
예를 들어 common 함수 실행->sub2함수 실행->load_HTML함수 실행과 같은 순서로 해당 로직들이 실행되면서 해당 페이지 하위 메뉴가 보이지 않는 문제가 발생했다. 왜냐하면 이와 같이 함수를 실행하면 sub2_menu가 로드되지도 않았는데 sub2 함수가 sub2_menu에 active 클래스 이름 추가하기 때문이다.
sub2_menu가 사라진 상태
sub2_menu가 보여지는 상태
/src/js/sub2.js
import("./load_HTML.js")
.then(({ default: load_HTML }) => {
load_HTML();
})
.catch((err) => {
console.error("load_HTML error", err);
});
import("./common.js")
.then(({ default: common }) => {
common();
$(function () {
sub2();
});
})
.catch((err) => {
console.error("common error", err);
});
function sub2() {
if ($(".sub2_menu").hasClass("active") === false) {
$(".sub2_menu").addClass("active");
$(".sub3_menu").removeClass("active");
$(".sub6_menu").removeClass("active");
for (let i = 2; i < 6; i++) {
if (window.location.href.split("/")[3] === `sub2_${i}.html`) {
$(".sub_header > ul > li").removeClass("on");
$(`.sub_header > ul > li:nth-child(${i})`).addClass("on");
}
}
}
}
/src/header_nav.html
<header id="header" class="clearfix">
<div class="inner">
<h1>
<a href="./index.html"> <p class="logo"></p> </a>
</h1>
<nav id="nav" class="clearfix only_pc">
<ul class="gnb clearfix">
<li><a href="./sub1.html">회사소개</a></li>
<li class="sub2_active">
<a href="./sub2.html">서비스</a>
<ul class="sub_gnb">
<li><a href="sub2.html">풀필먼트 서비스</a></li>
<li><a href="sub2_2.html">SAVE3</a></li>
<li><a href="sub2_3.html">해외수입 유통물류</a></li>
<li><a href="sub2_4.html">라이브쇼핑/이벤트 물류</a></li>
<li><a href="sub2_5.html">쿠팡쉽먼트</a></li>
</ul>
</li>
...
<div class="sub_header sub2_menu">
<ul>
<li class="on"><a href="sub2.html">풀필먼트 서비스</a></li>
<li><a href="sub2_2.html">SAVE3</a></li>
<li><a href="sub2_3.html">해외수입 유통물류</a></li>
<li><a href="sub2_4.html">라이브쇼핑/이벤트 물류</a></li>
<li><a href="sub2_5.html">쿠팡쉽먼트</a></li>
</ul>
</div>
<div class="sub_header sub3_menu">
<ul>
<li class="on"><a href="sub3.html">요금안내</a></li>
<li><a href="sub3_2.html">실시간 견적 서비스</a></li>
<li><a href="sub3_3.html">스마트스토어 셀러 견적 서비스</a></li>
</ul>
</div>
<div class="sub_header sub6_menu">
<ul>
<li class="on"><a href="sub6.html">자주묻는 질문</a></li>
<li><a href="sub6_2.html">공지사항</a></li>
<li>
<a onclick="window.open('https://modument.com/welcome/')">1:1문의</a>
</li>
</ul>
</div>
</header>
/src/js/load_HTML.js
function load_HTML() {
$(function () {
$("#header_nav").load("header_nav.html", function () {
console.log("hello");
});
$("#footer_float_menu").load("footer_float_menu.html");
$(".top_banner").load("top_banner.html");
});
}
export default load_HTML;
/src/js/common.js
function common() {
$(function () {
$(".gnb > li > a").on("mouseover", function () {
$(".sub_gnb").removeClass("active");
$(this).siblings(".sub_gnb").addClass("active");
});
$("#header").on("mouseleave", function () {
$(".sub_gnb").removeClass("active");
});
$(".float_top").on("click", function () {
$("html, body").animate(
{
scrollTop: 0,
},
400
);
return false;
});
$(".togglebar").on("click", function () {
$("#m_nav").addClass("on");
$("#m_nav .close").on("click", function () {
$("#m_nav").removeClass("on");
});
});
$(window).on("scroll", function () {
if ($(window).scrollTop() >= 120) {
$("#header").addClass("sticky");
} else {
$("#header").removeClass("sticky");
}
});
console.log("load common");
});
}
원하는 js load 순서는 다음과 같다.
1. load_HTML.js
2. common.js
3. sub2.js
HtmlWebpackPlugin git의 example에서 chunks순서를 조절할 수 있는 옵션에 대한 예시가 나온다. 다음 코드와 같이 chunksSortMode를 manual로 설정한 후 chunks를 내가 원하는 순서대로 맞추면 된다.
new HtmlWebpackPlugin({
inject: true,
filename: 'second-file.html',
template: 'template.html',
chunksSortMode: 'manual',
chunks: ['a', 'b', 'd']
}),
webpack.config.js
module.exports = (env, options) => {
const prod = options.mode === "production";
const htmlPageNames = [
"index",
"sub1",
"sub2",
"sub2_2", //3
"sub2_3",
"sub2_4", //5
"sub2_5", //6
"sub3", //7
"sub3_2",
"sub3_3",
"sub4", //10
"sub5", //11
"sub6",
"sub6_2",
"sub6_2_detail",
"sub6_3",
"service_use_term",
"privacy_info_use_term", //17
"header_nav",
"footer_float_menu",
"top_banner",
];
let entry = {
load_HTML: path.resolve(__dirname, "src/js/load_HTML.js"),
load_common: path.resolve(__dirname, "src/js/load_common.js"),
common: path.resolve(__dirname, "src/js/common.js"),
review_slider: path.resolve(__dirname, "src/js/review_slider.js"),
};
const multipleHtmlPlugins = htmlPageNames.map((name, idx) => {
const splited = name.split("_")[0];
let chunks = idx < 18 ? ["load_HTML", "load_common"] : [];
(splited === "index" ||
splited === "sub2" ||
splited === "sub5" ||
splited === "sub6") &&
((entry[splited] = path.resolve(__dirname, `src/js/${splited}.js`)),
(chunks = ["load_HTML", splited]));//load_HTML을 앞에 두기
splited === "sub3" &&
((entry[splited] = path.resolve(__dirname, `src/js/${splited}.ts`)),
(chunks = ["load_HTML", splited]));
((idx > 4 && idx < 8) || idx === 3 || idx === 10 || idx === 11) &&
chunks.push("review_slider");
console.log(name, chunks);//아래 이미지로 결과를 확인할 수 있습니다
return new HtmlWebpackPlugin({
template: path.resolve(`src/${name}.html`),
filename: `${name}.html`,
chunks,
inject: "body",
chunksSortMode: "manual",
});
});
이렇게 설정해 각 페이지별로 로드되는 chunks 순서를 다음과 같이 정렬시킨다.
그리고 /src/js/sub2.js에서는 common.js만 로드하고 load_HTML은 따로sub2.js에서 import로 불러와 실행하지 않고 html에서 바로 실행되도록 다음과 같이 수정한다.
/src/js/load_HTML.js
$("#header_nav").load("header_nav.html", function () {
console.log("load html");
});
$("#footer_float_menu").load("footer_float_menu.html");
$(".top_banner").load("top_banner.html");
/src/js/sub2.js
import("./common.js")
.then(({ default: common }) => {
common();
$(function () {
sub2();
});
})
.catch((err) => {
console.error("common error", err);
});
function sub2() {
console.log("sub2");
if ($(".sub2_menu").hasClass("active") === false) {
$(".sub2_menu").addClass("active");
$(".sub3_menu").removeClass("active");
$(".sub6_menu").removeClass("active");
for (let i = 2; i < 6; i++) {
if (window.location.href.split("/")[3] === `sub2_${i}.html`) {
$(".sub_header > ul > li").removeClass("on");
$(`.sub_header > ul > li:nth-child(${i})`).addClass("on");
}
}
}
}
빌드 결과는 다음과 같다.
/dist/sub2.html
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta
name="viewport"
content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1"
/>
<title>MODUMENT</title>
<link rel="icon" href="assets/favicon.png" />
<link href="css/vendors.4e59dc5734b4c633e946.css" rel="stylesheet" />
</head>
<body>
<div id="header_nav"></div>
<div class="sub2_banner">
...
</div>
<div class="sub sub2">
...
</div>
<div id="footer_float_menu"></div>
<script defer="defer" src="js/runtime.9cd00242584b50ecc473.js"></script>
<script defer="defer" src="js/vendors.4e59dc5734b4c633e946.js"></script>
<script defer="defer" src="js/load_HTML.02b569f8b9344162b230.js"></script>
<script defer="defer" src="js/sub2.f18402af9e7adb7b11b8.js"></script>
</body>
</html>
참고:
https://github.com/jantimon/html-webpack-plugin/blob/main/examples/sort-manually/webpack.config.js