应用扩展安装 API

此页面介绍 src/install.js 文件,该文件仅在应用扩展安装时执行。并不是所有的扩展都需要一个安装脚本,这是一个可选项。

基本文件结构示例:

// 可以是异步的
export default function (api) {
  // 下面描述了 "api" 对象的属性和方法
}

api.engine

包含正在使用的 Quasar CLI 引擎名(字符串)。示例:@quasar/app-vite@quasar/app-webpack

api.hasVite

布尔值 - 是否在 @quasar/app-vite 上运行。

api.hasWebpack

布尔值 - 是否在 @quasar/app-webpack 上运行。

api.extId

包含此应用扩展的 ext-id(字符串)。

api.prompts

是一个包含在扩展时的提示答案的对象。有关提示的更多信息,请参阅 Prompts API

api.resolve

在运行此应用扩展的应用程序内解析路径。消除了导入 path 并自行解析路径的需求。

// 解析到应用程序的根目录
api.resolve.app('src/my-file.js')

// 解析到应用程序/src目录
api.resolve.src('my-file.js')

// 解析到应用程序/public目录
// (@quasar/app-webpack v3.4+ 或 @quasar/app-vite v1+)
api.resolve.public('my-image.png')

// 解析到应用程序/src-pwa目录
api.resolve.pwa('some-file.js')

// 解析到应用程序/src-ssr目录
api.resolve.ssr('some-file.js')

// 解析到应用程序/src-cordova目录
api.resolve.cordova('config.xml')

// 解析到应用程序/src-electron目录
api.resolve.electron('some-file.js')

// 解析到应用程序/src-bex目录
api.resolve.bex('some-file.js')

api.appDir

包含此扩展正在运行的宿主应根目录的完整路径(字符串)。

api.hasTypescript
@quasar/app-vite 1.6+
@quasar/app-webpack 3.11+

/**
 * @return {Promise<boolean>} 宿主项目是否启用 TypeScript
 */
await api.hasTypescript()

api.hasLint
@quasar/app-vite 1.6+
@quasar/app-webpack 3.11+

/**
 * @return {Promise<boolean>} 宿主项目是否启用 ESLint
 */
await api.hasLint()

api.getStorePackageName
@quasar/app-vite 1.6+
@quasar/app-webpack 3.11+

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

api.getNodePackagerName
@quasar/app-vite 1.6+
@quasar/app-webpack 3.11+

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

api.compatibleWith

通过 semver 条件确保扩展与宿主应用程序中安装的程序包兼容。

如果不满足semver条件,则 Quasar CLI 会出错并停止执行。

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

/**
 * @param {string} packageName
 * @param {string} semverCondition
 */
api.compatibleWith(packageName, '1.x')
// 更复杂的例子:
if (api.hasVite === true) {
  api.compatibleWith('@quasar/app-vite', '^1.0.0-beta.0')
}
else {
  api.compatbileWith('@quasar/app-webpack', '^3.4.0')
}

api.hasPackage

检查宿主应用是否安装了某个包,并且可以通过 semver 条件设置版本。

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

/**
 * @param {string} packageName
 * @param {string} (可选) semver 条件
 * @return {boolean} 软件包已安装并满足可选的 semver 条件
 */
if (api.hasPackage('vuelidate')) {
  // 应用安装了这个包(任何版本)
}
if (api.hasPackage('quasar', '^2.0.0')) {
  // 应用安装了 quasar v2
}

api.hasExtension

检查另一个应用扩展是否通过 npm 安装并由 Quasar CLI 调用。

/**
 * 检查另一个应用扩展是否已安装
 *
 * @param {string} extId
 * @return {boolean} 扩展已安装并被调用
 */
if (api.hasExtension(extId)) {
  // 是的,我们安装了它
}

api.getPackageVersion

获取宿主应用的版本号

/**
 * @param {string} packageName
 * @return {string|undefined} 应用程序包的版本
 */
console.log(api.getPackageVersion(packageName))
// 输出示例:
//   1.1.3
//   undefined(未找到包时)

api.extendPackageJson

通过新属性扩展 package.json 文件的辅助方法。如果指定了现有属性,将覆盖它们。

/**
 * @param {object|string} extPkg - 要扩展的对象或一个 JSON 文件的相对路径
 */
api.extendPackageJson({
  scripts: {
    'electron': 'quasar dev -m electron'
  }
})

上面的示例向应用程序的 package.json 添加了一个 npm 脚本,因此您可以执行 yarn electron(或等效的 npm run electron)。

api.extendJsonFile

使用新属性(深度合并)扩展 JSON 文件。如果指定了现有属性,将覆盖它们。

/**
 * @param {string} file(相对于应用程序根目录的文件路径)
 * @param {object} newData(要合并的对象)
 */
api.extendJsonFile('src/some.json', {
  newProp: 'some-value'
})

api.render

从扩展的复制模版文件夹(您指定的任何文件夹)到应用的根目录。保持与模板文件夹具有相同的文件夹结构。

如果应用中已经存在某些文件,则会询问用户是否应覆盖它们。

调用 render() 需要传递模版文件夹的相对路径

/**
 * 从扩展模板复制一个文件夹到开发环境
 * 需要传递模版文件夹的相对路径,相对于调用 api.render 的文件
 *
 * @param {string} templatePath(模版文件夹的相对路径)
 * @param {object} scope(可选;渲染范围变量)
 */
api.render('./path/to/a/template/folder')

文件名的特殊情况

如果要渲染(复制)一个模板文件,其名称以点开头(例如 .env),则必须遵循特定的命名约定,因为发布插件到 npm 时会忽略点开头的文件:

# 包含点文件的模板必须使用下划线,替代其名称中的点:

some-folder/_env

# 当调用 api.render('./some-folder') 时,这将在项目文件夹中渲染为:

/.env

如果要渲染一个文件,其名称实际上以下划线开头,则文件名必须以 __(两个下划线字符而不是一个)开头:

some-folder/__my.css

# 当调用 api.render('./template') 时,这将在项目文件夹中渲染为:

/_my.css

使用范围

您还可以通过插值使用 lodash/template 语法将一些决策代码注入到要渲染的文件中。

示例:

// (my-folder 与当前文件位于相同的文件夹中)
api.render('./my-folder', {
  prompts: api.prompts
})

假设我们还使用了 Prompts API 文件。它询问用户是否要 “功能 X” 并将答案存储在名为 “featureX” 的变量中。

在渲染过程中,我们可以决定渲染的文件的样子。这样就不需要创建两个文件夹,也不需要根据某些决定来决定渲染哪个文件夹。

<% if (prompts.featureX) { %>
const message = '这是当存在 "功能 X" 时的内容'
<% } else { %>
const message = '这是当我们没有 "功能 X" 时的内容'
<% } %>

可能性仅受您的想象力限制。

api.renderFile

与 api.render() 类似,区别在于该方法渲染单个文件。

/**
 * 从扩展渲染(复制)一个模板文件到开发环境
 * 需要传递模版文件的相对路径,相对于调用 api.render 的文件
 *
 * @param {string} relativeSourcePath(源文件的相对路径,相对于此文件)
 * @param {string} relativeTargetPath(相对于应用程序根目录的目标路径 - 包括文件名!)
 * @param {object} scope(可选;渲染范围变量)
 */
api.renderFile('./path/to/a/template/filename', 'path/relative/to/app/root/filename', {
  prompts: api.prompts
})

api.renderFile('./my-file.json', 'src/my-file.json')

api.getPersistentConf

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

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

api.setPersistentConf

设置此扩展的内部持久配置。如果已存在,则将其覆盖。

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

api.mergePersistentConf

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

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

api.onExitLog

在 App CLI 完成安装应用扩展并即将退出时添加一条日志。可以多次调用以注册多个退出日志。

/**
 * @param {string} msg
 */
api.onExitLog('感谢安装我的扩展')