mirror of
https://github.com/gotson/komga.git
synced 2025-12-06 08:32:25 +01:00
handle dynamic base url
This commit is contained in:
parent
2fdc876b34
commit
722c14bf3f
8 changed files with 94 additions and 6 deletions
|
|
@ -60,3 +60,56 @@ Components are automatically imported using [unplugin-vue-components](https://gi
|
|||
## Icons
|
||||
|
||||
[UnoCSS Icons preset](https://unocss.dev/presets/icons) is used for icons, with the MDI set from Iconify.
|
||||
|
||||
## Base URL
|
||||
|
||||
The generated bundle is server by Apache Tomcat when running Spring. By default the site is hosted at `/`, but if `server.servlet-context-path` is set, the base URL can be dynamic.
|
||||
|
||||
The base URL needs to be set correctly so the web app works:
|
||||
|
||||
- in the API client
|
||||
- in the Vue Router, to properly handle the web history
|
||||
- in the generated bundle, to load other files (js/css/images)
|
||||
|
||||
1. Vite is [configured](./vite.config.mts) with the experimental `renderBuiltUrl`, which will use a dynamic function (`window.buildUrl`) defined in `index.html` to generate the asset path at runtime. This is only supported withing JS files though.
|
||||
2. To handle the dynamic path in `index.html`, a Gradle task `prepareThymeLeafNext` modifies `index.html` to duplicate `href`, `src` and `content` attributes as Thymeleaf variants.
|
||||
|
||||
For example the following:
|
||||
|
||||
```html
|
||||
<script
|
||||
type="module"
|
||||
crossorigin
|
||||
src="/assets/index-xEUJQodq.js"
|
||||
></script>
|
||||
<link
|
||||
rel="stylesheet"
|
||||
crossorigin
|
||||
href="/assets/index-CQqFNa2f.css"
|
||||
/>
|
||||
```
|
||||
|
||||
will be transformed to:
|
||||
|
||||
```html
|
||||
<script
|
||||
type="module"
|
||||
crossorigin
|
||||
src="/assets/index-xEUJQodq.js"
|
||||
th:src="@{/assets/index-xEUJQodq.js}"
|
||||
></script>
|
||||
<link
|
||||
rel="stylesheet"
|
||||
crossorigin
|
||||
href="/assets/index-CQqFNa2f.css"
|
||||
th:href="@{/assets/index-CQqFNa2f.css}"
|
||||
/>
|
||||
```
|
||||
|
||||
In Thymeleaf, `@{}` will prepend the path with the context path dynamically when serving `index.html`.
|
||||
|
||||
3. when the `index.html` is served by the `IndexController`, a `baseUrl` attribute is injected, which contains the servlet context path (by default `/`, but could be `/komga` for example)
|
||||
4. the `index.html` contains a Thymeleaf script block that will be processed when serving the page, effectively injecting the `baseUrl` value into `window.ressourceBaseUrl`.
|
||||
5. `window.ressourceBaseUrl` is subsequently used in Typescript code to set the base URL for:
|
||||
- the API client and the images served [by API](./src/api/base.ts)
|
||||
- the [Vue Router](./src/router/index.ts)
|
||||
|
|
|
|||
|
|
@ -11,6 +11,16 @@
|
|||
content="width=device-width, initial-scale=1.0"
|
||||
/>
|
||||
<title>Komga</title>
|
||||
<script th:inline="javascript">
|
||||
/*<![CDATA[*/
|
||||
window.resourceBaseUrl = /*[(${"'" + baseUrl + "'"})]*/ '/'
|
||||
/*]]>*/
|
||||
</script>
|
||||
<script>
|
||||
window.buildUrl = (filename) => {
|
||||
return `${window.resourceBaseUrl}${filename}`
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
|
|
|
|||
8
next-ui/src/api/base.ts
Normal file
8
next-ui/src/api/base.ts
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
declare global {
|
||||
interface Window {
|
||||
resourceBaseUrl: string
|
||||
}
|
||||
}
|
||||
|
||||
export const API_BASE_URL =
|
||||
import.meta.env.VITE_KOMGA_API_URL || window.location.origin + window.resourceBaseUrl
|
||||
|
|
@ -1,14 +1,16 @@
|
|||
import { API_BASE_URL } from '@/api/base'
|
||||
|
||||
export function seriesThumbnailUrl(seriesId?: string): string | undefined {
|
||||
if (seriesId) return `${import.meta.env.VITE_KOMGA_API_URL}/api/v1/series/${seriesId}/thumbnail`
|
||||
if (seriesId) return `${API_BASE_URL}/api/v1/series/${seriesId}/thumbnail`
|
||||
return undefined
|
||||
}
|
||||
|
||||
export function bookThumbnailUrl(bookId?: string): string | undefined {
|
||||
if (bookId) return `${import.meta.env.VITE_KOMGA_API_URL}/api/v1/books/${bookId}/thumbnail`
|
||||
if (bookId) return `${API_BASE_URL}/api/v1/books/${bookId}/thumbnail`
|
||||
return undefined
|
||||
}
|
||||
|
||||
export function pageHashKnownThumbnailUrl(hash?: string): string | undefined {
|
||||
if (hash) return `${import.meta.env.VITE_KOMGA_API_URL}/api/v1/page-hashes/${hash}/thumbnail`
|
||||
if (hash) return `${API_BASE_URL}/api/v1/page-hashes/${hash}/thumbnail`
|
||||
return undefined
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import type { Middleware } from 'openapi-fetch'
|
||||
import createClient from 'openapi-fetch'
|
||||
import type { paths } from '@/generated/openapi/komga'
|
||||
import { API_BASE_URL } from '@/api/base'
|
||||
|
||||
// Middleware that throws on error, so it works with Pinia Colada
|
||||
const coladaMiddleware: Middleware = {
|
||||
|
|
@ -27,7 +28,7 @@ const coladaMiddleware: Middleware = {
|
|||
}
|
||||
|
||||
const client = createClient<paths>({
|
||||
baseUrl: import.meta.env.VITE_KOMGA_API_URL,
|
||||
baseUrl: API_BASE_URL,
|
||||
// required to pass the session cookie on all requests
|
||||
credentials: 'include',
|
||||
// required to avoid browser basic-auth popups
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import { createOpenApiHttp } from 'openapi-msw'
|
||||
import type { paths } from '@/generated/openapi/komga'
|
||||
import { API_BASE_URL } from '@/api/base'
|
||||
|
||||
export const httpTyped = createOpenApiHttp<paths>({ baseUrl: import.meta.env.VITE_KOMGA_API_URL })
|
||||
export const httpTyped = createOpenApiHttp<paths>({ baseUrl: API_BASE_URL })
|
||||
|
|
|
|||
|
|
@ -10,7 +10,9 @@ import { setupLayouts } from 'virtual:generated-layouts'
|
|||
import { routes } from 'vue-router/auto-routes'
|
||||
|
||||
const router = createRouter({
|
||||
history: createWebHistory(import.meta.env.BASE_URL),
|
||||
history: createWebHistory(
|
||||
import.meta.env.PROD ? window.resourceBaseUrl : import.meta.env.BASE_URL,
|
||||
),
|
||||
routes: setupLayouts(routes),
|
||||
})
|
||||
|
||||
|
|
|
|||
|
|
@ -81,6 +81,17 @@ export default defineConfig({
|
|||
server: {
|
||||
port: 3000,
|
||||
},
|
||||
base: '/',
|
||||
// support for the runtime base url (depending on the server.servlet.context-path)
|
||||
// window.buildUrl is a function defined in index.html that dynamically provides the path
|
||||
// it only works within js files though
|
||||
experimental: {
|
||||
renderBuiltUrl(filename, { hostType }) {
|
||||
if (hostType === 'js') return { runtime: `window.buildUrl(${JSON.stringify(filename)})` }
|
||||
// else if (hostType === 'html') return `@{/${filename}}`
|
||||
else return { relative: true }
|
||||
},
|
||||
},
|
||||
optimizeDeps: {
|
||||
exclude: ['vuetify'],
|
||||
},
|
||||
|
|
|
|||
Loading…
Reference in a new issue