quasar.config file
这个文件是您配置 SSR 配置项的入口,例如,您可以指定客户端是使用 SPA (Single Page Application – 默认值) 接管还是由 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 with PWA 页面。
您可能也想为 /src 下的 UI 修改 Vite 的配置:
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
默认情况下,Quasar CLI 会在客户端帮您处理 Pinia store(如果您使用了的话)的水化(hydrating)。
然而,您可能也想自己手动来处理它的水化过程,您需要先设置 quasar.config file > ssr > manualStoreHydration: true,然后一个推荐的方式是,创建一个 boot 文件 来处理它:
// 确保配置这个 boot 文件只在客户端运行
import { defineBoot } from "#q-app/wrappers";
export default defineBoot(({ store }) => {
// For Pinia
store.state.value = window.__INITIAL_STATE__;
});手动触发 post-hydration
默认情况下,Quasar CLI 会封装您的 App 组件然后在客户端挂载这个封装组件时调用 $q.onSSRHydrated() 方法。这时客户端代码就会接管。您不需要为此做任何的配置。
然后,如果您想重写上述逻辑,您需要先修改 quasar.config file > ssr > manualPostHydrationTrigger: true。无论您想重写此处的原因是什么,请参考下面手动触发水化 (post hydration) 的例子:
// App.vue
import { onMounted } from 'vue'
import { useQuasar } from 'quasar'
export default {
// ....
setup () {
// ...
const $q = useQuasar()
onMounted(() => {
$q.onSSRHydrated()
})
}
}Nodejs Server
添加 SSR 模式时会为 Quasar 项目创建一个 /src-ssr 目录,其中包含专门用于处理 SSR 的文件:
您可以自由编辑这些文件。这两个文件夹都有各自的文档页面(请检查左侧菜单)。
注意事项:
当您从 node_modules 中引入一个库时,请确保它被您添加在了 package.json 中的 “dependencies” 下,而不是 “devDependencies”。
/src-ssr/middlewares中的文件使用单独的 Esbuild 配置打包,您可以在/quasar.config文件中通过下面的方法修改它的配置:
return {
// ...
ssr: {
// ...
extendSSRWebserverConf(esbuildConf) {
// tamper with esbuildConf here
},
},
};- 关于
/src-ssr/server.js文件的详细描述,请见 SSR Webserver 页面,如果您需要支持 serverless functions 请阅读该页面。
提升 SEO
您选择开发 SSR 而不是 SPA 的一个主要原因可能是关心网站的 SEO。通过使用 Quasar Meta Plugin 插件来动态管理搜索引擎所需的 html 标签,可以大大提高 SEO。
Boot 文件
当运行在 SSR 模式时,您的 app 代码需要是同构(isomorphic)的或者通用(universal)的,意味它们必须可以同时运行在 Node.js 环境下和浏览器中,您的 Boot 文件 也是如此。
然而,您可能希望有些 boot 文件只运行在指定的环境中,您可以通过下面的配置实现:
return {
// ...
boot: [
"some-boot-file", // 同时运行在服务端和客户端
{ path: "some-other", server: false }, // 这个 boot 文件只会在客户端运行
{ path: "third", client: false }, // 这个 boot 文件只会在服务端运行
],
};不过,要确保您的应用程序是一致的。
当一个 boot 文件运行在服务端时,您可以在默认导出的函数的参数中多拿到一个叫 ssrContext 的对象。
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:
// {{ ssrContext.someProp }}
}当您在 /index.html 中添加此类引用时,请确保告诉 Quasar 它只对 SSR 模式有效:
<% if (ctx.mode.ssr) { %>{{ ssrContext.someProp }} <% } %>