yarn 4
This commit is contained in:
42
frontend/.htaccess
Normal file
42
frontend/.htaccess
Normal file
@@ -0,0 +1,42 @@
|
||||
AddType application/javascript .mjs
|
||||
|
||||
#DirectoryIndex index.html spa.html
|
||||
DirectoryIndex index
|
||||
# DirectoryIndex spa.html
|
||||
|
||||
SetEnv MATOMO no
|
||||
|
||||
<ifModule mod_rewrite.c>
|
||||
RewriteEngine On
|
||||
RewriteBase /
|
||||
|
||||
RewriteRule ^/?api/(.*)$ http://tibi-server:8080/api/v1/_/__NAMESPACE__/$1 [P,QSA,L]
|
||||
|
||||
# Set the Host header for requests to sentry
|
||||
RequestHeader set Host sentry.basehosts.de env=proxy-sentry
|
||||
RequestHeader unset Authorization env=proxy-sentry
|
||||
# need to update project id
|
||||
RewriteRule ^/?_s(.*)$ https://sentry.basehosts.de/api/3/envelope/$1 [P,L,E=proxy-sentry:1]
|
||||
|
||||
# set in vhost or global in apache
|
||||
#SSLProxyEngine On
|
||||
#SSLProxyVerify none
|
||||
#SSLProxyCheckPeerCN off
|
||||
#SSLProxyCheckPeerName off
|
||||
#SSLProxyCheckPeerExpire off
|
||||
# set url to header for proxy
|
||||
|
||||
SetEnvIf Request_URI "^(.*)$" REQUEST_URI=$1
|
||||
RequestHeader set x-ssr-url "%{REQUEST_URI}e" env=proxy-ssr
|
||||
# set env if header x-ssr-skip is set to track request
|
||||
SetEnvIfNoCase x-ssr-skip ".+" MATOMO=yes
|
||||
# append to log
|
||||
SetEnvIfNoCase x-ssr-ref "^(.+)$" LOG_REFERER=$1
|
||||
SetEnvIfNoCase x-ssr-res "^(.+)$" LOG_RESOLUTION=$1
|
||||
|
||||
RewriteCond %{REQUEST_FILENAME} !-f
|
||||
RewriteCond %{REQUEST_FILENAME} !-d
|
||||
RewriteRule ^/?(.*)$ http://tibi-server:8080/api/v1/_/__NAMESPACE__/ssr [P,QSA,L,E=proxy-ssr]
|
||||
# RewriteRule (.*) /spa.html [QSA,L]
|
||||
|
||||
</ifModule>
|
||||
40
frontend/spa.html
Normal file
40
frontend/spa.html
Normal file
@@ -0,0 +1,40 @@
|
||||
<!doctype html>
|
||||
<html lang="de">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||
<title>__PROJECT_TITLE__</title>
|
||||
<base href="/" />
|
||||
<link rel="stylesheet" href="/dist/index.css?t=__TIMESTAMP__" />
|
||||
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="/assets/img/apple-touch-icon.png" />
|
||||
<link rel="icon" type="image/png" sizes="32x32" href="/assets/img/favicon-32x32.png" />
|
||||
<link rel="icon" type="image/png" sizes="16x16" href="/assets/img/favicon-16x16.png" />
|
||||
<link rel="manifest" href="/assets/img/site.webmanifest" />
|
||||
<link rel="mask-icon" href="/assets/img/safari-pinned-tab.svg" color="#e20019" />
|
||||
<meta name="msapplication-TileColor" content="#e20019" />
|
||||
<meta name="theme-color" content="#ffffff" />
|
||||
|
||||
<!--HEAD-->
|
||||
|
||||
<!--PRELOAD-->
|
||||
</head>
|
||||
<body>
|
||||
<div id="appContainer"><!--HTML--></div>
|
||||
<script type="module" src="/dist/index.mjs?t=__TIMESTAMP__"></script>
|
||||
<script nomodule src="/dist/index.es5.js?t=__TIMESTAMP__"></script>
|
||||
<!-- <script
|
||||
src="//cc.webmakers.de/cc.js"
|
||||
defer
|
||||
id="ccScript"
|
||||
data-cc-tags="googleMaps"
|
||||
data-cc-privacy-policy-url="/datenschutz"
|
||||
data-cc-secondary-color="#c4253e"
|
||||
data-cc-necessary-cookies="likecmsSession"
|
||||
></script> -->
|
||||
</body>
|
||||
|
||||
<!--SSR.ERROR-->
|
||||
<!--SSR.COMMENT-->
|
||||
</html>
|
||||
40
frontend/src/App.svelte
Normal file
40
frontend/src/App.svelte
Normal file
@@ -0,0 +1,40 @@
|
||||
<script lang="ts">
|
||||
import { metricCall } from "./config"
|
||||
import { location } from "./lib/store"
|
||||
export let url = ""
|
||||
|
||||
if (url) {
|
||||
// ssr
|
||||
let l = url.split("?")
|
||||
$location = {
|
||||
path: l[0],
|
||||
search: l.length > 1 ? l[1] : "",
|
||||
hash: "",
|
||||
push: false,
|
||||
pop: false,
|
||||
}
|
||||
}
|
||||
|
||||
// metrics
|
||||
let oldPath: string
|
||||
$: if (metricCall && typeof window !== "undefined" && oldPath !== $location.path) {
|
||||
const ref = oldPath ? document.location.protocol + "//" + document.location.host + oldPath : document.referrer
|
||||
oldPath = $location.path
|
||||
const fetchPath = oldPath + (oldPath.includes("?") ? "&" : "?") + "metrics"
|
||||
fetch(fetchPath, {
|
||||
headers: {
|
||||
"x-ssr-skip": "204",
|
||||
"x-ssr-ref": ref,
|
||||
"x-ssr-res": `${window.innerWidth}x${window.innerHeight}`,
|
||||
// no cache
|
||||
"cache-control": "no-cache, no-store, must-revalidate",
|
||||
},
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
<h1>Tibi Svelte Starter</h1>
|
||||
|
||||
<style lang="less" global>
|
||||
@import "./css/style.less";
|
||||
</style>
|
||||
14
frontend/src/config.ts
Normal file
14
frontend/src/config.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
// @ts-ignore
|
||||
import * as sentry from "./sentry"
|
||||
import configClient from "../../api/hooks/config-client"
|
||||
|
||||
export const apiBaseURL = configClient.apiClientBaseURL
|
||||
export const release = configClient.release
|
||||
|
||||
export const sentryDSN = ""
|
||||
export const sentryTracingOrigins = ["localhost", "project-domain.tld", /^\//]
|
||||
export const sentryEnvironment: string = "local"
|
||||
// need to execute early for fetch wrapping
|
||||
// sentry.init(sentryDSN, sentryTracingOrigins, sentryEnvironment, release)
|
||||
|
||||
export const metricCall = false
|
||||
0
frontend/src/css/style.less
Normal file
0
frontend/src/css/style.less
Normal file
14
frontend/src/index.ts
Normal file
14
frontend/src/index.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
import App from "./App.svelte"
|
||||
|
||||
let appContainer = document?.getElementById("appContainer")
|
||||
|
||||
const hydrate = true //import.meta?.env?.MODE !== "development"
|
||||
console.log("Features: ", { hydrate })
|
||||
|
||||
const app = new App({
|
||||
target: appContainer,
|
||||
props: {},
|
||||
hydrate,
|
||||
})
|
||||
|
||||
export default app
|
||||
84
frontend/src/lib/store.ts
Normal file
84
frontend/src/lib/store.ts
Normal file
@@ -0,0 +1,84 @@
|
||||
import { get, writable } from "svelte/store"
|
||||
|
||||
/*********** location **************************/
|
||||
|
||||
const initLoc = {
|
||||
path: (typeof window !== "undefined" && window.location?.pathname) || "/",
|
||||
search: (typeof window !== "undefined" && window.location?.search) || "",
|
||||
hash: (typeof window !== "undefined" && window.location?.hash) || "",
|
||||
push: false,
|
||||
pop: false,
|
||||
}
|
||||
export const location = writable<LocationStore>(initLoc)
|
||||
|
||||
const publishLocation = (_p?: string) => {
|
||||
let _s: string
|
||||
let _h: string
|
||||
if (_p) {
|
||||
const parts = _p.split("#")
|
||||
_p = parts.shift()
|
||||
_h = parts.join()
|
||||
if (_h) _h = "#" + _h
|
||||
|
||||
const parts2 = _p.split("?")
|
||||
_p = parts2.shift()
|
||||
_s = parts2.join()
|
||||
if (_s) _s = "?" + _s
|
||||
}
|
||||
|
||||
const newLocation: LocationStore = {
|
||||
path: _p || (typeof window !== "undefined" && window.location?.pathname),
|
||||
search: _p ? _s : typeof window !== "undefined" && window.location?.search,
|
||||
hash: _p ? _h : typeof window !== "undefined" && window.location?.hash,
|
||||
push: !!_p,
|
||||
pop: !_p,
|
||||
previousLocation: get(location),
|
||||
}
|
||||
location.set(newLocation)
|
||||
}
|
||||
|
||||
if (typeof history !== "undefined") {
|
||||
if (typeof Proxy !== "undefined") {
|
||||
// modern browser
|
||||
const historyApply = (
|
||||
target: (this: any, ...args: readonly any[]) => unknown,
|
||||
thisArg: any,
|
||||
argumentsList: string | readonly any[]
|
||||
) => {
|
||||
publishLocation(argumentsList && argumentsList.length >= 2 && argumentsList[2])
|
||||
Reflect.apply(target, thisArg, argumentsList)
|
||||
}
|
||||
|
||||
history.pushState = new Proxy(history.pushState, {
|
||||
apply: historyApply,
|
||||
})
|
||||
|
||||
history.replaceState = new Proxy(history.replaceState, {
|
||||
apply: historyApply,
|
||||
})
|
||||
} else {
|
||||
// ie11
|
||||
const pushStateFn = history.pushState
|
||||
const replaceStateFn = history.replaceState
|
||||
|
||||
history.pushState = function (data: any, title: string, url?: string) {
|
||||
publishLocation(url)
|
||||
// @ts-ignore
|
||||
return pushStateFn.apply(history, arguments)
|
||||
}
|
||||
history.replaceState = function (data: any, title: string, url?: string) {
|
||||
publishLocation(url)
|
||||
// @ts-ignore
|
||||
return replaceStateFn.apply(history, arguments)
|
||||
}
|
||||
}
|
||||
} // else ssr -> no history handling
|
||||
|
||||
typeof window !== "undefined" &&
|
||||
window.addEventListener("popstate", (event) => {
|
||||
publishLocation()
|
||||
})
|
||||
|
||||
/********************** override for admin ui *****************/
|
||||
|
||||
export const apiBaseOverride = writable<string | null>(null)
|
||||
52
frontend/src/sentry.ts
Normal file
52
frontend/src/sentry.ts
Normal file
@@ -0,0 +1,52 @@
|
||||
import * as Sentry from "@sentry/svelte"
|
||||
|
||||
let initialized = false
|
||||
|
||||
export const init = (dsn: string, tracingOrigins: (string | RegExp)[], environment: string, release: string) => {
|
||||
if (typeof window !== "undefined") {
|
||||
Sentry.init({
|
||||
dsn: dsn,
|
||||
tunnel: "/_s",
|
||||
tracePropagationTargets: tracingOrigins,
|
||||
integrations: [
|
||||
Sentry.browserTracingIntegration(),
|
||||
Sentry.replayIntegration({
|
||||
maskAllText: false,
|
||||
maskAllInputs: false,
|
||||
blockAllMedia: false,
|
||||
networkDetailAllowUrls: [/\/api\//],
|
||||
mutationLimit: 99999,
|
||||
mutationBreadcrumbLimit: 2000,
|
||||
}),
|
||||
],
|
||||
environment: environment,
|
||||
tracesSampleRate: 1.0,
|
||||
debug: false,
|
||||
release: release,
|
||||
replaysSessionSampleRate: 1.0,
|
||||
replaysOnErrorSampleRate: 1.0,
|
||||
})
|
||||
console.log("Sentry initialized")
|
||||
initialized = true
|
||||
}
|
||||
}
|
||||
|
||||
// export const startSpan = (opt: { name: string; op: string }) => {
|
||||
// if (typeof window !== "undefined" && initialized) {
|
||||
// return Sentry.startInactiveSpan(opt)
|
||||
// }
|
||||
// }
|
||||
|
||||
export const currentTransaction = () => {
|
||||
const activeSpan = Sentry.getActiveSpan()
|
||||
if (activeSpan && activeSpan) {
|
||||
return activeSpan
|
||||
}
|
||||
return null
|
||||
}
|
||||
export const setUser = (user: Sentry.User) => {
|
||||
if (typeof window !== "undefined" && initialized) {
|
||||
user.ip_address = "{{auto}}"
|
||||
Sentry.setUser(user)
|
||||
}
|
||||
}
|
||||
3
frontend/src/ssr.ts
Normal file
3
frontend/src/ssr.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
import App from "./App.svelte"
|
||||
|
||||
export default App
|
||||
Reference in New Issue
Block a user