Copyright © 2008 ~ 2024 MUKI space* / omegaBook theme All Rights Reserved.

需求與緣起

我們公司開發了一個網站後台,當初,因為以下考量,我選擇了 Vue.js 結合 SPA 的方式來開發應用程式,而不是使用 Nuxt.js 預設的 SSR 模式:

  • 他是網站後台
  • 需要帳號密碼才能登入管理
  • 不需要做搜尋引擎優化 (SEO)

需求調整

後台上線一段時間後,跟 B 公司有業務合作,B 公司希望能讓他們的客戶也使用這個後台,但前提是,需要將「登入網址」以及 LOGO 替換成他們家的品牌。如下所示:

  • 原本 (A) 的後台登入頁:https://mukispace.com
  • 新增 (B) 的後台登入頁:https://mukispace.com/b_company

  • 在沒有登入的情況下,訪客瀏覽這兩頁,會跳到對應的登入頁,但看到的 LOGO 會不同。
  • 登入情況下,訪客瀏覽 (A) 登入頁,會跳轉至 https://mukispace.com/home;訪客瀏覽 (B) 登入頁,一樣會跳轉到 https://mukispace.com/home
  • 呈上,跳轉的網址一樣,但是 LOGO 不同

設定路由匹配同個元件

要做到上述功能,其實很簡單。我們只要新增 /b_company 路由,並渲染元件 login 即可。這樣就會有兩個路由都使用同一個 login 元件。

{
  path: '/login',
  name: 'Login',
  meta: {
    head: '公司 A 的登入頁',
    title: '登錄',
    platform: 'ACompany'
  },
  component: Login
}, {
  path: '/b_company',
  name: 'bLogin',
  meta: {
    head: '公司 B 的登入頁',
    title: '登錄',
    platform: 'BCompany'
  },
  component: Login
}

至於該如何顯示對應的 LOGO?我使用 meta.platform 來作識別

<!-- 取得 route.meta.platform 後,再根據 platform 顯示對應的 LOGO  -->

<template>
  <img v-if="platform === 'BCompany'" src="/b.svg">
</template>

<script setup lang="ts">
  import { useRoute } from 'vue-router'
  const route = useRoute()
  const platform = route.meta.platform
</script>

登入後的 LOGO,則使用如 vuex, pinia 等狀態管理取得 platform 資料

<!-- 取得 store 的 platform 值後,再根據 platform 顯示對應的 LOGO  -->

<template>
  <img v-if="platform === 'BCompany'" src="/b.svg">
</template>

<script lang="ts" setup>
  import { useUserStore } from '@/stores'
  const useStore = useUserStore()
  const platform = useStore.platform
</script>

登入後不需要分兩個網址,也不需要拆成兩個站,所以我只處理登入頁的路由,以及顯示的 LOGO 。

原本以為這樣就交付完成,直到這兩天發現新的問題 ... 😂

網站標題與設定不符

當客戶將新的登入頁網址:https://mukispace.com/b_company 透過 LINE、FB 等社群分享給他人時,我們發現預覽顯示的網站標題,不是我在路由設定的 '公司 B 的登入頁'

▼ 我期望的是,從 /b_company 進來的訪客,看到的是 meta.head 的「公司 B 的登入頁」

{
  path: '/login',
  name: 'Login',
  meta: {
    head: '公司 A 的登入頁',
    title: '登錄',
    platform: 'ACompany'
  },
  component: Login
}, {
  path: '/b_company',
  name: 'bLogin',
  meta: {
    head: '公司 B 的登入頁',
    title: '登錄',
    platform: 'BCompany'
  },
  component: Login
}

但事實上,雖然我可以透過修改 document.title 去替換網站的標題,但這是透過 JavaScript 動態修改的,只有在瀏覽器的網站標題才有效;如果透過社群分享,他們抓的是靜態 HTML 的網站標題,也就是 dist/index.html 的網站標題

▼ 搜尋引擎與社群分享爬的內容來自於 index.html,執行 npm run build 之後會產出至 dist/index.html

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8" />
  <link rel="icon" type="image/svg+xml" href="/favicon.svg" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <title>公司 A 的登入頁</title>
</head>

<body>
  <div id="app"></div>
  <script type="module" src="/src/main.ts"></script>
</body>

</html>

因此不管我輸入哪一個網址,透過分享都會抓到 dist/index.html 的標題:「公司 A 的登入頁」

這是使用 SPA 最基本的常識,當時我也有想到這個問題,但當時只是要先提案,所以我給了一個簡單的 DEMO,也沒特別處理這塊,沒想到繞了一圈,還是要回來搞這個坑 😂...。

想了一堆方案

當時想了一堆有的沒的方案,甚至還想說要不要換框架整個重寫 (真的瘋了,這什麼鬼 XXD),也曾想說乾脆自己用 HTML + jQuery + AJAX 寫一個重複的登入頁好了,但想想又覺得好麻煩 QQ。

後來在洗澡的時候,靈光一閃!

洗澡真的是寫 code 的好朋友,

洗澡好棒!洗澡我愛你!大家每天都要洗澡唷 ^.<

打包 (build) 網站的過程中,是將 index.html 打包成 dist/index.html

那我只要複製一份 index.html 到 b.html,修改 b.html 的標題後,打包成 dist/b.html;再透過 nginx 指向,將 https://mukispace.com/b_company 指到 dist/b.html,這樣好像就能解決我的問題了。

▼ 簡易示意圖如下

步驟一:複製一份 b.html

▼ 原本的 index.html

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8" />
  <link rel="icon" type="image/svg+xml" href="/favicon.svg" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <title>公司 A 的登入頁</title>
</head>

<body>
  <div id="app"></div>
  <script type="module" src="/src/main.ts"></script>
</body>

</html>

▼ 另存一份成為 b.html,並修改網站標題

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8" />
  <link rel="icon" type="image/svg+xml" href="/favicon.svg" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <title>公司 B 的登入頁</title>
</head>

<body>
  <div id="app"></div>
  <script type="module" src="/src/main.ts"></script>
</body>

</html>

步驟二:修改 vite 設定檔

▼ vite 有一個 rollupOptions 可以設定打包後的檔案,我們在此設定好對應的 input 資料

import path from 'path'

export default () => {
  build: {
    rollupOptions: {
      input: {
        main: path.resolve(__dirname, 'index.html'),
        b_company: path.resolve(__dirname, 'b.html')
      }
    }
  }
}

有朋友提到這個就是 Vite 的 Multi Page App,我也補上連結給大家參考

步驟三:nginx 指向

▼ 前端的路由維持原樣,不需修改

{
  path: '/b_company',
  name: 'bLogin',
  meta: {
    head: '公司 B 的登入頁',
    title: '登錄',
    platform: 'BCompany'
  },
  component: Login
}

請後端增加 nginx 指向,例如:將 https://mukispace.com/b_company 指向到 dist/b.html


修改後,再開啟 https://mukispace.com/b_company(此為示意網址,不要真的點唷 😂),搜尋引擎就會爬到 dist/b.html 這份檔案,並顯示 b.html 的網站標題。

如此就能做到兩個入口連到同一個網站後台,而且有獨立的標題與 LOGO。

後記

在這篇文章中,跟大家分享了如何在 Vue.js 中設定多個入口網址,並顯示對應的網站標題。希望你在閱讀這篇文章後,能對你有所幫助。

這篇文章是基於我個人的學習經驗和理解寫成的,如果有任何錯誤或不足,歡迎指正。有任何問題或建議,都歡迎在下方留言唷!

歡迎給我點鼓勵,讓我知道你來過 :)

13
5
Subscribe
Notify of
guest

0 則留言
Inline Feedbacks
View all comments