diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 26e4786a3..37ea98417 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -1,8 +1,10 @@ { "name": "listmonk", "dockerComposeFile": "../dev/docker-compose.yml", - "service": "backend", + "service": "devcontainer", "workspaceFolder": "/app", - "forwardPorts": [9000], - "postStartCommand": "make dist && ./listmonk --install --idempotent --yes --config dev/config.toml" + "runServices": ["adminer", "mailhog", "db", "backend", "front"], + "features": { + "ghcr.io/devcontainers/features/docker-outside-of-docker:1": {} + } } diff --git a/Makefile b/Makefile index 5f82cf54f..e2a5684e4 100644 --- a/Makefile +++ b/Makefile @@ -119,9 +119,12 @@ release-dry: release: goreleaser release --parallelism 1 --clean +# App services for `make dev-docker` (excludes the devcontainer workspace). +DEV_DOCKER_SERVICES = adminer mailhog db backend front + # Build local docker images for development. .PHONY: build-dev-docker -build-dev-docker: build ## Build docker containers for the entire suite (Front/Core/PG). +build-dev-docker: ## Build docker containers for the entire suite (Front/Core/PG). cd dev; \ docker compose build ; \ @@ -129,21 +132,28 @@ build-dev-docker: build ## Build docker containers for the entire suite (Front/C .PHONY: dev-docker dev-docker: build-dev-docker ## Build and spawns docker containers for the entire suite (Front/Core/PG). cd dev; \ - docker compose up + docker compose up $(DEV_DOCKER_SERVICES) # Run the backend in docker-dev mode. The frontend assets in dev mode are loaded from disk from frontend/dist. .PHONY: run-backend-docker run-backend-docker: CGO_ENABLED=0 go run -ldflags="-s -w -X 'main.buildString=${BUILDSTR}' -X 'main.versionString=${VERSION}' -X 'main.frontendDir=frontend/dist'" ./cmd --config=dev/config.toml +# Build assets and install the DB schema for the docker dev suite. +.PHONY: init-docker +init-docker: + @test -d frontend/dist || $(MAKE) build-frontend + @test -f $(BIN) || $(MAKE) build + ./listmonk --install --idempotent --yes --config dev/config.toml + # Tear down the complete local development docker suite. .PHONY: rm-dev-docker -rm-dev-docker: build ## Delete the docker containers including DB volumes. +rm-dev-docker: ## Delete the docker containers including DB volumes. cd dev; \ docker compose down -v ; \ # Setup the db for local dev docker suite. .PHONY: init-dev-docker -init-dev-docker: build-dev-docker ## Delete the docker containers including DB volumes. +init-dev-docker: build-dev-docker ## Build assets and install the DB schema in docker. cd dev; \ - docker compose run --rm backend sh -c "make dist && ./listmonk --install --idempotent --yes --config dev/config.toml" + docker compose run --rm init diff --git a/dev/app.Dockerfile b/dev/app.Dockerfile index 3afcc8c42..8f22a358b 100644 --- a/dev/app.Dockerfile +++ b/dev/app.Dockerfile @@ -1,6 +1,6 @@ FROM golang:1.24.1 AS go -FROM node:16 AS node +FROM node:24 AS node COPY --from=go /usr/local/go /usr/local/go ENV GOPATH /go diff --git a/dev/docker-compose.yml b/dev/docker-compose.yml index 080c98d1a..c5f0b696a 100644 --- a/dev/docker-compose.yml +++ b/dev/docker-compose.yml @@ -33,6 +33,21 @@ services: source: listmonk-dev-db target: /var/lib/postgresql/data + init: + build: + context: ../ + dockerfile: dev/app.Dockerfile + command: ["make", "init-docker"] + depends_on: + db: + condition: service_started + volumes: + - ../:/app + - ${GOPATH:-${HOME}/go}/pkg/mod/cache:/go/pkg/mod/cache + networks: + - listmonk-dev + restart: "no" + front: build: context: ../ @@ -42,6 +57,7 @@ services: - "8080:8080" environment: - LISTMONK_API_URL=http://backend:9000 + - LISTMONK_VITE_HOST=true depends_on: - db volumes: @@ -57,13 +73,34 @@ services: ports: - "9000:9000" depends_on: - - db + db: + condition: service_started + init: + condition: service_completed_successfully volumes: - ../:/app - ${GOPATH:-${HOME}/go}/pkg/mod/cache:/go/pkg/mod/cache networks: - listmonk-dev + # Workspace container for VS Code / Cursor devcontainers. Omitted from + # `make dev-docker`; the editor starts this service when reopening in container. + devcontainer: + image: dev-devcontainer + build: + context: ../ + dockerfile: dev/app.Dockerfile + command: ["sleep", "infinity"] + volumes: + - ../:/app + - ${GOPATH:-${HOME}/go}/pkg/mod/cache:/go/pkg/mod/cache + - /var/run/docker.sock:/var/run/docker.sock + depends_on: + db: + condition: service_started + networks: + - listmonk-dev + volumes: listmonk-dev-db: diff --git a/docs/docs/content/developer-setup.md b/docs/docs/content/developer-setup.md index 58137329c..0de551367 100644 --- a/docs/docs/content/developer-setup.md +++ b/docs/docs/content/developer-setup.md @@ -30,8 +30,7 @@ After setting up the dev environment, you can visit `http://localhost:8080`. 2. Inside containers (Using Makefile) - - Run `make init-dev-docker` to setup container for db. - - Run `make dev-docker` to setup docker container suite. + - Run `make dev-docker` to build and start the docker container suite. - Run `make rm-dev-docker` to clean up docker container suite. 3. Inside containers (Using devcontainer) diff --git a/frontend/.env.sample b/frontend/.env.sample index 367c37a82..91f253079 100644 --- a/frontend/.env.sample +++ b/frontend/.env.sample @@ -1,2 +1,4 @@ LISTMONK_FRONTEND_PORT=8080 LISTMONK_API_URL="http://127.0.0.1:9000" +# Bind Vite to 0.0.0.0 (required for Docker port publishing). Set by dev/docker-compose.yml. +# LISTMONK_VITE_HOST=true diff --git a/frontend/vite.config.js b/frontend/vite.config.js index 4a45f7e5c..f3e19a7cf 100644 --- a/frontend/vite.config.js +++ b/frontend/vite.config.js @@ -21,6 +21,7 @@ export default defineConfig(({ _, mode }) => { }, server: { port: env.LISTMONK_FRONTEND_PORT || 8080, + host: env.LISTMONK_VITE_HOST === 'true', proxy: { '^/$': { target: env.LISTMONK_API_URL || 'http://127.0.0.1:9000',