fix it for docker setup

This commit is contained in:
einhornimmond 2025-01-18 17:55:01 +01:00
parent 833890e0ba
commit 43f982bd5a
9 changed files with 203 additions and 165 deletions

View File

@ -1,37 +1,45 @@
const Joi = require('joi')
module.exports = {
BROWSER_PROTOCOL: Joi.string()
.valid('http', 'https')
.description(
'Protocol for all URLs in the browser, must be either http or https to prevent mixed content issues.',
)
.default('http')
browserUrls: Joi.array()
.items(Joi.string().uri())
.custom((value, helpers) => {
const protocol = new URL(value[0]).protocol
for (const url of value) {
if (new URL(url).protocol !== protocol) {
return helpers.error('any.invalid')
}
}
return value;
})
.required()
.description('All URLs need to have same protocol to prevent mixed block errors'),
DECAY_START_TIME: Joi.date()
.iso() // ISO 8601 format for date validation
.description('The start time for decay, expected in ISO 8601 format (e.g. 2021-05-13T17:46:31Z)')
.default(new Date('2021-05-13T17:46:31Z')) // default to the specified date if not provided
.required(),
COMMUNITY_URL: Joi.string()
.uri({ scheme: ['http', 'https'] })
.when('BROWSER_PROTOCOL', {
is: 'https',
then: Joi.string().uri({ scheme: 'https' }),
otherwise: Joi.string().uri({ scheme: 'http' }),
.custom((value, helpers) => {
if (value.endsWith('/')) {
return helpers.error('any.invalid', { message: 'URL should not end with a slash (/)' })
}
return value;
})
.description('The base URL of the community, should have the same scheme like frontend, admin and backend api to prevent mixed contend issues.')
.description('The base URL of the community, should have the same protocol as frontend, admin and backend api to prevent mixed contend issues.')
.default('http://0.0.0.0')
.required(),
GRAPHQL_URI: Joi.string()
.uri({ scheme: ['http', 'https'] })
.when('BROWSER_PROTOCOL', {
is: 'https',
then: Joi.string().uri({ scheme: 'https' }),
otherwise: Joi.string().uri({ scheme: 'http' }),
})
.description(
`
The external URL of the backend service,
accessible from outside the server (e.g., via Nginx or the server's public URL),
must use the same protocol as browser_protocol.
should have the same protocol as frontend and admin to prevent mixed contend issues.
`,
)
.default('http://0.0.0.0/graphql')
@ -67,7 +75,7 @@ module.exports = {
.description('Geographical location of the community in "latitude, longitude" format')
.default('49.280377, 9.690151'),
GRAPHIQL: Joi.boolean()
GRAPHIQL: Joi.boolean()
.description('Flag for enabling GraphQL playground for debugging.')
.default(false)
.when('NODE_ENV', {
@ -163,7 +171,7 @@ module.exports = {
NODE_ENV: Joi.string()
.valid('production', 'development')
.default('development')
.description('Specifies the environment in which the application is running, "production" or "development".'),
.description('Specifies the environment in which the application is running.'),
DEBUG: Joi.boolean()
.description('Indicates whether the application is in debugging mode. Set to true when NODE_ENV is not "production".')

View File

@ -63,7 +63,7 @@ EMAIL_LINK_VERIFICATION_PATH=/checkEmail/{optin}{code}
EMAIL_LINK_SETPASSWORD_PATH=/reset-password/{optin}
EMAIL_LINK_FORGOTPASSWORD_PATH=/forgot-password
EMAIL_LINK_OVERVIEW_PATH=/overview
ADMIN_AUTH_PATH=/admin/authenticate?token={token}
ADMIN_AUTH_PATH=/admin/authenticate?token=
GRAPHQL_PATH=/graphql
# login expire time

View File

@ -9,7 +9,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

@ -26,7 +26,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
# - ./frontend/.env

View File

@ -1,6 +1,6 @@
# Endpoints
GRAPHQL_PATH=/graphql
ADMIN_AUTH_PATH=/admin/authenticate?token={token}
ADMIN_AUTH_PATH=/admin/authenticate?token=
# Community
COMMUNITY_NAME=Gradido Entwicklung

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
ENV NODE_ENV="production"
## App relevant Envs

View File

@ -3,15 +3,12 @@
// Load Package Details for some default values
const pkg = require('../../package')
const schema = require('./schema')
// const joi = require('joi')
const constants = {
DECAY_START_TIME: new Date('2021-05-13 17:46:31-0000'), // GMT+0
}
const version = {
BROWSER_PROTOCOL: process.env.BROWSER_PROTOCOL ?? 'http',
FRONTEND_MODULE_PROTOCOL: process.env.FRONTEND_MODULE_PROTOCOL ?? 'http',
FRONTEND_MODULE_HOST: process.env.FRONTEND_MODULE_HOST ?? '0.0.0.0',
FRONTEND_MODULE_PORT: process.env.FRONTEND_MODULE_PORT ?? '3000',
@ -21,7 +18,9 @@ const version = {
BUILD_COMMIT_SHORT: (process.env.BUILD_COMMIT ?? '0000000').slice(0, 7),
}
let FRONTEND_MODULE_URL
// in case of hosting the frontend module with a nginx
let FRONTEND_MODULE_URL = version.FRONTEND_MODULE_PROTOCOL + '://' + version.FRONTEND_MODULE_HOST
// in case of hosting the frontend module with a nodejs-instance
if (process.env.FRONTEND_HOSTING === 'nodejs') {
FRONTEND_MODULE_URL =
@ -30,9 +29,6 @@ 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 // +
@ -97,26 +93,8 @@ const CONFIG = {
...endpoints,
...community,
...meta,
...constants,
FRONTEND_MODULE_URL,
}
// Check config
// TODO: use validate and construct error message including description
// joi.attempt(CONFIG, schema)
const { error } = schema.validate(CONFIG, { stack: true, debug: true })
const schemaJson = schema.describe()
if (error) {
error.details.forEach((err) => {
const key = err.context.key
const description = schemaJson.keys[key]
? schema.describe().keys[key].flags.description
: 'No description available'
if (CONFIG[key] === undefined) {
throw new Error(`Environment Variable '${key}' is missing. ${description}`)
} else {
throw new Error(`Error on Environment Variable '${key}': ${err.message}. ${description}`)
}
})
}
module.exports = { ...CONFIG, ...constants }
module.exports = CONFIG

View File

@ -1,6 +1,6 @@
import {
const {
browserUrls,
APP_VERSION,
BROWSER_PROTOCOL,
BUILD_COMMIT,
BUILD_COMMIT_SHORT,
COMMUNITY_DESCRIPTION,
@ -9,19 +9,20 @@ import {
COMMUNITY_LOCATION,
COMMUNITY_URL,
DEBUG,
DECAY_START_TIME,
GMS_ACTIVE,
GRAPHQL_URI,
HUMHUB_ACTIVE,
NODE_ENV,
PRODUCTION,
} from '../../../config/common.schema'
} = require('../../../config/common.schema') // from '../../../config/common.schema'
const Joi = require('joi')
// console.log(commonSchema)
module.exports = Joi.object({
browserUrls,
APP_VERSION,
BROWSER_PROTOCOL,
BUILD_COMMIT,
BUILD_COMMIT_SHORT,
COMMUNITY_DESCRIPTION,
@ -30,6 +31,7 @@ module.exports = Joi.object({
COMMUNITY_LOCATION,
COMMUNITY_URL,
DEBUG,
DECAY_START_TIME,
GMS_ACTIVE,
GRAPHQL_URI,
HUMHUB_ACTIVE,
@ -38,40 +40,46 @@ module.exports = Joi.object({
ADMIN_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 for admin-frontend')
.default('http://0.0.0.0/admin/authenticate?token=')
.required(),
COMMUNITY_REGISTER_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('URL for Register a new Account in frontend.')
.required(),
FRONTEND_MODULE_PROTOCOL: Joi.string()
.valid('http', 'https')
.when('BROWSER_PROTOCOL', {
is: 'https',
then: Joi.string().uri({ scheme: 'https' }),
otherwise: Joi.string().uri({ scheme: 'http' }),
FRONTEND_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(
'Protocol for frontend module hosting, has to be the same as for backend api url and admin to prevent mixed block errors'
"Base Url for reaching frontend in browser, only needed if COMMUNITY_URL wasn't set",
)
.optional(), // optional in general, but conditionally required
FRONTEND_MODULE_PROTOCOL: Joi.string()
.when('FRONTEND_HOSTING', {
is: Joi.valid('nodejs'),
then: Joi.valid('http').required(),
otherwise: Joi.valid('http', 'https').required(),
})
.description(
`
Protocol for frontend module hosting
- it has to be the same as for backend api url and admin to prevent mixed block errors,
- if frontend is served with nodejs:
is have to be http or setup must be updated to include a ssl certificate
`,
)
.default('http')
.required(),
FRONTEND_HOSTING: Joi.string()
.valid('nodejs')
.valid('nodejs', 'nginx')
.description('set to `nodejs` if frontend is hosted by vite with a own nodejs instance')
.optional(),

View File

@ -7,6 +7,7 @@ import Icons from 'unplugin-icons/vite'
import IconsResolve from 'unplugin-icons/resolver'
import EnvironmentPlugin from 'vite-plugin-environment'
import { createHtmlPlugin } from 'vite-plugin-html'
import schema from './src/config/schema'
import { BootstrapVueNextResolver } from 'bootstrap-vue-next'
import dotenv from 'dotenv'
@ -16,100 +17,141 @@ dotenv.config() // load env vars from .env
const CONFIG = require('./src/config')
// https://vitejs.dev/config/
export default defineConfig({
server: {
host: CONFIG.FRONTEND_MODULE_HOST, // '0.0.0.0',
port: CONFIG.FRONTEND_MODULE_PORT, // 3000,
https: CONFIG.FRONTEND_MODULE_PROTOCOL === 'https',
},
resolve: {
alias: {
'@': path.resolve(__dirname, './src'),
assets: path.join(__dirname, 'src/assets'),
'@vee-validate/i18n/dist/locale/en.json':
'/node_modules/@vee-validate/i18n/dist/locale/en.json',
'@vee-validate/i18n/dist/locale/de.json':
'/node_modules/@vee-validate/i18n/dist/locale/de.json',
'@vee-validate/i18n/dist/locale/es.json':
'/node_modules/@vee-validate/i18n/dist/locale/es.json',
'@vee-validate/i18n/dist/locale/fr.json':
'/node_modules/@vee-validate/i18n/dist/locale/fr.json',
'@vee-validate/i18n/dist/locale/nl.json':
'/node_modules/@vee-validate/i18n/dist/locale/nl.json',
'@vee-validate/i18n/dist/locale/tr.json':
'/node_modules/@vee-validate/i18n/dist/locale/tr.json',
export default defineConfig(({ command }) => {
if (command === 'serve') {
CONFIG.FRONTEND_HOSTING = 'nodejs'
} else {
CONFIG.FRONTEND_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.ADMIN_AUTH_URL,
CONFIG.COMMUNITY_URL,
CONFIG.COMMUNITY_REGISTER_URL,
CONFIG.GRAPHQL_URI,
CONFIG.FRONTEND_MODULE_URL,
],
}
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 {
server: {
host: CONFIG.FRONTEND_MODULE_HOST, // '0.0.0.0',
port: CONFIG.FRONTEND_MODULE_PORT, // 3000,
https: CONFIG.FRONTEND_MODULE_PROTOCOL === 'https',
fs: {
strict: true,
},
esbuild: {
minify: CONFIG.PRODUCTION === true,
},
},
extensions: ['.mjs', '.js', '.ts', '.jsx', '.tsx', '.json', '.vue'],
},
plugins: [
vue(),
createHtmlPlugin({
minify: true,
inject: {
data: {
VITE_META_TITLE_DE: CONFIG.META_TITLE_DE,
VITE_META_TITLE_EN: CONFIG.META_TITLE_EN,
VITE_META_DESCRIPTION_DE: CONFIG.META_DESCRIPTION_DE,
VITE_META_DESCRIPTION_EN: CONFIG.META_DESCRIPTION_EN,
VITE_META_KEYWORDS_DE: CONFIG.META_KEYWORDS_DE,
VITE_META_KEYWORDS_EN: CONFIG.META_KEYWORDS_EN,
VITE_META_AUTHOR: CONFIG.META_AUTHOR,
VITE_META_URL: CONFIG.META_URL,
resolve: {
alias: {
'@': path.resolve(__dirname, './src'),
assets: path.join(__dirname, 'src/assets'),
'@vee-validate/i18n/dist/locale/en.json':
'/node_modules/@vee-validate/i18n/dist/locale/en.json',
'@vee-validate/i18n/dist/locale/de.json':
'/node_modules/@vee-validate/i18n/dist/locale/de.json',
'@vee-validate/i18n/dist/locale/es.json':
'/node_modules/@vee-validate/i18n/dist/locale/es.json',
'@vee-validate/i18n/dist/locale/fr.json':
'/node_modules/@vee-validate/i18n/dist/locale/fr.json',
'@vee-validate/i18n/dist/locale/nl.json':
'/node_modules/@vee-validate/i18n/dist/locale/nl.json',
'@vee-validate/i18n/dist/locale/tr.json':
'/node_modules/@vee-validate/i18n/dist/locale/tr.json',
},
extensions: ['.mjs', '.js', '.ts', '.jsx', '.tsx', '.json', '.vue'],
},
plugins: [
vue(),
createHtmlPlugin({
minify: CONFIG.PRODUCTION === true,
inject: {
data: {
VITE_META_TITLE_DE: CONFIG.META_TITLE_DE,
VITE_META_TITLE_EN: CONFIG.META_TITLE_EN,
VITE_META_DESCRIPTION_DE: CONFIG.META_DESCRIPTION_DE,
VITE_META_DESCRIPTION_EN: CONFIG.META_DESCRIPTION_EN,
VITE_META_KEYWORDS_DE: CONFIG.META_KEYWORDS_DE,
VITE_META_KEYWORDS_EN: CONFIG.META_KEYWORDS_EN,
VITE_META_AUTHOR: CONFIG.META_AUTHOR,
VITE_META_URL: CONFIG.META_URL,
},
},
}),
Components({
resolvers: [BootstrapVueNextResolver(), IconsResolve()],
dts: true,
}),
Icons({
compiler: 'vue3',
autoInstall: true,
}),
EnvironmentPlugin({
BUILD_COMMIT: null,
GMS_ACTIVE: null,
HUMHUB_ACTIVE: null,
DEFAULT_PUBLISHER_ID: null,
PORT: null,
COMMUNITY_HOST: null,
URL_PROTOCOL: null,
COMMUNITY_URL: CONFIG.COMMUNITY_URL,
GRAPHQL_PATH: null,
GRAPHQL_URI: CONFIG.GRAPHQL_URI, // null,
ADMIN_AUTH_PATH: CONFIG.ADMIN_AUTH_PATH ?? null, // it is the only env without exported default
ADMIN_AUTH_URL: CONFIG.ADMIN_AUTH_URL, // null,
COMMUNITY_NAME: null,
COMMUNITY_REGISTER_PATH: null,
COMMUNITY_REGISTER_URL: null,
COMMUNITY_DESCRIPTION: null,
COMMUNITY_SUPPORT_MAIL: null,
META_URL: null,
META_TITLE_DE: null,
META_TITLE_EN: null,
META_DESCRIPTION_DE: null,
META_DESCRIPTION_EN: null,
META_KEYWORDS_DE: null,
META_KEYWORDS_EN: null,
META_AUTHOR: null,
}),
commonjs(),
],
css: {
extract: CONFIG.PRODUCTION === true,
preprocessorOptions: {
scss: {
additionalData: `@import "@/assets/scss/gradido.scss";`,
},
},
}),
Components({
resolvers: [BootstrapVueNextResolver(), IconsResolve()],
dts: true,
}),
Icons({
compiler: 'vue3',
autoInstall: true,
}),
EnvironmentPlugin({
BUILD_COMMIT: null,
GMS_ACTIVE: null,
HUMHUB_ACTIVE: null,
NODE_ENV: null,
DEFAULT_PUBLISHER_ID: null,
PORT: null,
COMMUNITY_HOST: null,
URL_PROTOCOL: null,
COMMUNITY_URL: null,
GRAPHQL_PATH: null,
GRAPHQL_URI: CONFIG.GRAPHQL_URI, // null,
ADMIN_AUTH_PATH: CONFIG.ADMIN_AUTH_PATH ?? null, // it is the only env without exported default
ADMIN_AUTH_URL: CONFIG.ADMIN_AUTH_URL, // null,
COMMUNITY_NAME: null,
COMMUNITY_REGISTER_PATH: null,
COMMUNITY_REGISTER_URL: null,
COMMUNITY_DESCRIPTION: null,
COMMUNITY_SUPPORT_MAIL: null,
META_URL: null,
META_TITLE_DE: null,
META_TITLE_EN: null,
META_DESCRIPTION_DE: null,
META_DESCRIPTION_EN: null,
META_KEYWORDS_DE: null,
META_KEYWORDS_EN: null,
META_AUTHOR: null,
CONFIG_VERSION: null,
}),
commonjs(),
],
css: {
extract: true,
preprocessorOptions: {
scss: {
additionalData: `@import "@/assets/scss/gradido.scss";`,
},
},
},
build: {
outDir: path.resolve(__dirname, './build'),
chunkSizeWarningLimit: 1600,
rollupOptions: {
external: ['joi'],
build: {
outDir: path.resolve(__dirname, './build'),
chunkSizeWarningLimit: 1600,
minify: 'esbuild',
sourcemap: false,
},
},
}
})