Skip to content

Commit 6becaa7

Browse files
Merge pull request #19 from exelearning/17-build-docker-image
Version jump to 4.0.0 and new Docker image
2 parents 29d9c19 + fbca180 commit 6becaa7

13 files changed

Lines changed: 294 additions & 38 deletions

File tree

.dockerignore

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
.git
2+
.github
3+
.vscode
4+
.idea
5+
.claude
6+
node_modules
7+
scripts
8+
docs
9+
server.js
10+
package.json
11+
package-lock.json
12+
*.md
13+
IDEAS*.md

.env.dist

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# eXeViewer – deployment configuration
2+
# Copy this file to .env and edit the values you need.
3+
# Variables not set here keep the application defaults.
4+
5+
# Google Apps Script proxy URL for Google Drive support.
6+
# Leave empty to disable.
7+
GAS_PROXY_URL=
8+
9+
# Automatically restore the last viewed content on page load.
10+
AUTO_RESTORE_CONTENT=true
11+
12+
# Open external links in a new tab (recommended when embedded in an iframe).
13+
OPEN_EXTERNAL_LINKS_IN_NEW_WINDOW=true
14+
15+
# Reject ZIP files that are not valid eXeLearning packages.
16+
VALIDATE_EXE_CONTENT=true
17+
18+
# Show the download button enabled by default in the share dialog.
19+
ALLOW_DOWNLOAD_BY_DEFAULT=true

.github/workflows/docker.yml

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
name: Publish Docker image
2+
3+
on:
4+
push:
5+
branches:
6+
- main
7+
tags:
8+
- 'v*'
9+
10+
permissions:
11+
contents: read
12+
packages: write
13+
14+
jobs:
15+
build-and-push:
16+
runs-on: ubuntu-latest
17+
18+
steps:
19+
- name: Checkout
20+
uses: actions/checkout@v4
21+
22+
- name: Log in to GitHub Container Registry
23+
uses: docker/login-action@v3
24+
with:
25+
registry: ghcr.io
26+
username: ${{ github.repository_owner }}
27+
password: ${{ secrets.GITHUB_TOKEN }}
28+
29+
- name: Set up Docker Buildx
30+
uses: docker/setup-buildx-action@v3
31+
32+
- name: Extract metadata
33+
id: meta
34+
uses: docker/metadata-action@v5
35+
with:
36+
images: ghcr.io/${{ github.repository }}
37+
tags: |
38+
type=raw,value=latest,enable={{is_default_branch}}
39+
type=semver,pattern={{version}}
40+
type=semver,pattern={{major}}.{{minor}}
41+
42+
- name: Build and push
43+
uses: docker/build-push-action@v6
44+
with:
45+
context: .
46+
platforms: linux/amd64,linux/arm64
47+
push: true
48+
tags: ${{ steps.meta.outputs.tags }}
49+
labels: ${{ steps.meta.outputs.labels }}
50+
cache-from: type=gha
51+
cache-to: type=gha,mode=max

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
# Node modules
22
node_modules/
33

4+
# Local deployment config (copy from .env.dist)
5+
.env
6+
47
# OS generated files
58
.DS_Store
69
Thumbs.db

CHANGELOG.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
# CHANGELOG
22

3-
## v1.0.4 – 2026-04-13
3+
## v4.0.0-rc1 – 2026-04-14
44

5+
- Version jump to 4.0.0 to align numbering with eXeLearning for consistency across related projects.
6+
- Add Docker image (published to GitHub Container Registry) for optional containerized deployment.
7+
- Add a deployment configuration file to override default settings defined in `app.js`.
58
- Request persistent storage to prevent the browser from evicting IndexedDB content.
69
- Improve Web Worker lifecycle management by properly terminating the worker, clearing its reference and standardizing error reporting.
710
- Align license declaration for consistency across the project.
811
- Improve error handling and user feedback for storage-related failures, including insufficient storage space conditions.
9-
- Add a deployment configuration file to override default settings defined in `app.js`.
1012

1113
---
1214

Dockerfile

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
FROM nginx:alpine
2+
3+
COPY index.html manifest.json sw.js /usr/share/nginx/html/
4+
COPY css/ /usr/share/nginx/html/css/
5+
COPY js/ /usr/share/nginx/html/js/
6+
COPY lang/ /usr/share/nginx/html/lang/
7+
COPY img/ /usr/share/nginx/html/img/
8+
COPY vendor/ /usr/share/nginx/html/vendor/
9+
10+
COPY nginx.conf /etc/nginx/conf.d/default.conf
11+
12+
COPY docker/entrypoint.sh /entrypoint.sh
13+
RUN chmod +x /entrypoint.sh
14+
15+
EXPOSE 80
16+
ENTRYPOINT ["/entrypoint.sh"]

README.md

Lines changed: 71 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,54 @@ The application will work on:
117117

118118
For the share functionality to work, the application must be served over HTTPS (or HTTP on localhost).
119119

120+
### Docker
121+
122+
A pre-built image is published to the GitHub Container Registry on every release. It uses nginx on Alpine Linux (~8 MB base image).
123+
124+
#### Quick start
125+
126+
```bash
127+
docker run -p 8080:80 ghcr.io/exelearning/exeviewer:latest
128+
```
129+
130+
Then open `http://localhost:8080` in your browser.
131+
132+
#### Docker Compose (recommended)
133+
134+
Download the provided `docker-compose.yml` and the configuration template:
135+
136+
```bash
137+
curl -O https://raw.githubusercontent.com/exelearning/exeviewer/main/docker-compose.yml
138+
curl -O https://raw.githubusercontent.com/exelearning/exeviewer/main/.env.dist
139+
cp .env.dist .env
140+
```
141+
142+
Edit `.env` if you need to customise any settings (e.g. Google Drive proxy), then start the container:
143+
144+
```bash
145+
docker compose up -d
146+
```
147+
148+
#### Configuration via environment variables
149+
150+
Instead of editing `js/config.js`, Docker deployments are configured through environment variables, either in `.env` or in the `environment:` block of your Compose file:
151+
152+
| Variable | Default | Description |
153+
|---|---|---|
154+
| `GAS_PROXY_URL` | _(empty)_ | Google Apps Script proxy URL for Google Drive support |
155+
| `AUTO_RESTORE_CONTENT` | `true` | Restore last viewed content on page load |
156+
| `OPEN_EXTERNAL_LINKS_IN_NEW_WINDOW` | `true` | Open external links in a new tab |
157+
| `VALIDATE_EXE_CONTENT` | `true` | Reject ZIPs that are not valid eXeLearning packages |
158+
| `ALLOW_DOWNLOAD_BY_DEFAULT` | `true` | Show download button enabled by default in share dialog |
159+
160+
Variables not set in `.env` keep their default values. You only need to include the ones you want to change.
161+
162+
#### HTTPS
163+
164+
**HTTPS is required.** The Service Worker (the core mechanism that serves extracted ZIP content) will not register on non-secure origins. This is a browser security restriction, not an eXeViewer limitation. The only exception is `localhost`, which works without HTTPS for local development.
165+
166+
For production deployments, ensure TLS is terminated before reaching the browser. The most common approach is a reverse proxy in front of the container (Nginx, Traefik, Caddy, etc.), but cloud load balancers or any other TLS termination point work equally well.
167+
120168
### Running locally without a web server
121169

122170
If you don't have a web server installed, you can use the included `server.js`:
@@ -261,26 +309,32 @@ Firefox doesn't support PWA installation natively. Use the [PWAs for Firefox](ht
261309

262310
```
263311
exeviewer/
264-
├── index.html # Main application page
265-
├── manifest.json # PWA manifest
266-
├── sw.js # Service Worker
267-
├── server.js # Development server (Bun/Node.js)
268-
├── package.json # Project configuration
312+
├── index.html # Main application page
313+
├── manifest.json # PWA manifest
314+
├── sw.js # Service Worker
315+
├── server.js # Development server (Bun/Node.js)
316+
├── package.json # Project configuration
317+
├── Dockerfile # Docker image definition
318+
├── nginx.conf # nginx configuration for the Docker image
319+
├── docker-compose.yml # Docker Compose example
320+
├── .env.dist # Environment variable template for Docker deployments
321+
├── docker/
322+
│ └── entrypoint.sh # Generates js/config.js from environment variables at startup
269323
├── css/
270-
│ └── styles.css # Custom styles
324+
│ └── styles.css # Custom styles
271325
├── js/
272-
│ ├── app.js # Main application logic
273-
│ ├── config.js # Deployment configuration (overrides defaults in app.js)
274-
│ ├── i18n.js # Internationalization module
275-
│ └── zip.worker.js # Web Worker for ZIP extraction
326+
│ ├── app.js # Main application logic
327+
│ ├── config.js # Deployment configuration (overrides defaults in app.js)
328+
│ ├── i18n.js # Internationalization module
329+
│ └── zip.worker.js # Web Worker for ZIP extraction
276330
├── lang/
277-
│ ├── en.json # English translations
278-
│ └── es.json # Spanish translations
279-
├── img/ # Icons and images
280-
├── vendor/ # Third-party libraries
281-
│ ├── bootstrap/ # Bootstrap 5.3.2
282-
│ ├── bootstrap-icons/# Bootstrap Icons 1.11.1
283-
│ └── fflate/ # fflate 0.8.2
331+
│ ├── en.json # English translations
332+
│ └── es.json # Spanish translations
333+
├── img/ # Icons and images
334+
├── vendor/ # Third-party libraries
335+
│ ├── bootstrap/ # Bootstrap 5.3.2
336+
│ ├── bootstrap-icons/ # Bootstrap Icons 1.11.1
337+
│ └── fflate/ # fflate 0.8.2
284338
└── scripts/
285339
└── generate-icons.js # Icon generation script (requires Node.js + sharp)
286340
```

README_es.md

Lines changed: 71 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,54 @@ La aplicación funcionará en:
117117

118118
Para que la opción de compartir funcione, la aplicación se debe servir por HTTPS (o HTTP en localhost).
119119

120+
### Docker
121+
122+
Se publica una imagen precompilada en el GitHub Container Registry con cada nueva versión. Usa nginx sobre Alpine Linux (~8 MB de imagen base).
123+
124+
#### Inicio rápido
125+
126+
```bash
127+
docker run -p 8080:80 ghcr.io/exelearning/exeviewer:latest
128+
```
129+
130+
Abre `http://localhost:8080` en tu navegador.
131+
132+
#### Docker Compose (recomendado)
133+
134+
Descarga el `docker-compose.yml` incluido y la plantilla de configuración:
135+
136+
```bash
137+
curl -O https://raw.githubusercontent.com/exelearning/exeviewer/main/docker-compose.yml
138+
curl -O https://raw.githubusercontent.com/exelearning/exeviewer/main/.env.dist
139+
cp .env.dist .env
140+
```
141+
142+
Edita `.env` si necesitas personalizar algún parámetro (por ejemplo, la URL del proxy de Google Drive) y arranca el contenedor:
143+
144+
```bash
145+
docker compose up -d
146+
```
147+
148+
#### Configuración mediante variables de entorno
149+
150+
En lugar de editar `js/config.js`, los despliegues con Docker se configuran mediante variables de entorno, ya sea en el fichero `.env` o en el bloque `environment:` de tu fichero Compose:
151+
152+
| Variable | Valor por defecto | Descripción |
153+
|---|---|---|
154+
| `GAS_PROXY_URL` | _(vacío)_ | URL del proxy de Google Apps Script para Google Drive |
155+
| `AUTO_RESTORE_CONTENT` | `true` | Restaurar el último contenido visto al cargar la página |
156+
| `OPEN_EXTERNAL_LINKS_IN_NEW_WINDOW` | `true` | Abrir los enlaces externos en una pestaña nueva |
157+
| `VALIDATE_EXE_CONTENT` | `true` | Rechazar ZIP que no sean paquetes eXeLearning válidos |
158+
| `ALLOW_DOWNLOAD_BY_DEFAULT` | `true` | Mostrar el botón de descarga activado por defecto en el diálogo de compartir |
159+
160+
Las variables no definidas en `.env` conservan sus valores por defecto; solo es necesario incluir las que se quieran cambiar.
161+
162+
#### HTTPS
163+
164+
**HTTPS es obligatorio.** El Service Worker (el mecanismo central que sirve el contenido ZIP extraído) no se registra en orígenes no seguros. Es una restricción del navegador, no de eXeViewer. La única excepción es `localhost`, que funciona sin HTTPS para desarrollo local.
165+
166+
En despliegues en producción, asegúrate de que TLS se termina antes de que la petición llegue al navegador. Lo más habitual es un proxy inverso delante del contenedor (Nginx, Traefik, Caddy, etc.), pero también funcionan los balanceadores de carga o cualquier otro punto de terminación TLS.
167+
120168
### Ejecución local sin servidor web
121169

122170
Si no tienes un servidor web instalado, puedes usar el `server.js` incluido:
@@ -261,26 +309,32 @@ Firefox no soporta la instalación de PWA de forma nativa. Usa la extensión [PW
261309

262310
```
263311
exeviewer/
264-
├── index.html # Página principal de la aplicación
265-
├── manifest.json # Manifiesto PWA
266-
├── sw.js # Service Worker
267-
├── server.js # Servidor de desarrollo (Bun/Node.js)
268-
├── package.json # Configuración del proyecto
312+
├── index.html # Página principal de la aplicación
313+
├── manifest.json # Manifiesto PWA
314+
├── sw.js # Service Worker
315+
├── server.js # Servidor de desarrollo (Bun/Node.js)
316+
├── package.json # Configuración del proyecto
317+
├── Dockerfile # Definición de la imagen Docker
318+
├── nginx.conf # Configuración de nginx para la imagen Docker
319+
├── docker-compose.yml # Ejemplo de Docker Compose
320+
├── .env.dist # Plantilla de variables de entorno para despliegues Docker
321+
├── docker/
322+
│ └── entrypoint.sh # Genera js/config.js a partir de variables de entorno al arrancar
269323
├── css/
270-
│ └── styles.css # Estilos personalizados
324+
│ └── styles.css # Estilos personalizados
271325
├── js/
272-
│ ├── app.js # Lógica principal de la aplicación
273-
│ ├── config.js # Configuración del despliegue (sobreescribe los valores por defecto de app.js)
274-
│ ├── i18n.js # Módulo de internacionalización
275-
│ └── zip.worker.js # Web Worker para extracción ZIP
326+
│ ├── app.js # Lógica principal de la aplicación
327+
│ ├── config.js # Configuración del despliegue (sobreescribe los valores por defecto de app.js)
328+
│ ├── i18n.js # Módulo de internacionalización
329+
│ └── zip.worker.js # Web Worker para extracción ZIP
276330
├── lang/
277-
│ ├── en.json # Traducciones en inglés
278-
│ └── es.json # Traducciones en español
279-
├── img/ # Iconos e imágenes
280-
├── vendor/ # Bibliotecas de terceros
281-
│ ├── bootstrap/ # Bootstrap 5.3.2
282-
│ ├── bootstrap-icons/# Bootstrap Icons 1.11.1
283-
│ └── fflate/ # fflate 0.8.2
331+
│ ├── en.json # Traducciones en inglés
332+
│ └── es.json # Traducciones en español
333+
├── img/ # Iconos e imágenes
334+
├── vendor/ # Bibliotecas de terceros
335+
│ ├── bootstrap/ # Bootstrap 5.3.2
336+
│ ├── bootstrap-icons/ # Bootstrap Icons 1.11.1
337+
│ └── fflate/ # fflate 0.8.2
284338
└── scripts/
285339
└── generate-icons.js # Script de generación de iconos (requiere Node.js + sharp)
286340
```

docker-compose.yml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
services:
2+
exeviewer:
3+
image: ghcr.io/exelearning/exeviewer:latest
4+
ports:
5+
- "8080:80"
6+
env_file:
7+
- .env
8+
restart: unless-stopped

docker/entrypoint.sh

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
#!/bin/sh
2+
set -e
3+
4+
# Generate js/config.js from environment variables at container startup.
5+
# Any value not set in the environment keeps the application default (see js/app.js).
6+
cat > /usr/share/nginx/html/js/config.js <<EOF
7+
window.exeViewerConfig = {
8+
gasProxyUrl: '${GAS_PROXY_URL:-}',
9+
autoRestoreContent: ${AUTO_RESTORE_CONTENT:-true},
10+
openExternalLinksInNewWindow: ${OPEN_EXTERNAL_LINKS_IN_NEW_WINDOW:-true},
11+
validateExeContent: ${VALIDATE_EXE_CONTENT:-true},
12+
allowDownloadByDefault: ${ALLOW_DOWNLOAD_BY_DEFAULT:-true}
13+
};
14+
EOF
15+
16+
exec nginx -g 'daemon off;'

0 commit comments

Comments
 (0)