Füge Docker- und Babel-Konfigurationen hinzu, aktualisiere Svelte- und Esbuild-Setups, erweitere Typdefinitionen und aktualisiere die README-Datei
This commit is contained in:
6
.env
6
.env
@@ -11,6 +11,12 @@ SENTRY_PROJECT=
|
|||||||
RSYNC_HOST=ftp1.webmakers.de
|
RSYNC_HOST=ftp1.webmakers.de
|
||||||
RSYNC_PORT=22223
|
RSYNC_PORT=22223
|
||||||
|
|
||||||
|
PRODUCTION_SERVER=dock4.basehosts.de
|
||||||
|
PRODUCTION_TIBI_PREFIX=wmbasic
|
||||||
|
PRODUCTION_PATH=/webroots2/customers/_CUSTOMER_ID_/____
|
||||||
|
|
||||||
|
STAGING_PATH=/staging/__ORG__/__PROJECT__/dev
|
||||||
|
|
||||||
LIVE_URL=https://www
|
LIVE_URL=https://www
|
||||||
STAGING_URL=https://dev-__PROJECT_NAME__.staging.testversion.online
|
STAGING_URL=https://dev-__PROJECT_NAME__.staging.testversion.online
|
||||||
|
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
"check-parameters"
|
"check-parameters"
|
||||||
],
|
],
|
||||||
"no-var-keyword": true,
|
"no-var-keyword": true,
|
||||||
"svelteSortOrder": "scripts-markup-styles",
|
"svelteSortOrder": "scripts-options-markup-styles",
|
||||||
"svelteStrictMode": true,
|
"svelteStrictMode": true,
|
||||||
"svelteBracketNewLine": true,
|
"svelteBracketNewLine": true,
|
||||||
"svelteAllowShorthand": true,
|
"svelteAllowShorthand": true,
|
||||||
|
|||||||
14
Dockerfile
Normal file
14
Dockerfile
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
FROM node:latest
|
||||||
|
|
||||||
|
ADD webserver/ /webserver/
|
||||||
|
WORKDIR /webserver
|
||||||
|
RUN npm install
|
||||||
|
EXPOSE 80
|
||||||
|
|
||||||
|
ADD frontend/ /data/
|
||||||
|
|
||||||
|
ENV INDEX ""
|
||||||
|
ENV API ""
|
||||||
|
ENV WEBROOT ""
|
||||||
|
|
||||||
|
CMD [ "node", "webserver.js" ]
|
||||||
62
Makefile
62
Makefile
@@ -1,13 +1,16 @@
|
|||||||
DOCKER_COMPOSE := docker compose -f docker-compose-local.yml
|
DOCKER_COMPOSE=docker compose -f docker-compose-local.yml
|
||||||
.DEFAULT_GOAL := help
|
|
||||||
.PHONY: docker-up docker-start docker-down docker-logs
|
|
||||||
|
|
||||||
export UID := $(shell id -u)
|
.DEFAULT_GOAL := help
|
||||||
export GID := $(shell id -g)
|
|
||||||
|
.PHONY: docker-up docker-up-tibi-dev docker-start docker-start-tibi-dev docker-down docker-ps docker-logs yarn-upgrade fix-permissions
|
||||||
|
|
||||||
|
include ./.env
|
||||||
|
|
||||||
help: ## show this help
|
help: ## show this help
|
||||||
@echo MAKE TARGETS
|
@echo MAKE TARGETS
|
||||||
@grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}'
|
@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-up: ## bring docker compose stack up in background
|
||||||
$(DOCKER_COMPOSE) --profile tibi up -d
|
$(DOCKER_COMPOSE) --profile tibi up -d
|
||||||
@@ -15,27 +18,58 @@ docker-up: ## bring docker compose stack up in background
|
|||||||
docker-up-tibi-dev: ## bring docker compose stack up in background with tibi-dev
|
docker-up-tibi-dev: ## bring docker compose stack up in background with tibi-dev
|
||||||
$(DOCKER_COMPOSE) --profile tibi-dev up -d
|
$(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-down: ## take docker compose stack down
|
||||||
$(DOCKER_COMPOSE) --profile tibi-dev --profile tibi down
|
$(DOCKER_COMPOSE) --profile tibi-dev --profile tibi --profile chisel down
|
||||||
|
|
||||||
docker-start: ## start docker compose stack in foreground and take it down after CTRL-C
|
docker-start: ## start docker compose stack in foreground and take it down after CTRL-C
|
||||||
$(DOCKER_COMPOSE) --profile tibi up; $(DOCKER_COMPOSE) --profile tibi-dev --profile tibi down
|
$(DOCKER_COMPOSE) --profile tibi up; $(DOCKER_COMPOSE) --profile tibi-dev --profile tibi --profile chisel down
|
||||||
|
|
||||||
docker-start-tibi-dev: ## start docker compose stack in foreground and take it down after CTRL-C (with tibi-dev)
|
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) --profile tibi-dev --profile tibi down
|
$(DOCKER_COMPOSE) --profile tibi-dev up; $(DOCKER_COMPOSE) --profile tibi-dev --profile tibi --profile chisel down
|
||||||
|
|
||||||
docker-ps: ## show container state
|
docker-ps: ## show container state
|
||||||
$(DOCKER_COMPOSE) --profile tibi-dev --profile tibi ps
|
$(DOCKER_COMPOSE) --profile tibi-dev --profile tibi --profile chisel ps
|
||||||
|
|
||||||
docker-logs: ## show docker logs and follow
|
docker-logs: ## show docker logs and follow
|
||||||
$(DOCKER_COMPOSE) --profile tibi-dev --profile tibi logs -f || true
|
$(DOCKER_COMPOSE) --profile tibi-dev --profile tibi --profile chisel logs -f --tail=100 || true
|
||||||
|
|
||||||
|
docker-pull: ## pull docker images
|
||||||
|
$(DOCKER_COMPOSE) --profile tibi-dev --profile tibi --profile chisel pull
|
||||||
|
|
||||||
docker-%:
|
docker-%:
|
||||||
$(DOCKER_COMPOSE) $*
|
$(DOCKER_COMPOSE) $*
|
||||||
|
|
||||||
yarn-upgrade: # interactive yarn upgrade
|
yarn-upgrade: ## interactive yarn upgrade
|
||||||
$(DOCKER_COMPOSE) run --rm yarnstart yarn upgrade-interactive
|
$(DOCKER_COMPOSE) run --rm yarnstart yarn upgrade-interactive
|
||||||
$(DOCKER_COMPOSE) restart yarnstart
|
$(DOCKER_COMPOSE) restart yarnstart
|
||||||
|
|
||||||
fix-permissions: # set files/directories owner to UID:GID from .env
|
fix-permissions: ## set files/directories owner to UID:GID from .env
|
||||||
sudo chown -R $(UID):$(GID) ./
|
sudo chown -R $(CODER_UID):$(CODER_GID) ./
|
||||||
|
|
||||||
|
mongo-sync-master-to-local: ## sync mongo from master to local
|
||||||
|
$(DOCKER_COMPOSE) up mongo -d
|
||||||
|
read -s -p "Enter chisel password: " CHISEL_PASSWORD; \
|
||||||
|
chisel client --auth coder:$$CHISEL_PASSWORD http://$(PRODUCTION_SERVER):10987 27017:mongo:27017 &
|
||||||
|
sleep 3
|
||||||
|
mongodump --archive --gzip --db=$(PRODUCTION_TIBI_PREFIX)_$(TIBI_NAMESPACE) | $(DOCKER_COMPOSE) exec -T mongo mongorestore --archive --gzip --nsFrom='$(PRODUCTION_TIBI_PREFIX)_$(TIBI_NAMESPACE).*' --nsTo='tibi_$(TIBI_NAMESPACE).*' --nsInclude='$(PRODUCTION_TIBI_PREFIX)_$(TIBI_NAMESPACE).*' --drop
|
||||||
|
sleep 3
|
||||||
|
killall chisel
|
||||||
|
|
||||||
|
media-sync-master-to-local: ## sync attachments from master to local
|
||||||
|
rsync -v -e "ssh -i ~/.ssh/id_deploy -p 22223 -l 10052300,33,$(PRODUCTION_PATH)/media" -az --info=progress2 ftp1.webmakers.de:/ media/
|
||||||
|
|
||||||
|
mongo-sync-local-to-staging: ## sync mongo from local to staging area
|
||||||
|
$(DOCKER_COMPOSE) up mongo -d
|
||||||
|
read -s -p "Enter chisel password: " CHISEL_PASSWORD; \
|
||||||
|
chisel client --auth coder:$$CHISEL_PASSWORD https://chisel-dev-tibi.staging.testversion.online 27017:mongo:27017 &
|
||||||
|
sleep 3
|
||||||
|
|
||||||
|
$(DOCKER_COMPOSE) exec -T mongo mongodump --archive --gzip --db=$(TIBI_PREFIX)_$(TIBI_NAMESPACE) | mongorestore --archive --gzip --nsFrom='$(TIBI_PREFIX)_$(TIBI_NAMESPACE).*' --nsTo='$(TIBI_PREFIX)_$(TIBI_NAMESPACE).*' --nsInclude='$(TIBI_PREFIX)_$(TIBI_NAMESPACE).*' --drop
|
||||||
|
sleep 3
|
||||||
|
killall chisel
|
||||||
|
|
||||||
|
media-sync-local-to-staging: ## sync attachments from local to staging area
|
||||||
|
sudo rsync -v -az --info=progress2 media $(STAGING_PATH)/
|
||||||
|
|||||||
35
README.md
35
README.md
@@ -27,24 +27,6 @@ git lfs pull
|
|||||||
yarn install
|
yarn install
|
||||||
```
|
```
|
||||||
|
|
||||||
### Entwickeln mit dev-Webserver
|
|
||||||
|
|
||||||
```sh
|
|
||||||
yarn start
|
|
||||||
```
|
|
||||||
|
|
||||||
oder mit abweichender API für "/api"-Proxy
|
|
||||||
|
|
||||||
```sh
|
|
||||||
API_BASE=https://login.tibicms.de/api/v1_/__NAMESPACE__ yarn start
|
|
||||||
```
|
|
||||||
|
|
||||||
### Entwickeln mit externem Webserver (z.B. vscode live server)
|
|
||||||
|
|
||||||
```sh
|
|
||||||
yarn dev
|
|
||||||
```
|
|
||||||
|
|
||||||
### Entwickeln auf dem Code-Server mit Docker Compose Stack
|
### Entwickeln auf dem Code-Server mit Docker Compose Stack
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
@@ -58,17 +40,9 @@ make docker-down
|
|||||||
|
|
||||||
| UI | URL |
|
| UI | URL |
|
||||||
| --- | --- |
|
| --- | --- |
|
||||||
| Website | https://tibi-svelte-starter.code.testversion.online/ |
|
| Website | <https://tibi-svelte-starter.code.testversion.online/> |
|
||||||
| Tibi Admin | https://tibi-svelte-starter-tibiadmin.code.testversion.online/ |
|
| Tibi Admin | <https://tibi-svelte-starter-tibiadmin.code.testversion.online/> |
|
||||||
| Admin Mongo | https://tibi-svelte-starter-adminmongo.code.testversion.online/ |
|
| Maildev | <https://tibi-svelte-starter-maildev.code.testversion.online/> |
|
||||||
| Maildev | https://tibi-svelte-starter-maildev.code.testversion.online/ |
|
|
||||||
|
|
||||||
### Testen
|
|
||||||
|
|
||||||
```sh
|
|
||||||
yarn build:istanbul # instrumentiert Code für coverage-Report
|
|
||||||
yarn cy:docker:run # oder mit Xserver und UI cy:docker:open
|
|
||||||
```
|
|
||||||
|
|
||||||
### Bauen
|
### Bauen
|
||||||
|
|
||||||
@@ -81,4 +55,7 @@ yarn build:legacy
|
|||||||
|
|
||||||
# serverseitiges Rendering
|
# serverseitiges Rendering
|
||||||
yarn build:server
|
yarn build:server
|
||||||
|
|
||||||
|
# Admin-Module
|
||||||
|
yarn build:admin
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -10,16 +10,11 @@
|
|||||||
"version": "3",
|
"version": "3",
|
||||||
"proposals": true
|
"proposals": true
|
||||||
},
|
},
|
||||||
"targets": ">0.5%, IE 11, not dead"
|
"targets": ">0.5%, IE 11, not dead",
|
||||||
|
"debug": true,
|
||||||
|
"forceAllTransforms": true
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
"plugins": [
|
"plugins": []
|
||||||
[
|
|
||||||
"@babel/plugin-transform-spread",
|
|
||||||
{
|
|
||||||
"loose": true
|
|
||||||
}
|
|
||||||
]
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
|
|||||||
5
babel.config.server.json
Normal file
5
babel.config.server.json
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"sourceMaps": "inline",
|
||||||
|
"inputSourceMap": true,
|
||||||
|
"plugins": [["@babel/plugin-transform-async-to-generator"]]
|
||||||
|
}
|
||||||
@@ -2,12 +2,18 @@ name: ${PROJECT_NAME}
|
|||||||
|
|
||||||
services:
|
services:
|
||||||
yarnstart:
|
yarnstart:
|
||||||
image: node:18
|
profiles:
|
||||||
user: ${UID}:${GID}
|
- tibi
|
||||||
|
- tibi-dev
|
||||||
|
image: node:20
|
||||||
volumes:
|
volumes:
|
||||||
- ./:/data
|
- ./:/data
|
||||||
|
- ./tmp:/tmp
|
||||||
|
- ./tmp/nonexistent:/nonexistent
|
||||||
|
- ./tmp/.npm:/.npm
|
||||||
|
- ./tmp/.yarn:/.yarn
|
||||||
working_dir: /data
|
working_dir: /data
|
||||||
command: sh -c "yarn install && API_BASE=http://tibiserver:8080/api/v1/_/${TIBI_NAMESPACE} yarn start"
|
command: sh -c "yarn install && API_BASE=http://tibiserver:8080/api/v1/_/${TIBI_NAMESPACE} yarn start${START_SCRIPT}"
|
||||||
expose:
|
expose:
|
||||||
- 3000
|
- 3000
|
||||||
labels:
|
labels:
|
||||||
@@ -15,25 +21,36 @@ services:
|
|||||||
- online.testversion.code.subdomain=${PROJECT_NAME}
|
- online.testversion.code.subdomain=${PROJECT_NAME}
|
||||||
- traefik.http.routers.${PROJECT_NAME}-yarnstart.middlewares=${PROJECT_NAME}-yarnstart
|
- traefik.http.routers.${PROJECT_NAME}-yarnstart.middlewares=${PROJECT_NAME}-yarnstart
|
||||||
- traefik.http.middlewares.${PROJECT_NAME}-yarnstart.basicauth.usersfile=${PWD}/.basic-auth-web
|
- traefik.http.middlewares.${PROJECT_NAME}-yarnstart.basicauth.usersfile=${PWD}/.basic-auth-web
|
||||||
|
user: ${CODER_UID}:${CODER_GID}
|
||||||
|
|
||||||
tibiserver:
|
tibiserver:
|
||||||
image: gitbase.de/cms/tibi-server
|
|
||||||
profiles:
|
profiles:
|
||||||
- tibi
|
- tibi
|
||||||
|
image: gitbase.de/cms/tibi-server
|
||||||
volumes:
|
volumes:
|
||||||
- ./:/data
|
- ./:/data
|
||||||
environment:
|
environment:
|
||||||
DB_DIAL: mongodb://mongo
|
DB_DIAL: mongodb://mongo
|
||||||
DB_PREFIX: ${TIBI_PREFIX}
|
DB_PREFIX: ${TIBI_PREFIX}
|
||||||
MAIL_HOST: maildev:25
|
MAIL_HOST: maildev:25
|
||||||
|
SECURITY_ALLOWABSOLUTEPATHS: "true"
|
||||||
|
SECURITY_ALLOWUPPERPATHS: "true"
|
||||||
depends_on:
|
depends_on:
|
||||||
- mongo
|
- 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:
|
tibiserver-dev:
|
||||||
hostname: tibiserver
|
hostname: tibiserver
|
||||||
|
build:
|
||||||
|
context: ./
|
||||||
|
dockerfile: ./../../cms/tibi-server/Dockerfile.air
|
||||||
profiles:
|
profiles:
|
||||||
- tibi-dev
|
- tibi-dev
|
||||||
image: cosmtrek/air
|
|
||||||
volumes:
|
volumes:
|
||||||
- ./:/data
|
- ./:/data
|
||||||
- ./../../cms/tibi-server:/tibi-server
|
- ./../../cms/tibi-server:/tibi-server
|
||||||
@@ -44,14 +61,22 @@ services:
|
|||||||
DB_DIAL: mongodb://mongo
|
DB_DIAL: mongodb://mongo
|
||||||
DB_PREFIX: ${TIBI_PREFIX}
|
DB_PREFIX: ${TIBI_PREFIX}
|
||||||
MAIL_HOST: maildev:25
|
MAIL_HOST: maildev:25
|
||||||
|
SECURITY_ALLOWABSOLUTEPATHS: "true"
|
||||||
|
SECURITY_ALLOWUPPERPATHS: "true"
|
||||||
depends_on:
|
depends_on:
|
||||||
- mongo
|
- mongo
|
||||||
user: ${UID}:${GID}
|
user: ${CODER_UID}:${CODER_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:
|
tibiadmin:
|
||||||
image: gitbase.de/cms/tibi-admin
|
|
||||||
profiles:
|
profiles:
|
||||||
- tibi
|
- tibi
|
||||||
|
image: gitbase.de/cms/tibi-admin
|
||||||
environment:
|
environment:
|
||||||
INDEX: spa.html
|
INDEX: spa.html
|
||||||
WEBROOT: /data
|
WEBROOT: /data
|
||||||
@@ -70,7 +95,7 @@ services:
|
|||||||
tibiadmin-dev:
|
tibiadmin-dev:
|
||||||
profiles:
|
profiles:
|
||||||
- tibi-dev
|
- tibi-dev
|
||||||
image: node:18
|
image: node:20
|
||||||
volumes:
|
volumes:
|
||||||
- ./../../cms/tibi-admin:/data
|
- ./../../cms/tibi-admin:/data
|
||||||
working_dir: /data
|
working_dir: /data
|
||||||
@@ -82,20 +107,24 @@ services:
|
|||||||
- online.testversion.code.subdomain=${PROJECT_NAME}-tibiadmin-dev
|
- online.testversion.code.subdomain=${PROJECT_NAME}-tibiadmin-dev
|
||||||
- traefik.http.routers.${PROJECT_NAME}-tibiadmin-dev.middlewares=${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
|
- traefik.http.middlewares.${PROJECT_NAME}-tibiadmin-dev.basicauth.usersfile=${PWD}/.basic-auth-code
|
||||||
user: ${UID}:${GID}
|
user: ${CODER_UID}:${CODER_GID}
|
||||||
|
|
||||||
mongo:
|
mongo:
|
||||||
|
profiles:
|
||||||
|
- tibi
|
||||||
|
- tibi-dev
|
||||||
image: gitbase.de/server/mongo:4.2
|
image: gitbase.de/server/mongo:4.2
|
||||||
user: ${UID}:${GID}
|
|
||||||
volumes:
|
volumes:
|
||||||
- ./tmp/mongo-data:/data/db
|
- ./tmp/mongo-data:/data/db
|
||||||
|
user: ${CODER_UID}:${CODER_GID}
|
||||||
|
|
||||||
adminmongo:
|
adminmongo:
|
||||||
|
profiles:
|
||||||
|
- tibi
|
||||||
|
- tibi-dev
|
||||||
image: gitbase.de/server/adminmongo
|
image: gitbase.de/server/adminmongo
|
||||||
environment:
|
environment:
|
||||||
CONN_NAME: mongo
|
CONN_NAME: mongo
|
||||||
# DB_USERNAME: root
|
|
||||||
# DB_PASSWORD: root
|
|
||||||
DB_HOST: mongo
|
DB_HOST: mongo
|
||||||
PORT: 1234
|
PORT: 1234
|
||||||
expose:
|
expose:
|
||||||
@@ -107,6 +136,9 @@ services:
|
|||||||
- traefik.http.middlewares.${PROJECT_NAME}-adminmongo.basicauth.usersfile=${PWD}/.basic-auth-code
|
- traefik.http.middlewares.${PROJECT_NAME}-adminmongo.basicauth.usersfile=${PWD}/.basic-auth-code
|
||||||
|
|
||||||
maildev:
|
maildev:
|
||||||
|
profiles:
|
||||||
|
- tibi
|
||||||
|
- tibi-dev
|
||||||
image: maildev/maildev
|
image: maildev/maildev
|
||||||
command: node bin/maildev --web 1080 --smtp 25 -v --hide-extensions=STARTTLS
|
command: node bin/maildev --web 1080 --smtp 25 -v --hide-extensions=STARTTLS
|
||||||
expose:
|
expose:
|
||||||
@@ -117,3 +149,14 @@ services:
|
|||||||
- traefik.http.services.${PROJECT_NAME}-maildev.loadbalancer.server.port=1080
|
- traefik.http.services.${PROJECT_NAME}-maildev.loadbalancer.server.port=1080
|
||||||
- traefik.http.routers.${PROJECT_NAME}-maildev.middlewares=${PROJECT_NAME}-maildev
|
- traefik.http.routers.${PROJECT_NAME}-maildev.middlewares=${PROJECT_NAME}-maildev
|
||||||
- traefik.http.middlewares.${PROJECT_NAME}-maildev.basicauth.usersfile=${PWD}/.basic-auth-code
|
- 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
|
||||||
|
|||||||
14
docker-compose-staging.yml
Normal file
14
docker-compose-staging.yml
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
services:
|
||||||
|
www:
|
||||||
|
build: .
|
||||||
|
image: ${PROJECT_NAME}:dev
|
||||||
|
container_name: dev-${PROJECT_NAME}
|
||||||
|
environment:
|
||||||
|
#INDEX: spa.html
|
||||||
|
SSR: https://dev-tibi-server.staging.testversion.online/api/v1/_/${TIBI_NAMESPACE}/ssr?url=
|
||||||
|
WEBROOT: /data
|
||||||
|
API: /tibiapi:https://dev-tibi-server.staging.testversion.online/api/v1/_/${TIBI_NAMESPACE}
|
||||||
|
PORT: 80
|
||||||
|
labels:
|
||||||
|
traefik.enable: "true"
|
||||||
|
online.testversion.staging.subdomain: dev-${PROJECT_NAME}
|
||||||
22
esbuild.config.admin.js
Normal file
22
esbuild.config.admin.js
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
const config = require("./esbuild.config.js")
|
||||||
|
const svelteConfig = require("./svelte.config")
|
||||||
|
|
||||||
|
config.options.minify = false
|
||||||
|
config.options.entryPoints = ["./frontend/src/admin.ts"]
|
||||||
|
config.options.outfile = "./" + config.distDir + "/admin.mjs"
|
||||||
|
delete config.options.outdir
|
||||||
|
config.options.splitting = false
|
||||||
|
config.options.plugins = [
|
||||||
|
config.sveltePlugin({
|
||||||
|
compilerOptions: {
|
||||||
|
css: false,
|
||||||
|
hydratable: false,
|
||||||
|
dev: (process.argv?.length > 2 ? process.argv[2] : "build") !== "build",
|
||||||
|
},
|
||||||
|
preprocess: svelteConfig.preprocess,
|
||||||
|
cache: true,
|
||||||
|
}),
|
||||||
|
config.resolvePlugin,
|
||||||
|
]
|
||||||
|
|
||||||
|
module.exports = config
|
||||||
@@ -1,3 +1,5 @@
|
|||||||
|
const fs = require("fs")
|
||||||
|
|
||||||
const resolvePlugin = {
|
const resolvePlugin = {
|
||||||
name: "resolvePlugin",
|
name: "resolvePlugin",
|
||||||
setup(build) {
|
setup(build) {
|
||||||
@@ -15,11 +17,12 @@ const resolvePlugin = {
|
|||||||
|
|
||||||
const sveltePlugin = require("esbuild-svelte")
|
const sveltePlugin = require("esbuild-svelte")
|
||||||
|
|
||||||
const distDir = "frontend"
|
const frontendDir = "./frontend"
|
||||||
|
const distDir = frontendDir + "/dist"
|
||||||
|
|
||||||
console.log("copy public dir...")
|
// console.log("copy public dir...")
|
||||||
const copydir = require("copy-dir")
|
// const copydir = require("copy-dir")
|
||||||
copydir.sync(__dirname + "/public", __dirname + "/" + distDir)
|
// copydir.sync(__dirname + "/public", __dirname + "/" + distDir)
|
||||||
/*copydir.sync(
|
/*copydir.sync(
|
||||||
__dirname + "/public/index.html",
|
__dirname + "/public/index.html",
|
||||||
__dirname + "/" + distDir + "/template.html"
|
__dirname + "/" + distDir + "/template.html"
|
||||||
@@ -28,22 +31,27 @@ copydir.sync(__dirname + "/public", __dirname + "/" + distDir)
|
|||||||
const svelteConfig = require("./svelte.config")
|
const svelteConfig = require("./svelte.config")
|
||||||
const esbuildSvelte = sveltePlugin({
|
const esbuildSvelte = sveltePlugin({
|
||||||
compilerOptions: {
|
compilerOptions: {
|
||||||
css: false,
|
css: "external",
|
||||||
hydratable: true,
|
hydratable: true,
|
||||||
dev: (process.argv?.length > 2 ? process.argv[2] : "build") !== "build",
|
dev: (process.argv?.length > 2 ? process.argv[2] : "build") !== "build",
|
||||||
},
|
},
|
||||||
preprocess: svelteConfig.preprocess,
|
preprocess: svelteConfig.preprocess,
|
||||||
cache: true,
|
cache: true,
|
||||||
|
filterWarnings: (warning) => {
|
||||||
|
// filter out a11y
|
||||||
|
if (warning.code.match(/^a11y/)) return false
|
||||||
|
return true
|
||||||
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
const options = {
|
const options = {
|
||||||
logLevel: "info",
|
logLevel: "info",
|
||||||
color: true,
|
color: true,
|
||||||
entryPoints: ["./src/index.ts"],
|
entryPoints: ["./frontend/src/index.ts"],
|
||||||
outfile: "./" + distDir + "/_dist_/index.mjs",
|
outfile: distDir + "/index.mjs",
|
||||||
metafile: true, //"./" + distDir + "/_dist_/meta.json",
|
metafile: true,
|
||||||
format: "esm",
|
format: "esm",
|
||||||
minify: true,
|
minify: process.argv[2] == "build",
|
||||||
bundle: true,
|
bundle: true,
|
||||||
splitting: false,
|
splitting: false,
|
||||||
plugins: [esbuildSvelte, resolvePlugin],
|
plugins: [esbuildSvelte, resolvePlugin],
|
||||||
@@ -53,8 +61,6 @@ const options = {
|
|||||||
".eot": "file",
|
".eot": "file",
|
||||||
".svg": "file",
|
".svg": "file",
|
||||||
".ttf": "file",
|
".ttf": "file",
|
||||||
".png": "file",
|
|
||||||
".jpg": "file",
|
|
||||||
},
|
},
|
||||||
sourcemap: true,
|
sourcemap: true,
|
||||||
target: ["es2020", "chrome61", "firefox60", "safari11", "edge18"],
|
target: ["es2020", "chrome61", "firefox60", "safari11", "edge18"],
|
||||||
@@ -64,22 +70,44 @@ const bsMiddleware = []
|
|||||||
|
|
||||||
if (process.argv[2] == "start") {
|
if (process.argv[2] == "start") {
|
||||||
const { createProxyMiddleware } = require("http-proxy-middleware")
|
const { createProxyMiddleware } = require("http-proxy-middleware")
|
||||||
const apiBase = process.env.API_BASE || "http://localhost:8080/api/v1/_/" + process.env.NAMESPACE
|
const dotEnv = fs.readFileSync(__dirname + "/.env", "utf8")
|
||||||
|
const TIBI_NAMESPACE = dotEnv.match(/TIBI_NAMESPACE=(.*)/)[1]
|
||||||
|
const apiBase = process.env.API_BASE || "http://localhost:8080/api/v1/_/" + TIBI_NAMESPACE
|
||||||
bsMiddleware.push(
|
bsMiddleware.push(
|
||||||
createProxyMiddleware("/api", {
|
createProxyMiddleware({
|
||||||
|
pathFilter: "/api",
|
||||||
target: apiBase,
|
target: apiBase,
|
||||||
pathRewrite: { "^/api": "" },
|
pathRewrite: { "^/api": "" },
|
||||||
changeOrigin: true,
|
changeOrigin: true,
|
||||||
|
logLevel: "debug",
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if (process.env.SSR) {
|
||||||
|
bsMiddleware.push(
|
||||||
|
createProxyMiddleware({
|
||||||
|
pathFilter: function (path, req) {
|
||||||
|
return !path.match(/\./)
|
||||||
|
},
|
||||||
|
target: apiBase,
|
||||||
|
changeOrigin: true,
|
||||||
|
logLevel: "debug",
|
||||||
|
pathRewrite: function (path, req) {
|
||||||
|
console.log(path)
|
||||||
|
return "/ssr?url=" + encodeURIComponent(path)
|
||||||
|
},
|
||||||
|
})
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
sveltePlugin: sveltePlugin,
|
sveltePlugin: sveltePlugin,
|
||||||
resolvePlugin: resolvePlugin,
|
resolvePlugin: resolvePlugin,
|
||||||
options: options,
|
options: options,
|
||||||
|
distDir,
|
||||||
watch: {
|
watch: {
|
||||||
path: [__dirname + "/src/**/*"],
|
path: [__dirname + "/" + frontendDir + "/src/**/*"],
|
||||||
},
|
},
|
||||||
serve: {
|
serve: {
|
||||||
onRequest(args) {
|
onRequest(args) {
|
||||||
@@ -88,7 +116,7 @@ module.exports = {
|
|||||||
},
|
},
|
||||||
browserSync: {
|
browserSync: {
|
||||||
server: {
|
server: {
|
||||||
baseDir: distDir,
|
baseDir: frontendDir,
|
||||||
middleware: [
|
middleware: [
|
||||||
require("morgan")("dev"),
|
require("morgan")("dev"),
|
||||||
...bsMiddleware,
|
...bsMiddleware,
|
||||||
|
|||||||
@@ -5,7 +5,10 @@ config.options.sourcemap = "inline"
|
|||||||
config.options.minify = false
|
config.options.minify = false
|
||||||
config.options.platform = "node"
|
config.options.platform = "node"
|
||||||
config.options.format = "cjs"
|
config.options.format = "cjs"
|
||||||
config.options.entryPoints = ["./src/ssr.ts"]
|
// es2015 will transform async/await to generators, but not working with svelte
|
||||||
|
// so we need babel to transform async/await to promises
|
||||||
|
// config.options.target = "es2015"
|
||||||
|
config.options.entryPoints = ["./frontend/src/ssr.ts"]
|
||||||
config.options.outfile = __dirname + "/_temp/app.server.js"
|
config.options.outfile = __dirname + "/_temp/app.server.js"
|
||||||
config.options.plugins = [
|
config.options.plugins = [
|
||||||
config.sveltePlugin({
|
config.sveltePlugin({
|
||||||
@@ -16,6 +19,11 @@ config.options.plugins = [
|
|||||||
dev: (process.argv?.length > 2 ? process.argv[2] : "build") !== "build",
|
dev: (process.argv?.length > 2 ? process.argv[2] : "build") !== "build",
|
||||||
},
|
},
|
||||||
preprocess: svelteConfig.preprocess,
|
preprocess: svelteConfig.preprocess,
|
||||||
|
filterWarnings: (warning) => {
|
||||||
|
// filter out a11y
|
||||||
|
if (warning.code.match(/^a11y/)) return false
|
||||||
|
return true
|
||||||
|
},
|
||||||
}),
|
}),
|
||||||
config.resolvePlugin,
|
config.resolvePlugin,
|
||||||
]
|
]
|
||||||
|
|||||||
45
frontend/src/admin.ts
Normal file
45
frontend/src/admin.ts
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
import type { SvelteComponent } from "svelte"
|
||||||
|
|
||||||
|
function getRenderedElement(
|
||||||
|
component: typeof SvelteComponent,
|
||||||
|
options?: { props: { [key: string]: any }; addCss?: string[] },
|
||||||
|
nestedElements?: { tagName: string; className?: string }[]
|
||||||
|
) {
|
||||||
|
const el = document.createElement("div")
|
||||||
|
el.attachShadow({ mode: "open" })
|
||||||
|
|
||||||
|
const body = document.createElement("body")
|
||||||
|
|
||||||
|
// build nested divs with css classes
|
||||||
|
let target: HTMLElement = body
|
||||||
|
nestedElements?.forEach((e) => {
|
||||||
|
const newElement = document.createElement(e.tagName)
|
||||||
|
if (e.className) {
|
||||||
|
newElement.className = e.className
|
||||||
|
}
|
||||||
|
target.appendChild(newElement)
|
||||||
|
target = newElement
|
||||||
|
})
|
||||||
|
|
||||||
|
el.shadowRoot.appendChild(body)
|
||||||
|
|
||||||
|
options?.addCss?.forEach((css) => {
|
||||||
|
const link = document.createElement("link")
|
||||||
|
link.rel = "stylesheet"
|
||||||
|
link.href = css
|
||||||
|
link.type = "text/css"
|
||||||
|
el.shadowRoot.appendChild(link)
|
||||||
|
})
|
||||||
|
|
||||||
|
new component({
|
||||||
|
target: target,
|
||||||
|
props: options?.props,
|
||||||
|
})
|
||||||
|
|
||||||
|
return el
|
||||||
|
}
|
||||||
|
|
||||||
|
export {
|
||||||
|
getRenderedElement,
|
||||||
|
// pass also required svelte components here
|
||||||
|
}
|
||||||
160
frontend/src/api.ts
Normal file
160
frontend/src/api.ts
Normal file
@@ -0,0 +1,160 @@
|
|||||||
|
import { get } from "svelte/store"
|
||||||
|
import { apiRequest, obj2str } from "../../api/hooks/lib/ssr"
|
||||||
|
import * as sentry from "./sentry"
|
||||||
|
import { apiBaseOverride } from "./lib/store"
|
||||||
|
|
||||||
|
// fetch polyfill
|
||||||
|
// [MIT License](LICENSE.md) © [Jason Miller](https://jasonformat.com/)
|
||||||
|
const _f = function (url: string, options?: { [key: string]: any }) {
|
||||||
|
if (typeof XMLHttpRequest === "undefined") {
|
||||||
|
return Promise.resolve(null)
|
||||||
|
}
|
||||||
|
|
||||||
|
options = options || {}
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
const request = new XMLHttpRequest()
|
||||||
|
const keys: string[] = []
|
||||||
|
// @ts-ignore
|
||||||
|
const all = []
|
||||||
|
const headers = {}
|
||||||
|
|
||||||
|
const response = () => ({
|
||||||
|
ok: ((request.status / 100) | 0) == 2, // 200-299
|
||||||
|
statusText: request.statusText,
|
||||||
|
status: request.status,
|
||||||
|
url: request.responseURL,
|
||||||
|
text: () => Promise.resolve(request.responseText),
|
||||||
|
json: () => Promise.resolve(request.responseText).then(JSON.parse),
|
||||||
|
blob: () => Promise.resolve(new Blob([request.response])),
|
||||||
|
clone: response,
|
||||||
|
headers: {
|
||||||
|
// @ts-ignore
|
||||||
|
keys: () => keys,
|
||||||
|
// @ts-ignore
|
||||||
|
entries: () => all,
|
||||||
|
// @ts-ignore
|
||||||
|
get: (n) => headers[n.toLowerCase()],
|
||||||
|
// @ts-ignore
|
||||||
|
has: (n) => n.toLowerCase() in headers,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
request.open(options.method || "get", url, true)
|
||||||
|
|
||||||
|
request.onload = () => {
|
||||||
|
request
|
||||||
|
.getAllResponseHeaders()
|
||||||
|
// @ts-ignore
|
||||||
|
.replace(/^(.*?):[^\S\n]*([\s\S]*?)$/gm, (m, key, value) => {
|
||||||
|
keys.push((key = key.toLowerCase()))
|
||||||
|
all.push([key, value])
|
||||||
|
// @ts-ignore
|
||||||
|
headers[key] = headers[key] ? `${headers[key]},${value}` : value
|
||||||
|
})
|
||||||
|
resolve(response())
|
||||||
|
}
|
||||||
|
|
||||||
|
request.onerror = reject
|
||||||
|
|
||||||
|
request.withCredentials = options.credentials == "include"
|
||||||
|
|
||||||
|
for (const i in options.headers) {
|
||||||
|
request.setRequestHeader(i, options.headers[i])
|
||||||
|
}
|
||||||
|
|
||||||
|
request.send(options.body || null)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// fetch must be declared after sentry import to get the hijacked fetch
|
||||||
|
// @ts-ignore
|
||||||
|
export const _fetch: typeof fetch =
|
||||||
|
typeof fetch === "undefined" ? (typeof window === "undefined" ? _f : window.fetch || _f) : fetch
|
||||||
|
|
||||||
|
export const api = async <T>(
|
||||||
|
endpoint: string,
|
||||||
|
options?: ApiOptions,
|
||||||
|
body?: any
|
||||||
|
): Promise<{ data: T; count: number } | any> => {
|
||||||
|
const _apiBaseOverride = get(apiBaseOverride) || ""
|
||||||
|
let data = await apiRequest(_apiBaseOverride + endpoint, options, body, sentry, _fetch)
|
||||||
|
// @ts-ignore
|
||||||
|
// console.log(data, "data")
|
||||||
|
return data
|
||||||
|
}
|
||||||
|
|
||||||
|
const cache: {
|
||||||
|
[key: string]: {
|
||||||
|
expire: number
|
||||||
|
data: any
|
||||||
|
}
|
||||||
|
} = {}
|
||||||
|
|
||||||
|
type CollectionNameT = "medialib" | "content" | "product"
|
||||||
|
|
||||||
|
type EntryTypeSwitch<T> = T extends "medialib"
|
||||||
|
? MedialibEntry
|
||||||
|
: T extends "content"
|
||||||
|
? ContentEntry
|
||||||
|
: T extends "product"
|
||||||
|
? ProductEntry
|
||||||
|
: never
|
||||||
|
|
||||||
|
export async function getDBEntries<T extends CollectionNameT>(
|
||||||
|
collectionName: T,
|
||||||
|
filter?: { [key: string]: any },
|
||||||
|
sort: string = "sort",
|
||||||
|
limit?: number,
|
||||||
|
offset?: number,
|
||||||
|
projection?: string,
|
||||||
|
params?: { [key: string]: string }
|
||||||
|
): Promise<EntryTypeSwitch<T>[]> {
|
||||||
|
const c = await api<EntryTypeSwitch<T>[]>(collectionName, {
|
||||||
|
filter,
|
||||||
|
sort,
|
||||||
|
limit,
|
||||||
|
offset,
|
||||||
|
projection,
|
||||||
|
params,
|
||||||
|
})
|
||||||
|
return c.data
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getCachedEntries<T extends CollectionNameT>(
|
||||||
|
collectionName: T,
|
||||||
|
filter?: { [key: string]: any },
|
||||||
|
sort: string = "sort",
|
||||||
|
limit?: number,
|
||||||
|
offset?: number,
|
||||||
|
projection?: string,
|
||||||
|
params?: { [key: string]: string }
|
||||||
|
): Promise<EntryTypeSwitch<T>[]> {
|
||||||
|
const filterStr = obj2str({ collectionName, filter, sort, limit, offset, projection, params })
|
||||||
|
if (cache[filterStr] && cache[filterStr].expire >= Date.now()) {
|
||||||
|
return cache[filterStr].data
|
||||||
|
}
|
||||||
|
const entries = await getDBEntries<T>(collectionName, filter, sort, limit, offset, projection, params)
|
||||||
|
// expire in 1h
|
||||||
|
cache[filterStr] = { expire: Date.now() + 1000 * 60 * 60, data: entries }
|
||||||
|
return entries
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getDBEntry<T extends CollectionNameT>(
|
||||||
|
collectionName: T,
|
||||||
|
filter: { [key: string]: any },
|
||||||
|
params?: { [key: string]: string }
|
||||||
|
) {
|
||||||
|
return (await getDBEntries<T>(collectionName, filter, "_id", null, null, null, params))?.[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getCachedEntry<T extends CollectionNameT>(
|
||||||
|
collectionName: T,
|
||||||
|
filter: { [key: string]: any },
|
||||||
|
params?: { [key: string]: string }
|
||||||
|
) {
|
||||||
|
return (await getCachedEntries<T>(collectionName, filter, "_id", null, null, null, params))?.[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function postDBEntry<T extends CollectionNameT>(collectionName: T, entry: EntryTypeSwitch<T>) {
|
||||||
|
return api<EntryTypeSwitch<T>>(collectionName, { method: "POST" }, entry)
|
||||||
|
}
|
||||||
@@ -9,9 +9,6 @@ module.exports = {
|
|||||||
sveltePreprocess({
|
sveltePreprocess({
|
||||||
sourceMap: true,
|
sourceMap: true,
|
||||||
typescript: false,
|
typescript: false,
|
||||||
/* scss: {
|
|
||||||
includePaths: ["src/theme"],
|
|
||||||
}, */
|
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
|
|||||||
15
types/global.d.ts
vendored
15
types/global.d.ts
vendored
@@ -41,3 +41,18 @@ interface FileField {
|
|||||||
type: string
|
type: string
|
||||||
size: number
|
size: number
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface MedialibEntry {
|
||||||
|
id: string
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ContentEntry {
|
||||||
|
id: string
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ProductEntry {
|
||||||
|
id: string
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user