quasar.config 文件(quasar.config file)
¥quasar.config file
你可以在此处配置一些 SSR 选项。例如,如果你希望客户端以 SPA(单页应用 - 默认行为)或 PWA(渐进式 Web 应用)的形式接管。
¥This is the place where you can configure some SSR options. Like if you want the client side to takeover as a SPA (Single Page Application – the default behaviour), or as a PWA (Progressive Web App).
return {
// ...
ssr: {
/**
* If a PWA should take over or just a SPA.
* @default false
*/
pwa?: boolean;
/**
* When using SSR+PWA, this is the name of the
* PWA index html file that the client-side fallbacks to.
* For production only.
* * Do NOT use index.html as name as it will mess SSR up!
* * @default 'offline.html'
*/
pwaOfflineHtmlFilename?: string;
/**
* Extend/configure the Workbox GenerateSW options
* Specify Workbox options which will be applied on top of
* `pwa > extendGenerateSWOptions()`.
* More info: https://developer.chrome.com/docs/workbox/the-ways-of-workbox/
*/
pwaExtendGenerateSWOptions?: (config: object) => void;
/**
* Extend/configure the Workbox InjectManifest options
* Specify Workbox options which will be applied on top of
* `pwa > extendInjectManifestOptions()`.
* More info: https://developer.chrome.com/docs/workbox/the-ways-of-workbox/
*/
pwaExtendInjectManifestOptions?: (config: object) => void;
/**
* Manually serialize the store state and provide it yourself
* as window.__INITIAL_STATE__ to the client-side (through a <script> tag)
* @default false
*/
manualStoreSerialization?: boolean;
/**
* Manually inject the store state into ssrContext.state
* @default false
*/
manualStoreSsrContextInjection?: boolean;
/**
* Manually handle the store hydration instead of letting Quasar CLI do it.
* * For Pinia: store.state.value = window.__INITIAL_STATE__
* * @default false
*/
manualStoreHydration?: boolean;
/**
* Manually call $q.onSSRHydrated() instead of letting Quasar CLI do it.
* This announces that client-side code should takeover.
* @default false
*/
manualPostHydrationTrigger?: boolean;
/**
* The default port (3000) that the production server should use
* (gets superseded if process.env.PORT is specified at runtime)
* @default 3000
*/
prodPort?: number;
/**
* List of middleware files in src-ssr/middlewares
* Order is important.
*/
middlewares?: string[];
/**
* Add/remove/change properties of production generated package.json
*/
extendPackageJson?: (pkg: { [index in string]: any }) => void;
/**
* Extend the Esbuild config that is used for the SSR webserver
* (which includes the SSR middlewares)
*/
extendSSRWebserverConf?: (config: EsbuildConfiguration) => void;
}
}
如果你决定使用 PWA 客户端接管(这是一个杀手级组合),Quasar CLI PWA 模式也会被安装。你可能还需要查看 Quasar PWA 指南。但最重要的是,请务必阅读 SSR 模式 PWA 页。
¥If you decide to go with a PWA client takeover (which is a killer combo), the Quasar CLI PWA mode will be installed too. You may want to check out the Quasar PWA guide too. But most importantly, make sure you read SSR with PWA page.
如果你想要篡改 /src 目录下的 Vite UI 配置:
¥Should you want to tamper with the Vite config for UI in /src:
export default defineConfig((ctx) => {
return {
build: {
extendViteConf (viteConf, { isClient, isServer }) {
if (ctx.mode.ssr) {
// do something with viteConf
// or return an object to deeply merge with current viteConf
}
}
}
}
})
手动触发 store-hydration(Manually triggering store hydration)
¥Manually triggering store hydration
默认情况下,Quasar CLI 负责在客户端补充 Pinia 存储(如果你使用)。
¥By default, Quasar CLI takes care of hydrating the Pinia stores (if you use it) on client-side.
但是,如果你希望手动进行水合,则需要设置 quasar.config 文件 > ssr > manualStoreHydration:true。一个很好的例子是从 启动文件 开始:
¥However, should you wish to manually hydrate it yourself, you need to set quasar.config file > ssr > manualStoreHydration: true. One good example is doing it from a boot file:
// MAKE SURE TO CONFIGURE THIS BOOT FILE
// TO RUN ONLY ON CLIENT-SIDE
import { defineBoot } from '#q-app/wrappers'
export default defineBoot(({ store }) => {
// For Pinia
store.state.value = window.__INITIAL_STATE__
})
手动触发 post-hydration(Manually triggering post-hydration)
¥Manually triggering post-hydration
默认情况下,Quasar CLI 会封装你的 App 组件,并在安装此封装器组件时在客户端调用 $q.onSSRHydrated()
。这是客户端接管的时刻。你无需为此进行任何配置。
¥By default, Quasar CLI wraps your App component and calls $q.onSSRHydrated()
on the client-side when this wrapper component gets mounted. This is the moment that the client-side takes over. You don’t need to configure anything for this to happen.
但是,如果你希望覆盖发生这种情况的时刻,则需要设置 quasar.config 文件 > ssr > manualPostHydrationTrigger:true。无论你的理由是什么(非常自定义的用例),以下是手动触发后期水合的示例:
¥However should you wish to override the moment when this happens, you need to set quasar.config file > ssr > manualPostHydrationTrigger: true. For whatever your reason is (very custom use-case), this is an example of manually triggering the post hydration:
// App.vue
import { onMounted } from 'vue'
import { useQuasar } from 'quasar'
export default {
// ....
setup () {
// ...
const $q = useQuasar()
onMounted(() => {
$q.onSSRHydrated()
})
}
}
Nodejs 服务器(Nodejs Server)
¥Nodejs Server
将 SSR 模式添加到 Quasar 项目意味着将创建一个新文件夹:/src-ssr
,包含 SSR 特定文件:
¥Adding SSR mode to a Quasar project means a new folder will be created: /src-ssr
, which contains SSR specific files:
你可以自由编辑这些文件。两个文件夹在其各自的文档页面中都有详细说明(请查看左侧菜单)。
¥You can freely edit these files. Each of the two folders are detailed in their own doc pages (check left-side menu).
注意以下几点:
¥Notice a few things:
如果你从 node_modules 导入任何内容,请确保该包在 package.json > “dependencies” 中指定,而不是在 “devDependencies” 中指定。
¥If you import anything from node_modules, then make sure that the package is specified in package.json > “dependencies” and NOT in “devDependencies”.
/src-ssr/middlewares
通过单独的 Esbuild 配置构建。你可以通过/quasar.config
文件扩展这些文件的 Esbuild 配置:¥The
/src-ssr/middlewares
is built through a separate Esbuild config. You can extend the Esbuild configuration of these files through the/quasar.config
file:
return {
// ...
ssr: {
// ...
extendSSRWebserverConf (esbuildConf) {
// tamper with esbuildConf here
},
}
}
/src-ssr/server.js
文件的详细说明请参阅 SSR Web 服务器 页面。尤其如果你需要支持无服务器函数,请阅读它。¥The
/src-ssr/server.js
file is detailed in SSR Webserver page. Read it especially if you need to support serverless functions.
帮助 SEO(Helping SEO)
¥Helping SEO
开发 SSR 而不是 SPA 的主要原因之一是要考虑 SEO。使用 Quasar Meta 插件 管理搜索引擎所需的动态 HTML 标记可以显著提升 SEO。
¥One of the main reasons when you develop a SSR instead of a SPA is for taking care of the SEO. And SEO can be greatly improved by using the Quasar Meta Plugin to manage dynamic html markup required by the search engines.
启动文件(Boot Files)
¥Boot Files
在 SSR 模式下运行时,你的应用代码需要同构或 “universal”,这意味着它必须同时在 Node 上下文和浏览器中运行。这也适用于你的 启动文件。
¥When running on SSR mode, your application code needs to be isomorphic or “universal”, which means that it must run both on a Node context and in the browser. This applies to your Boot Files too.
但是,在某些情况下,你只希望某些启动文件仅在服务器或客户端运行。你可以通过以下方式实现:
¥However, there are cases where you only want some boot files to run only on the server or only on the client-side. You can achieve that by specifying:
return {
// ...
boot: [
'some-boot-file', // runs on both server and client
{ path: 'some-other', server: false }, // this boot file gets embedded only on client-side
{ path: 'third', client: false } // this boot file gets embedded only on server-side
]
}
不过,请确保你的应用保持一致。
¥Just make sure that your app is consistent, though.
当启动文件在服务器上运行时,你将可以在默认导出函数中访问另一个参数(称为 ssrContext):
¥When a boot file runs on the server, you will have access to one more parameter (called ssrContext) on the default exported function:
export default ({ app, ..., ssrContext }) => {
// You can add props to the ssrContext then use them in the /index.html.
// Example - let's say we ssrContext.someProp = 'some value', then in index template we can reference it:
// {{ someProp }}}
当你将此类引用(上例中用括号括起来的 someProp
)添加到 /index.html
中时,请务必告知 Quasar 它仅对 SSR 构建有效:
¥When you add such references (someProp
surrounded by brackets in the example above) into your /index.html
, make sure you tell Quasar it’s only valid for SSR builds:
<% if (ctx.mode.ssr) { %>{{ someProp }} <% } %>