demo project
This commit is contained in:
parent
751b6e753c
commit
57bfba5b8d
1
.basic-auth-code
Normal file
1
.basic-auth-code
Normal file
@ -0,0 +1 @@
|
||||
code:$apr1$AeePIAei$E9E6E6jtFFtwmtGhIEG.Y/
|
2
.basic-auth-web
Normal file
2
.basic-auth-web
Normal file
@ -0,0 +1,2 @@
|
||||
code:$apr1$AeePIAei$E9E6E6jtFFtwmtGhIEG.Y/
|
||||
web:$apr1$/zc/TBtD$ZGr3RqPiULYMD0kJUup5E0
|
111
.drone.yml
111
.drone.yml
@ -11,15 +11,21 @@ steps:
|
||||
commands:
|
||||
- yarn install
|
||||
|
||||
- name: build
|
||||
##############################
|
||||
# Build and deploy docs
|
||||
##############################
|
||||
- name: build docs
|
||||
image: node:18
|
||||
pull: if-not-exists
|
||||
environment:
|
||||
FORCE_COLOR: "true"
|
||||
commands:
|
||||
- yarn build
|
||||
- yarn docpress:build
|
||||
when:
|
||||
branch: [master]
|
||||
event: [push]
|
||||
|
||||
- name: deploy
|
||||
- name: deploy docs
|
||||
image: instrumentisto/rsync-ssh
|
||||
pull: if-not-exists
|
||||
environment:
|
||||
@ -39,3 +45,102 @@ steps:
|
||||
branch: [master]
|
||||
event: [push]
|
||||
|
||||
##############################
|
||||
# Demo project
|
||||
##############################
|
||||
- name: modify config
|
||||
image: alpine/git
|
||||
commands:
|
||||
- sed -i 's#\(sentryEnvironment.*\)".*"#\1"${DRONE_BRANCH}"#g' frontend/src/config.ts
|
||||
- sed -i 's#//\( sentry\\.init.*\)#\1#g' frontend/src/config.ts
|
||||
- export $(cat .env | xargs)
|
||||
- echo "PROJECT_RELEASE=$${RELEASE_PROJECT_SLUG}.r`git rev-list HEAD --count`-`git describe --all --long | sed 's+/+-+'`" >> .env
|
||||
- export $(cat .env | xargs)
|
||||
- cat .env
|
||||
- sed -i 's#\(const release = \).*#\1"'$${PROJECT_RELEASE}'"#g' api/hooks/config-client.js
|
||||
|
||||
- name: build
|
||||
image: node:18
|
||||
commands:
|
||||
- yarn build
|
||||
|
||||
- name: build ssr
|
||||
image: node:18
|
||||
commands:
|
||||
- yarn build:server
|
||||
|
||||
- name: build legacy
|
||||
image: node:18
|
||||
commands:
|
||||
- yarn build:legacy
|
||||
|
||||
- name: modify html
|
||||
image: bash
|
||||
commands:
|
||||
- bash scripts/preload-meta.sh frontend/spa.html
|
||||
- bash scripts/preload-meta.sh frontend/spa.html > frontend/_spa.html
|
||||
- cp frontend/_spa.html frontend/spa.html
|
||||
- export stamp=`date +%s`
|
||||
- echo $$stamp
|
||||
- sed -i s/__TIMESTAMP__/$$stamp/g frontend/spa.html
|
||||
- sed -i s/__TIMESTAMP__/$$stamp/g frontend/serviceworker.js
|
||||
- cat frontend/serviceworker.js
|
||||
- cp frontend/spa.html api/templates/spa.html
|
||||
- cat frontend/spa.html
|
||||
|
||||
# staging
|
||||
- name: copy api config to staging
|
||||
image: instrumentisto/rsync-ssh
|
||||
volumes:
|
||||
- name: data
|
||||
path: /data
|
||||
commands:
|
||||
- rsync -av api /data/
|
||||
- mkdir -p /data/frontend/dist
|
||||
- rsync -av frontend/dist/ /data/frontend/dist/
|
||||
when:
|
||||
branch: [dev]
|
||||
event: [push]
|
||||
|
||||
- name: review in staging
|
||||
image: docker/compose:1.22.0
|
||||
commands:
|
||||
- docker-compose -p ${DRONE_BRANCH}-${DRONE_REPO_NAME}-${DRONE_REPO_OWNER} up -d --build --remove-orphans
|
||||
volumes:
|
||||
- name: docker
|
||||
path: /var/run/docker.sock
|
||||
when:
|
||||
branch: [dev]
|
||||
event: [push]
|
||||
|
||||
# live
|
||||
- name: deploy master
|
||||
image: instrumentisto/rsync-ssh
|
||||
environment:
|
||||
RSYNC_USER: ""
|
||||
RSYNC_PASS:
|
||||
from_secret: rsync_master
|
||||
commands:
|
||||
- apk add --no-cache sshpass curl
|
||||
- scripts/deploy.sh ftp1.webmakers.de $${RSYNC_USER} $${RSYNC_PASS}
|
||||
# - curl -X POST "https://www....de/api/ssr?token=TowendQhi&clear=1"
|
||||
when:
|
||||
branch: [master]
|
||||
event: [push]
|
||||
|
||||
# - name: upload sourcemaps for glitchtip
|
||||
# image: node
|
||||
# environment:
|
||||
# GLITCHTIP_TOKEN:
|
||||
# from_secret: glitchtip_token
|
||||
# commands:
|
||||
# - yarn upload:sourcemaps
|
||||
|
||||
########
|
||||
volumes:
|
||||
- name: data
|
||||
host:
|
||||
path: /data/${DRONE_REPO_OWNER}/${DRONE_REPO_NAME}/${DRONE_BRANCH}
|
||||
- name: docker
|
||||
host:
|
||||
path: /var/run/docker.sock
|
||||
|
7
.env
Normal file
7
.env
Normal file
@ -0,0 +1,7 @@
|
||||
PROJECT_NAME=tibi-docs
|
||||
TIBI_PREFIX=tibi
|
||||
TIBI_NAMESPACE=tibi-docs
|
||||
UID=100
|
||||
GID=101
|
||||
RELEASE_ORG_SLUG=webmakers-gmbh
|
||||
RELEASE_PROJECT_SLUG=tibi-docs
|
4
.gitignore
vendored
4
.gitignore
vendored
@ -1,3 +1,5 @@
|
||||
_docpress
|
||||
node_modules
|
||||
./media
|
||||
media
|
||||
tmp
|
||||
frontend/dist
|
15
.prettierrc
Normal file
15
.prettierrc
Normal file
@ -0,0 +1,15 @@
|
||||
{
|
||||
"printWidth": 120,
|
||||
"tabWidth": 4,
|
||||
"singleQuote": false,
|
||||
"trailingComma": "es5",
|
||||
"semi": false,
|
||||
"newline-before-return": true,
|
||||
"no-duplicate-variable": [true, "check-parameters"],
|
||||
"no-var-keyword": true,
|
||||
"svelteSortOrder": "scripts-markup-styles",
|
||||
"svelteStrictMode": true,
|
||||
"svelteBracketNewLine": true,
|
||||
"svelteAllowShorthand": true,
|
||||
"svelteIndentScriptAndStyle": true
|
||||
}
|
16
.vscode/settings.json
vendored
16
.vscode/settings.json
vendored
@ -1,6 +1,9 @@
|
||||
{
|
||||
"editor.tabCompletion": "on",
|
||||
"diffEditor.codeLens": true,
|
||||
"editor.formatOnSave": true,
|
||||
"editor.formatOnPaste": true,
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode",
|
||||
"yaml.schemas": {
|
||||
"./../../cms/tibi-types/schemas/api-config/config.json": "api/config.y*ml",
|
||||
"./../../cms/tibi-types/schemas/api-config/collection.json": "api/collections/*.y*ml",
|
||||
@ -9,5 +12,16 @@
|
||||
"./../../cms/tibi-types/schemas/api-config/job.json": "api/jobs/*.y*ml",
|
||||
"./../../cms/tibi-types/schemas/api-config/assets.json": "api/assets/*.y*ml"
|
||||
},
|
||||
"yaml.customTags": ["!include scalar"]
|
||||
"yaml.customTags": ["!include scalar"],
|
||||
"filewatcher.commands": [
|
||||
{
|
||||
"match": "/api/.*(\\.ya?ml|js|env)$",
|
||||
"isAsync": false,
|
||||
"cmd": "docker compose -p tibi-docs restart tibiserver",
|
||||
"event": "onFileChange"
|
||||
}
|
||||
],
|
||||
"i18n-ally.localesPaths": ["frontend/locales"],
|
||||
"i18n-ally.sourceLanguage": "de",
|
||||
"i18n-ally.keystyle": "nested"
|
||||
}
|
49
Makefile
Normal file
49
Makefile
Normal file
@ -0,0 +1,49 @@
|
||||
DOCKER_COMPOSE=docker compose -f docker-compose-local.yml
|
||||
DOCKER_ALL_PROFILES=--profile docpress --profile tibi-dev --profile tibi --profile chisel
|
||||
|
||||
.DEFAULT_GOAL := help
|
||||
|
||||
.PHONY: docker-up docker-up-tibi-dev docker-up-chisel docker-up-docpress docker-start docker-start-tibi-dev docker-down docker-ps docker-logs docker-pull yarn-upgrade fix-permissions
|
||||
|
||||
include ./.env
|
||||
|
||||
help: ## show this help
|
||||
@echo MAKE TARGETS
|
||||
@grep -h -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}'
|
||||
|
||||
docker-up: ## bring docker compose stack up in background
|
||||
$(DOCKER_COMPOSE) --profile tibi up -d
|
||||
|
||||
docker-up-tibi-dev: ## bring docker compose stack up in background with tibi-dev
|
||||
$(DOCKER_COMPOSE) --profile tibi-dev up -d
|
||||
|
||||
docker-up-chisel: ## bring up chisel tunnel
|
||||
$(DOCKER_COMPOSE) --profile chisel up -d
|
||||
|
||||
docker-down: ## take docker compose stack down
|
||||
$(DOCKER_COMPOSE) $(DOCKER_ALL_PROFILES) down
|
||||
|
||||
docker-start: ## start docker compose stack in foreground and take it down after CTRL-C
|
||||
$(DOCKER_COMPOSE) --profile tibi up; $(DOCKER_COMPOSE) $(DOCKER_ALL_PROFILES) down
|
||||
|
||||
docker-start-tibi-dev: ## start docker compose stack in foreground and take it down after CTRL-C (with tibi-dev)
|
||||
$(DOCKER_COMPOSE) --profile tibi-dev up; $(DOCKER_COMPOSE) $(DOCKER_ALL_PROFILES) down
|
||||
|
||||
docker-ps: ## show container state
|
||||
$(DOCKER_COMPOSE) $(DOCKER_ALL_PROFILES) ps
|
||||
|
||||
docker-logs: ## show docker logs and follow
|
||||
$(DOCKER_COMPOSE) $(DOCKER_ALL_PROFILES) logs -f || true
|
||||
|
||||
docker-pull: ## pull docker images
|
||||
$(DOCKER_COMPOSE) $(DOCKER_ALL_PROFILES) pull
|
||||
|
||||
docker-%:
|
||||
$(DOCKER_COMPOSE) $(DOCKER_ALL_PROFILES) $*
|
||||
|
||||
yarn-upgrade: # interactive yarn upgrade
|
||||
$(DOCKER_COMPOSE) run --rm yarnstart yarn upgrade-interactive
|
||||
$(DOCKER_COMPOSE) restart yarnstart
|
||||
|
||||
fix-permissions: # set files/directories owner to UID:GID from .env
|
||||
sudo chown -R $(UID):$(GID) ./
|
10
api/hooks/config-client.js
Normal file
10
api/hooks/config-client.js
Normal file
@ -0,0 +1,10 @@
|
||||
const release = "tibi-docs.dirty"
|
||||
|
||||
// @ts-ignore
|
||||
if (release && typeof context !== "undefined") {
|
||||
context.response.header("X-Release", release)
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
release,
|
||||
}
|
20
babel.config.json
Normal file
20
babel.config.json
Normal file
@ -0,0 +1,20 @@
|
||||
{
|
||||
"sourceMaps": "inline",
|
||||
"inputSourceMap": true,
|
||||
"presets": [
|
||||
[
|
||||
"@babel/preset-env",
|
||||
{
|
||||
"useBuiltIns": "usage",
|
||||
"corejs": {
|
||||
"version": "3",
|
||||
"proposals": true
|
||||
},
|
||||
"targets": ">0.5%, IE 11, not dead",
|
||||
"debug": true,
|
||||
"forceAllTransforms": true
|
||||
}
|
||||
]
|
||||
],
|
||||
"plugins": []
|
||||
}
|
178
docker-compose-local.yml
Normal file
178
docker-compose-local.yml
Normal file
@ -0,0 +1,178 @@
|
||||
version: "3.8"
|
||||
name: tibi-docs
|
||||
|
||||
services:
|
||||
docpress:
|
||||
profiles:
|
||||
- docpress
|
||||
image: node:18
|
||||
volumes:
|
||||
- ./:/data
|
||||
- ./tmp:/tmp
|
||||
- ./tmp/nonexistent:/nonexistent
|
||||
working_dir: /data
|
||||
command: sh -c "yarn install && yarn docpress:serve"
|
||||
expose:
|
||||
- 3000
|
||||
labels:
|
||||
- traefik.enable=true
|
||||
- online.testversion.code.subdomain=${PROJECT_NAME}-docpress
|
||||
user: ${UID}:${GID}
|
||||
|
||||
yarnstart:
|
||||
profiles:
|
||||
- tibi
|
||||
- tibi-dev
|
||||
image: node:18
|
||||
volumes:
|
||||
- ./:/data
|
||||
- ./tmp:/tmp
|
||||
- ./tmp/nonexistent:/nonexistent
|
||||
working_dir: /data
|
||||
command: sh -c "yarn install && API_BASE=http://tibiserver:8080/api/v1/_/${TIBI_NAMESPACE} yarn start"
|
||||
expose:
|
||||
- 3000
|
||||
labels:
|
||||
- traefik.enable=true
|
||||
- online.testversion.code.subdomain=${PROJECT_NAME}
|
||||
- traefik.http.routers.${PROJECT_NAME}-yarnstart.middlewares=${PROJECT_NAME}-yarnstart
|
||||
- traefik.http.middlewares.${PROJECT_NAME}-yarnstart.basicauth.usersfile=${PWD}/.basic-auth-web
|
||||
user: ${UID}:${GID}
|
||||
|
||||
tibiserver:
|
||||
profiles:
|
||||
- tibi
|
||||
image: gitbase.de/cms/tibi-server
|
||||
volumes:
|
||||
- ./:/data
|
||||
environment:
|
||||
DB_DIAL: mongodb://mongo
|
||||
DB_PREFIX: ${TIBI_PREFIX}
|
||||
MAIL_HOST: maildev:25
|
||||
SECURITY_ALLOWABSOLUTEPATHS: "true"
|
||||
SECURITY_ALLOWUPPERPATHS: "true"
|
||||
depends_on:
|
||||
- mongo
|
||||
expose:
|
||||
- 8080
|
||||
labels:
|
||||
- traefik.enable=true
|
||||
- traefik.http.services.${PROJECT_NAME}-tibiserver.loadbalancer.server.port=8080
|
||||
- online.testversion.code.subdomain=${PROJECT_NAME}-tibiserver
|
||||
|
||||
tibiserver-dev:
|
||||
hostname: tibiserver
|
||||
build:
|
||||
context: ./
|
||||
dockerfile: ./../../cms/tibi-server/Dockerfile.air
|
||||
profiles:
|
||||
- tibi-dev
|
||||
volumes:
|
||||
- ./:/data
|
||||
- ./../../cms/tibi-server:/tibi-server
|
||||
- ./../../../../tmp/go/pkg:/go/pkg
|
||||
working_dir: /tibi-server
|
||||
environment:
|
||||
GOCACHE: /tmp/
|
||||
DB_DIAL: mongodb://mongo
|
||||
DB_PREFIX: ${TIBI_PREFIX}
|
||||
MAIL_HOST: maildev:25
|
||||
SECURITY_ALLOWABSOLUTEPATHS: "true"
|
||||
SECURITY_ALLOWUPPERPATHS: "true"
|
||||
depends_on:
|
||||
- mongo
|
||||
user: ${UID}:${GID}
|
||||
expose:
|
||||
- 8080
|
||||
labels:
|
||||
- traefik.enable=true
|
||||
- traefik.http.services.${PROJECT_NAME}-tibiserver.loadbalancer.server.port=8080
|
||||
- online.testversion.code.subdomain=${PROJECT_NAME}-tibiserver
|
||||
|
||||
tibiadmin:
|
||||
profiles:
|
||||
- tibi
|
||||
image: gitbase.de/cms/tibi-admin
|
||||
environment:
|
||||
INDEX: spa.html
|
||||
WEBROOT: /data
|
||||
API: /api:http://tibiserver:8080/api/v1
|
||||
PORT: 80
|
||||
depends_on:
|
||||
- tibiserver
|
||||
expose:
|
||||
- 80
|
||||
labels:
|
||||
- traefik.enable=true
|
||||
- online.testversion.code.subdomain=${PROJECT_NAME}-tibiadmin
|
||||
- traefik.http.routers.${PROJECT_NAME}-tibiadmin.middlewares=${PROJECT_NAME}-tibiadmin
|
||||
- traefik.http.middlewares.${PROJECT_NAME}-tibiadmin.basicauth.usersfile=${PWD}/.basic-auth-code
|
||||
|
||||
tibiadmin-dev:
|
||||
profiles:
|
||||
- tibi-dev
|
||||
image: node:18
|
||||
volumes:
|
||||
- ./../../cms/tibi-admin:/data
|
||||
working_dir: /data
|
||||
command: sh -c "yarn install && API_BASE=http://tibiserver:8080/api/v1 yarn start:code-server"
|
||||
expose:
|
||||
- 3000
|
||||
labels:
|
||||
- traefik.enable=true
|
||||
- online.testversion.code.subdomain=${PROJECT_NAME}-tibiadmin-dev
|
||||
- traefik.http.routers.${PROJECT_NAME}-tibiadmin-dev.middlewares=${PROJECT_NAME}-tibiadmin-dev
|
||||
- traefik.http.middlewares.${PROJECT_NAME}-tibiadmin-dev.basicauth.usersfile=${PWD}/.basic-auth-code
|
||||
user: ${UID}:${GID}
|
||||
|
||||
mongo:
|
||||
profiles:
|
||||
- tibi
|
||||
- tibi-dev
|
||||
image: gitbase.de/server/mongo:4.2
|
||||
volumes:
|
||||
- ./tmp/mongo-data:/data/db
|
||||
user: ${UID}:${GID}
|
||||
|
||||
adminmongo:
|
||||
profiles:
|
||||
- tibi
|
||||
- tibi-dev
|
||||
image: gitbase.de/server/adminmongo
|
||||
environment:
|
||||
CONN_NAME: mongo
|
||||
DB_HOST: mongo
|
||||
PORT: 1234
|
||||
expose:
|
||||
- 1234
|
||||
labels:
|
||||
- traefik.enable=true
|
||||
- online.testversion.code.subdomain=${PROJECT_NAME}-adminmongo
|
||||
- traefik.http.routers.${PROJECT_NAME}-adminmongo.middlewares=${PROJECT_NAME}-adminmongo
|
||||
- traefik.http.middlewares.${PROJECT_NAME}-adminmongo.basicauth.usersfile=${PWD}/.basic-auth-code
|
||||
|
||||
maildev:
|
||||
profiles:
|
||||
- tibi
|
||||
- tibi-dev
|
||||
image: maildev/maildev
|
||||
command: node bin/maildev --web 1080 --smtp 25 -v --hide-extensions=STARTTLS
|
||||
expose:
|
||||
- 1080
|
||||
labels:
|
||||
- traefik.enable=true
|
||||
- online.testversion.code.subdomain=${PROJECT_NAME}-maildev
|
||||
- traefik.http.services.${PROJECT_NAME}-maildev.loadbalancer.server.port=1080
|
||||
- traefik.http.routers.${PROJECT_NAME}-maildev.middlewares=${PROJECT_NAME}-maildev
|
||||
- traefik.http.middlewares.${PROJECT_NAME}-maildev.basicauth.usersfile=${PWD}/.basic-auth-code
|
||||
|
||||
chisel:
|
||||
profiles:
|
||||
- chisel
|
||||
image: jpillora/chisel
|
||||
expose:
|
||||
- 8080
|
||||
labels:
|
||||
- traefik.enable=true
|
||||
- online.testversion.code.subdomain=${PROJECT_NAME}-chisel
|
||||
command: server --port 8080 --auth coder:coder
|
109
esbuild.config.js
Normal file
109
esbuild.config.js
Normal file
@ -0,0 +1,109 @@
|
||||
const resolvePlugin = {
|
||||
name: "resolvePlugin",
|
||||
setup(build) {
|
||||
let path = require("path")
|
||||
// url in css does not resolve via esbuild-svelte correctly
|
||||
build.onResolve({ filter: /.*/, namespace: "fakecss" }, (args) => {
|
||||
// console.log(args)
|
||||
if (args.path.match(/^\./)) return { path: path.dirname(args.importer) + "/" + args.path }
|
||||
// return { path: path.join(args.resolveDir, "public", args.path) }
|
||||
})
|
||||
},
|
||||
}
|
||||
|
||||
////////////////////////// esbuild-svelte
|
||||
|
||||
const sveltePlugin = require("esbuild-svelte")
|
||||
|
||||
const frontendDir = "./frontend"
|
||||
const distDir = frontendDir + "/dist"
|
||||
|
||||
// console.log("copy public dir...")
|
||||
// const copydir = require("copy-dir")
|
||||
// copydir.sync(__dirname + "/public", __dirname + "/" + distDir)
|
||||
/*copydir.sync(
|
||||
__dirname + "/public/index.html",
|
||||
__dirname + "/" + distDir + "/template.html"
|
||||
)*/
|
||||
|
||||
const svelteConfig = require("./svelte.config")
|
||||
const esbuildSvelte = sveltePlugin({
|
||||
compilerOptions: {
|
||||
css: false,
|
||||
hydratable: true,
|
||||
dev: (process.argv?.length > 2 ? process.argv[2] : "build") !== "build",
|
||||
},
|
||||
preprocess: svelteConfig.preprocess,
|
||||
cache: true,
|
||||
filterWarnings: (warning) => {
|
||||
// filter out a11y
|
||||
if (warning.code.match(/^a11y/)) return false
|
||||
return true
|
||||
},
|
||||
})
|
||||
|
||||
const options = {
|
||||
logLevel: "info",
|
||||
color: true,
|
||||
entryPoints: ["./frontend/src/index.ts"],
|
||||
outfile: distDir + "/index.mjs",
|
||||
metafile: true,
|
||||
format: "esm",
|
||||
minify: process.argv[2] == "build",
|
||||
bundle: true,
|
||||
splitting: false,
|
||||
plugins: [esbuildSvelte, resolvePlugin],
|
||||
loader: {
|
||||
".woff2": "file",
|
||||
".woff": "file",
|
||||
".eot": "file",
|
||||
".svg": "file",
|
||||
".ttf": "file",
|
||||
},
|
||||
sourcemap: true,
|
||||
target: ["es2020", "chrome61", "firefox60", "safari11", "edge18"],
|
||||
}
|
||||
|
||||
const bsMiddleware = []
|
||||
|
||||
if (process.argv[2] == "start") {
|
||||
const { createProxyMiddleware } = require("http-proxy-middleware")
|
||||
const apiBase = process.env.API_BASE || "http://localhost:8080/api/v1/_/" + process.env.NAMESPACE
|
||||
bsMiddleware.push(
|
||||
createProxyMiddleware("/api", {
|
||||
target: apiBase,
|
||||
pathRewrite: { "^/api": "" },
|
||||
changeOrigin: true,
|
||||
logLevel: "debug",
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
sveltePlugin: sveltePlugin,
|
||||
resolvePlugin: resolvePlugin,
|
||||
options: options,
|
||||
watch: {
|
||||
path: [__dirname + "/" + frontendDir + "/src/**/*"],
|
||||
},
|
||||
serve: {
|
||||
onRequest(args) {
|
||||
console.log(args)
|
||||
},
|
||||
},
|
||||
browserSync: {
|
||||
server: {
|
||||
baseDir: frontendDir,
|
||||
middleware: [
|
||||
require("morgan")("dev"),
|
||||
...bsMiddleware,
|
||||
require("connect-history-api-fallback")({
|
||||
index: "/spa.html",
|
||||
// verbose: true,
|
||||
}),
|
||||
],
|
||||
},
|
||||
open: false,
|
||||
// logLevel: "debug",
|
||||
},
|
||||
}
|
8
esbuild.config.legacy.js
Normal file
8
esbuild.config.legacy.js
Normal file
@ -0,0 +1,8 @@
|
||||
const config = require("./esbuild.config.js")
|
||||
|
||||
config.options.sourcemap = "inline"
|
||||
config.options.minify = false
|
||||
config.options.format = "iife"
|
||||
config.options.outfile = __dirname + "/_temp/index.js"
|
||||
|
||||
module.exports = config
|
23
esbuild.config.server.js
Normal file
23
esbuild.config.server.js
Normal file
@ -0,0 +1,23 @@
|
||||
const config = require("./esbuild.config.js")
|
||||
const svelteConfig = require("./svelte.config")
|
||||
|
||||
config.options.sourcemap = "inline"
|
||||
config.options.minify = false
|
||||
config.options.platform = "node"
|
||||
config.options.format = "cjs"
|
||||
config.options.entryPoints = ["./frontend/src/ssr.ts"]
|
||||
config.options.outfile = __dirname + "/_temp/app.server.js"
|
||||
config.options.plugins = [
|
||||
config.sveltePlugin({
|
||||
compilerOptions: {
|
||||
generate: "ssr",
|
||||
css: false,
|
||||
hydratable: true,
|
||||
dev: (process.argv?.length > 2 ? process.argv[2] : "build") !== "build",
|
||||
},
|
||||
preprocess: svelteConfig.preprocess,
|
||||
}),
|
||||
config.resolvePlugin,
|
||||
]
|
||||
|
||||
module.exports = config
|
16
frontend/.htaccess
Normal file
16
frontend/.htaccess
Normal file
@ -0,0 +1,16 @@
|
||||
AddType application/javascript .mjs
|
||||
|
||||
#DirectoryIndex index.html spa.html
|
||||
DirectoryIndex noindex
|
||||
|
||||
<ifModule mod_rewrite.c>
|
||||
RewriteEngine On
|
||||
RewriteBase /
|
||||
|
||||
RewriteRule ^/?api/(.*)$ http://tibi-server:8080/api/v1/_/demo/$1 [P,QSA,L]
|
||||
|
||||
RewriteCond %{REQUEST_FILENAME} !-f
|
||||
RewriteCond %{REQUEST_FILENAME} !-d
|
||||
RewriteRule ^/?(.*)$ http://tibi-server:8080/api/v1/_/demo/ssr?token=owshwerNwoa&url=/$1 [P,QSA,L]
|
||||
#RewriteRule (.*) /spa.html [QSA,L]
|
||||
</ifModule>
|
23
frontend/spa.html
Normal file
23
frontend/spa.html
Normal file
@ -0,0 +1,23 @@
|
||||
<!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>TibiCMS</title>
|
||||
<base href="/" />
|
||||
<link rel="stylesheet" href="/dist/index.css?t=__TIMESTAMP__" />
|
||||
|
||||
<!--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>
|
||||
</body>
|
||||
|
||||
<!--SSR.ERROR-->
|
||||
<!--SSR.COMMENT-->
|
||||
</html>
|
22
frontend/src/components/App.svelte
Normal file
22
frontend/src/components/App.svelte
Normal file
@ -0,0 +1,22 @@
|
||||
<script lang="ts">
|
||||
import { location } from "../store"
|
||||
|
||||
export let url = ""
|
||||
|
||||
if (url) {
|
||||
// ssr
|
||||
let l = url.split("?")
|
||||
$location = {
|
||||
path: l[0],
|
||||
search: l.length > 1 ? l[1] : "",
|
||||
hash: "",
|
||||
categoryPath: l[0].replace(/\/[^_\/]+_[^\/]+$/, ""),
|
||||
push: false,
|
||||
pop: false,
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof window !== "undefined") console.log("App initialized")
|
||||
</script>
|
||||
|
||||
<h1>Hello World</h1>
|
5
frontend/src/config.ts
Normal file
5
frontend/src/config.ts
Normal file
@ -0,0 +1,5 @@
|
||||
import configClient from "../../api/hooks/config-client"
|
||||
|
||||
export const apiBaseURL = "/api/"
|
||||
export const release = configClient.release
|
||||
console.log("Release: ", release)
|
86
frontend/src/index.ts
Normal file
86
frontend/src/index.ts
Normal file
@ -0,0 +1,86 @@
|
||||
import App from "./components/App.svelte"
|
||||
import { location } from "./store"
|
||||
|
||||
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 = {
|
||||
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,
|
||||
categoryPath: "",
|
||||
}
|
||||
newLocation.categoryPath = newLocation.path.replace(/\/[^_\/]+_[^\/]+$/, "")
|
||||
location.set(newLocation)
|
||||
}
|
||||
|
||||
if (typeof history !== "undefined") {
|
||||
if (typeof Proxy !== "undefined") {
|
||||
// modern browser
|
||||
const historyApply = (target, thisArg, argumentsList) => {
|
||||
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)
|
||||
return pushStateFn.apply(history, arguments)
|
||||
}
|
||||
history.replaceState = function (
|
||||
data: any,
|
||||
title: string,
|
||||
url?: string
|
||||
) {
|
||||
publishLocation(url)
|
||||
return replaceStateFn.apply(history, arguments)
|
||||
}
|
||||
}
|
||||
} // else ssr -> no history handling
|
||||
|
||||
typeof window !== "undefined" &&
|
||||
window.addEventListener("popstate", (event) => {
|
||||
publishLocation()
|
||||
})
|
||||
|
||||
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
|
11
frontend/src/store.ts
Normal file
11
frontend/src/store.ts
Normal file
@ -0,0 +1,11 @@
|
||||
import { writable } from "svelte/store"
|
||||
|
||||
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,
|
||||
categoryPath: "",
|
||||
}
|
||||
export const location = writable(initLoc)
|
47
package.json
47
package.json
@ -6,15 +6,52 @@
|
||||
"author": "Sebastian Frank <sebastian@webmakers.de>",
|
||||
"license": "MIT",
|
||||
"packageManager": "yarn@3.2.4",
|
||||
"scripts": {
|
||||
"docpress:serve": "docpress serve",
|
||||
"docpress:build": "docpress build",
|
||||
"validate": "svelte-check && tsc --noEmit",
|
||||
"dev": "node scripts/esbuild-wrapper.js watch",
|
||||
"start": "NAMESPACE=renz_shop node scripts/esbuild-wrapper.js start",
|
||||
"build": "node scripts/esbuild-wrapper.js build",
|
||||
"build:legacy": "node scripts/esbuild-wrapper.js build esbuild.config.legacy.js && babel _temp/index.js -o _temp/index.babeled.js && esbuild _temp/index.babeled.js --outfile=frontend/dist/index.es5.js --target=es5 --bundle --minify --sourcemap",
|
||||
"build:server": "node scripts/esbuild-wrapper.js build esbuild.config.server.js && babel _temp/app.server.js -o _temp/app.server.babeled.js && esbuild _temp/app.server.babeled.js --outfile=api/hooks/lib/app.server.js --target=es5 --bundle --sourcemap --platform=node",
|
||||
"build:test": "node scripts/esbuild-wrapper.js build esbuild.config.test.js && babel --config-file ./babel.config.test.json _temp/hook.test.js -o _temp/hook.test.babeled.js && esbuild _temp/hook.test.babeled.js --outfile=api/hooks/lib/hook.test.js --target=es5 --bundle --sourcemap --platform=node",
|
||||
"upload:sourcemaps": "scripts/upload-sourcemaps.sh"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/cli": "^7.20.7",
|
||||
"@babel/core": "^7.20.12",
|
||||
"@babel/preset-env": "^7.20.2",
|
||||
"@tsconfig/svelte": "^3.0.0",
|
||||
"@types/lodash": "^4.14.191",
|
||||
"browser-sync": "^2.27.11",
|
||||
"chokidar": "^3.5.3",
|
||||
"connect-history-api-fallback": "^2.0.0",
|
||||
"docpress": "^0.8.2",
|
||||
"tibi-types": "https://gitbase.de/cms/tibi-types.git#commit=c795339d1c7c91266cafd8b5914a57972565939a"
|
||||
"esbuild": "^0.17.4",
|
||||
"esbuild-svelte": "^0.7.3",
|
||||
"http-proxy-middleware": "^2.0.6",
|
||||
"less": "^4.1.3",
|
||||
"morgan": "^1.10.0",
|
||||
"node-fetch": "^3.3.0",
|
||||
"postcss": "^8.4.21",
|
||||
"prettier": "^2.8.3",
|
||||
"prettier-plugin-svelte": "^2.9.0",
|
||||
"sass": "^1.57.1",
|
||||
"svelte": "^3.55.1",
|
||||
"svelte-check": "^3.0.2",
|
||||
"svelte-hmr": "^0.15.1",
|
||||
"svelte-preprocess": "^5.0.1",
|
||||
"svelte-preprocess-esbuild": "^3.0.1",
|
||||
"svelte-routing": "^1.6.0",
|
||||
"tslib": "^2.4.1",
|
||||
"typescript": "^4.9.4"
|
||||
},
|
||||
"dependencies": {
|
||||
"@sentry/browser": "^7.31.1",
|
||||
"@sentry/cli": "^2.11.0",
|
||||
"@sentry/tracing": "^7.31.1",
|
||||
"core-js": "3.27.2",
|
||||
"markdown-it-code-include": "./markdown-it-code-include"
|
||||
},
|
||||
"scripts": {
|
||||
"serve": "docpress serve",
|
||||
"build": "docpress build"
|
||||
}
|
||||
}
|
||||
|
42
scripts/deploy.sh
Executable file
42
scripts/deploy.sh
Executable file
@ -0,0 +1,42 @@
|
||||
#!/bin/sh
|
||||
|
||||
# if RSYNC_USER or RSYNC_PASS is not set, exit
|
||||
if [ -z "${RSYNC_USER}" ] || [ -z "${RSYNC_PASS}" ]; then
|
||||
echo "RSYNC_USER or RSYNC_PASS not set, exiting"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
excludes=""
|
||||
if [ "${DRONE_BRANCH}" == "master" ]; then
|
||||
excludes='--exclude=src --exclude=*.map'
|
||||
echo "master deploy, excluding $excludes"
|
||||
fi
|
||||
|
||||
# sync frontend
|
||||
rsync -rlcgD --perms -i -u -v --stats --progress \
|
||||
--delete \
|
||||
-e "sshpass -p ${RSYNC_PASS} ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -p 22222" \
|
||||
$excludes \
|
||||
frontend/ \
|
||||
${RSYNC_USER}@ftp1.webmakers.de:./frontend/ \
|
||||
|
||||
# sync images getter
|
||||
rsync -rlcgD --perms -i -u -v --stats --progress \
|
||||
-e "sshpass -p ${RSYNC_PASS} ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -p 22222" \
|
||||
images/ \
|
||||
${RSYNC_USER}@ftp1.webmakers.de:./images/
|
||||
|
||||
# sync api config
|
||||
rsync -rlcgD --perms -i -u -v --stats --progress \
|
||||
--delete \
|
||||
-e "sshpass -p ${RSYNC_PASS} ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -p 22222" \
|
||||
api/ \
|
||||
${RSYNC_USER}@ftp1.webmakers.de:./api/
|
||||
|
||||
# create media directory
|
||||
mkdir media
|
||||
chmod 770 media
|
||||
rsync -rlcgD --perms -i -u -v --stats --progress \
|
||||
-e "sshpass -p ${RSYNC_PASS} ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -p 22222" \
|
||||
media \
|
||||
${RSYNC_USER}@ftp1.webmakers.de:./
|
78
scripts/esbuild-wrapper.js
Normal file
78
scripts/esbuild-wrapper.js
Normal file
@ -0,0 +1,78 @@
|
||||
const esbuild = require("esbuild")
|
||||
const fs = require("fs")
|
||||
const path = require("path")
|
||||
|
||||
const config = require(process.cwd() + (process.argv?.length > 3 ? "/" + process.argv[3] : "/esbuild.config.js"))
|
||||
const { watch } = require("chokidar")
|
||||
|
||||
function log(str, clear) {
|
||||
if (clear && process.stdout.cursorTo && process.stdout.clearScreenDown) {
|
||||
process.stdout.cursorTo(0, 0)
|
||||
process.stdout.clearScreenDown()
|
||||
}
|
||||
console.log("\x1b[36m%s\x1b[0m", str)
|
||||
}
|
||||
|
||||
let buildResults
|
||||
let ctx
|
||||
|
||||
async function build(catchError) {
|
||||
if (!ctx) ctx = await esbuild.context(config.options)
|
||||
log((buildResults ? "re" : "") + "building...")
|
||||
const timerStart = Date.now()
|
||||
try {
|
||||
buildResults = await ctx.rebuild()
|
||||
if (config.options.metafile) {
|
||||
fs.writeFileSync(
|
||||
(config.options.outfile ? path.dirname(config.options.outfile) : config.options.outdir) + "/meta.json",
|
||||
JSON.stringify(buildResults.metafile, null, 4)
|
||||
)
|
||||
}
|
||||
} catch (e) {
|
||||
console.log(e)
|
||||
if (!catchError) throw e
|
||||
}
|
||||
|
||||
const timerEnd = Date.now()
|
||||
log(`built in ${timerEnd - timerStart}ms.`)
|
||||
}
|
||||
|
||||
let bs
|
||||
switch (process.argv?.length > 2 ? process.argv[2] : "build") {
|
||||
case "serve":
|
||||
console.log("\x1b[36m%s\x1b[0mserving...")
|
||||
esbuild.context(config.options).then(function (_ctx) {
|
||||
_ctx.serve(config.serve).catch((err) => {
|
||||
console.error(err)
|
||||
process.exit(1)
|
||||
})
|
||||
})
|
||||
break
|
||||
case "start":
|
||||
bs = require("browser-sync")
|
||||
bs.init(config.browserSync)
|
||||
case "watch":
|
||||
// config.options.incremental = true
|
||||
build(true)
|
||||
const watcher = watch(config.watch.path)
|
||||
log("watching files...")
|
||||
watcher.on("change", function (path) {
|
||||
log(`${path} changed`, true)
|
||||
build(true).then(() => {
|
||||
if (bs) {
|
||||
bs.reload()
|
||||
}
|
||||
})
|
||||
})
|
||||
break
|
||||
default:
|
||||
esbuild.build(config.options).then(function (buildResults) {
|
||||
if (config.options.metafile) {
|
||||
fs.writeFileSync(
|
||||
(config.options.outfile ? path.dirname(config.options.outfile) : config.options.outdir) +
|
||||
"/meta.json",
|
||||
JSON.stringify(buildResults.metafile, null, 4)
|
||||
)
|
||||
}
|
||||
})
|
||||
}
|
16
scripts/preload-meta.sh
Executable file
16
scripts/preload-meta.sh
Executable file
@ -0,0 +1,16 @@
|
||||
#!/bin/bash
|
||||
|
||||
if [ "$1" == "" ]; then
|
||||
echo template filename required
|
||||
exit 1
|
||||
fi
|
||||
|
||||
preload=$(for f in frontend/dist/*.woff2; do
|
||||
echo "<link rel=\"preload\" href=\"/dist/`basename $f`\" as=\"font\" type=\"font/woff2\" crossorigin />"
|
||||
done)
|
||||
|
||||
template="`cat $1 | sed -e 's#<!--PRELOAD-->#\$preload#'`"
|
||||
|
||||
eval "cat <<EOF
|
||||
$template
|
||||
EOF"
|
10
scripts/upload-sourcemaps.sh
Executable file
10
scripts/upload-sourcemaps.sh
Executable file
@ -0,0 +1,10 @@
|
||||
#!/bin/sh
|
||||
BASEDIR=$(dirname $0)
|
||||
|
||||
. $BASEDIR/../.env
|
||||
|
||||
echo deleting old release ${RELEASE_ORG_SLUG} ${RELEASE_VERSION:-$RELEASE_PROJECT_SLUG.dirty}
|
||||
sentry-cli --url https://glitchtip.basehosts.de/ --auth-token ${GLITCHTIP_TOKEN} releases --org ${RELEASE_ORG_SLUG} --project ${RELEASE_PROJECT_SLUG} delete ${RELEASE_VERSION:-$RELEASE_PROJECT_SLUG.dirty}
|
||||
|
||||
echo creating release ${RELEASE_ORG_SLUG} ${RELEASE_VERSION:-$RELEASE_PROJECT_SLUG.dirty} and uploading sourcemaps
|
||||
sentry-cli --url https://glitchtip.basehosts.de/ --auth-token ${GLITCHTIP_TOKEN} releases --org ${RELEASE_ORG_SLUG} --project ${RELEASE_PROJECT_SLUG} files ${RELEASE_VERSION:-$RELEASE_PROJECT_SLUG.dirty} upload-sourcemaps --url-prefix='~/' --ext js --ext mjs --ext svelte --ext map frontend
|
16
svelte.config.js
Normal file
16
svelte.config.js
Normal file
@ -0,0 +1,16 @@
|
||||
const { typescript } = require("svelte-preprocess-esbuild")
|
||||
const sveltePreprocess = require("svelte-preprocess")
|
||||
module.exports = {
|
||||
preprocess: [
|
||||
typescript({
|
||||
sourcemap: true,
|
||||
}),
|
||||
sveltePreprocess({
|
||||
sourceMap: true,
|
||||
typescript: false,
|
||||
scss: {
|
||||
includePaths: ["frontend/src/theme"],
|
||||
},
|
||||
}),
|
||||
],
|
||||
}
|
24
tsconfig.json
Normal file
24
tsconfig.json
Normal file
@ -0,0 +1,24 @@
|
||||
{
|
||||
"extends": "@tsconfig/svelte/tsconfig.json",
|
||||
|
||||
"include": ["frontend/src/**/*", "types/**/*", "./../../cms/tibi-types", "api/**/*"],
|
||||
"compilerOptions": {
|
||||
"module": "esnext",
|
||||
"typeRoots": ["./node_modules/@types", "./types"],
|
||||
|
||||
"target": "esnext",
|
||||
"moduleResolution": "node",
|
||||
"jsx": "preserve",
|
||||
"noEmit": true,
|
||||
"skipLibCheck": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"resolveJsonModule": true,
|
||||
"useDefineForClassFields": true,
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"importsNotUsedAsValues": "error",
|
||||
"preserveValueImports": true,
|
||||
|
||||
"allowJs": true,
|
||||
"checkJs": true
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user