diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml
index f10a034..2832688 100644
--- a/.github/workflows/pr.yml
+++ b/.github/workflows/pr.yml
@@ -45,5 +45,6 @@ jobs:
with:
push: true
tags: rmcampos/tasknote:${{ github.event.number }}
+ build-args: BUILD=${{ github.event.number }}
cache-from: type=gha
cache-to: type=gha,mode=max
diff --git a/Caddyfile b/Caddyfile
new file mode 100644
index 0000000..ba30628
--- /dev/null
+++ b/Caddyfile
@@ -0,0 +1,57 @@
+{
+ auto_https off
+ admin off
+}
+
+:5000 {
+ root * /app/dist
+
+ encode gzip
+
+ log {
+ output stdout
+ format console {
+ time_format iso8601
+ level_format color
+ }
+ level "{$LOG_LEVEL}"
+ }
+
+ header {
+ X-Frame-Options "SAMEORIGIN"
+ X-XSS-Protection "1;mode=block"
+ Cache-Control "no-store, no-cache, must-revalidate, proxy-revalidate"
+ X-Content-Type-Options "nosniff"
+ Strict-Transport-Security "max-age=31536000"
+ Content-Security-Policy "
+ base-uri 'self';
+ connect-src 'self';
+ default-src 'self';
+ font-src https://cdn.jsdelivr.net/npm/ 'self';
+ frame-src 'self';
+ img-src 'self';
+ manifest-src 'self';
+ media-src 'self';
+ object-src 'none';
+ script-src 'unsafe-inline' 'report-sample' 'self';
+ style-src https://cdn.jsdelivr.net/npm/ 'report-sample' 'self';
+ worker-src 'none';
+ "
+ Referrer-Policy "same-origin"
+ }
+
+ handle /env.js {
+ header Content-Type "text/javascript"
+ respond `window.config = {"BUILD":"{$BUILD}"};`
+ }
+
+ file_server
+
+ handle_errors {
+ @404 {
+ expression {http.error.status_code} == 404
+ }
+ rewrite @404 /
+ file_server
+ }
+}
diff --git a/Dockerfile b/Dockerfile
new file mode 100644
index 0000000..938292c
--- /dev/null
+++ b/Dockerfile
@@ -0,0 +1,32 @@
+# Build static files
+# Node Bullseye has npm
+FROM node:20.17-bullseye-slim AS build
+ENV NODE_OPTIONS="--max-old-space-size=3072"
+
+# Build
+WORKDIR /app
+COPY *.html *.json *.ts ./
+COPY ./src ./src
+COPY ./public ./public
+RUN npm ci --ignore-scripts --no-update-notifier --omit=dev && \
+ npm run build && \
+ rm -rf node_modules
+
+# Deploy container
+# Caddy serves static files
+FROM caddy:2.8.4-alpine
+RUN apk add --no-cache ca-certificates curl
+
+# Receive build number as argument, retain as environment variable
+ARG BUILD
+ENV BUILD=${BUILD}
+
+# Copy files and run formatting
+COPY --from=build /app/dist/ /app/dist
+COPY Caddyfile /etc/caddy/Caddyfile
+RUN caddy fmt --overwrite /etc/caddy/Caddyfile
+
+# User, port and healthcheck
+EXPOSE 5000
+HEALTHCHECK CMD curl -f http://localhost:5000
+USER 1001
diff --git a/README.md b/README.md
index 86a4151..7ea3ac4 100644
--- a/README.md
+++ b/README.md
@@ -69,7 +69,7 @@ Contributions are what make the open-source community such an amazing place to l
## 📄 License
-Distributed under the MIT License. See `LICENSE` for more information.
+Distributed under GPLv3 License. See `LICENSE` for more information.
## 📞 Contact
diff --git a/docker-compose.yml b/docker-compose.yml
new file mode 100644
index 0000000..1e86a86
--- /dev/null
+++ b/docker-compose.yml
@@ -0,0 +1,36 @@
+---
+
+services:
+ tasknote:
+ container_name: tasknote
+ profiles:
+ - "dev"
+ image: node:20.17-bullseye-slim
+ ports:
+ - "5000:5000"
+ entrypoint: sh -c "npm i --no-update-notifier && npm start"
+ user: root
+ volumes:
+ - "./:/app"
+ working_dir: /app
+ environment:
+ LOG_LEVEL: debug
+ healthcheck:
+ test: timeout 10s bash -c 'true > /dev/tcp/127.0.0.1/3000'
+
+ caddy:
+ container_name: caddy
+ profiles:
+ - "caddy"
+ build:
+ context: .
+ args:
+ BUILD: nightly
+ ports:
+ - "80:5000"
+ volumes:
+ - "./Caddyfile:/etc/caddy/Caddyfile"
+ environment:
+ LOG_LEVEL: debug
+ healthcheck:
+ test: timeout 10s bash -c 'true > /dev/tcp/127.0.0.1/3000'
diff --git a/src/components/Footer.tsx b/src/components/Footer.tsx
index bf4f5a0..440f433 100644
--- a/src/components/Footer.tsx
+++ b/src/components/Footer.tsx
@@ -1,14 +1,20 @@
import React from 'react';
import style from './Footer.module.css';
+import { env } from '../env';
-const Footer = () => (
-
-);
+const Footer = () => {
+ const build = env.BUILD;
+
+ return (
+
+ );
+};
export default Footer;
diff --git a/tools.md b/tools.md
index e8f1956..45d08c8 100644
--- a/tools.md
+++ b/tools.md
@@ -3,3 +3,22 @@
- **TaskNote:** https://tasknote.local
- **Docker Hub:** https://hub.docker.com/
- **Time tracking:** https://track.toggl.com/timer
+
+# Building locally
+
+Build with Docker:
+
+```sh
+docker build --build-arg BUILD=nightly -t tasknote:nightly .
+```
+
+Run with Docker:
+```sh
+docker run -it --rm \
+ --name tasknote \
+ tasknote:nightly
+```
+Build and run with Docker Compose:
+```sh
+docker compose --profile caddy up --build
+```
diff --git a/vite.config.ts b/vite.config.ts
index 0fbe8d1..33be9da 100644
--- a/vite.config.ts
+++ b/vite.config.ts
@@ -5,7 +5,27 @@ import { fileURLToPath } from 'url';
export default defineConfig(({ mode }: ConfigEnv) => {
const config: UserConfig = {
define: {} as any,
- plugins: [react()],
+ plugins: [
+ react(),
+ {
+ name: 'build-html',
+ apply: 'build',
+ transformIndexHtml: (html) => {
+ return {
+ html,
+ tags: [
+ {
+ tag: 'script',
+ attrs: {
+ src: '/env.js'
+ },
+ injectTo: 'head'
+ }
+ ]
+ }
+ }
+ }
+ ],
build: {
outDir: 'dist',
sourcemap: true