Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 0 additions & 8 deletions celements-admin-frontend/.dockerignore

This file was deleted.

13 changes: 0 additions & 13 deletions celements-admin-frontend/docker/Caddyfile

This file was deleted.

8 changes: 8 additions & 0 deletions celements-static/.dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
**/node_modules
**/dist
**/.git
**/.gitignore
**/.env
**/.env.*
**/*.log
**/public/config.js
30 changes: 15 additions & 15 deletions celements-admin-frontend/Dockerfile → celements-static/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,25 +1,25 @@
# ____ _____ _ _ _ _ __ __ _
# / __ \ / ____| | | | | /\ | | (_) \ \ / / | | /\
# | | | |_ __ ___ _ __ ______| | ___| | ___ _ __ ___ ___ _ __ | |_ ___ / \ __| |_ __ ___ _ _ __ \ \ /\ / /__| |__ / \ _ __ _ __
# | | | | '_ \ / _ \ '_ \______| | / _ \ |/ _ \ '_ ` _ \ / _ \ '_ \| __/ __| / /\ \ / _` | '_ ` _ \| | '_ \ \ \/ \/ / _ \ '_ \ / /\ \ | '_ \| '_ \
# | |__| | |_) | __/ | | | | |___| __/ | __/ | | | | | __/ | | | |_\__ \ / ____ \ (_| | | | | | | | | | | \ /\ / __/ |_) / ____ \| |_) | |_) |
# \____/| .__/ \___|_| |_| \_____\___|_|\___|_| |_| |_|\___|_| |_|\__|___/ /_/ \_\__,_|_| |_| |_|_|_| |_| \/ \/ \___|_.__/_/ \_\ .__/| .__/
# | | | | | |
# |_| |_| |_| #
# ____ _____ _ _
# / __ \ / ____| | | | |
# | | | |_ __ ___ _ __ ______| | ___| | ___ _ __ ___ ___ _ __ | |_ ___
# | | | | '_ \ / _ \ '_ \______| | / _ \ |/ _ \ '_ ` _ \ / _ \ '_ \| __/ __|
# | |__| | |_) | __/ | | | | |___| __/ | __/ | | | | | __/ | | | |_\__ \
# \____/| .__/ \___|_| |_| \_____\___|_|\___|_| |_| |_|\___|_| |_|\__|___/
# | |
# |_|
#
# Open-Celements Admin WebApp Vue Frontend
# Celements static

## Stage: build
FROM node:lts AS build
## Stage: build admin frontend
FROM node:lts AS admin-frontend

WORKDIR /app

# Layer: dependencies
COPY package*.json ./
COPY admin-frontend/package*.json ./
RUN npm ci

# Layer: package
COPY . .
COPY admin-frontend/ .
RUN npm run build

## Stage: execute
Expand All @@ -29,13 +29,13 @@ ARG VERSION
ARG REVISION

LABEL org.opencontainers.image.source="https://github.com/celements/celements-web" \
org.opencontainers.image.description="Celements admin frontend" \
org.opencontainers.image.description="Celements static assets" \
org.opencontainers.image.version="${VERSION}" \
org.opencontainers.image.revision="${REVISION}"

WORKDIR /srv

COPY --from=build /app/dist /srv
COPY --from=admin-frontend /app/dist /srv/admin
COPY docker/Caddyfile /etc/caddy/Caddyfile
COPY --chmod=755 docker/entrypoint.sh /usr/local/bin/start
RUN caddy fmt /etc/caddy/Caddyfile --overwrite
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

dockerImagePipeline(
org: 'celements',
image: 'celements-admin-frontend',
appDir: 'celements-admin-frontend',
image: 'celements-static',
appDir: 'celements-static',
mode: 'node'
)
26 changes: 26 additions & 0 deletions celements-static/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# Celements static

This image serves the static Celements applications. `admin-frontend` is its first payload.
The local `package.json` versions the assembled image independently of its payloads.

Build it from the repository root:

```sh
docker build -t celements-static celements-static
```

## Potential improvements

### Asset cache version

The Celements webapp templates append an asset version as `?ver=`. A future
`$services.celementsweb.getAssetVersion()` helper should return the last startup timestamp in
production and the current timestamp in local development (cluster=local), so local changes always
bypass browser caching without disabling production cacheability.

### Entrypoint extension

The image currently has one entrypoint for its first static app. If additional apps need startup
configuration, each app can provide an entrypoint script that the aggregate image copies into
`entrypoint.d/`; a generic runner can execute those scripts in lexical order and fail startup if one
fails.
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,8 @@ The container generates `config.js` from its runtime environment. `.env.local` i

| Command | Description |
| -------------------- | ----------------------------------------------------------------- |
| `npm run dev` | Start dev server with concurrent type-checking and test watching |
| `npm run dev` | Build-watch into the local celements-webapp Tomcat target |
| `npm run dev:standalone` | Start the standalone Vite server with type-checking and test watching |
| `npm run build` | Type-check + run tests + build production bundle |
| `npm run preview` | Preview the production build locally |
| `npm run test` | Run unit tests once with Vitest |
Expand Down Expand Up @@ -103,14 +104,13 @@ The app exposes a `createCelementsAdminApp()` factory function from `bootstrap.t

## 🐳 Deployment

The project ships with a multi-stage `Dockerfile` that builds the static assets and serves them via [Caddy](https://caddyserver.com/).
The parent `celements-static` image builds and serves this frontend via [Caddy](https://caddyserver.com/).
Run these commands from the repository root:

```sh
# Build the Docker image (pass the active profile to select the correct .env file)
docker build --build-arg PROFILE_ACTIVE=prod -t celements-admin-frontend .
docker build -t celements-static celements-static

# Run the container
docker run -p 80:80 celements-admin-frontend
docker run -p 80:80 celements-static
```

---
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,9 @@
<html lang="">
<head>
<meta charset="UTF-8">
<link rel="icon" href="/favicon.ico">
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no">
<title>Celements Admin</title>
<script src="/config.js"></script>
<script src="%BASE_URL%config.js"></script>
</head>
<body class="bg-grau-20">
<div id="app" class="3xl:mx-auto max-w-screen-3xl"></div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@
"./src/*": "./src/*"
},
"scripts": {
"dev": "concurrently \"vite\" \"npm:type-check-watch\" \"npm:test-watch\"",
"dev": "vite build --watch --outDir ../../celements-webapp/target/celements-web/static/admin",
"dev:standalone": "concurrently \"vite\" \"npm:type-check-watch\" \"npm:test-watch\"",
"build": "npm run type-check && npm run test && vite build",
"preview": "vite preview",
"test": "vitest run",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ export default defineConfig(({ mode }) => getViteConfig(mode));
export const getViteConfig = (mode: string) => {
const env = loadEnv(mode, process.cwd());
return defineConfig({
base: mode === 'production' ? '/static/' : '/',
base: '/static/admin/',
plugins: [
vue({
template: {
Expand All @@ -22,6 +22,7 @@ export const getViteConfig = (mode: string) => {
],
build: {
manifest: true,
emptyOutDir: true,
chunkSizeWarningLimit: 1500,
rollupOptions: {
input: {
Expand Down
13 changes: 13 additions & 0 deletions celements-static/docker/Caddyfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
:80 {
root * /srv

handle /health {
respond 200
}

handle {
@config path */config.js
header @config Cache-Control "no-store, no-cache, must-revalidate"
file_server
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ escape_js_string() {
-e "s/'/\\\\'/g"
}

cat > /srv/config.js <<EOF
cat > /srv/admin/config.js <<EOF
window.__APP_CONFIG__ = {
defaultLocale: '$(escape_js_string "${DEFAULT_LOCALE:-de}")'
};
Expand Down
5 changes: 5 additions & 0 deletions celements-static/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"name": "@celements/static",
"version": "1.0.0-SNAPSHOT",
"private": true
}
5 changes: 3 additions & 2 deletions celements-webapp/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,9 @@
"private": true,
"type": "module",
"scripts": {
"dev": "vite build --watch",
"build": "tsc && vite build"
"dev": "vite build --watch --outDir target/celements-web/resources/dist",
"build": "npm run type-check && vite build",
"type-check": "tsc --noEmit"
},
"devDependencies": {
"@babel/standalone": "^7.0.0",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,9 @@
$!jsService.includeExtJsFile($extJsParamSync.setJsFile(':celJS/tailwind/tailwind.js'))
$!jsService.includeExtJsFile($extJsParamSync.setJsFile(':celJS/tailwind/tailwind.config.js'))

#set($requestHost = "$!context.getRequest().getHeader('host')")
#if($requestHost.indexOf('localhost') != -1)
<script type="module" src="http://localhost:5173/@vite/client"></script>
<script type="module" src="http://localhost:5173/src/embedded.ts"></script>
#else
<link rel="stylesheet" href="/static/assets/embedded.css?ver=$!{services.celementsweb.getLastStartupTimeStamp()}" />
<link rel="stylesheet" href="/static/assets/vendor.css?ver=$!{services.celementsweb.getLastStartupTimeStamp()}" />
<script type="module" src="/static/assets/embedded.js?ver=$!{services.celementsweb.getLastStartupTimeStamp()}"></script>
#end
<link rel="stylesheet" href="/static/admin/assets/embedded.css?ver=$!{services.celementsweb.getLastStartupTimeStamp()}" />
<link rel="stylesheet" href="/static/admin/assets/vendor.css?ver=$!{services.celementsweb.getLastStartupTimeStamp()}" />
<script type="module" src="/static/admin/assets/embedded.js?ver=$!{services.celementsweb.getLastStartupTimeStamp()}"></script>

<div class="cel_cell" id="userAdmin">
<div class="cel_cell" id="content">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,9 @@
$!jsService.includeExtJsFile($extJsParamSync.setJsFile(':celJS/tailwind/tailwind.js'))
$!jsService.includeExtJsFile($extJsParamSync.setJsFile(':celJS/tailwind/tailwind.config.js'))

#set($requestHost = "$!context.getRequest().getHeader('host')")
#if($requestHost.indexOf('localhost') != -1)
<script type="module" src="http://localhost:5173/@vite/client"></script>
<script type="module" src="http://localhost:5173/src/embedded.ts"></script>
#else
<link rel="stylesheet" href="/static/assets/embedded.css?ver=$!{services.celementsweb.getLastStartupTimeStamp()}" />
<link rel="stylesheet" href="/static/assets/vendor.css?ver=$!{services.celementsweb.getLastStartupTimeStamp()}" />
<script type="module" src="/static/assets/embedded.js?ver=$!{services.celementsweb.getLastStartupTimeStamp()}"></script>
#end
<link rel="stylesheet" href="/static/admin/assets/embedded.css?ver=$!{services.celementsweb.getLastStartupTimeStamp()}" />
<link rel="stylesheet" href="/static/admin/assets/vendor.css?ver=$!{services.celementsweb.getLastStartupTimeStamp()}" />
<script type="module" src="/static/admin/assets/embedded.js?ver=$!{services.celementsweb.getLastStartupTimeStamp()}"></script>

<div class="cel_cell" id="userAdmin">
<div class="cel_cell" id="content">
Expand Down
8 changes: 5 additions & 3 deletions celements-webapp/vite.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@ import { fileURLToPath, URL } from 'node:url';
import input from './src/main/frontend/celements/index.ts';

export default defineConfig({
plugins: [],
build: {
watch: process.argv.includes('--watch') ? { buildDelay: 2000 } : null,
outDir: 'src/main/webapp/resources/dist',
emptyOutDir: true,
manifest: '.vite/manifest.celements.json',
Expand All @@ -13,13 +15,13 @@ export default defineConfig({
// Use .mjs extension for celements module detection
entryFileNames: '[name].[hash].mjs',
chunkFileNames: '[name].[hash].mjs',
}
},
},
sourcemap: true,
},
resolve: {
alias: {
'@': fileURLToPath(new URL('./src/main/frontend', import.meta.url))
}
'@': fileURLToPath(new URL('./src/main/frontend', import.meta.url)),
},
},
});