为什么捐赠
API 浏览器
联系站长
App Extension Index API

本页面介绍 /ae/src/index.js|ts 文件,它在 quasar devquasar build 时执行。这是你修改构建以满足 App Extension 需求的主要入口。例如,注册 boot 文件、修改 Vite 配置、注册 CSS、注册 UI 组件、注册 Quasar CLI 命令等。

文件的基本结构示例:

/ae/src/index.js (or .ts)

import { defineIndexScript } from '#q-app'

// can be async
export default defineIndexScript(api => {})

API 参数

api.ctx

/quasar.config 文件中的 ctx 相同。帮助你根据 quasar devquasar build 运行的上下文做出决策。

示例:你可能只想在 Electron 模式下使用某个 api 方法。

if (api.ctx.dev && api.ctx.mode.electron) {
  api.beforeDev(api => {
    // do something when running quasar dev and
    // with Electron mode
  })
}
api.ctx example:

{
  dev: true,
  prod: false,
  mode: { spa: true },
  modeName: 'spa',
  target: {},
  targetName: undefined,
  arch: {},
  archName: undefined,
  bundler: {},
  bundlerName: undefined,
  debug: false,
  publish: undefined,
  vueDevtools: false,
  appPaths: {
    cliDir: '...absolute path of it',
    appDir: '...absolute path of it',
    srcDir: '...absolute path of it',
    publicDir: '...absolute path of it',
    pwaDir: '...absolute path of it',
    ssrDir: '...absolute path of it',
    cordovaDir: '...absolute path of it',
    capacitorDir: '...absolute path of it',
    electronDir: '...absolute path of it',
    bexDir: '...absolute path of it',
    quasarConfigFilename: '...absolute path of the quasar.config file',
    quasarConfigInputFormat: 'js', // or 'ts'
    resolve: {
      cli: (...paths) => theAbsolutePathToCliDir,
      app: (...paths) => theAbsolutePathToAppDir,
      src: (...paths) => theAbsolutePathToAppSrcDir,
      public: (...paths) => theAbsolutePathToPublicDir,
      pwa: (...paths) => theAbsolutePathToAppSrcPwaDir,
      ssr: (...paths) => theAbsolutePathToAppSrcSsrDir,
      cordova: (...paths) => theAbsolutePathToAppSrcCordovaDir,
      capacitor: (...paths) => theAbsolutePathToAppSrcCapacitorDir,
      electron: (...paths) => theAbsolutePathToAppSrcElectronDir,
      bex: (...paths) => theAbsolutePathToAppSrcBexDir
    }
  }
}

api.extId

包含此 App Extension 的 ext-id(字符串)。

api.prompts

一个包含此 App Extension 安装时用户回答的对象。更多关于 prompts 的信息,请查看 Prompts API

api.resolve

解析运行此 App Extension 的应用中的路径。无需自己导入 path 并解析路径。

// resolves to root of app
api.resolve.app('src/my-file.js')

// resolves to root/src of app
api.resolve.src('my-file.js')

// resolves to root/public of app
api.resolve.public('my-image.png')

// resolves to root/src-pwa of app
api.resolve.pwa('some-file.js')

// resolves to root/src-ssr of app
api.resolve.ssr('some-file.js')

// resolves to root/src-cordova of app
api.resolve.cordova('config.xml')

// resolves to root/src-electron of app
api.resolve.electron('some-file.js')

// resolves to root/src-electron of app
api.resolve.electron('some-file.js')

// resolves to root/src-bex of app
api.resolve.bex('some-file.js')

api.appDir

包含运行此 App Extension 的应用根目录的完整路径(字符串)。

api.logger

一个作用域为当前 App Extension 的日志工具。每个方法的输出都会标记 AE (<extId>),方便用户识别哪行日志来自哪个扩展。

api.logger.log('hello') // 绿色横幅行
api.logger.warn('careful') // 黄色横幅警告
api.logger.fatal('boom') // 红色横幅错误;以退出码 1 退出
api.logger.tip('try foo') // TIP 标签提示行
api.logger.info('synced') // INFO 标签行
api.logger.info('synced', 'SYNC') // 自定义标签文本替代 INFO
api.logger.success('built')
api.logger.error('oh no')
api.logger.warning('hmm')

const finish = api.logger.progress({
  tool: 'ssg',
  waitAction: 'building',
  doneAction: 'built'
})
// ...稍后
finish() // 打印 DONE 行及耗时

api.logger.dot // 辅助方法打印的圆点字符

api.hasTypescript

/**
 * @return {Promise<boolean>} host project has TypeScript active or not
 */
await api.hasTypescript()

api.getStorePackageName

/**
 * @return {Promise<string|undefined>} 'pinia' | 'vuex' | undefined
 */
await api.getStorePackageName()

api.getNodePackagerName

/**
 * @return {Promise<'npm' | 'yarn' | 'pnpm' | 'bun'>}
 */
await api.getNodePackagerName()

api.compatibleWith

通过 semver 条件确保 App Extension 与宿主应用中安装的包兼容。

如果不满足 semver 条件,@quasar/app 将报错并停止执行。

semver 条件示例:'1.x || >=2.5.0 || 5.0.0 - 7.2.3'

/**
 * @param {string} packageName
 * @param {string} semverCondition
 */
api.compatibleWith('@quasar/app-vite', '3.x')
A more complex example

api.compatibleWith('@quasar/app-vite', '^3.0.0-rc.1')

api.hasPackage

通过 semver 条件判断宿主应用中是否安装了某个包。

semver 条件示例:'1.x || >=2.5.0 || 5.0.0 - 7.2.3'

/**
 * @param {string} packageName
 * @param {string} (optional) semverCondition
 * @return {boolean} package is installed and meets optional semver condition
 */
if (api.hasPackage('vuelidate')) {
  // hey, this app has it (any version of it)
}
if (api.hasPackage('quasar', '^2.0.0')) {
  // hey, this app has Quasar UI v2 installed
}

api.hasExtension

检查另一个 app extension 是否已通过 npm 安装且 Quasar CLI 已调用它。

/**
 * Check if another app extension is installed
 *
 * @param {string} extId
 * @return {boolean} has the extension installed & invoked
 */
if (api.hasExtension(extId)) {
  // hey, we have it
}

api.getPackageVersion

获取宿主应用中某个包的版本。

/**
 * @param {string} packageName
 * @return {string|undefined} version of app's package
 */
console.log(api.getPackageVersion(packageName))
// output examples:
//   1.1.3
//   undefined (when package not found)

api.extendQuasarConf

扩展 quasar.config 文件

extendQuasarConf: Callback<
  (
    cfg: QuasarConf,
    api: IndexAPI
  ) => QuasarConf | void | Promise<QuasarConf | void>
>

// Example:
api.extendQuasarConf((conf, api) => {
  // Do something with quasar.config file.
  // Optionally, return a config that will be merged
  // with the default one
})

注册 boot 和 css 文件

import { defineIndexScript } from '#q-app'

export default defineIndexScript(api => {
  api.extendQuasarConf((conf, api) => {
    return {
      // make sure my-ext boot file is registered
      boot: ['~quasar-app-extension-my-ext/src/runtime/boot.register.js'],
      // make sure my global my-ext css goes through Vite
      css: ['~quasar-app-extension-my-ext/src/runtime/style.sass']
    }
  })

  // Alternatively, directly touch the "conf" param
  api.extendQuasarConf((conf, api) => {
    // make sure my-ext boot file is registered
    conf.boot.push('~quasar-app-extension-my-ext/src/runtime/boot.register.js')
    // make sure my global my-ext css goes through Vite
    conf.css.push('~quasar-app-extension-my-ext/src/runtime/style.sass')
  })
})

TIP

注意路径前面的波浪号(~)。它告诉 Quasar CLI 该路径是 node_modules 中的依赖,而不是相对于 App Extension index 脚本文件的相对路径。

api.registerCommand

注册一个命令,可通过 quasar run <ext-id> <cmd> [...args] 使用。

/**
 * @param {string} commandName
 * @param {function} fn
 *   (processArgv: string[]) => ?Promise
 */
api.registerCommand('start', processArgv => {
  // do something here
  // this registers the "start" command
  // and this handler is executed when running
  // $ quasar run <ext-id> start
})

定义和解析参数的示例:

// import { parseArgs } from 'node:util'

api.registerCommand('fun', () => {
  try {
    const { values, positionals } = parseArgs({
      options: {
        name: { type: 'string', short: 'n' },
        debug: { type: 'boolean' }
      },
      strict: true,
      allowPositionals: true
    })

    console.log(values, positionals)
  } catch (err) {
    console.error(err.message)
  }
})

api.registerDescribeApi

quasar describe 命令注册一个 API 文件。

/**
 * @param {string} name
 * @param {string} relativePath
 *   (relative path starting from the file where you have this call)
 */
api.registerDescribeApi(
  'MyComponent',
  './relative/path/to/my/component/file.json'
)

上面的代码将响应 quasar describe MyComponent 命令。

关于此类 JSON 文件的语法,请查看项目目录中的 /node_modules/quasar/dist/api。注意你的 JSON 必须包含 type 属性(“component”、“directive”、“plugin”)。例如:

{
  "type": "component",
  "props": {
  },
  ...
}

TIP

你可能还想看看 Quasar JSON API Schema 页面。

TIP

始终使用 quasar describe 命令测试以确保语法正确且没有错误。

api.getPersistentConf

获取此扩展的内部持久化配置。如果没有则返回空对象。

/**
 * @return {object} cfg
 */
api.getPersistentConf()

api.setPersistentConf

设置此扩展的内部持久化配置。如果已存在则会被覆盖。

/**
 * @param {object} cfg
 */
api.setPersistentConf({
  // ....
})

api.mergePersistentConf

深度合并到此扩展的内部持久化配置中。如果扩展还没有设置任何配置,这本质上等同于首次设置。

/**
 * @param {object} cfg
 */
api.mergePersistentConf({
  // ....
})

api.beforeDev

quasar dev 命令运行前准备外部服务,例如启动后端或应用依赖的其他服务。

可以使用 async/await 或直接返回 Promise。

/**
 * @param {function} fn
 *   (api, { quasarConf }) => ?Promise
 */
api.beforeDev((api, { quasarConf }) => {
  // do something
})

api.afterDev

在 Quasar 开发服务器启动后运行钩子(quasar dev)。此时开发服务器已启动,你可以对其进行操作。

可以使用 async/await 或直接返回 Promise。

/**
 * @param {function} fn
 *   (api, { quasarConf }) => ?Promise
 */
api.afterDev((api, { quasarConf }) => {
  // do something
})

api.beforeBuild

在 Quasar 为生产环境构建应用之前运行钩子(quasar build)。此时 dist 目录尚未创建。

可以使用 async/await 或直接返回 Promise。

/**
 * @param {function} fn
 *   (api, { quasarConf }) => ?Promise
 */
api.beforeBuild((api, { quasarConf }) => {
  // do something
})

api.afterBuild

在 Quasar 为生产环境构建应用之后运行钩子(quasar build)。此时 dist 目录已创建,你可以对其进行操作。

可以使用 async/await 或直接返回 Promise。

/**
 * @param {function} fn
 *   (api, { quasarConf }) => ?Promise
 */
api.afterBuild((api, { quasarConf }) => {
  // do something
})

api.onPublish

如果请求了发布(quasar build -P),在 Quasar 为生产环境构建应用且 afterBuild 钩子(如果指定了)执行完毕后运行此钩子。

可以使用 async/await 或直接返回 Promise。

/**
 * @param {function} fn
 *   () => ?Promise
 * @param {object} opts
 *   * arg - argument supplied to "--publish"/"-P" parameter
 *   * distDir - folder where distributables were built
 */
api.onPublish((api, opts) => {
  // do something
})

api.extendViteConf

/**
 * Extend the Vite config generated by Quasar CLI.
 *
 * Can be async. Can directly modify the "config" parameter or
 * return a new one that will be merged with the default one.
 */
api.extendViteConf: (
  config: ViteUserConfig,
  invokeParams: { isClient: boolean, isServer: boolean },
  api
) => ViteUserConfig | void | Promise<ViteUserConfig | void>;

// Example:
api.extendViteConf((viteConf, { isClient, isServer }, api) => {
  // add/remove/change Quasar CLI generated Vite config object;
  // similar in use to /quasar.config > build > extendViteConf
})

api.extendSSRWebserverConf

/**
 * Extend the Rolldown config that is used for the SSR webserver
 * (which includes the SSR middlewares).
 *
 * Can be async. Can directly modify the "rolldownConf" parameter or
 * return a new one that will be merged with the default one.
 */
api.extendSSRWebserverConf: (
  config: RolldownOptions,
  api
) => void | RolldownOptions | Promise<void | RolldownOptions>;

// Example:
api.extendSSRWebserverConf((rolldownConf, api) => {
  // add/remove/change Quasar CLI generated Rolldown config object;
  // similar in use to /quasar.config > ssr > extendSSRWebserverConf
})

api.extendSSRPackageJson
@quasar/app-vite v3+

/**
 * Add/remove/change properties of SSR production generated package.json
 *
 * Can be async. Can directly modify the "pkgJson" parameter or
 * return a new one that will be merged with the default one.
 */
api.extendSSRPackageJson: (
  pkgJson: { [index in string]: any },
  api: IndexAPI
) =>
  | void
  | { [index in string]: any }
  | Promise<void | { [index in string]: any }>;

// Example:
api.extendSSRPackageJson((pkgJson, api) => {
  // add/remove/change pkgJson;
  // similar in use to /quasar.config > ssr > extendSSRPackageJson
})

api.extendSSRGenerateSWOptions
@quasar/app-vite v3+

/**
 * Extend/configure the Workbox GenerateSW options
 * Specify Workbox options which will be applied on top of
 *  `pwa > extendPWAGenerateSWOptions()`.
 * https://developer.chrome.com/docs/workbox/the-ways-of-workbox/
 *
 * Can be async. Can directly modify the "config" parameter or
 * return a new one that will be merged with the default one.
 */
api.extendSSRGenerateSWOptions: (
  config: GenerateSWOptions,
  api: IndexAPI
) => void | GenerateSWOptions | Promise<void | GenerateSWOptions>;

// Example:
api.extendSSRGenerateSWOptions((config, api) => {
  // add/remove/change config;
  // similar in use to /quasar.config > ssr > extendSSRGenerateSWOptions
})

api.extendSSRInjectManifestOptions
@quasar/app-vite v3+

/**
 * Extend/configure the Workbox InjectManifest options
 * Specify Workbox options which will be applied on top of
 *  `pwa > extendPWAInjectManifestOptions()`.
 * https://developer.chrome.com/docs/workbox/the-ways-of-workbox/
 *
 * Can be async. Can directly modify the "config" parameter or
 * return a new one that will be merged with the default one.
 */
api.extendSSRInjectManifestOptions: (
  config: InjectManifestOptions,
  api: IndexAPI
) => void | InjectManifestOptions | Promise<void | InjectManifestOptions>;

// Example:
api.extendSSRInjectManifestOptions((config, api) => {
  // add/remove/change config;
  // similar in use to /quasar.config > ssr > extendSSRInjectManifestOptions
})

api.extendElectronMainConf

/**
 * Extend the Rolldown config that is used for the electron-main thread.
 *
 * Can be async. Can directly modify the "config" parameter or
 * return a new one that will be merged with the default one.
 */
api.extendElectronMainConf: (
  config: RolldownOptions,
  api
) => void | RolldownOptions | Promise<void | RolldownOptions>;

// Example:
api.extendElectronMainConf((rolldownConf, api) => {
  // add/remove/change Quasar CLI generated Rolldown config object;
  // similar in use to /quasar.config > electron > extendElectronMainConf
})

api.extendElectronPreloadConf

/**
 * Extend the Rolldown config that is used for the electron-preload thread.
 *
 * Can be async. Can directly modify the "config" parameter or
 * return a new one that will be merged with the default one.
 */
api.extendElectronPreloadConf: (
  config: RolldownOptions,
  api
) => void | RolldownOptions | Promise<void | RolldownOptions>;

// Example:
api.extendElectronPreloadConf((rolldownConf, api) => {
  // add/remove/change Quasar CLI generated Rolldown config object;
  // similar in use to /quasar.config > electron > extendElectronPreloadConf
})

api.extendElectronPackageJson
@quasar/app-vite v3+

/**
 * Add/remove/change properties of Electron production generated package.json
 *
 * Can be async. Can directly modify the "pkgJson" parameter or
 * return a new one that will be merged with the default one.
 */
api.extendElectronPackageJson: (
  pkgJson: { [index in string]: any },
  api: IndexAPI
) =>
  | void
  | { [index in string]: any }
  | Promise<void | { [index in string]: any }>;

// Example:
api.extendElectronPackageJson((pkgJson, api) => {
  // add/remove/change pkgJson;
  // similar in use to /quasar.config > electron > extendElectronPackageJson
})

api.extendPWACustomSWConf

/**
 * Extend the Rolldown config that is used for the custom service worker
 * (if using it through workboxMode: 'InjectManifest').
 *
 * Can be async. Can directly modify the "config" parameter or
 * return a new one that will be merged with the default one.
 */
api.extendPWACustomSWConf: (
  config: RolldownOptions,
  api
) => void | RolldownOptions | Promise<void | RolldownOptions>;

// Example:
api.extendPWACustomSWConf((rolldownConf, api) => {
  // add/remove/change Quasar CLI generated Rolldown config object;
  // similar in use to /quasar.config > pwa > extendPWACustomSWConf
})

api.extendPWAManifestJson
@quasar/app-vite v3+

/**
 * Should you need some dynamic changes to the /src-pwa/manifest.json,
 * use this method to do it.
 *
 * Can be async. Can directly modify the "json" parameter or
 * return a new one that will be merged with the default one.
 */
api.extendPWAManifestJson: (
  json: PwaManifestOptions,
  api: IndexAPI
) => void | PwaManifestOptions | Promise<void | PwaManifestOptions>;

// Example:
api.extendPWAManifestJson((json, api) => {
  // add/remove/change json;
  // similar in use to /quasar.config > pwa > extendPWAManifestJson
})

api.extendPWAGenerateSWOptions
@quasar/app-vite v3+

/**
 * Extend/configure the Workbox GenerateSW options.
 *
 * Can be async. Can directly modify the "config" parameter or
 * return a new one that will be merged with the default one.
 */
api.extendPWAGenerateSWOptions: (
  config: GenerateSWOptions,
  api: IndexAPI
) => void | GenerateSWOptions | Promise<void | GenerateSWOptions>;

// Example:
api.extendPWAGenerateSWOptions((config, api) => {
  // add/remove/change config;
  // similar in use to /quasar.config > pwa > extendPWAGenerateSWOptions
})

api.extendPWAInjectManifestOptions
@quasar/app-vite v3+

/**
 * Extend/configure the Workbox InjectManifest options.
 *
 * Can be async. Can directly modify the "config" parameter or
 * return a new one that will be merged with the default one.
 */
api.extendPWAInjectManifestOptions: (
  config: InjectManifestOptions,
  api: IndexAPI
) => void | InjectManifestOptions | Promise<void | InjectManifestOptions>;

// Example:
api.extendPWAInjectManifestOptions((config, api) => {
  // add/remove/change config;
  // similar in use to /quasar.config > pwa > extendPWAInjectManifestOptions
})

api.extendBexScriptsConf

/**
 * Extend the Rolldown config that is used for the bex scripts
 * (background, content scripts, dom script).
 *
 * Can be async. Can directly modify the "config" parameter or
 * return a new one that will be merged with the default one.
 */
api.extendBexScriptsConf: (
  config: RolldownOptions,
  api
) => void | RolldownOptions | Promise<void | RolldownOptions>;

// Example:
api.extendBexScriptsConf((rolldownConf, api) => {
  // add/remove/change Quasar CLI generated Rolldown config object;
  // similar in use to /quasar.config > bex > extendBexScriptsConf
})

api.extendBexManifestJson
@quasar/app-vite v3+

/**
 * Should you need some dynamic changes to the Browser Extension manifest file
 * (/src-bex/manifest.json) then use this method to do it.
 *
 * Can be async. Can directly modify the "json" parameter or
 * return a new one that will be merged with the default one.
 */
api.extendBexManifestJson: (
  json: object,
  api: IndexAPI
) => void | object | Promise<void | object>;

// Example:
api.extendBexManifestJson((json, api) => {
  // add/remove/change json;
  // similar in use to /quasar.config > bex > extendBexManifestJson
})