为什么捐赠
API 浏览器
升级指南
NEW!
创建新项目
quasar.config 配置文件
从 Webpack 项目转换
浏览器兼容性
TypeScript 支持
目录结构
命令列表
CSS 预处理器
使用 VueRouter 进行页面路由
懒加载 - 代码分割
资源处理
Boot 文件
预取特性
API 代理
配置 Vite
处理 import.meta.env
使用 Pinia 管理状态
代码检查与格式化
测试与审计
开发移动应用
Ajax 请求
开放开发服务器到公网
联系站长
Quasar CLI with Vite - @quasar/app-vite
Quasar CLI with Vite 升级指南

重要!

本指南是关于将 @quasar/app-vite v2 项目升级到 @quasar/app-vite v3。 对于更旧的版本,请参考 https://legacy-app.quasar.dev

App Extensions 开发者注意事项

你可能需要发布新版本的 Quasar App Extensions 以支持新的 @quasar/app-vite。如果你没有修改 quasar.config 配置,那么只需要更改以下内容即可:

api.compatibleWith(
 '@quasar/app-vite',
'^2.0.0' // [!code --]
'^3.0.0-rc.1' // [!code ++]
)

WARNING

App Extensions 背后的引擎变更今后只兼容 @quasar/app-vite v3+。你需要放弃对 @quasar/app-vite v2 和 @quasar/app-webpack(任何版本)的支持。

移除了 api.engineapi.hasViteapi.hasWebpackapi.hasLint

所有 api.extendX(fn, api) 方法现在可以是异步的,并且可以选择性地返回一个(Rolldown 等)配置对象,该对象将与默认配置合并。

api.extendX() 示例

api.extendSSRWebserverConf((rolldownConf, api) => {
  // 添加/移除/修改 Quasar CLI 生成的 Rolldown 配置对象

  // 新功能!现在可以选择性地返回一个配置对象,
  // 它将被合并到默认配置中
  return {
    output: {
      banner: '/**! My Banner */'
    }
  }
})

许多新的 Index API 方法:


/**
 * 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 }>;

/**
 * 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>;

/**
 * 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>;

新增了 api.logger(在所有四个脚本中可用:Index、Install、Uninstall、Prompts),它以 Quasar CLI 自己的输出风格打印日志,并在每行前标注你的扩展 ID。参见 api.logger

@quasar/app-vite 现在还为 Index/Prompts/Install/Uninstall 脚本提供了新的类型包装器。IDE 自动补全,我们来了。

通过 App Extension 提供的 CLI 命令的简写形式已被移除:

# 仍然有效;推荐的方式!
quasar run <ext-id> <cmd> [...args]

# 以下方式将不再有效:
quasar <ext-id> <cmd> [...args]

并且 api.registerCommand() 的参数也发生了变化。

我们还大幅升级了 AE 的开发体验。你可能想从头到尾重新阅读一遍 AE 文档,从 AE 开发指南 开始,并创建一个新的 AE 项目目录来体验所有新功能。包含 TS 版本!

鸟瞰新特性

  • ⚡ 极速编译:我们用 Rolldown 替代了 esbuild 来处理 /src-* 目录,并彻底重新设计了构建架构。所有 Quasar 模式的构建步骤现在都是并行化的,带来了显著更快的速度和更小的生产包体积。

  • ⚙️ 新一代环境变量管理:我们从零开始重新设计了 env 文件管理。修改这些文件后不再需要重启开发服务器,而且你现在可以直接在 quasar.config 文件中使用它们!

  • 🔒 增强安全性与现代标准:我们从 process.env 迁移到了现代的 import.meta.env(与 Vite 原生模型对齐),并提供完整的 TypeScript 支持。新的安全层确保客户端文件只能使用可配置前缀的环境变量定义,防止敏感数据泄露。

  • 📦 更智能的依赖隔离:我们现在对每个 Quasar 模式的依赖有了清晰的分离。你可以直接在各自的 /src-* 目录中安装模式特定的包。例如,默认的 Electron 应用不再需要在其 dist 目录中安装依赖——只有你在 /src-electron 中显式安装的才会被包含。

  • 🌍 重新设计的 SSR 架构:SSR 模式现在对自定义 Web 服务器和 TypeScript 集成有了更好的支持。添加 SSR 时,CLI 会提示你使用 Hono、Fastify、Express 或 Koa 来生成预配置的 /src-ssr 目录(欢迎告诉我们你还想要哪些开箱即用的服务器支持!)。

  • 📂 SSR 新增服务器资源目录:我们引入了 /src-ssr/server-assets 目录以及实用的工具函数。这使得在开发和生产运行时中引用资源(如 HTTPS 证书)变得非常简单,消除了对 Apache/Nginx 包装器的严格需求。我们还让 serverless 支持变得轻而易举。

  • 🚀 为 SSG 铺路:这个新的 SSR 架构为我们未来正式发布静态站点生成(SSG)模式奠定了必要的基础。

  • 🖥️ 全新的 Electron 模式:我们添加了大量新功能使桌面开发更加顺畅。类似于 SSR,我们引入了 /src-electron/electron-assets 目录。通过 /src-electron 和 /src 中可用的新工具方法,从这里(或从 /public 目录)引用文件现在变得更加容易。

  • 🛣️ Vue Router:对基于文件名的路由提供一流支持。

  • 🚀 更智能的重载(仅在绝对必要时):你会发现开发体验有了显著提升,在修改 quasar.config 文件或 dotenv 文件时有更智能的启发式策略。

  • 🛠️ 现代化核心:代码库已更新以充分利用 Node.js v22+ 的特性,以及所有 Quasar 模式中无数其他小而重要的改进来提升你的生产力。CLI 使用的依赖大幅减少。

开始升级

TIP

如果你不确定是否会遗漏某些推荐的更改,你可以随时使用 @quasar/app-vite v3 创建一个新的项目目录,然后从那里轻松地移植你的应用。


pnpm create quasar@latest

PNPM 相关

如果你使用的是 PNPM v11,编辑你的 /pnpm-workspace.yaml 文件。不再需要 shamefullyHoist 配置。

# https://pnpm.io/settings

allowBuilds:
  '@parcel/watcher': true
  core-js: true
  electron-winstaller: true
  esbuild: true
  lightningcss: true
  rolldown: true
  unrs-resolver: true

同时,在 /src-<bex|pwa|electron|ssr> 中创建 pnpm-workspace.yaml 文件,内容如下:

/src-<bex|pwa|electron|ssr>/pnpm-workspace.yaml

# 此文件用于强制 pnpm 在此处安装依赖,不受上层 workspace 影响
# https://pnpm.io/settings

/package.json

编辑你的 /package.json,更新 @quasar/app-vite 条目:

/package.json

"devDependencies": {
"@quasar/app-vite": "^2.0.0", // [!code --]
"@quasar/app-vite": "^3.0.0-rc.1" // [!code ++]
}

同时确保你的 Vue Router 版本为 v5+,这是现在的最低版本要求!

/package.json

"dependencies": {
  "vue-router": "^5.0.6"
}

全局搜索替换

全局搜索 #q-app/wrappers 并替换为 #q-app

为了更好地与 Vue 生态系统对齐,Quasar CLI 现在只注入一个别名:@/。请在你的代码中对 import 语句进行全局搜索替换,如下表所示。或者,你也可以自行注入旧的别名(查看表格下方了解如何操作)。

别名状态说明
@/新增!指向 /src,替代旧的 src 别名。
app/已移除将导入替换为 @/../
src/已移除将导入替换为 @/
components/已移除将导入替换为 @/components/
layouts/已移除将导入替换为 @/layouts/
pages/已移除将导入替换为 @/pages/
assets/已移除将导入替换为 @/assets/。同时将 .vue 文件 <template> 中的 ~assets/... 替换为 ~@/assets/...
boot/已移除将代码中的引用替换为 @/boot/
stores/已移除将代码中的引用替换为 @/stores/

别名变更的替代方案

如果你愿意,可以自行注入旧的别名来避免上述变更:

/quasar.config file

import { defineConfig } from '#q-app'

export default defineConfig(ctx => ({
  build: {
    alias: {
      src: ctx.appPaths.srcDir,
      app: ctx.appPaths.appDir,
      components: ctx.appPaths.resolve.src('components'),
      layouts: ctx.appPaths.resolve.src('layouts'),
      pages: ctx.appPaths.resolve.src('pages'),
      assets: ctx.appPaths.resolve.src('assets'),
      boot: ctx.appPaths.resolve.src('boot'),
      stores: ctx.appPaths.resolve.src('stores')
    }
  }
}))

全局搜索 process.env 并替换为 import.meta.env。对于 Quasar 提供的常量,你还需要加上 QUASAR_ 前缀。以下是完整列表:

process.env -> import.meta.env

// 新增的布尔值常量!
import.meta.env.QUASAR_SPA_MODE
import.meta.env.QUASAR_PWA_MODE
import.meta.env.QUASAR_SSR_MODE
import.meta.env.QUASAR_ELECTRON_MODE
import.meta.env.QUASAR_BEX_MODE
import.meta.env.QUASAR_CAPACITOR_MODE
import.meta.env.QUASAR_CORDOVA_MODE

process.env.DEV // [!code --]
process.env.PROD // [!code --]
import.meta.env.QUASAR_DEV // [!code ++]
import.meta.env.QUASAR_PROD // [!code ++]

// 注意 DEBUGGING -> DEBUG 的变化!
process.env.DEBUGGING // [!code --]
import.meta.env.QUASAR_DEBUG // [!code ++]

process.env.MODE // [!code --]
process.env.TARGET // [!code --]
import.meta.env.QUASAR_MODE // [!code ++]
import.meta.env.QUASAR_TARGET // [!code ++]

process.env.CLIENT // [!code --]
process.env.SERVER // [!code --]
import.meta.env.QUASAR_CLIENT // [!code ++]
import.meta.env.QUASAR_SERVER // [!code ++]

process.env.SERVICE_WORKER_FILE // [!code --]
process.env.PWA_FALLBACK_HTML // [!code --]
process.env.PWA_SERVICE_WORKER_REGEX // [!code --]
import.meta.env.QUASAR_SERVICE_WORKER_FILE // [!code ++]
import.meta.env.QUASAR_PWA_FALLBACK_HTML // [!code ++]
import.meta.env.QUASAR_PWA_SERVICE_WORKER_REGEX // [!code ++]

process.env.QUASAR_ELECTRON_PRELOAD_FOLDER // [!code --]
process.env.APP_URL // [!code --]
import.meta.env.QUASAR_ELECTRON_PRELOAD_FOLDER // [!code ++]
import.meta.env.QUASAR_APP_URL // [!code ++]
// 已移除;请使用 ".cjs" 代替: // [!code --]
process.env.QUASAR_ELECTRON_PRELOAD_EXTENSION // [!code --]

对于 /index.html 文件,不再使用之前的 “process.env.X”,现在可以使用:

<!-- 旧方式,请替换! -->
<%= process.env.MY_ENV_VAR_OR_DEFINE %> // [!code --]

<!-- 新方式: -->
<%= importMetaEnv.MY_ENV_VAR_OR_DEFINE %> // [!code ++]
<!-- 或者简写方式: -->
%MY_ENV_VAR_OR_DEFINE% // [!code ++]

<% if (importMetaEnv.MY_ENV_VAR_OR_DEFINE) { %>Wow!<% } %>

Quasar 模式的 package.json

编辑你的 /package.json 文件,移除 Quasar 模式特定的依赖,并将它们迁移到新的 /src-<mode>/package.json(需要创建这些文件!):

/package.json 迁移到新的 /src-<mode>/package.json

// create /src-bex/package.json: // [!code ++]
{
  "name": "quasar-bex-app",
  "version": "1.0.0",
  "description": "Quasar BEX Folder",
  "private": true,
  "type": "module",
  "devDependencies": {
    "@types/chrome": "^0.1.40" // for TS only
  }
}

/quasar.config 文件的重要变更

编辑你的 /quasar.config 文件。以下是你需要注意的重要变更:

/quasar.config 文件

build: {
rawDefine: {} // [!code --]
define: {} // 值需要经过 JSON.stringify() 处理 // [!code ++]

env: {}, // [!code --]
defineEnv: {} // 或使用长格式 "define",key 中带 'import.meta.env.' 前缀 // [!code ++]

vueOptionsAPI // 如果需要请改为 "true";现在默认为 "false"! // [!code ++]
polyfillModulePreload // 已移除,使用 Vite 的默认配置 // [!code --]

// 新增!Vue Router v5+ 基于文件名的路由 // [!code ++]
filenameBasedRouting: boolean | VueRouterVitePluginOptions // [!code ++]

// 非 async,但现在也可以返回一个新配置
// 将与默认配置合并
extendTsConfig: (tsConfig: TSConfig) => void | TSConfig,

// 已移除;请自行添加你偏好的分析器; // [!code --]
// 下方有示例 // [!code --]
analyze // [!code --]
},

sourceFiles: {
 // 现在默认为:'src-pwa/register-sw'!
 // 修改文件名或设置为你当前使用的:
pwaRegisterServiceWorker: 'src-pwa/register-service-worker', // [!code ++]

 // 现在默认为 'src-pwa/custom-sw'!
 // 修改文件名或设置为你当前使用的:
pwaServiceWorker: 'src-pwa/custom-service-worker', // [!code ++]
},

cordova: {
noIosLegacyBuildFlag: true, // 不再可用;仅使用现代构建系统 // [!code --]
},

ssr: {
extendPackageJson (pkgJson) {}, // [!code --]
// 现在可以是异步的,并且可以选择性地返回对象与默认配置合并 // [!code ++]
extendSSRPackageJson (pkgJson) {}, // [!code ++]

extendSSRWebserverConf (esbuildConf) {}, // [!code --]
// 现在可以是异步的,并且可以选择性地返回对象与默认配置合并 // [!code ++]
extendSSRWebserverConf (rolldownConf) {}, // [!code ++]

pwaExtendGenerateSWOptions (conf) {}, // [!code --]
pwaExtendInjectManifestOptions (conf) {}, // [!code --]
// 现在可以是异步的,并且可以选择性地返回对象与默认配置合并 // [!code ++]
extendSSRGenerateSWOptions (conf) {}, // [!code ++]
// 现在可以是异步的,并且可以选择性地返回对象与默认配置合并 // [!code ++]
extendSSRInjectManifestOptions (conf) {}, // [!code ++]
},

pwa: {
// 新增!非 async,但现在也可以返回一个新配置
// 将与默认配置合并
extendPWASwTsConfig: (tsConfig: TSConfig) => void | TSConfig,

extendManifestJson (json) {}, // [!code --]
// 现在可以是异步的,并且可以选择性地返回对象与默认配置合并 // [!code ++]
extendPWAManifestJson (json) {}, // [!code ++]

injectPwaMetaTags: boolean // [!code --]
injectPWAMetaTags: boolean // [!code ++]

extendGenerateSWOptions (conf) {}, // [!code --]
extendInjectManifestOptions (conf) {}, // [!code --]
// 现在可以是异步的,并且可以选择性地返回对象与默认配置合并 // [!code ++]
extendPWAGenerateSWOptions (conf) {}, // [!code ++]
// 现在可以是异步的,并且可以选择性地返回对象与默认配置合并 // [!code ++]
extendPWAInjectManifestOptions (conf) {}, // [!code ++]

extendPWACustomSWConf (esbuildConf) {}, // [!code --]
// 现在可以是异步的,并且可以选择性地返回对象与默认配置合并 // [!code ++]
extendPWACustomSWConf (rolldownConf) {}, // [!code ++]
},

electron: {
extendPackageJson (pkgJson) {}, // [!code --]
// 现在可以是异步的,并且可以选择性地返回对象与默认配置合并 // [!code ++]
extendElectronPackageJson (pkgJson) {}, // [!code ++]

extendElectronMainConf (esbuildConf) {}, // [!code --]
extendElectronPreloadConf (esbuildConf) {}, // [!code --]
// 现在可以是异步的,并且可以选择性地返回对象与默认配置合并 // [!code ++]
extendElectronMainConf (rolldownConf) {}, // [!code ++]
// 现在可以是异步的,并且可以选择性地返回对象与默认配置合并 // [!code ++]
extendElectronPreloadConf (rolldownConf) {}, // [!code ++]
},

bex: {
extendBexScriptsConf (esbuildConf) {}, // [!code --]
// 现在可以是异步的,并且可以选择性地返回对象与默认配置合并 // [!code ++]
extendBexScriptsConf (rolldownConf) {}, // [!code ++]
}

由于 build.analyze 已被移除,以下是手动实现的方式:

build.analyze 的替代方案

// pnpm/yarn/npm/bun add -D rollup-plugin-visualizer
// ...rollup-* 插件与 Rolldown 兼容

import { defineConfig } from '#q-app'

export default defineConfig(ctx => {
  return {
    build: {
      vitePlugins: [
        ctx.prod
          ? [
              "rollup-plugin-visualizer",
              {
                open: true,
                filename: ctx.appPaths.resolve.cache("stats.html")
              },
              { client: true }
            ]
          : null
      ]
    }
  }
})

ctx 对象现在包含一个以 Quasar CLI 自己的输出风格打印日志的 logger。参见 通过 ctx 记录日志

TypeScript 变更

你唯一需要的 .d.ts 文件将位于项目根目录:

/env.d.ts

/**
 * 为你的自定义变量添加类型(Quasar CLI 未自动添加的),
 * 以避免 TypeScript 错误,例如动态的 process.env 变量
 * 或仅为 /quasar.config 文件本身配置的 dotenv 文件中的定义。
 *
 * @example
 * interface ImportMetaEnv {
 *   readonly MY_VAR: string;
 *   readonly MY_OTHER_VAR: string;
 * }
 */
interface ImportMetaEnv {}

你之前使用的以下内容需要从所有 .d.ts 文件中移除。建议只保留上面定义的 /env.d.ts 文件即可。

*env.d.ts

/**
 * 移除这些!不再需要了。
 * 删除整个代码块:
 */
declare namespace NodeJS {
  interface ProcessEnv {
    NODE_ENV: string
    VUE_ROUTER_MODE: 'hash' | 'history' | 'abstract' | undefined
    VUE_ROUTER_BASE: string | undefined
    // ...以及其他之前 Quasar 需要的定义
  }
}

你可以阅读关于 import.meta.env 的文档。强烈推荐,其中展示了所有新特性。

安装新依赖

然后在根目录和每个 /src-<mode> 目录中运行 pnpm/yarn/npm/bun install,并在根目录运行 quasar prepare。重启你的 IDE 以确保新依赖被正确识别。

确保使用最新的规范更新你的 /quasar.config 文件以满足类型要求。请检查以下所有章节。

重要的破坏性变更

  • 所有从 #q-app/wrappers 的导入需要替换为 #q-app。请进行全局搜索替换。
  • process.env 切换到了现代的 import.meta.env链接
  • /quasar.config > build > vueOptionsAPI 现在默认为 false
  • /quasar.config > build > polyfillModulePreload(已移除,现在使用 Vite 自身的配置)
  • /index.html -> 新的 HTML 常量替换<% if (process.env.X) %> 将不再有效。
  • 新的 dotenv 文件支持,包括 /quasar.config 文件本身。默认情况下,Quasar CLI 只会查找 .env.env.local,但你可以添加其他文件以支持带有 prod/dev/mode 后缀的文件。
  • /quasar.config > env 现在被新的 dotenv 支持使用。同时移除了 build > rawDefine。请使用新的 build > definedefineEnv 代替。链接
  • Boot 文件和 preFetch > redirect() 的用法已更改。调用后需要立即返回。不再支持通过抛出错误(或返回 Promise)配合 { url } 语法的方式。请直接使用 redirect() 代替。
  • /quasar.config 文件只能使用 .js.ts 扩展名。已移除对 .cjs.mjs.cts.mts 的支持。
  • 所有 Quasar 模式现在都需要在其 /src-<mode> 目录下直接安装特定依赖。
  • Rolldown 替代了 esbuild 来处理所有特定 Quasar 模式文件(在其 /src-<mode> 目录下)。这也影响了所有 /quasar.config 中的 extendX() 方法,因为它们现在接收的是 Rolldown 配置对象。
  • 所有 /quasar.config 中的 extendX() 方法现在可以是异步的,并且可以选择性地返回一个(Rolldown 等)配置对象,该对象将与默认配置合并。
  • 移除了对 Capacitor v4 及以下版本的支持
  • 移除了对 @electron/packager v18 及以下版本的支持
  • Cordova 的 iOS 现在使用现代构建系统。noIosLegacyBuildFlag 已被移除。
  • “quasar dev -m cordova” 命令现在会打开对应的 IDE(就像 Capacitor 模式一样)
  • “quasar dev/build -m bex” 命令现在默认使用 “chrome” 目标,所以 -t|--target 选项可以省略。

Electron 模式变更

我们引入了 quasarRuntime更多信息

将你的 /src-electron/icons 移动到 /src-electron/electron-assets/icons(创建新的 electron-assets 文件夹)。

Preload 脚本

/src-electron/electron-preload (Optional!)

/**
 * Only one preload script should contain this
 */

import { contextBridge } from 'electron'
import { quasarRuntime } from '#q-app/electron/preload'

/**
 * Can be used in the renderer process through `window.quasarRuntime`
 */
contextBridge.exposeInMainWorld('quasarRuntime', quasarRuntime)

Main 脚本

你可能还需要更新 /src-electron/electron-main 脚本:

/src-electron/electron-main

- import { fileURLToPath } from 'url'
- const currentDir = fileURLToPath(new URL('.', import.meta.url));

+ import {
+  registerQuasarRuntime,
+  resolveElectronAssetsPath
+ } from "#q-app/electron/main";

- let mainWindow: BrowserWindow | undefined;
- async function createWindow() {
-  mainWindow = new BrowserWindow({
-    icon: path.resolve(currentDir, 'icons/icon.png'), // tray icon
-    webPreferences: {
-      preload: path.resolve(
-        currentDir,
-        path.join(process.env.QUASAR_ELECTRON_PRELOAD_FOLDER, 'electron-preload' + process.env.QUASAR_ELECTRON_PRELOAD_EXTENSION)
-      ),
-    },
+ async function createWindow() {
+  const mainWindow = new BrowserWindow({
+    icon: resolveElectronAssetsPath("icons/icon.png"), // linux
+    webPreferences: {
+      preload: path.join(import.meta.dirname, "electron-preload.cjs")
+    },

-  if (process.env.DEV) {
-    await mainWindow.loadURL(process.env.APP_URL);
-  }
+  if (import.meta.env.QUASAR_DEV) {
+    await mainWindow.loadURL(import.meta.env.QUASAR_APP_URL);
+  }

-  mainWindow.on('closed', () => {
-    mainWindow = undefined;
-  });
}

- void app.whenReady().then(createWindow);
- app.on('window-all-closed', () => {
-  if (platform !== 'darwin') {
-    app.quit();
-  }
- });
- app.on('activate', () => {
-  if (mainWindow === undefined) {
-    void createWindow();
-  }
- });
+ void app.whenReady().then(async () => {
+   await registerQuasarRuntime();
+   void createWindow();
+   app.on("activate", () => {
+     if (BrowserWindow.getAllWindows().length === 0) {
+       void createWindow();
+     }
+   });
+ });
+ app.on("window-all-closed", () => {
+   if (platform !== "darwin") {
+     app.quit();
+   }
+ });

其他 Electron 相关

SSR 模式变更

我们大幅改进了对非 Express.js Web 服务器的支持,并显著提升了类型定义。当项目添加 SSR 模式时,Quasar CLI 会询问你想使用哪个 Web 服务器框架,可以从 Hono/Express.js/Fastify/Koa 中选择。

这里不做逐行对比,建议你查看以下页面(即使你仍想继续使用 Express.js):

  • 安装 SSR 依赖
  • Web 服务器:查看 Hono/Express/Fastify/Koa 的示例:SSR Webserver;或者移除并重新添加 SSR 模式。
  • 中间件:查看 Hono/Express/Fastify/Koa 的示例:SSR Middleware;或者移除并重新添加 SSR 模式。
  • 查看 SSR 处理 404 和 500 错误 页面。
  • 如果使用 serverless 架构,请查看 SSR Webserver 页面中新的 Serverless 章节。
  • 你可能还想使用新的 /src-ssr/server-assets 文件夹(需要创建)。它会原样复制到 dist,在开发时也可以通过 resolve.serverAssets()folders.serverAssets 使用。
  • 还有一点需要注意,对于 SSR 中间件:serve.error() 已更改为 serve.devError()(参数也有变化)。

PWA 模式变更

/src-pwa/sw/ 子目录用于 Service Worker

Service Worker 和 PWA 专属的 tsconfig.json(TypeScript 项目)现在位于 /src-pwa/sw/ 内。主线程文件 register-sw.{js,ts} 保留在 /src-pwa/ 根目录。

背景:TypeScript 在从项目根目录运行 tsc/vue-tsc不会识别嵌套的 tsconfig.json 文件,因此之前的平铺布局(src-pwa/custom-sw.ts + 同级 tsconfig.json)会产生错误的类型报错,如 Property 'skipWaiting' does not exist on type 'ServiceWorkerGlobalScope'。另外,在 register service worker 脚本中也无法使用 DOM 类型(如 location.reload()),而它在运行时是完全正常的。Quasar 生成的 .quasar/tsconfig.json 现在会自动排除 /src-pwa/sw/,使根 tsc/vue-tsc 跳过它,通过独立检查,嵌套的 tsconfig 像以前一样在 IDE 中处理 SW 类型。

迁移步骤:

  1. 创建 /src-pwa/sw/

  2. 移动 /src-pwa/custom-sw.{js,ts} -> /src-pwa/sw/custom-sw.{js,ts}

  3. 仅 TS:移动 /src-pwa/tsconfig.json -> /src-pwa/sw/tsconfig.json,然后将内容替换为指向 Quasar 生成的 SW 配置的简洁引用:

    /src-pwa/sw/tsconfig.json

    {
      "extends": "../../.quasar/tsconfig.pwa-sw.json"
    }

    生成的 `.quasar/tsconfig.pwa-sw.json` 处理了 WebWorker lib 替换和作用域 include/exclude。如果你在旧的 `src-pwa/tsconfig.json` 中有自定义设置,可以使用 `quasar.config file > pwa > extendPWASwTsConfig` 来自定义生成的配置。详情参见 [PWA 与 TypeScript](/quasar-cli-vite/developing-pwa/pwa-with-typescript)。

  4. 更新你的 ESLint 配置 glob:

    {
      files: ['src-pwa/custom-service-worker.ts'], // [!code --]
      files: ['src-pwa/sw/**/*.ts'], // [!code ++]
      languageOptions: {
        globals: {
          ...globals.serviceworker
        }
      }
    }

  5. 如果你在 quasar.config 中显式设置了 sourceFiles.pwaServiceWorker,请更新它:

    sourceFiles: {
      pwaServiceWorker: 'src-pwa/custom-service-worker', // [!code --]
      pwaServiceWorker: 'src-pwa/sw/custom-sw', // [!code ++]
    }

    如果没有设置,新的默认值会自动生效。

  6. (可选)TypeScript + ESLint:要在 dev/build 时对 SW 进行类型检查,在 vite-plugin-checker 选项中添加一个 typescript 条目(与 vueTsc: true 并列):

/quasar.config.ts

vitePlugins: [
  [
    'vite-plugin-checker',
    {
      vueTsc: true,
      typescript: { // [!code ++]
        tsconfigPath: './src-pwa/sw/tsconfig.json' // [!code ++]
      } // [!code ++]
      // ...
    },
    { server: false }
  ]
]
  1. (可选)TypeScript:添加一个 package.json 脚本来检查根和 SW 的类型:

    /package.json

    "scripts": {
     "typecheck": "vue-tsc --noEmit && tsc --project src-pwa/sw/tsconfig.json --noEmit", // [!code ++]
      // ...
    }

Capacitor 模式变更

.js / .ts capacitor.config

@quasar/app-vite 新增了对 capacitor.config.jscapacitor.config.ts 文件的支持,并移除了对 capacitor.config.json 的支持。.js 和 .ts 变体更加灵活,没有 .json 版本的 git 噪音(.json 版本在每次 “quasar dev” / “quasar build” 时都会被重写相关字段)。升级前你必须迁移到 capacitor.config.ts(TypeScript 项目)或 capacitor.config.js(JS 项目),详情见下文。

“quasar mode add capacitor” 命令现在为 JS 项目生成 capacitor.config.js,为 TypeScript 项目生成 capacitor.config.ts。详情参见 配置 Capacitor。配置文件使用来自 “@quasar/app-vite/capacitor” 的新 defineCapacitorConfig 辅助函数:


import { defineCapacitorConfig } from '@quasar/app-vite/capacitor';

export default defineCapacitorConfig({
  appId: 'org.example.app',
  appName: 'My App'
});

该辅助函数默认 webDir'www',在开发模式下注入 server.url(Android 上还有 server.cleartext: true),并根据 “@capacitor/cli” 的 CapacitorConfig 对你的输入进行类型检查。你自己的值总是优先,源文件不会被修改。在配置中,import.meta.env.QUASAR_DEVQUASAR_TARGETQUASAR_APP_URL 以及你自己的 .env / build.env 值都可用。详情阅读 配置 Capacitor

从 “.json” 迁移时,将文件替换为携带相同字段的 defineCapacitorConfig({...}) 调用。webDir 可以省略:

从 capacitor.config.json 迁移

-{
-  "appId": "org.example.app",
-  "appName": "My App",
-  "webDir": "www"
-}
+const { defineCapacitorConfig } = require('@quasar/app-vite/capacitor');
+
+module.exports = defineCapacitorConfig({
+  appId: 'org.example.app',
+  appName: 'My App'
+});

移除:quasar.config > capacitor.{appName, version, description}

quasar.config > capacitor 下的三个字段已移除。它们都没有按预期工作。

versiondescription 从未被 Capacitor CLI 读取,无论是从 capacitor.config.* 还是从 src-capacitor/package.json。iOS 和 Android 从 android/app/build.gradle(versionName / versionCode)和 ios/App/App/Info.plist(CFBundleShortVersionString / CFBundleVersion)获取版本号。发布到商店时请直接编辑这些文件。参见 发布到商店

appName 有一些效果,但很有限。Capacitor 会将它写入 Info.plist 的 “CFBundleDisplayName”(iOS)和 “strings.xml” > app_name(Android),但仅在 “cap add” 时。“cap sync” 和 “cap copy” 命令不会重新执行那一步,所以 quasar.config 文件中的字段暗示了一个实际上并不存在的实时设置。现在它通过 “quasar mode add capacitor” 时的提示捕获,写入脚手架生成的 capacitor.config.*,并在添加平台时应用到原生项目。后续重命名通过直接编辑 Info.plist 和 strings.xml,或者删除并重新添加平台来完成。

如果你设置了这些字段,请移除它们:

/quasar.config file

capacitor: {
  appName: 'My App', // [!code --]
  version: '1.2.0', // [!code --]
  description: 'My great app' // [!code --]
   // hideSplashscreen, capacitorCliPreparationParams 保留
 }

src-capacitor/package.json 不再被重写

Quasar 过去会在每次 “quasar dev/build” 命令时覆盖 src-capacitor/package.json 中的 “name”、“version”、“description” 和 “author”。Capacitor CLI 并不读取其中大部分内容,所以这些重写没有实际意义(且在 git 中产生噪音)。新项目会生成一个静态的 quasar-capacitor-app / 1.0.0 模板。现有项目可以更新为匹配,或保持不变。Quasar 不会再修改它。

其他注意事项

切换到 Oxlint 和 Oxfmt

你可能还想将代码检查和格式化切换到 oxlintoxfmt。在我们看来,这是未来的趋势。在不久的将来,Quasar 的项目脚手架工具将只提供这个选项用于代码检查。

在撰写本文时,对 .vue 文件的支持还不完全,但你仍然可以从中受益良多。

更多信息

基于文件名的路由(Vue Router v5+)

我们现在对 Vue Router 的基于文件名的路由提供了一流支持。你可能想要试试看

升级到 @quasar/extras v2

可选(但强烈推荐)同时升级到新的 @quasar/extras v2:发布说明

新 CLI 命令选项

所有命令:–no-color

默认情况下,所有 CLI 命令在终端中输出彩色文本(在非 CI 环境中运行时)。如果你希望禁用彩色输出,可以在运行任何 CLI 命令时使用 --no-color 选项。

build 命令:–no-summary

如果你希望构建时跳过打印构建摘要(从而稍微加快速度):

quasar build --no-summary

运行 AE 命令

通过 App Extension 提供的 CLI 命令的简写形式已被移除:

# 仍然有效;推荐的方式!
quasar run <ext-id> <cmd> [...args]

# 以下方式将不再有效:
quasar <ext-id> <cmd> [...args]

CSP(内容安全策略)

你可能想在 /index.html 中添加一个 CSP meta 标签。这对 Electron 模式特别有用(会显示缺少 CSP 的警告),但对所有 Quasar 模式来说也是一个好的安全措施:

<!doctype html>
<html>
  <head>
    <!-- 添加到 head 中 -->
    <meta
      http-equiv="Content-Security-Policy"
      content="default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline';<% if (ctx.dev) { %> connect-src 'self' ws://localhost:*; worker-src 'self' blob:;<% } %>"
    />
  </head>
</html>

TIP

这与 Oxlint 和 Oxfmt 配合良好。但是,如果使用 ESLint 和 vite-plugin-checker,上述配置可能需要稍作调整。

最后

请考虑支持我们的工作!如果你在工作中使用 Quasar,请向你的管理层提一下在 https://donate.quasar.dev/ 赞助我们。我们依靠你的支持来实现这样的大规模更新!

享受你的全新现代化配置吧!就是这样!🚀