為何捐款
API 瀏覽器
升級指南
NEW!
quasar.config 檔案
轉換專案至 CLI with Vite
瀏覽器相容性
支援 TypeScript
目錄結構
命令列表
CSS 預處理器
路由
延遲載入 - 程式碼分割
處理資源
啟動檔案
預先載入功能
API 代理
處理 Vite
處理 process.env
使用 Pinia 進行狀態管理
使用 Vuex 進行狀態管理
程式碼檢查器
測試 & 稽核
開發行動應用程式
Ajax 請求
開放開發伺服器給公眾
Quasar CLI with Vite - @quasar/app-vite
啟動檔案

Quasar 應用程式的常見使用案例是在根 Vue 應用程式實例化之前執行程式碼,例如注入和初始化您自己的依賴項 (範例:Vue 元件、函式庫...) 或只是設定應用程式的一些啟動程式碼。

由於您無法存取任何 /main.js 檔案 (以便 Quasar CLI 可以無縫地初始化和建置 SPA/PWA/SSR/Cordova/Electron 的相同程式碼庫),Quasar 提供了一個優雅的解決方案,允許使用者定義所謂的啟動檔案。

在早期的 Quasar 版本中,若要在根 Vue 實例化之前執行程式碼,您可以修改 /src/main.js 檔案並新增任何您需要執行的程式碼。

這種方法存在一個主要問題:隨著專案的成長,您的 main.js 檔案很可能會變得雜亂且難以維護,這違反了 Quasar 鼓勵開發人員編寫可維護且優雅的跨平台應用程式的概念。

透過啟動檔案,可以將您的每個依賴項拆分為獨立、易於維護的檔案。停用任何啟動檔案,甚至透過 quasar.config 檔案配置,上下文判斷哪些啟動檔案進入建置也變得輕而易舉。

啟動檔案的結構

啟動檔案是一個簡單的 JavaScript 檔案,它可以選擇性地匯出一個函式。Quasar 接著會在啟動應用程式時呼叫匯出的函式,並額外將一個物件與以下屬性傳遞給該函式

屬性名稱描述
appVue 應用程式實例
router來自 'src/router/index.js' 的 Vue Router 實例
storePinia 或 Vuex store 的實例 - 僅當您的專案使用 Pinia (您有 src/stores) 或 Vuex (您有 src/store) 時,才會傳遞 store
ssrContext僅在伺服器端可用,如果為 SSR 建置。更多資訊
urlPathURL 的路徑名稱 (路徑 + 搜尋) 部分。它也包含客戶端上的雜湊。
publicPath配置的 public path。
redirect呼叫以重新導向到另一個 URL 的函式。接受字串 (完整 URL) 或 Vue Router 位置字串或物件。
export default ({ app, router, store }) => {
  // something to do
}

啟動檔案也可以是非同步的

export default async ({ app, router, store }) => {
  // something to do
  await something()
}

您可以使用 boot 輔助程式包裝傳回的函式,以獲得更好的 IDE 自動完成體驗 (透過 Typescript)

import { boot } from 'quasar/wrappers'

export default boot(async ({ app, router, store }) => {
  // something to do
  await something()
})

請注意,我們正在使用ES6 解構賦值。僅分配您實際需要/使用的內容。

您可能會問自己為什麼我們需要匯出一個函式。這實際上是可選的,但在您決定移除預設匯出之前,您需要了解何時需要它

// Outside of default export:
//  - Code here gets executed immediately,
//  - Good place for import statements,
//  - No access to router, Vuex store, ...

export default async ({ app, router, store }) => {
  // Code here has access to the Object param above, connecting
  // with other parts of your app;

  // Code here can be async (use async/await or directly return a Promise);

  // Code here gets executed by Quasar CLI at the correct time in app's lifecycle:
  //  - we have a Router instantiated,
  //  - we have the optional Vuex store instantiated,
  //  - we have the root app's component ["app" prop in Object param] Object with
  //      which Quasar will instantiate the Vue app
  //      ("new Vue(app)" -- do NOT call this by yourself),
  //  - ...
}

何時使用啟動檔案

警告

請確保您了解啟動檔案解決了什麼問題以及何時適合使用它們,以避免在不需要它們的情況下應用它們。

啟動檔案實現了一個特殊目的:它們在應用程式的 Vue 根元件實例化之前執行程式碼,同時讓您可以存取某些變數,如果您需要初始化函式庫、干預 Vue Router、注入 Vue prototype 或注入 Vue 應用程式的根實例,則需要這些變數。

啟動檔案的適當使用範例

  • 您的 Vue 插件有安裝說明,例如需要對其呼叫 app.use()
  • 您的 Vue 插件需要實例化新增至根實例的資料 - 一個範例是vue-i18n
  • 您想要使用 app.mixin() 新增全域 mixin。
  • 您想要在 Vue 應用程式 globalProperties 中新增一些內容以方便存取 - 一個範例是在您的 Vue 檔案中方便地使用 this.$axios (對於 Options API),而不是在每個此類檔案中匯入 Axios。
  • 您想要干預路由器 - 一個範例是使用 router.beforeEach 進行身份驗證
  • 您想要干預 Pinia 或 Vuex store 實例 - 一個範例是使用 vuex-router-sync 套件
  • 配置函式庫的各方面 - 一個範例是建立具有基本 URL 的 Axios 實例;然後您可以將其注入 Vue prototype 和/或匯出它 (以便您可以從應用程式中的任何其他位置匯入該實例)

不需要使用啟動檔案的範例

  • 對於像 Lodash 這樣的純 JavaScript 函式庫,它們在使用前不需要任何初始化。例如,Lodash 可能僅在您想要使用它注入 Vue prototype 時,例如能夠在您的 Vue 檔案中使用 this.$_ 時,才適合用作啟動檔案。

啟動檔案的使用方式

第一步始終是使用 Quasar CLI 產生新的啟動檔案

$ quasar new boot <name> [--format ts]

其中 <name> 應替換為適合您啟動檔案的名稱。

此命令會建立一個新檔案:/src/boot/<name>.js,其中包含以下內容

// import something here

// "async" is optional!
// remove it if you don't need it
export default async ({ /* app, router, store */ }) => {
  // something to do
}

您也可以傳回 Promise

// import something here

export default ({ /* app, router, store */ }) => {
  return new Promise((resolve, reject) => {
    // do something
  })
}

提示

如果您不需要預設匯出,則可以將其從啟動檔案中省略。在這些情況下,您不需要存取 “app”、“router”、“store” 等。

現在您可以根據啟動檔案的預期用途,將內容新增至該檔案。

別忘了您的預設匯出需要是一個函式。但是,如果啟動檔案為了稍後使用而公開某些內容,您可以擁有任意數量的具名匯出。在這種情況下,您可以在應用程式中的任何位置匯入任何這些具名匯出。

最後一步是告訴 Quasar 使用您的新啟動檔案。為了實現這一點,您需要在 /quasar.config 中新增該檔案

boot: [
  // references /src/boot/<name>.js
  '<name>'
]

在建置 SSR 應用程式時,您可能希望某些啟動檔案僅在伺服器上或僅在客戶端上執行,在這種情況下,您可以像下面這樣做

boot: [
  {
    server: false, // run on client-side only!
    path: '<name>' // references /src/boot/<name>.js
  },
  {
    client: false, // run on server-side only!
    path: '<name>' // references /src/boot/<name>.js
  }
]

如果您想要從 node_modules 指定啟動檔案,您可以透過在路徑前面加上 ~ (波浪符號) 字元來執行此操作

boot: [
  // boot file from an npm package
  '~my-npm-package/some/file'
]

如果您希望僅針對特定建置類型將啟動檔案注入到您的應用程式中

boot: [
  ctx.mode.electron ? 'some-file' : ''
]

重新導向到另一個頁面

警告

重新導向時請注意,因為您可能會將應用程式配置為進入無限重新導向迴圈。

export default ({ urlPath, redirect }) => {
  // ...
  const isAuthorized = // ...
  if (!isAuthorized && !urlPath.startsWith('/login')) {
    redirect({ path: '/login' })
    return
  }
  // ...
}

redirect() 方法接受字串 (完整 URL) 或 Vue Router 位置字串或物件。在 SSR 上,它可以接收第二個參數,該參數應為任何重新導向瀏覽器的 HTTP 狀態碼 (3xx 狀態碼) 的數字。

// Examples for redirect() with a Vue Router location:
redirect('/1') // Vue Router location as String
redirect({ path: '/1' }) // Vue Router location as Object

// Example for redirect() with a URL:
redirect('https://quasar.dev.org.tw')

重要!

Vue Router 位置 (以字串或物件形式) 並非指 URL 路徑 (和雜湊),而是指您已定義的實際 Vue Router 路由。因此請勿將 publicPath 新增至其中,如果您使用的是 Vue Router 雜湊模式,則請勿將雜湊新增至其中。


假設我們定義了這個 Vue Router 路由

{
  path: '/one',
  component: PageOne
}


那麼無論我們的 publicPath 為何,我們都可以像這樣呼叫 redirect()

// publicPath: /wiki; vueRouterMode: history
redirect('/one') // good way
redirect({ path: '/one' }) // good way
redirect('/wiki/one') // WRONG!

// publicPath: /wiki; vueRouterMode: hash
redirect('/one') // good way
redirect({ path: '/one' }) // good way
redirect('/wiki/#/one') // WRONG!

// no publicPath; vueRouterMode: hash
redirect('/one') // good way
redirect({ path: '/one' }) // good way
redirect('/#/one') // WRONG!

如先前章節所述,啟動檔案的預設匯出可以傳回 Promise。如果此 Promise 因包含 “url” 屬性的物件而被拒絕,則 Quasar CLI 會將使用者重新導向到該 URL

export default ({ urlPath }) => {
  return new Promise((resolve, reject) => {
    // ...
    const isAuthorized = // ...
    if (!isAuthorized && !urlPath.startsWith('/login')) {
      // the "url" param here is of the same type
      // as for "redirect" above
      reject({ url: '/login' })
      return
    }
    // ...
  })
}

或更簡單的等效方式

export default () => {
  // ...
  const isAuthorized = // ...
  if (!isAuthorized && !urlPath.startsWith('/login')) {
    return Promise.reject({ url: '/login' })
  }
  // ...
}

Quasar 應用程式流程

為了更好地了解啟動檔案的工作原理及其作用,您需要了解您的網站/應用程式是如何啟動的

  1. Quasar 已初始化 (元件、指令、插件、Quasar i18n、Quasar 圖示集)
  2. Quasar Extras 已匯入 (Roboto 字體 – 如果使用、圖示、動畫、…)
  3. Quasar CSS 和您應用程式的全域 CSS 已匯入
  4. App.vue 已載入 (尚未使用)
  5. Store 已匯入 (如果使用 src/stores 中的 Pinia 或 src/store 中的 Vuex)
  6. Pinia (如果使用) 已注入到 Vue 應用程式實例中
  7. Router 已匯入 (在 src/router 中)
  8. 啟動檔案已匯入
  9. 執行 Router 預設匯出函式
  10. 啟動檔案取得其預設匯出函式的執行
  11. (如果在 Electron 模式下) Electron 已匯入並注入到 Vue prototype 中
  12. (如果在 Cordova 模式下) 監聽 “deviceready” 事件,然後才繼續後續步驟
  13. 使用根元件實例化 Vue 並附加到 DOM

啟動檔案範例

Axios

import { boot } from 'quasar/wrappers'
import axios from 'axios'

const api = axios.create({ baseURL: 'https://api.example.com' })

export default boot(({ app }) => {
  // for use inside Vue files (Options API) through this.$axios and this.$api

  app.config.globalProperties.$axios = axios
  // ^ ^ ^ this will allow you to use this.$axios (for Vue Options API form)
  //       so you won't necessarily have to import axios in each vue file

  app.config.globalProperties.$api = api
  // ^ ^ ^ this will allow you to use this.$api (for Vue Options API form)
  //       so you can easily perform requests against your app's API
})

export { axios, api }

vue-i18n

import { boot } from 'quasar/wrappers'
import { createI18n } from 'vue-i18n'
import messages from 'src/i18n'

export default boot(({ app }) => {
  // Create I18n instance
  const i18n = createI18n({
    locale: 'en-US',
    messages
  })

  // Tell app to use the I18n instance
  app.use(i18n)
})

路由器身份驗證

某些啟動檔案可能需要干預 Vue Router 配置

import { boot } from 'quasar/wrappers'

export default boot(({ router, store }) => {
  router.beforeEach((to, from, next) => {
    // Now you need to add your authentication logic here, like calling an API endpoint
  })
})

從啟動檔案存取資料

有時您想要在您無法存取根 Vue 實例的檔案中,存取您在啟動檔案中配置的資料。

幸運的是,由於啟動檔案只是普通的 JavaScript 檔案,您可以在啟動檔案中新增任意數量的具名匯出。

讓我們以 Axios 為例。有時您想要在您的 JavaScript 檔案中存取您的 Axios 實例,但您無法存取根 Vue 實例。若要解決此問題,您可以匯出啟動檔案中的 Axios 實例,並在其他位置匯入它。

考慮以下 axios 的啟動檔案

axios 啟動檔案 (src/boot/axios.js)

import axios from 'axios'

// We create our own axios instance and set a custom base URL.
// Note that if we wouldn't set any config here we do not need
// a named export, as we could just `import axios from 'axios'`
const api = axios.create({
  baseURL: 'https://api.example.com'
})

// for use inside Vue files through this.$axios and this.$api
// (only in Vue Options API form)
export default ({ app }) => {
  app.config.globalProperties.$axios = axios
  app.config.globalProperties.$api = api
}

// Here we define a named export
// that we can later use inside .js files:
export { axios, api }

在任何 JavaScript 檔案中,您都可以像這樣匯入 axios 實例。

// we import one of the named exports from src/boot/axios.js
import { api } from 'boot/axios'

語法延伸閱讀:ES6 匯入ES6 匯出