iT邦幫忙

2021 iThome 鐵人賽

DAY 4
0
Modern Web

不只懂 Vue 語法:Vue.js 觀念篇系列 第 4

不只懂 Vue 語法:請說明 Vue CLI 的目錄架構?

問題回答

開發時主要在 src 資料夾進行開發,最後打包輸出時是 dist 資料夾。在 src 裏,一定會用到 assets, components, views 以及 main.js 檔案。assets 用作放靜態資源,components 放元件,views 放頁面元件,而 main.js 則是整個應用程式的進入點,意思是需要經 Webpack 編譯的檔案都需要在這裏引入。

此篇文章我會使用 Vue CLI 創建檔案,並設定加入 ESLint、 CSS 預處理器、Vue router、Vuex 來作說明。

Vue CLI 的目錄架構

為了縮短篇幅,此圖沒顯示 gitignorebabelnode_modufles 等檔案和資料夾。

public 與 src/assets 資料夾的分別

src/assets 資料夾

  • 使用相對路徑引入資源。例如:<img src="./assets/logo.png">
  • 官方建議把靜態資源放在 src/assets 裏。例如是圖片、字型等等。
  • 所有在 src 裏的資源都會經由 Webpack 編譯。因此有以下好處:
    • 資源和程式檔案都會被壓縮和打包在一起,減少額外的網絡請求。
    • 如果在開發時,有缺少載入任何檔案,Vue CLI 會在編譯時報錯,而非等到用瀏覽器瀏覽時才出現 404 錯誤。
    • 避免因為瀏覽器的快取機制,導致用戶只會看到舊版本的網頁。因為 Webpack 最終打包後的文件名稱會帶 hash,強制瀏覽器執行最新的程式檔案,因此不存在此問題。

最後一點也真的很方便!有時候改了一些樣式,但因為檔名沒更動過,因此瀏覽器會以為沒有什麼更動,因而繼續顯示緩存的檔案。所以,常聽說有些做法是在檔案名稱後加 timestamp 來強制瀏覽器更新。但如果用了 Webpack,因為輸出的檔案名稱會帶 hash,因此就能放心了,不用再用在檔案名上加 timestamp 之類的手法。

public 資料夾

  • 當你要引用放在 public 資料夾裏的資料,就需要使用絕對路徑。這涉及到你部署的 domain 是否在根路徑,這個之後會再談及。
  • 放靜態資源。包括 index.html 以及 favicon。雖然如此,但官方建議把靜態資源放在 src/assets 裏。
  • 在這資料夾裏的資源大多不會經過 Webpack 編譯。但注意,有些情況還是會由 Webpack 去做編譯,例如:
    • 以上提到 index.html 會被 webpack 相關的套件去處理。
    • 當我們使用相對路徑在 JavaScript、CSS 或 .vue 檔案引入任何靜態資源,它們都會被 Webpack 編譯,並被視為該 module 的依賴。

例外情況

所以,大部分情況是建議把靜態資源放在 src/assets 裏,但官方網站也有提到一些需要用到 public 的原因,例如函式庫與 webpack 不相容。

另一個比較明顯的例子是,這篇文章有提到,假設我要用 v-html 來顯示放在 src/assets 裏的 logo.png,並在 DOM 裏塞入 <img src="../assets/logo.png"> 這樣的內容來引入 logo.png,最後是無法顯示圖片,因為輸出時會直接當成字串輸出 ../assets/logo.png,沒有經過編譯,因此並非正確路徑。解決方法是我們需要在 public 引入 logo.png

詳細完整示範:https://codesandbox.io/s/vue-cli-ru-he-yong-v-html-xian-shi-tu-pian-50rn1?file=/src/App.vue

components 與 views 的分別

components 是放元件,views 是放頁面元件。一個頁面元件上會由多個元件組成。

https://example.com/#/products 這個 products 頁面為例。已知我們一定會有一個叫 Products.vue 作為頁面元件。假如在此頁面上,頂部有一個 swiper 輪播圖片,下方是一個個卡片來顯示每個產品。這情況可能就會出現兩個檔案,Swiper.vueProductCard.vue

src/
    components/
        Swiper.vue
        ProductCard.vue
    views/
        Products.vue   

router、store

在建立 Vue CLI 時,可以選擇加入 Vue router 和 Vuex,前者會建立一個 router 資料夾,後者則是 store 資料夾,並且會自動在 main.js 引入這些資料夾。

App.vue

App.vue 是根元件。所有元件都會掛載在這個元件上。當我們切換頁面,其實就是在 App.vue 此根元件裏切換顯示不同元件。

應用程式的進入點 main.js

main.js 是我們整個應用程式的進入點。把所有此應用程式用到的模組全都 import 進去 main.js。之後 webpack 就會編譯這個檔案,輸出瀏覽器看得懂的檔案。概念如下:

圖片來源:https://webpack.js.org/

因為瀏覽器只看懂 HTML、CSS 和 JavaScript 檔案,看不懂 .vue.scss 這些檔案,所以需要透過 Webpack 此工具去編譯,輸出 HTML、CSS 和 JavaScript 檔案。

注意,所有在 main.js 引入以及有關連的檔案,才會被 webpack 編譯。

補充一點,因為 Vue 預設是 SPA 框架,所以只會有一個進入點檔案(main.js)。但如果想使用 MPA(多頁式應用),就需要我們自己建立其他進入點檔案。例如建立一個 product.js (進入點檔案),以及 product.html (頁面檔案)。之後在 vue.config.js 再做相關的設定,詳細可參考 Kuro 大大這篇的文章說明。

打包後會產生 dist 資料夾

所謂打包,透過在終端機輸入 npm run build 指令,以 webpack 編譯,最後輸出 HTML、CSS 和 JavaScript 檔案,並被放在 dist 資料夾裏:

如果是靜態應用程式,例如此專案只是串接公共 API ,我們只需把此 dist 資料夾部署到 GitHub Pages、Netlify 等靜態網頁託管服務上。以下用部署到 GitHub Pages 作為例子。

  1. 需要設定 publicPath。

因為 Vue Cli 預設你所部署的 domain 是在根路徑'/',例如 https://my-vue-app.com/。如果是在子路徑,例如 https://github.com/alysachan830/my-vue-app/#/,就要設定 publicPath/my-vue-app/

如果你是使用 Vue 3,做法就是在根目錄建立 vue.config.js,內容如下:

module.exports = {
    publicPath: process.env.NODE_ENV === 'production'
      ? '/my-vue-app/'
      : '/'
}

以上做法能夠在打包後,使 dist 裏的index.html裏所載入的js、css檔案路徑都改回正確的相對路徑

  1. 最後,cd 到 dist 檔案並進行git init、add、commit,之後推到gh-pages分支

以下的資源詳細說明了以上步驟。

關於 vue.config.js的設定可看這篇:
https://tzuhui.github.io/2020/03/02/Vue/Vue-CLI3-to-github-pages/

原因細節可參考這個影片:
https://www.youtube.com/watch?v=njlABvVRB68&ab_channel=%E5%85%AD%E8%A7%92%E5%AD%B8%E9%99%A2

(大概54:25開始)

關於第 2 點的流程,可看這篇:
https://hsiangfeng.github.io/vue/20190513/948497494/

此外,如果是需要與後端程式做串接,就把此 dist 資料夾放到後端的伺服器資料夾裏,並把路由指向 dist 資料夾中 index.html 的位置,最後由後端處理部署。如果是用 Express.js 作為後端框架,可參考這篇文章,示範如何設定後端路由來連接 Vue。

總結

  • 把靜態資源放在 public 資料夾,它們不會被 Webpack 編譯(除非在其他檔案有使用 import 引入這些資源)。
  • 引用靜態資源時,需留意你之後部署此應用程式的 domin 是否在根路徑。若不是,就要設定 publicPath
  • App.vue 是根元件,所有元件都會掛載在它上面。
  • main.js 是整個 Vue 應用程式的進入點檔案,所有在此檔案引入的資源以及有關連的檔案,都會被 Vue 使用 Webpack 來進行編譯。
  • 使用 npm run build 來進行編譯,最後會輸出 dist 資料夾以及 HTML、CSS、JavaScript 檔案。因為瀏覽器只能讀取這三種檔案,所以需要進行以上提到的編譯動作。

參考資料

How to Structure a Large Scale Vue.js Application
Vue CLI 環境設定與打包部署
How To Develop and Build Vue.js App With NodeJS
Vue 2.x & Vue CLI 3 配置與靜態檔引用路徑


上一篇
不只懂 Vue 語法:以 Vue 和 Nuxt 為例,說明 SPA 和 SSR 的概念?
下一篇
不只懂 Vue 語法: 在 Vue 2 為何無法直接修改物件型別資料裏的值?
系列文
不只懂 Vue 語法:Vue.js 觀念篇31
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言