Füge Docker- und Babel-Konfigurationen hinzu, aktualisiere Svelte- und Esbuild-Setups, erweitere Typdefinitionen und aktualisiere die README-Datei
This commit is contained in:
parent
77cb64b260
commit
7a6a2cbd22
6
.env
6
.env
@ -11,6 +11,12 @@ SENTRY_PROJECT=
|
||||
RSYNC_HOST=ftp1.webmakers.de
|
||||
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
|
||||
STAGING_URL=https://dev-__PROJECT_NAME__.staging.testversion.online
|
||||
|
||||
|
@ -10,7 +10,7 @@
|
||||
"check-parameters"
|
||||
],
|
||||
"no-var-keyword": true,
|
||||
"svelteSortOrder": "scripts-markup-styles",
|
||||
"svelteSortOrder": "scripts-options-markup-styles",
|
||||
"svelteStrictMode": true,
|
||||
"svelteBracketNewLine": 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
|
||||
.DEFAULT_GOAL := help
|
||||
.PHONY: docker-up docker-start docker-down docker-logs
|
||||
DOCKER_COMPOSE=docker compose -f docker-compose-local.yml
|
||||
|
||||
export UID := $(shell id -u)
|
||||
export GID := $(shell id -g)
|
||||
.DEFAULT_GOAL := help
|
||||
|
||||
.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
|
||||
@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_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_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) --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_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_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_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_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_COMPOSE) $*
|
||||
|
||||
yarn-upgrade: # interactive yarn upgrade
|
||||
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) ./
|
||||
fix-permissions: ## set files/directories owner to UID:GID from .env
|
||||
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
|
||||
```
|
||||
|
||||
### 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
|
||||
|
||||
```sh
|
||||
@ -58,17 +40,9 @@ make docker-down
|
||||
|
||||
| UI | URL |
|
||||
| --- | --- |
|
||||
| Website | https://tibi-svelte-starter.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/ |
|
||||
|
||||
### Testen
|
||||
|
||||
```sh
|
||||
yarn build:istanbul # instrumentiert Code für coverage-Report
|
||||
yarn cy:docker:run # oder mit Xserver und UI cy:docker:open
|
||||
```
|
||||
| Website | <https://tibi-svelte-starter.code.testversion.online/> |
|
||||
| Tibi Admin | <https://tibi-svelte-starter-tibiadmin.code.testversion.online/> |
|
||||
| Maildev | <https://tibi-svelte-starter-maildev.code.testversion.online/> |
|
||||
|
||||
### Bauen
|
||||
|
||||
@ -81,4 +55,7 @@ yarn build:legacy
|
||||
|
||||
# serverseitiges Rendering
|
||||
yarn build:server
|
||||
|
||||
# Admin-Module
|
||||
yarn build:admin
|
||||
```
|
||||
|
@ -10,16 +10,11 @@
|
||||
"version": "3",
|
||||
"proposals": true
|
||||
},
|
||||
"targets": ">0.5%, IE 11, not dead"
|
||||
"targets": ">0.5%, IE 11, not dead",
|
||||
"debug": true,
|
||||
"forceAllTransforms": true
|
||||
}
|
||||
]
|
||||
],
|
||||
"plugins": [
|
||||
[
|
||||
"@babel/plugin-transform-spread",
|
||||
{
|
||||
"loose": true
|
||||
}
|
||||
]
|
||||
]
|
||||
"plugins": []
|
||||
}
|
||||
|
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:
|
||||
yarnstart:
|
||||
image: node:18
|
||||
user: ${UID}:${GID}
|
||||
profiles:
|
||||
- tibi
|
||||
- tibi-dev
|
||||
image: node:20
|
||||
volumes:
|
||||
- ./:/data
|
||||
- ./tmp:/tmp
|
||||
- ./tmp/nonexistent:/nonexistent
|
||||
- ./tmp/.npm:/.npm
|
||||
- ./tmp/.yarn:/.yarn
|
||||
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:
|
||||
- 3000
|
||||
labels:
|
||||
@ -15,25 +21,36 @@ services:
|
||||
- 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: ${CODER_UID}:${CODER_GID}
|
||||
|
||||
tibiserver:
|
||||
image: gitbase.de/cms/tibi-server
|
||||
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
|
||||
image: cosmtrek/air
|
||||
volumes:
|
||||
- ./:/data
|
||||
- ./../../cms/tibi-server:/tibi-server
|
||||
@ -44,14 +61,22 @@ services:
|
||||
DB_DIAL: mongodb://mongo
|
||||
DB_PREFIX: ${TIBI_PREFIX}
|
||||
MAIL_HOST: maildev:25
|
||||
SECURITY_ALLOWABSOLUTEPATHS: "true"
|
||||
SECURITY_ALLOWUPPERPATHS: "true"
|
||||
depends_on:
|
||||
- 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:
|
||||
image: gitbase.de/cms/tibi-admin
|
||||
profiles:
|
||||
- tibi
|
||||
image: gitbase.de/cms/tibi-admin
|
||||
environment:
|
||||
INDEX: spa.html
|
||||
WEBROOT: /data
|
||||
@ -70,7 +95,7 @@ services:
|
||||
tibiadmin-dev:
|
||||
profiles:
|
||||
- tibi-dev
|
||||
image: node:18
|
||||
image: node:20
|
||||
volumes:
|
||||
- ./../../cms/tibi-admin:/data
|
||||
working_dir: /data
|
||||
@ -82,20 +107,24 @@ services:
|
||||
- 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}
|
||||
user: ${CODER_UID}:${CODER_GID}
|
||||
|
||||
mongo:
|
||||
profiles:
|
||||
- tibi
|
||||
- tibi-dev
|
||||
image: gitbase.de/server/mongo:4.2
|
||||
user: ${UID}:${GID}
|
||||
volumes:
|
||||
- ./tmp/mongo-data:/data/db
|
||||
user: ${CODER_UID}:${CODER_GID}
|
||||
|
||||
adminmongo:
|
||||
profiles:
|
||||
- tibi
|
||||
- tibi-dev
|
||||
image: gitbase.de/server/adminmongo
|
||||
environment:
|
||||
CONN_NAME: mongo
|
||||
# DB_USERNAME: root
|
||||
# DB_PASSWORD: root
|
||||
DB_HOST: mongo
|
||||
PORT: 1234
|
||||
expose:
|
||||
@ -107,6 +136,9 @@ services:
|
||||
- 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:
|
||||
@ -117,3 +149,14 @@ services:
|
||||
- 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
|
||||
|
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 = {
|
||||
name: "resolvePlugin",
|
||||
setup(build) {
|
||||
@ -15,11 +17,12 @@ const resolvePlugin = {
|
||||
|
||||
const sveltePlugin = require("esbuild-svelte")
|
||||
|
||||
const distDir = "frontend"
|
||||
const frontendDir = "./frontend"
|
||||
const distDir = frontendDir + "/dist"
|
||||
|
||||
console.log("copy public dir...")
|
||||
const copydir = require("copy-dir")
|
||||
copydir.sync(__dirname + "/public", __dirname + "/" + distDir)
|
||||
// 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"
|
||||
@ -28,22 +31,27 @@ copydir.sync(__dirname + "/public", __dirname + "/" + distDir)
|
||||
const svelteConfig = require("./svelte.config")
|
||||
const esbuildSvelte = sveltePlugin({
|
||||
compilerOptions: {
|
||||
css: false,
|
||||
css: "external",
|
||||
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: ["./src/index.ts"],
|
||||
outfile: "./" + distDir + "/_dist_/index.mjs",
|
||||
metafile: true, //"./" + distDir + "/_dist_/meta.json",
|
||||
entryPoints: ["./frontend/src/index.ts"],
|
||||
outfile: distDir + "/index.mjs",
|
||||
metafile: true,
|
||||
format: "esm",
|
||||
minify: true,
|
||||
minify: process.argv[2] == "build",
|
||||
bundle: true,
|
||||
splitting: false,
|
||||
plugins: [esbuildSvelte, resolvePlugin],
|
||||
@ -53,8 +61,6 @@ const options = {
|
||||
".eot": "file",
|
||||
".svg": "file",
|
||||
".ttf": "file",
|
||||
".png": "file",
|
||||
".jpg": "file",
|
||||
},
|
||||
sourcemap: true,
|
||||
target: ["es2020", "chrome61", "firefox60", "safari11", "edge18"],
|
||||
@ -64,22 +70,44 @@ 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
|
||||
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(
|
||||
createProxyMiddleware("/api", {
|
||||
createProxyMiddleware({
|
||||
pathFilter: "/api",
|
||||
target: apiBase,
|
||||
pathRewrite: { "^/api": "" },
|
||||
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 = {
|
||||
sveltePlugin: sveltePlugin,
|
||||
resolvePlugin: resolvePlugin,
|
||||
options: options,
|
||||
distDir,
|
||||
watch: {
|
||||
path: [__dirname + "/src/**/*"],
|
||||
path: [__dirname + "/" + frontendDir + "/src/**/*"],
|
||||
},
|
||||
serve: {
|
||||
onRequest(args) {
|
||||
@ -88,7 +116,7 @@ module.exports = {
|
||||
},
|
||||
browserSync: {
|
||||
server: {
|
||||
baseDir: distDir,
|
||||
baseDir: frontendDir,
|
||||
middleware: [
|
||||
require("morgan")("dev"),
|
||||
...bsMiddleware,
|
||||
|
@ -5,7 +5,10 @@ config.options.sourcemap = "inline"
|
||||
config.options.minify = false
|
||||
config.options.platform = "node"
|
||||
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.plugins = [
|
||||
config.sveltePlugin({
|
||||
@ -16,6 +19,11 @@ config.options.plugins = [
|
||||
dev: (process.argv?.length > 2 ? process.argv[2] : "build") !== "build",
|
||||
},
|
||||
preprocess: svelteConfig.preprocess,
|
||||
filterWarnings: (warning) => {
|
||||
// filter out a11y
|
||||
if (warning.code.match(/^a11y/)) return false
|
||||
return true
|
||||
},
|
||||
}),
|
||||
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({
|
||||
sourceMap: true,
|
||||
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
|
||||
size: number
|
||||
}
|
||||
|
||||
interface MedialibEntry {
|
||||
id: string
|
||||
// ...
|
||||
}
|
||||
|
||||
interface ContentEntry {
|
||||
id: string
|
||||
// ...
|
||||
}
|
||||
|
||||
interface ProductEntry {
|
||||
id: string
|
||||
// ...
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user