为什么捐赠
API 资源管理器
升级指南
新增!
quasar.config 文件
转换为使用 Webpack 的 CLI
浏览器兼容性
支持 TypeScript
目录结构
命令列表
CSS 预处理器
路由
延迟加载 - 代码分割
处理资源
启动文件
预取功能
API 代理
处理 Webpack
处理 process.env
使用 Pinia 进行状态管理
使用 Vuex 进行状态管理
代码检查器
测试与审计
开发移动应用
Ajax 请求
向公众开放开发服务器
使用 Webpack 的 Quasar CLI - @quasar/app-webpack
启动文件

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 存储的实例 - **如果您的项目使用 Pinia(您有 src/stores)或 Vuex(您有 src/store),则只会传递 store**
ssrContext仅在服务器端可用,如果构建用于 SSR。 更多信息
urlPathURL 的路径名(路径 + 搜索)部分。它还在客户端包含哈希。
publicPath配置的公共路径。
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 原型或注入 Vue 应用程序的根实例,则需要这些变量。

启动文件使用示例

  • 您的 Vue 插件有安装说明,例如需要在其上调用 app.use()
  • 您的 Vue 插件需要实例化添加到根实例的数据 - 一个示例是 vue-i18n
  • 您希望使用 app.mixin() 添加全局混入。
  • 您希望将某些内容添加到 Vue 应用程序 globalProperties 以方便访问 - 一个示例是方便地在 Vue 文件中使用 this.$axios(对于选项 API)而不是在每个此类文件中导入 Axios。
  • 您希望干预路由器 - 一个示例是使用 router.beforeEach 进行身份验证
  • 您希望干预 Pinia 或 Vuex 存储实例 - 一个示例是使用 vuex-router-sync
  • 配置库的各个方面 - 一个示例是使用基本 URL 创建 Axios 实例;然后您可以将其注入 Vue 原型和/或导出它(以便您可以从应用程序中的任何其他位置导入该实例)

启动文件不需要使用示例

  • 对于像 Lodash 这样的普通 JavaScript 库,它们不需要在使用之前进行任何初始化。例如,只有当您希望使用它注入 Vue 原型时,Lodash 才有意义作为启动文件使用,例如能够在 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.org.cn')

重要!

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 原型中
  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 importES6 export