[Vue] Vue Router - chunk load fail ๋ก ์ธํ ์ฝ์ง๊ธฐ
TL;DR
์๋ฃจ์ ๐ง๐ฝโ๏ธ: router.onError ์ฝ๋ฐฑ์ผ๋ก chunk load ์๋ฌ ํธ๋ค๋ง
let nextPath: string;
router.onError((error) => {
console.error(error);
if (error.name === 'ChunkLoadError') {
window.location.href = nextPath || '/';
}
});
ํ์ฌ Vue๋ก ๊ฐ๋ฐํ๊ณ ์๋ ๋ฉํฐ ํด๋ผ์ฐ๋ ํ๋ซํผ, SpaceONE(์คํ์ด์ค์)์ ๊ฐ๋ฐํ๋ฉด์ vue router chunk load fail ์ด์๋ฅผ ๋ง๋ฌ๋ค.
์ด ๋ฌธ์ ๋ ์๊ฐ๋ณด๋ค ๊ฐ๋จํ ํด๊ฒฐ๋์ง๋ง, ํ๋ค๋ฆฌ๋ฅผ ์ ๋๋ก ์ง์ผ๋ฉด ๋งค์ฐ๋งค์ฐ ๊ณ ์ํ๋ค...
์ด ๊ธ์ ๊ทธ๋ ๊ฒ ๋งค์ฐ๋งค์ฐ ๊ณ ์ํ ์ด์ผ๊ธฐ๋ฅผ ๊ณต์ ํจ์ผ๋ก์จ,
1. ๋์ ๊ฐ์ ๋ฌธ์ ๋ฅผ ๊ฒช๊ณ ์๋ ๋ชจ๋์๊ฒ ์๊ฐ์ ์ ์ฝํ๊ฒ ๋๊ณ
2. Vue Router์ ๋์ ๋ฐฉ์์ ์ฌ๋ฏธ๋(?) ๋ฐฉ์์ผ๋ก ์ดํดํ๋๋ก ๋๊ณ ์
์์ฑํด๋ณธ๋ค.
Trouble Shooting
๋ฌธ์ ๐ฑ: Uncaught SyntaxError: Unexpected token '<'
์ด๊ฑฐ, ํ๋ฒ ์ฏค ๋ง๋๋ดค์ผ๋ฆฌ๋ผ.
์๋ฐ์คํฌ๋ฆฝํธ๊ฐ "๋์ ํ ๋ชป์ฝ๊ฒ ์ด. ์ด๋ป๊ฒ์ข ํด๋ด." ํ ๋ ๋ด๋ฟ๋ ์๋ฌ์ด๋ค.
์ฐ๋ฆฌํ์ ๊ฒฝ์ฐ๋, ์ด ์๋ฌ๊ฐ ๊ต์ฅํ ๊ฐํ์ ์ผ๋ก ๋ํ๋์ '๋ฌด์ ๋๋ฌธ์ ์ด ์๋ฌ๊ฐ ๋๋๊ฐ'๋ฅผ ๋ช ํํ ํ๊ธฐ ์ด๋ ค์ ๋๋ฐ, ์ฌ๋ฐฐํฌ์ ์ผ์ด๋๋ ์ด์๋ก ์ฐ์ ์ถ์ธกํ์๋ค.
๋ฌธ์ ๋ฐ์ ์ํฉ: ์ฌ๋ฐฐํฌ → ๋ฉ๋ด์ ์ด๋
์ด๊ฑด ์ธ์ ๋ฐ์ํ๋๋๋ฉด, ๋ฉ๋ด์ ์ด๋(url ๋ณ๊ฒฝ → ์๋ก์ด chunk ํ์ผ ์์ฒญ) ์์ ๋ํ๋๋ค.
๋ฌธ์ ๋ฅผ ์ถ์ ํด๋๊ฐ๊ธฐ ์ํด ์ํฉ์ ์ขํ,
"์ฌ๋ฐฐํฌ ํ, ๋ค๋ฅธ ํ์ด์ง์์ ์๋ฒ ๋ฉ๋ด๋ก ์ง์ ์ ํ๋ ๊ฒฝ์ฐ์ ๋ฐ์ํ๋ ๋ฌธ์ "
๋ผ๊ณ ์ ํด๋๊ณ ๋ฌธ์ ๋ฅผ ์ถ์ ํด ๋๊ฐ๋ณด์.
๋ฌธ์ ์ถ์ ๐ง 1. ๋ธ๋ผ์ฐ์ ๋ ํ์ผ์ ์ ํด์ํ์ง ๋ชปํ ๊น
์ฐธ๊ณ ๋ก, ์ฐ๋ฆฌ์ route config ๋ ์๋์ ๊ฐ์ด ์์ฑ๋์ด ์๋ค.
const Server = () => import(/* webpackChunkName: "Server" */ '@/views/inventory/server/pages/ServerPage.vue');
{
path: 'inventory',
name: INVENTORY_ROUTE._NAME,
redirect: 'inventory/cloud-service',
meta: { label: 'Inventory' },
component: { template: '<router-view />' },
children: [
{
path: 'server',
meta: {
label: 'Server',
},
component: { template: '<router-view />' },
children: [
{
path: '/',
name: INVENTORY_ROUTE.SERVER._NAME,
component: Server,
},
],
},
...
]
...
}
์ฌ๋ฐฐํฌ๋์ด ๋์ด์ Server.2937218a.js ํ์ผ์ด ์กด์ฌํ์ง ์๋ค๋ฉด "์ ๊ทธ๋ฐ ํ์ผ ์์ด~" ํ๊ณ ๋คํธ์ํฌ ์๋ฌ๊ฐ ๋์ผํ๋๋ฐ
๋ณด๋ค์ํผ ์ ์์ด๋ค.
๊ทธ๋ฌ๋,
์ด๋ฐ ์๋ฌ๊ฐ ๋ฌ๋ค.
๋ญ ์ด์จ๋ , ํ์ผ์ ๊ฐ์ ธ์์ผ๋๊น.
๊ฒฐ๊ตญ ๋ธ๋ผ์ฐ์ ๊ฐ ์ ๊ฑธ ๋ชป์ฝ๊ฒ ๋ค๊ณ ์ก์๋ผ๋ ์ํฉ์ธ๋ฐ.
์์ธํ ์์ค ํ์ผ์ ๋ค์ฌ๋ค๋ดค๋ค.
<!DOCTYPE html><html><head><base href=/ ><meta charset=utf-8><meta http-equiv=X-UA-Compatible content="IE=edge"><meta name=viewport content="width=device-width,initial-scale=1"><link rel="shortcut icon" type=image/x-icon href=/favicon.ico><link rel=manifest type=image/x-icon href=/manifest.json><link rel=apple-touch-icon href=/images/icons/icon-192x192.png><link rel=stylesheet type=text/css href=/reset.css><link rel=stylesheet type=text/css href=/site-loader.css><script src=lottie.js></script><link rel=preload href=/fonts/roboto/roboto-v27-latin-regular.woff2 as=font type=font/woff2 crossorigin=anonymous><title></title><link href=/AddEventRulePage.2443967e.js rel=prefetch><link href=/AddNotificationPage.423f99ad.js rel=prefetch><link href=/AddNotificationPage~ManageNotificationPage~ProjectNotificationsPage~UserNotificationPage.262ec027.js rel=prefetch><link href=/AddServiceAccount.dd2b033d.js rel=prefetch><link href=/AddSpotGroupPage.25309be0.js rel=prefetch><link href=/AddSpotGroupPage~AlertDashboardPage~AlertListPage~CloudService~CloudServicePage~CollectorHistory~Col~1fe78708.a45199fe.js rel=prefetch><link href=/AddSpotGroupPage~SpotGroupDetailPage.4c1b9c62.js rel=prefetch><link href=/AlertDashboardPage.4e22d8b6.js rel=prefetch><link href=/AlertDashboardPage~CloudServicePage~CollectorHistory~Dashboard~ProjectDashboardPage~Server~SpotDashb~225d570e.3ef4eef0.js rel=prefetch><link href=/AlertDetailPage.6dd37180.js rel=prefetch><link href=/AlertDetailPage~EscalationPolicyPage~ProjectSettings.f647fded.js rel=prefetch><link href=/AlertListPage.5c40c793.js rel=prefetch><link href=/AlertListPage~ProjectAlert.600d25ee.js rel=prefetch><link href=/CloudService.56a70266.js rel=prefetch><link href=/CloudServicePage.0f8b0712.js rel=prefetch><link href=/CloudServicePage~PowerSchedulerPage~Server~ServiceAccount.de259d30.js rel=prefetch><link href=/CloudServiceSearch.682a59e6.js rel=prefetch><link href=/CloudServiceTypeSearch.01c8bd65.js rel=prefetch><link href=/CloudService~ProjectPage~SpotAutomationMainPage.ac5686f6.js rel=prefetch><link href=/CollectorHistory.e1b75a33.js rel=prefetch><link href=/CollectorPage.60229ab2.js rel=prefetch><link href=/CollectorPlugin.ce9943a8.js rel=prefetch><link href=/CreateCollector.fe3bbe46.js rel=prefetch><link href=/Dashboard.5b60298a.js rel=prefetch><link href=/Dashboard~ProjectDashboardPage.12a8dfb0.js rel=prefetch><link href=/Dashboard~ProjectDashboardPage~SpotGroupDetailPage.5594adf1.js rel=prefetch><link href=/DomainAdminSignIn.6aba32d3.js rel=prefetch><link href=/EscalationPolicyPage.fd9b6910.js rel=prefetch><link href=/EscalationPolicyPage~ProjectSettings.3e13a324.js rel=prefetch><link href=/KeycloakPage.81a0cd20.js rel=prefetch><link href=/ManageNotificationPage.8c7a9cc9.js rel=prefetch><link href=/ManageNotificationPage~ProjectNotificationsPage~UserNotificationPage.8e793b36.js rel=prefetch><link href=/MonitoringMainPage.8a7d7a69.js rel=prefetch><link href=/NoResource.ba963788.js rel=prefetch><link href=/PowerSchedulerLanding.af0c625f.js rel=prefetch><link href=/PowerSchedulerPage.e2700908.js rel=prefetch><link href=/PowerSchedulerPage~ResourceGroup.cccb9af0.js rel=prefetch><link href=/ProjectAlert.3320370f.js rel=prefetch><link href=/ProjectAlertPage.12f4777b.js rel=prefetch><link href=/ProjectDashboardPage.4e5d56f8.js rel=prefetch><link href=/ProjectDetailPage.7548f76f.js rel=prefetch><link href=/ProjectDetailPage~ProjectMaintenanceWindowPage.379f8f0c.js rel=prefetch><link href=/ProjectMaintenanceWindowPage.1efe29a0.js rel=prefetch><link href=/ProjectMemberPage.823e92e3.js rel=prefetch><link href=/ProjectMemberPage~ProjectPage.4d8fe64a.js rel=prefetch><link href=/ProjectNotificationsPage.861e77e0.js rel=prefetch><link href=/ProjectPage.08327029.js rel=prefetch><link href=/ProjectSettings.06976158.js rel=prefetch><link href=/ProjectTagPage.8f9d0731.js rel=prefetch><link href=/ProjectWebhook.0dba36f9.js rel=prefetch><link href=/ResourceGroup.4cb9fcc0.js rel=prefetch><link href=/Server.2cf4907a.js rel=prefetch><link href=/ServiceAccount.57e4165d.js rel=prefetch><link href=/ServiceAccountSearchPage.3593fb1d.js rel=prefetch><link href=/SignIn.e6fa5cdb.js rel=prefetch><link href=/SpotAutomationMainPage.1fc3a4bd.js rel=prefetch><link href=/SpotDashboardPage.c4780986.js rel=prefetch><link href=/SpotGroupDetailPage.38ea0f92.js rel=prefetch><link href=/SpotGroupPage.071a8566.js rel=prefetch><link href=/SupervisorPlugin.0ab663f4.js rel=prefetch><link href=/User.73334390.js rel=prefetch><link href=/UserAPIKey.61c8765e.js rel=prefetch><link href=/UserAPIKey~UserManagement.3dfa8abf.js rel=prefetch><link href=/UserAccount.2c09bb9c.js rel=prefetch><link href=/UserManagement.50749944.js rel=prefetch><link href=/UserNotificationPage.d0308613.js rel=prefetch><link href=/chunk-0ba3f7fd.994916e4.js rel=prefetch><link href=/chunk-1bc4056e.486766a9.js rel=prefetch><link href=/chunk-1be89e71.b5868b40.js rel=prefetch><link href=/chunk-2d0c95ba.41fa8489.js rel=prefetch><link href=/chunk-2d0f0b9f.a2c22464.js rel=prefetch><link href=/chunk-2d22c0b4.64ad6b33.js rel=prefetch><link href=/chunk-2e0b8c86.205aa870.js rel=prefetch><link href=/chunk-44e90382.9851c8f0.js rel=prefetch><link href=/chunk-461a2683.42df45c5.js rel=prefetch><link href=/chunk-4aaaf80d.a48cd1a6.js rel=prefetch><link href=/chunk-55bc86f8.4b05952e.js rel=prefetch><link href=/chunk-f5f99b42.ebace51f.js rel=prefetch><link href=/css/AddEventRulePage.bd08c668.css rel=prefetch><link href=/css/AddNotificationPage.7d8db5de.css rel=prefetch><link href=/css/AddNotificationPage~ManageNotificationPage~ProjectNotificationsPage~UserNotificationPage.43013aec.css rel=prefetch><link href=/css/AddServiceAccount.9a85fb46.css rel=prefetch><link href=/css/AddSpotGroupPage.ed6ed8b6.css rel=prefetch><link href=/css/AddSpotGroupPage~SpotGroupDetailPage.6276a2de.css rel=prefetch><link href=/css/AlertDashboardPage.b6c5bca9.css rel=prefetch><link href=/css/AlertDetailPage.312f4992.css rel=prefetch><link href=/css/AlertDetailPage~EscalationPolicyPage~ProjectSettings.7289a2eb.css rel=prefetch><link href=/css/AlertListPage.b4992990.css rel=prefetch><link href=/css/AlertListPage~ProjectAlert.9c01661b.css rel=prefetch><link href=/css/CloudService.d79778b1.css rel=prefetch><link href=/css/CloudServicePage.9d676694.css rel=prefetch><link href=/css/CloudService~ProjectPage~SpotAutomationMainPage.03f9a2b0.css rel=prefetch><link href=/css/CollectorHistory.978dc00e.css rel=prefetch><link href=/css/CollectorPage.52d7bc4e.css rel=prefetch><link href=/css/CollectorPlugin.db59d594.css rel=prefetch><link href=/css/CreateCollector.ed5a306e.css rel=prefetch><link href=/css/Dashboard.48fa125d.css rel=prefetch><link href=/css/Dashboard~ProjectDashboardPage.11f5c19f.css rel=prefetch><link href=/css/DomainAdminSignIn.815cc6d2.css rel=prefetch><link href=/css/EscalationPolicyPage.c882677f.css rel=prefetch><link href=/css/EscalationPolicyPage~ProjectSettings.5d111922.css rel=prefetch><link href=/css/ManageNotificationPage.1180520a.css rel=prefetch><link href=/css/ManageNotificationPage~ProjectNotificationsPage~UserNotificationPage.8ebb6cfb.css rel=prefetch><link href=/css/MonitoringMainPage.3630c535.css rel=prefetch><link href=/css/NoResource.a102c29a.css rel=prefetch><link href=/css/PowerSchedulerLanding.d670e43d.css rel=prefetch><link href=/css/PowerSchedulerPage.15b06258.css rel=prefetch><link href=/css/PowerSchedulerPage~ResourceGroup.f616876f.css rel=prefetch><link href=/css/ProjectAlert.111e2064.css rel=prefetch><link href=/css/ProjectAlertPage.5545d2a1.css rel=prefetch><link href=/css/ProjectDashboardPage.73985304.css rel=prefetch><link href=/css/ProjectDetailPage.33c7bbd9.css rel=prefetch><link href=/css/ProjectDetailPage~ProjectMaintenanceWindowPage.5588b8cb.css rel=prefetch><link href=/css/ProjectMaintenanceWindowPage.bdc07193.css rel=prefetch><link href=/css/ProjectMemberPage~ProjectPage.e4cd3c16.css rel=prefetch><link href=/css/ProjectPage.ae16d886.css rel=prefetch><link href=/css/ProjectSettings.f73a4e4f.css rel=prefetch><link href=/css/ProjectTagPage.77cd1e1e.css rel=prefetch><link href=/css/ProjectWebhook.244e7aaa.css rel=prefetch><link href=/css/Server.25f42c1f.css rel=prefetch><link href=/css/ServiceAccount.c600b0fa.css rel=prefetch><link href=/css/SignIn.07f21294.css rel=prefetch><link href=/css/SpotAutomationMainPage.25a5327b.css rel=prefetch><link href=/css/SpotDashboardPage.de09b2d3.css rel=prefetch><link href=/css/SpotGroupDetailPage.bebff5b1.css rel=prefetch><link href=/css/SpotGroupPage.cb642963.css rel=prefetch><link href=/css/SupervisorPlugin.ace392a4.css rel=prefetch><link href=/css/User.401d7e26.css rel=prefetch><link href=/css/UserAPIKey.65e3cb4e.css rel=prefetch><link href=/css/UserAPIKey~UserManagement.43c226e9.css rel=prefetch><link href=/css/UserAccount.3d6f3f4f.css rel=prefetch><link href=/css/UserManagement.cac7e050.css rel=prefetch><link href=/css/UserNotificationPage.57b523f0.css rel=prefetch><link href=/css/chunk-0ba3f7fd.cfd75d8e.css rel=prefetch><link href=/css/chunk-1bc4056e.ea70c3f0.css rel=prefetch><link href=/css/chunk-1be89e71.d34b8ff7.css rel=prefetch><link href=/css/chunk-2e0b8c86.afb7cc4a.css rel=prefetch><link href=/css/chunk-44e90382.45ef29c4.css rel=prefetch><link href=/css/chunk-461a2683.c3a06ffd.css rel=prefetch><link href=/css/chunk-4aaaf80d.5eb1f8ea.css rel=prefetch><link href=/css/chunk-55bc86f8.5a3dab04.css rel=prefetch><link href=/css/chunk-f5f99b42.a608ca90.css rel=prefetch><link href=/app.d406ce09.js rel=preload as=script><link href=/css/vendor.a107d60e.css rel=preload as=style><link href=/js/runtime~app.c8b73606.js rel=preload as=script><link href=/vendor.9fa6f766.js rel=preload as=script><link href=/css/vendor.a107d60e.css rel=stylesheet></head><body><noscript><strong>We're sorry but this app doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><script src=page-initializer.js></script><div id=site-loader-wrapper><div id=site-loader></div><div id=site-loader-text>Loading SpaceONE</div></div><script src=site-loader.js></script><div id=app><script src=/js/runtime~app.c8b73606.js></script><script src=/vendor.9fa6f766.js></script><script src=/app.d406ce09.js></script></body></html>
๋ ์ฉ ์ํฉ.
js ํ์ผ์ ์ฌ... html ์ด ์๋ฆฌ์ก๊ณ ์๋.
๊ทธ๊ฒ๋ ์ดํด๊ฐ ์๊ฐ์ง๋ง, href=/site-loader.css ๋ญ ์ด๋ฐ์์ผ๋ก ๋ธ๋ผ์ฐ์ ๊ฐ ํ์ฑ์ ์ ํ ํ ์ ์๋ ํํ.
๊ฐ๋ฐ์ ๋๊ตฌ์ network > preview ํญ์ ๋ดค๋๋.
๋ ์ฉ ์ํฉ 2.
์ ์์ ์ธ ํ์ผ๋ค์
์ด๋ ๊ฒ ์๋ฐ์คํฌ๋ฆฝํธ๊ฐ ๋ค์ด์๋จ ๋ง์ด๋ค.
ํ์ผ์ ๋ก๋๋ ํด์ค๋๋ฐ, ์๋ฑํ๊ฑธ ๊ฐ์ ธ์จ๋ค?
๊ทธ๊ฒ๋ ์ ๋์ํ๋ค๊ฐ, ๊ฐ์๊ธฐ ์ด๋๋ ??
๋ฌธ์ ์ถ์ ๐ง 2. ์ ์์ ์ธ ๊ฒฝ์ฐ์ ๋น๊ตํ๊ธฐ
๊ฐ์ด ์์์... ์ ์๋์ํ๋ ๊ฒฝ์ฐ๋ ์ด๋ค์ง, ํ์ธํด๋ณด์๋ค.
๋ค๋ฅธ ํ์ด์ง์ ์๋ค๊ฐ ์๋ฒ ํ์ด์ง๋ก ์ด๋ํ๋๋ ์์ฒญ๋ ํ์ผ๋ค์ ์๋์ ๊ฐ๋ค.
์๋ฒ ํ์ด์ง๋ก ๊ฐ๋ค๊ณ ํด์ ์๋ฒํ์ด์ง๋ง ๋ก๋ํ๊ฒ ์๋๋ผ, ์๋ง๋ ๊ทธ ๋ผ์ฐํธ ์ ๋ณด๋ฅผ ๊ฐ์ง๊ณ ์๋ ๊ฒ์ผ๋ก ์ถ์ ๋๋ CloudServicePage~....js ํ์ผ์ ๋จผ์ ๋ก๋ํ ๊ฒ์ ํ์ธํ ์ ์๋ค.
๋ฌธ์ ์ํฉ์์๋ ์๋์ ์๋ ํ์ผ, ์ฆ Server.2937218a.js ์ด ๋๋ง ์์ฒญํ์๋๋ฐ ๋ง์ด๋ค.
์. ๊ทธ๋ฐ๋ฐ๋ง์ ๋๋ค...
ํ ... ์์ด. ์๋ฒ ํ์ด์ง๋ก ์ฐ๊ฒฐ๋๋ a ํ๊ทธ ํด๋ฆญ ํ๋๋ฐ, ์. ๋๋์ฒด ์ ๋ฐ ๊ฒ๋ค์ ๋ถ๋ฅด์ง?์, ๊ทธ๋ฌ๊ณ ๋ณด๋ a ํ๊ทธ๋ค? ๊ทธ๋ฌ๋ฉด href ๋ฅผ ๋ณด๋ฉด ๋์์?
๊ทธ๋ฐ๋ฐ ์ฐ๋ฆฌ ์๋น์ค๋ SPA ์๋น์ค์ด๊ณ , a ํ๊ทธ๋ก ํ์ด์ง ๋ก๋ ์์ด ์ด๋ํ๋ค๊ณ ?
๊ฐ์๊ธฐ ๋ชจ๋ ๊ฒ ์์์ฉ์๋ค. ๋ ๋๋ a ํ๊ทธ๋ ์๋์ฒ๋ผ ์๊ฒผ๋๋ฐ...
์ ๊ฑธ ๋๋ฅด๋ฉด ๋๋ฐ์์ด ์๋์ ๊ฐ์ ํ์ผ๋ค์ ์์ฒญํ๋ค...? ๐คช๐คช๐คช๐คช๐คช๐คช๐คช
๐ ์... ๋ฐ๋ณด...ใ ใ ์ด๊ฑฐ ํผ์ดํฌ๊ฒ ๊ตฌ๋ ใ ใ
๊ทธ๋ ๋ง์ด ์๋์ง. a ํ๊ทธ๋ ๊ทธ ํ์์ด ํ์ด์ง ์ฐ๊ฒฐ์ธ๋ฐ.๊ทธ์ ํด์๋ฑ ์ผ๋ก ์ฑ ๊ฐํผ ์ ๋์ธ๋ฐ...
์ ๋ฌธ์ ์ a ํ๊ทธ๋ Vue Router ์ router-link๋ฅผ ์ด์ฉํด ๋ง๋ค์ด์ค๋ค.
๊ทธ๋ ๋ค๋ฉด ์๋ง๋ router-link๋ a ํ๊ทธ๋ฅผ ๋ง๋ค์ด๋๊ณ , ๋ด๋ถ์ ์ธ ํ์ด์ง ์ด๋์ ๋ชจ๋ ์๋ฐ์คํฌ๋ฆฝํธ ์ฒ๋ฆฌ๊ฐ ๋์ด์์ ํฐ.
ํ๋ฒ ํ์ธํด๋ณด์.
๋ฌธ์ ์ถ์ ๐คจ 3. Vue Router ์ router-link ํํค์น๊ธฐ
router-link ๋ ๋ ๋ ๊ฒฐ๊ณผ๋ a ํ๊ทธ์ href ์์ฑ์ด ์ฐ๋ฆฌ๊ฐ ๋ณด๋ด๊ณ ์ถ์ url๋ก ์ฌ๋ฐ๋ฅด๊ฒ ๋ฐ์๋๋ค.
๊ทธ๋ฐ๋ฐ ๊ทธ ํ๊ทธ๋ฅผ ํด๋ฆญํ์ ๋์ ๋์์ ์ผ๋ฐ์ ์ธ a ํ๊ทธ์ ๋์๊ณผ ๋ค๋ฅด๋ค.
Vue Router ์ router-link๊ฐ ๋ด๋ถ์ ์ผ๋ก ์ด๋ป๊ฒ ๋์ํ๋์ง๋ฅผ ๋ณด์.
// link.js
export default {
name: 'RouterLink',
props: {
to: {
type: toTypes,
required: true
},
}
render (h: Function) {
...
const { location, href } = router.resolve(this.to)
const handler = e => {
router.push(location)
}
const on = { click: handler }
const attrs = { href }
return h('a', { on, attrs }, this.$slots.default)
}
}
// index.js
export default class VueRouter {
constructor (options: RouterOptions = {}) {
this.history = new HTML5History(this, options.base)
}
push (location: RawLocation) {
return new Promise((resolve, reject) => {
this.history.push(location, resolve, reject)
})
}
}
์ค๋ฆฌ์ง๋ ์ฝ๋๋ ๋๋ ๋ณต์กํด์, ์์ ๋ง ๊ฐ๋จํ ์์ฝํด๋ณด์๋ค.
- props๋ก ์ฃผ์ ๋ฐ์ to ๊ฐ์ฒด๋ฅผ ํตํด router.resolve() ํจ์๋ก href, location ์ ์์๋ธ๋ค.
- ์์๋ธ location์ผ๋ก router.push() ํด์ฃผ๋ handler() ํจ์๋ฅผ ๋ง๋ ๋ค.
- ์ด๋ฒคํธ ๋ฆฌ์ค๋ ๊ฐ์ฒด on ์ ๋ง๋ค์ด, click ์ด๋ฒคํธ์ handler()ํจ์๋ฅผ ๋ฐ์ธ๋ฉ ํด์ค๋ค.
- ์์ฑ ๊ฐ์ฒด attrs ๋ฅผ ๋ง๋ค์ด, ์์๋ธ href ๋ฅผ ๋ฐ์ธ๋ฉ ํด์ค๋ค.
- ์ด๋ฒคํธ ๋ฆฌ์ค๋์ ์์ฑ์ด ๋ฐ์ธ๋ฉ ๋ a ํ๊ทธ๋ฅผ ๋ง๋ค์ด์ค๋ค.
๊ฒฐ๊ตญ ๋ณด์ด๋๊ฑด href ์์ฑ์ด ๋ถ์ฌ๋ a ํ๊ทธ, ํด๋ฆญํ์ฌ ๋์ํ๋ ๊ฒ์ handler() ํจ์, ์ฆ router.push(location) ์ด๋ผ๋ ๊ฒ์ ์ ์ ์๋ค.
๊ณต์ ๋ฌธ์์๋ ์ด๋ ๊ฒ ์์ฑ๋์ด ์๋ค.
๋ค๋ฅธ URL๋ก ์ด๋ํ๋ ค๋ฉด router.push๋ฅผ ์ฌ์ฉํ์ญ์์ค. ์ด ๋ฉ์๋๋ ์๋ก์ด ํญ๋ชฉ์ ํ์คํ ๋ฆฌ ์คํ์ ๋ฃ๊ธฐ ๋๋ฌธ์ ์ฌ์ฉ์๊ฐ ๋ธ๋ผ์ฐ์ ์ ๋ค๋ก ๊ฐ๊ธฐ ๋ฒํผ์ ํด๋ฆญํ๋ฉด ์ด์ URL๋ก ์ด๋ํ๊ฒ๋๋ค. ์ด๊ฒ์ <router-link>๋ฅผ ํด๋ฆญ ํ ๋ ๋ด๋ถ์ ์ผ๋ก ํธ์ถ๋๋ ๋ฉ์๋์ด๋ฏ๋ก <router-link :to="...">๋ฅผ ํด๋ฆญํ๋ฉด router.push(...)๋ฅผ ํธ์ถํ๋ ๊ฒ๊ณผ ๊ฐ์ต๋๋ค. |
๋์ ๋์์ ์ฌ๊ธฐ๊น์ง ์๋๋ฐ ๋ฒ์ ์ด ๋์์๋ค. ใ ใ
๊ณต์๋ฌธ์๋ฅผ ์น์ด๋จน์ด์ผ ํ๋ ์ด์ . ์์ง๋ง ํญ์ ๋์น๋ ๋.
์ฌํผ ๊ฒฐ๋ก ์ ์ผ๋ก ์ถ์ธกํด๋ณผ ์ ์๋ ๊ฒ์,
a ํ๊ทธ๋ฅผ ๋๋ฅด๋ฉด, router.push(location) ๊ฐ ๋์ํ๋ฉด์ ๋ด๋ถ์ ์ผ๋ก ์ 2๊ฐ์ง ํ์ผ์ ์์ฒญํ ๊ฒ์ด๋ผ๋ ์ .
location์ ๋งค์น๋๋ ํ์ผ(์ปดํฌ๋ํธ)์ route config ์์ ์ฐพ์์ ์์ฒญํ ๊ฒ์ด๋ผ๋ ์ .
๊ทธ๋ฆฌ๊ณ ์์ฒญํ์ฌ ๋ฐ์์จ ํ์ผ ๋ด๋ถ์์ router-view๋ฅผ ๋ง๋, ๊ทธ ๋ค์ ํ์ผ์ ์์ฒญํ ๊ฒ์ด๋ผ๋ ์ !
๋ฐ๋ผ์,
์ด ํ์ผ๋ค์ ๋๋ต ๊ทธ ๊ณผ์ ์์ ์์๋๋ก ์์ฒญ๋ ๊ฒ์ด๋ผ๋ ์ .
๊ทธ๋... ๊ทธ๊ฒ์ ์๊ฒ ๋ค.
๊ทผ๋ฐ ๋ผ์ฐํฐ ๋๊ฐ ์์ฒญ์ ํ๊ณ ! ๋ต์ ์๋ฑํ๊ฒ ์๋ค๋๊ฒ ๋ฌธ์ ๋ค.
์ฌ๋ฐฐํฌ๋ฅผ ํด์ ์๋ค๊ณ 404๊ฐ ์์ผํ๋ ์ ๊ฐ, ์ ๋ฒ์ ์ด 200์ผ๋ก ๋ค์ด์ค๋๊ฑธ๊น.
๊ทธ๋ฆฌ๊ณ . ์ js๋ฅผ ์์ฒญํ๋๋ฐ html ๋ก ๋ ์์ค๋๊ฑธ๊น.
๋ฌธ์ ์ถ์ ๐คฎ 4. ์ js ๋ฅผ ์์ฒญํ๋๋ฐ html ๋ก ๋ ์์ค๋๊ฑธ๊น
์ฐ๋ฆฌ๋ ์น ์๋ฒ๋ก nginx ๋ฅผ ์ฐ๊ณ ์๋ค.
์ฒ์ ์ง์ ํ๋ ๊ฒฝ์ฐ๋ฅผ ์๊ฐํด๋ณด์.
- ์ฒ์์ ํน์ url๋ก ๋ธ๋ผ์ฐ์ ์ ์ง์ ํ๋ค. nginx ๋ ๋ชจ๋ ์์ฒญ์ ๋ํ์ฌ index.html์ ๋ฆฌํดํ๋๋ก ๋์ด ์๋๋ฐ, ๊ฑฐ๊ธฐ์ script ํ๊ทธ๋ก entry ํ์ผ์ด ๋ก๋๋๋ค.
- ๋ก๋๋ entry ํ์ผ์ด ์คํ๋๋ฉด์, router ํ ๋ ์คํ๋๊ณ ๋ค์ํ ์ผ์ด ์ผ์ด๋ ๊ฒ์ด๋ค.
- ๊ทธ๋ฆฌ๊ณ ๋ผ์ฐํธ ์ ๋ณด์์ ํ์ฌ ๋ธ๋ผ์ฐ์ ์ url๊ณผ ๋งค์น๋๋ ์ปดํฌ๋ํธ๋ค์ ์์ฒญํ๋ค. (Vue Router ์ฝ๋๋ฅผ ์ดํด๋ดค๋๋ฐ matched ์ ๋ณด๋ฅผ ์ด์ฉํ๋๋ผ.)
ํ์ด์ง ์ด๋ํ๋ ๊ฒฝ์ฐ๋ฅผ ์๊ฐํด๋ณด์.
- router.push๊ฐ ํน์ url๋ก ์ปดํฌ๋ํธ๋ฅผ GET ์์ฒญํ๋ค. ๊ทธ ํ์ผ์ด Server.aaa.js ๋ผ๊ณ ํด๋ณด์.
- ๊ทธ ํ์ผ์ ๋ฐ์ ์ ์ ๋ก๋ํ๋ค....๋ฉด ์ข๊ฒ ์ง๋ง, ์ฌ๊ธฐ์ ๋ก๋๋ฅผ ๋ชปํด์จ๋ค. ์? ํ์ผ์ด ๋ณ๊ฒฝ๋์ด์ Server.aaa.js๋ ๋์ด์ ์๋ค. nginx ๋ ํ์ผ์ด ์์ผ๋ฉด ๊ทธ๋๋ก ๋๋ ค์ฃผ์ง๋ง, ์์ผ๋ฉด index.html ์ ๋ณด๋ด์ฃผ๋๋ก ์ค์ ๋์ด ์๋ค.
location / { try_files $uri /index.html; }โ
nginx ๋ ์๋ฌธ๋ ๋ชจ๋ฅด๊ณ index.html ๋ฅผ ๋๋ ค๋ณด๋ด์ค๋ค. - ๋ธ๋ผ์ฐ์ ๋ nginx ๋ก๋ถํฐ ๋ฌด์ธ๊ฐ๋ฅผ ๋ฐ๊ธด ํ๋๋ฐ, ๊ทธ ํฌ๋งท์ด html ์ด๋ผ๋ ๊ฒ์ ๋ชจ๋ฅธ๋ค. ์ด๋ฅผ ์คํ ๊ฐ๋ฅํ javascript ๋ผ๊ณ ์๊ฐํ๊ณ ์คํํ๋ค. ๊ทธ๋ฆฌ๊ณ ... <!DOCTYPE html> ์ด๊ฑธ ๋ง๋๋ ์๊ฐ๋ถํฐ ์๋ฌ๊ฐ ๋๋ค.
๋ฌธ์ ์์ธ ๐: ์๋ชป๋ ํ์ผ ์์ฒญ์ index.html๋ก ๋ณด๋ด์ฃผ๋ nginx์ ์ ๋ฐํจ
์ด์ ์์๋ฒ๋ ธ๋ค. ๐คฉ
์๋ชป๋ chunk file์ ์์ฒญํ์์ผ๋, ์ด๋ฅผ index.html ๋ก ๋๋๋ ค์ค nginx ์ค์ ์ผ๋ก๋ถํฐ ์ด ๋ชจ๋ ๊ฒ์ด ์์๋์๋ค!
์ ์ค์ ์ SPA ์๋ ํ์์ ์ธ ์ค์ ์ด๋ค.
์?
๋ชจ๋ url์ ๋ณ๊ฒฝ์ฌํญ์ ์น ์ดํ๋ฆฌ์ผ์ด์ ์ด ๊ด์ฅํ์ฌ์ผ, ๋ง์น ํ๋์ ์ดํ๋ฆฌ์ผ์ด์ ์ฒ๋ผ ๋์ํ๋๋ก ๋ง๋ค ์ ์์ผ๋๊น.
์ ๊ทธ๋ ๋ค๋ฉด... ๋ฌธ์ ๋ ์์๋๋ฐ. ์ด๋ฅผ ์ด๋ป๊ฒ ํ์ด๋๊ฐ๋จ ๋ง์ธ๊ฐ.
router ๊ฐ ์ด๋ค ํ์ผ์ ๋ฌ๋ผ๊ณ ์์ฒญ์ ํ์๊ณ ,
๊ทธ๊ฒ์ ์ด์์ด ์๋ค๋ ๊ฒ์ ๊ฐ์งํ๋ค๋ฉด,
๊ทธ๊ฒ์ ์ฒ๋ฆฌํ๋ ์ ๋์ ๊ตฌ๋ฉ์ ํ๋์ง ์์์๊น?
์๋ฃจ์ ๐ง๐ฝโ๏ธ: router.onError ์ฝ๋ฐฑ์ผ๋ก chunk load ์๋ฌ ํธ๋ค๋ง
์ฐ๋ฆฌ๋ ์๋ ์๋์ฒ๋ผ ์๋ฌ ํธ๋ค๋ง์ ํด์ฃผ๊ณ ์์๋ค.
router.onError((error) => {
if (/loading chunk \d* failed./i.test(error.message)) {
window.location.reload();
}
});
๋ฌธ์ ๋ ๋ฌด์์ด๋ํ๋ฉด, ์ด๊ฒ ์๋จน๊ณ ์์๋ค๋ ๊ฒ...ใ
์ if ๋ฌธ์ ํ์ง ์๊ณ ์์๋ค๋ ๊ฑฐ์...!
์๋ง์ ๋น๋์, ๋ฌธ์ ์ํฉ์ ์ต์ง๋ก ๋ง๋ค์ด๋ด๊ฐ๋ฉฐ
์๋ฌ๋ ์ ํํ ChunkLoadError ๋ผ๋ ์ด๋ฆ์ผ๋ก ํ๋ณํ ์ ์๋ค๋๊ฑธ ์ฐพ์๋ด์๊ณ ,
let nextPath: string;
router.onError((error) => {
console.error(error);
if (error.name === 'ChunkLoadError') {
window.location.href = nextPath || '/';
}
});
์ด๋ ๊ฒ ๋ง๋ฌด๋ฆฌํ์๋ค.
์ฐธ๊ณ ๋ก, nextPath ์ด ์น๊ตฌ๋ beforeEach ํ ์์ to.fullPath ๋ฅผ ๋ฃ์ด์ฃผ๊ณ ์๋ค.
์ด์ ๋, onError ์ฝ๋ฐฑ ํจ์์ ์ธ์๋ก๋ ๊ทธ ์ด๋ค ๋ผ์ฐํธ ์ ๋ณด๊ฐ ๋์ด์ค์ง ์๊ธฐ ๋๋ฌธ์.
๋ง์น๋ฉฐ ๐
๋ผ์ฐํฐ ์๋ฌ ํธ๋ค๋ง์ผ๋ก ์ฒ๋ฆฌํด์ผ ํ๋ค๋๊ฑธ ์์์ ํ๊ณ ์์์ง๋ง,
์๋๋ฌธ์ ๊ฑ๊ฐ ํด์ค์ผ ํ๋๊ฑด์ง๋ ์ ํํ ๋ชฐ๋๋ค.
์ ํํ ์์ธ์ ํ์ ํ๊ธฐ ์ํด ์ด๋ ๊ฒ ์ ๋ ๊ฒ ๋นผ์ ์ ์ต ๋์๋์ ๋ช ํํ ํ๊ณ ๋๋..
์ฌ์์ง ์์ธํ๋ค. ์๋ฌ ํธ๋ค๋ฌ๋ฅผ ๋จผ์ ์ดํด๋ณผ๊ฑธ... ๐ญ
๊ทธ๋ ์ง๋ง ๋ค์ ํ ๋ฒ ๊ธฐ์ด๋ฅผ ๋ค์ ธ๋ณด๋ ์ ์๋ฏธํ ์ฝ์ง์ด ์๋์๋, ์ค์ค๋ก๋ฅผ ๋ค๋ ์ฌ๋ณธ๋ค.