copy new setup from frontend to admin

This commit is contained in:
einhornimmond 2025-01-18 18:24:19 +01:00
parent 43f982bd5a
commit 5061c83f0c
10 changed files with 209 additions and 92 deletions

View File

@ -11,7 +11,7 @@ ENV BUILD_DATE="1970-01-01T00:00:00.00Z"
## We cannot do $(npm run version).${BUILD_NUMBER} here so we default to 0.0.0.0
ENV BUILD_VERSION="0.0.0.0"
## We cannot do `$(git rev-parse --short HEAD)` here so we default to 0000000
ENV BUILD_COMMIT="0000000"
ENV BUILD_COMMIT_SHORT="0000000"
## SET NODE_ENV
ARG NODE_ENV="production"
## App relevant Envs

View File

@ -74,6 +74,7 @@
"eslint-plugin-prettier": "5.2.1",
"eslint-plugin-promise": "^5.1.1",
"eslint-plugin-vue": "8.7.1",
"joi": "^17.13.3",
"jsdom": "^25.0.0",
"mock-apollo-client": "^1.2.1",
"postcss": "^8.4.8",

View File

@ -3,15 +3,13 @@
// Load Package Details for some default values
const pkg = require('../../package')
const schema = require('./schema')
const joi = require('joi')
const version = {
ADMIN_MODULE_PROTOCOL: process.env.ADMIN_MODULE_PROTOCOL ?? 'http',
ADMIN_MODULE_HOST: process.env.ADMIN_MODULE_HOST ?? '0.0.0.0',
ADMIN_MODULE_PORT: process.env.ADMIN_MODULE_PORT ?? '8080',
APP_VERSION: pkg.version,
BUILD_COMMIT: process.env.BUILD_COMMIT ?? null,
BUILD_COMMIT: process.env.BUILD_COMMIT ?? undefined,
// self reference of `version.BUILD_COMMIT` is not possible at this point, hence the duplicate code
BUILD_COMMIT_SHORT: (process.env.BUILD_COMMIT ?? '0000000').slice(0, 7),
}
@ -58,10 +56,8 @@ const CONFIG = {
...environment,
...endpoints,
...debug,
ADMIN_MODULE_URL,
COMMUNITY_URL,
}
// Check config version
// TODO: use validate and construct error message including description
joi.attempt(CONFIG, schema)
module.exports = CONFIG

View File

@ -1,25 +1,59 @@
const commonSchema = require('../../../config/common.schema')
const {
browserUrls,
APP_VERSION,
BUILD_COMMIT,
BUILD_COMMIT_SHORT,
COMMUNITY_URL,
DEBUG,
GRAPHQL_URI,
NODE_ENV,
PRODUCTION,
} = require('../../../config/common.schema') // from '../../../config/common.schema'
const Joi = require('joi')
module.exports = commonSchema.keys({
module.exports = Joi.object({
browserUrls,
APP_VERSION,
BUILD_COMMIT,
BUILD_COMMIT_SHORT,
COMMUNITY_URL,
DEBUG,
GRAPHQL_URI,
NODE_ENV,
PRODUCTION,
ADMIN_HOSTING: Joi.string()
.valid('nodejs', 'nginx')
.description('set to `nodejs` if admin is hosted by vite with a own nodejs instance')
.optional(),
ADMIN_MODULE_URL: Joi.string()
.uri({ scheme: ['http', 'https'] })
.when('COMMUNITY_URL', {
is: Joi.exist(),
then: Joi.optional(), // not required if COMMUNITY_URL is provided
otherwise: Joi.required(), // required if COMMUNITY_URL is missing
})
.description("Base Url for reaching admin in browser, only needed if COMMUNITY_URL wasn't set")
.optional(), // optional in general, but conditionally required
ADMIN_MODULE_PROTOCOL: Joi.string()
.valid('http', 'https')
.when('BROWSER_PROTOCOL', {
is: 'https',
then: Joi.string().uri({ scheme: 'https' }),
otherwise: Joi.string().uri({ scheme: 'http' }),
.when('ADMIN_HOSTING', {
is: Joi.valid('nodejs'),
then: Joi.valid('http').required(),
otherwise: Joi.valid('http', 'https').required(),
})
.description(
'Protocol for admin module hosting, has to be the same as for backend api url and admin to prevent mixed block errors'
`
Protocol for admin module hosting
- it has to be the same as for backend api url and frontend to prevent mixed block errors,
- if admin is served with nodejs:
is have to be http or setup must be updated to include a ssl certificate
`,
)
.default('http')
.required(),
ADMIN_HOSTING: Joi.string()
.valid('nodejs')
.description('set to `nodejs` if admin is hosted by vite with a own nodejs instance')
.optional(),
ADMIN_MODULE_HOST: Joi.alternatives()
.try(
Joi.string().valid('localhost').messages({ 'any.invalid': 'Must be localhost' }),
@ -28,11 +62,20 @@ module.exports = commonSchema.keys({
.messages({ 'string.ip': 'Must be a valid IPv4 address' }),
Joi.string().domain().messages({ 'string.domain': 'Must be a valid domain' }),
)
.when('ADMIN_HOSTING', {
is: 'nodejs',
then: Joi.required(),
otherwise: Joi.optional(),
})
.when('COMMUNITY_URL', {
is: null,
then: Joi.required(),
otherwise: Joi.optional(),
})
.description(
'Host (domain, IPv4, or localhost) for the admin, default is 0.0.0.0 for local hosting during develop',
)
.default('0.0.0.0')
.required(), // required only if community_url isn't set or ADMIN_HOSTING is nodejs
.default('0.0.0.0'),
ADMIN_MODULE_PORT: Joi.number()
.integer()
@ -40,26 +83,20 @@ module.exports = commonSchema.keys({
.max(49151)
.description('Port for hosting Admin with Vite as a Node.js instance, default: 8080')
.default(8080)
.required(), // required only if ADMIN_HOSTING is nodejs
.when('ADMIN_HOSTING', {
is: 'nodejs',
then: Joi.required(),
otherwise: Joi.optional(),
}),
WALLET_AUTH_URL: Joi.string()
.uri({ scheme: ['http', 'https'] })
.when('browser_protocol', {
is: 'https',
then: Joi.string().uri({ scheme: 'https' }),
otherwise: Joi.string().uri({ scheme: 'http' }),
})
.description('Extern Url from wallet-frontend for forwarding from admin')
.default('http://0.0.0.0/authenticate?token=')
.required(),
WALLET_LOGIN_URL: Joi.string()
.uri({ scheme: ['http', 'https'] })
.when('browser_protocol', {
is: 'https',
then: Joi.string().uri({ scheme: 'https' }),
otherwise: Joi.string().uri({ scheme: 'http' }),
})
.description('Extern Url from wallet-frontend for forwarding after logout')
.default('http://0.0.0.0/login')
.required(),
@ -68,4 +105,4 @@ module.exports = commonSchema.keys({
.description('Flag for disable authorization during development')
.default(false)
.optional(), // true is only allowed in not-production setup
})
})

View File

@ -6,6 +6,7 @@ import Components from 'unplugin-vue-components/vite'
import IconsResolve from 'unplugin-icons/resolver'
import { BootstrapVueNextResolver } from 'bootstrap-vue-next'
import EnvironmentPlugin from 'vite-plugin-environment'
import schema from './src/config/schema'
import dotenv from 'dotenv'
@ -15,55 +16,93 @@ const CONFIG = require('./src/config')
const path = require('path')
export default defineConfig({
base: '/admin/',
server: {
host: CONFIG.ADMIN_MODULE_HOST, // '0.0.0.0',
port: CONFIG.ADMIN_MODULE_PORT, // 8080,
},
resolve: {
alias: {
'@': path.resolve(__dirname, './src'),
assets: path.join(__dirname, 'src/assets'),
},
extensions: ['.mjs', '.js', '.ts', '.jsx', '.tsx', '.json', '.vue'],
},
export default defineConfig(({ command }) => {
if (command === 'serve') {
CONFIG.ADMIN_HOSTING = 'nodejs'
} else {
CONFIG.ADMIN_HOSTING = 'nginx'
}
// Check config
const configDataForValidation = {
...CONFIG,
// make sure that all urls used in browser have the same protocol to prevent mixed content errors
browserUrls: [
CONFIG.WALLET_AUTH_URL,
CONFIG.COMMUNITY_URL,
CONFIG.WALLET_LOGIN_URL,
CONFIG.GRAPHQL_URI,
CONFIG.ADMIN_MODULE_URL,
],
}
plugins: [
vue({
template: {
compilerOptions: {
compatConfig: {
MODE: 2,
const { error } = schema.validate(configDataForValidation, { stack: true })
const schemaJson = schema.describe()
if (error) {
error.details.forEach((err) => {
const key = err.context.key
const value = err.context.value
const description = schemaJson.keys[key]
? schema.describe().keys[key].flags.description
: 'No description available'
if (configDataForValidation[key] === undefined) {
throw new Error(`Environment Variable '${key}' is missing. ${description}`)
} else {
throw new Error(
`Error on Environment Variable ${key} with value = ${value}: ${err.message}. ${description}`,
)
}
})
}
return {
base: '/admin/',
server: {
host: CONFIG.ADMIN_MODULE_HOST, // '0.0.0.0',
port: CONFIG.ADMIN_MODULE_PORT, // 8080,
},
resolve: {
alias: {
'@': path.resolve(__dirname, './src'),
assets: path.join(__dirname, 'src/assets'),
},
extensions: ['.mjs', '.js', '.ts', '.jsx', '.tsx', '.json', '.vue'],
},
plugins: [
vue({
template: {
compilerOptions: {
compatConfig: {
MODE: 2,
},
},
},
},
}),
Components({
resolvers: [IconsResolve(), BootstrapVueNextResolver()],
dts: true,
}),
Icons({
compiler: 'vue3',
}),
EnvironmentPlugin({
BUILD_COMMIT: null,
PORT: CONFIG.ADMIN_MODULE_PORT, // null,
COMMUNITY_HOST: CONFIG.ADMIN_MODULE_HOST, // null,
URL_PROTOCOL: CONFIG.ADMIN_MODULE_PROTOCOL, // null,
WALLET_URL: CONFIG.WALLET_AUTH_URL, // null,
GRAPHQL_URL: CONFIG.GRAPHQL_URI, // null,
GRAPHQL_PATH: process.env.GRAPHQL_PATH ?? '/graphql', // null,
WALLET_AUTH_PATH: CONFIG.WALLET_AUTH_URL, // null,
WALLET_LOGIN_PATH: CONFIG.WALLET_LOGIN_URL, // null,
DEBUG_DISABLE_AUTH: CONFIG.DEBUG_DISABLE_AUTH, // null,
// CONFIG_VERSION: CONFIG.CONFIG_VERSION, // null,
}),
commonjs(),
],
build: {
outDir: path.resolve(__dirname, './build'),
chunkSizeWarningLimit: 1600,
},
publicDir: '/admin',
}),
Components({
resolvers: [IconsResolve(), BootstrapVueNextResolver()],
dts: true,
}),
Icons({
compiler: 'vue3',
}),
EnvironmentPlugin({
BUILD_COMMIT: null,
PORT: CONFIG.ADMIN_MODULE_PORT, // null,
COMMUNITY_HOST: CONFIG.ADMIN_MODULE_HOST, // null,
URL_PROTOCOL: CONFIG.ADMIN_MODULE_PROTOCOL, // null,
WALLET_URL: CONFIG.WALLET_AUTH_URL, // null,
GRAPHQL_URL: CONFIG.GRAPHQL_URI, // null,
GRAPHQL_PATH: process.env.GRAPHQL_PATH ?? '/graphql', // null,
WALLET_AUTH_PATH: CONFIG.WALLET_AUTH_URL, // null,
WALLET_LOGIN_PATH: CONFIG.WALLET_LOGIN_URL, // null,
DEBUG_DISABLE_AUTH: CONFIG.DEBUG_DISABLE_AUTH, // null,
}),
commonjs(),
],
build: {
outDir: path.resolve(__dirname, './build'),
chunkSizeWarningLimit: 1600,
},
publicDir: '/admin',
}
})

View File

@ -1072,6 +1072,18 @@
resolved "https://registry.yarnpkg.com/@graphql-typed-document-node/core/-/core-3.2.0.tgz#5f3d96ec6b2354ad6d8a28bf216a1d97b5426861"
integrity sha512-mB9oAsNCm9aM3/SOv4YtBMqZbYj10R7dkq8byBqxGY/ncFwhf2oQzMV+LCRlWoDSEBJ3COiR1yeDvMtsoOsuFQ==
"@hapi/hoek@^9.0.0", "@hapi/hoek@^9.3.0":
version "9.3.0"
resolved "https://registry.yarnpkg.com/@hapi/hoek/-/hoek-9.3.0.tgz#8368869dcb735be2e7f5cb7647de78e167a251fb"
integrity sha512-/c6rf4UJlmHlC9b5BaNvzAcFv7HZ2QHaV0D4/HNlBdvFnvQq8RI4kYdhyPCl7Xj+oWvTWQ8ujhqS53LIgAe6KQ==
"@hapi/topo@^5.1.0":
version "5.1.0"
resolved "https://registry.yarnpkg.com/@hapi/topo/-/topo-5.1.0.tgz#dc448e332c6c6e37a4dc02fd84ba8d44b9afb012"
integrity sha512-foQZKJig7Ob0BMAYBfcJk8d77QtOe7Wo4ox7ff1lQYoNNAb6jwcY1ncdoy2e9wQZzvNy7ODZCYJkK8kzmcAnAg==
dependencies:
"@hapi/hoek" "^9.0.0"
"@humanwhocodes/config-array@^0.11.14":
version "0.11.14"
resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.11.14.tgz#d78e481a039f7566ecc9660b4ea7fe6b1fec442b"
@ -1471,6 +1483,23 @@
resolved "https://registry.yarnpkg.com/@rtsao/scc/-/scc-1.1.0.tgz#927dd2fae9bc3361403ac2c7a00c32ddce9ad7e8"
integrity sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==
"@sideway/address@^4.1.5":
version "4.1.5"
resolved "https://registry.yarnpkg.com/@sideway/address/-/address-4.1.5.tgz#4bc149a0076623ced99ca8208ba780d65a99b9d5"
integrity sha512-IqO/DUQHUkPeixNQ8n0JA6102hT9CmaljNTPmQ1u8MEhBo/R4Q8eKLN/vGZxuebwOroDB4cbpjheD4+/sKFK4Q==
dependencies:
"@hapi/hoek" "^9.0.0"
"@sideway/formula@^3.0.1":
version "3.0.1"
resolved "https://registry.yarnpkg.com/@sideway/formula/-/formula-3.0.1.tgz#80fcbcbaf7ce031e0ef2dd29b1bfc7c3f583611f"
integrity sha512-/poHZJJVjx3L+zVD6g9KgHfYnb443oi7wLu/XKojDviHy6HOEOA6z1Trk5aR1dGcmPenJEgb2sK2I80LeS3MIg==
"@sideway/pinpoint@^2.0.0":
version "2.0.0"
resolved "https://registry.yarnpkg.com/@sideway/pinpoint/-/pinpoint-2.0.0.tgz#cff8ffadc372ad29fd3f78277aeb29e632cc70df"
integrity sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ==
"@types/estree@1.0.6", "@types/estree@^1.0.0":
version "1.0.6"
resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.6.tgz#628effeeae2064a1b4e79f78e81d87b7e5fc7b50"
@ -4712,6 +4741,17 @@ jest-canvas-mock@~2.5.2:
cssfontparser "^1.2.1"
moo-color "^1.0.2"
joi@^17.13.3:
version "17.13.3"
resolved "https://registry.yarnpkg.com/joi/-/joi-17.13.3.tgz#0f5cc1169c999b30d344366d384b12d92558bcec"
integrity sha512-otDA4ldcIx+ZXsKHWmp0YizCweVRZG96J10b0FevjfuncLO1oX59THoAmHkNubYJ+9gWsYsp5k8v4ib6oDv1fA==
dependencies:
"@hapi/hoek" "^9.3.0"
"@hapi/topo" "^5.1.0"
"@sideway/address" "^4.1.5"
"@sideway/formula" "^3.0.1"
"@sideway/pinpoint" "^2.0.0"
js-beautify@^1.14.9:
version "1.15.1"
resolved "https://registry.yarnpkg.com/js-beautify/-/js-beautify-1.15.1.tgz#4695afb508c324e1084ee0b952a102023fc65b64"

View File

@ -27,7 +27,7 @@ services:
build:
target: development
environment:
- NODE_ENV="development"
- NODE_ENV=development
# - DEBUG=true
volumes:
# This makes sure the docker container has its own node modules.

View File

@ -54,7 +54,9 @@ services:
# - BUILD_DATE="1970-01-01T00:00:00.00Z"
# - BUILD_VERSION="0.0.0.0"
# - BUILD_COMMIT="0000000"
- NODE_ENV="production"
- NODE_ENV=production
volumes:
- ./config:/config
# env_file:
# - ./.env
# - ./admin/.env

View File

@ -18,8 +18,7 @@ const version = {
BUILD_COMMIT_SHORT: (process.env.BUILD_COMMIT ?? '0000000').slice(0, 7),
}
// in case of hosting the frontend module with a nginx
let FRONTEND_MODULE_URL = version.FRONTEND_MODULE_PROTOCOL + '://' + version.FRONTEND_MODULE_HOST
let FRONTEND_MODULE_URL
// in case of hosting the frontend module with a nodejs-instance
if (process.env.FRONTEND_HOSTING === 'nodejs') {
@ -29,6 +28,9 @@ if (process.env.FRONTEND_HOSTING === 'nodejs') {
version.FRONTEND_MODULE_HOST +
':' +
version.FRONTEND_MODULE_PORT
} else {
// in case of hosting the frontend module with a nginx
FRONTEND_MODULE_URL = version.FRONTEND_MODULE_PROTOCOL + '://' + version.FRONTEND_MODULE_HOST
}
// const FRONTEND_MODULE_URI = version.FRONTEND_MODULE_PROTOCOL + '://' + version.FRONTEND_MODULE_HOST // +

View File

@ -49,6 +49,11 @@ module.exports = Joi.object({
.description('URL for Register a new Account in frontend.')
.required(),
FRONTEND_HOSTING: Joi.string()
.valid('nodejs', 'nginx')
.description('set to `nodejs` if frontend is hosted by vite with a own nodejs instance')
.optional(),
FRONTEND_MODULE_URL: Joi.string()
.uri({ scheme: ['http', 'https'] })
.when('COMMUNITY_URL', {
@ -78,11 +83,6 @@ module.exports = Joi.object({
.default('http')
.required(),
FRONTEND_HOSTING: Joi.string()
.valid('nodejs', 'nginx')
.description('set to `nodejs` if frontend is hosted by vite with a own nodejs instance')
.optional(),
FRONTEND_MODULE_HOST: Joi.alternatives()
.try(
Joi.string().valid('localhost').messages({ 'any.invalid': 'Must be localhost' }),