diff --git a/cmd/program/program.go b/cmd/program/program.go index 95a735fb..77e55b7b 100644 --- a/cmd/program/program.go +++ b/cmd/program/program.go @@ -610,6 +610,21 @@ func (p *Project) CreateMainFile() error { return err } + if p.AdvancedOptions[string(flags.React)] { + NginxConf, err := os.Create(filepath.Join(projectPath, "nginx.conf")) + if err != nil { + return err + } + defer NginxConf.Close() + + // inject nginx.conf template + NginxConfTemplate := template.Must(template.New("nginx.conf").Parse(string(advanced.NginxConf()))) + err = NginxConfTemplate.Execute(NginxConf, p) + if err != nil { + return err + } + } + if p.DBDriver == "none" || p.DBDriver == "sqlite" { Dockercompose, err := os.Create(filepath.Join(projectPath, "docker-compose.yml")) diff --git a/cmd/template/advanced/docker.go b/cmd/template/advanced/docker.go index 85adf1ed..31770754 100644 --- a/cmd/template/advanced/docker.go +++ b/cmd/template/advanced/docker.go @@ -10,6 +10,9 @@ var dockerfileTemplate []byte //go:embed files/docker/docker_compose.yml.tmpl var dockerComposeTemplate []byte +//go:embed files/docker/nginx.conf.tmpl +var nginxConfTemplate []byte + func Dockerfile() []byte { return dockerfileTemplate } @@ -17,3 +20,7 @@ func Dockerfile() []byte { func DockerCompose() []byte { return dockerComposeTemplate } + +func NginxConf() []byte { + return nginxConfTemplate +} diff --git a/cmd/template/advanced/files/docker/docker_compose.yml.tmpl b/cmd/template/advanced/files/docker/docker_compose.yml.tmpl index 48edb7b4..9bd97dc0 100644 --- a/cmd/template/advanced/files/docker/docker_compose.yml.tmpl +++ b/cmd/template/advanced/files/docker/docker_compose.yml.tmpl @@ -23,7 +23,7 @@ services: target: frontend restart: unless-stopped ports: - - 5173:5173 + - 80:80 depends_on: - app {{- end }} diff --git a/cmd/template/advanced/files/docker/dockerfile.tmpl b/cmd/template/advanced/files/docker/dockerfile.tmpl index 961b5a56..2bbdedbb 100644 --- a/cmd/template/advanced/files/docker/dockerfile.tmpl +++ b/cmd/template/advanced/files/docker/dockerfile.tmpl @@ -38,9 +38,8 @@ RUN npm install COPY frontend/. . RUN npm run build -FROM node:23-slim AS frontend -RUN npm install -g serve -COPY --from=frontend_builder /frontend/dist /app/dist -EXPOSE 5173 -CMD ["serve", "-s", "/app/dist", "-l", "5173"] +FROM nginx:alpine AS frontend +COPY --from=frontend_builder /frontend/dist /usr/share/nginx/html +COPY nginx.conf /etc/nginx/conf.d/default.conf +EXPOSE 80 {{- end}} diff --git a/cmd/template/advanced/files/docker/nginx.conf.tmpl b/cmd/template/advanced/files/docker/nginx.conf.tmpl new file mode 100644 index 00000000..7a16215b --- /dev/null +++ b/cmd/template/advanced/files/docker/nginx.conf.tmpl @@ -0,0 +1,29 @@ +server { + listen 80; + server_name _; + root /usr/share/nginx/html; + index index.html; + + location ~* \.(?:css|js|jpg|jpeg|gif|png|ico|cur|gz|svg|svgz|mp4|ogg|ogv|webm|htc)$ { + expires 1M; + access_log off; + add_header Cache-Control "public"; + } + + location / { + try_files $uri $uri/ /index.html; + add_header Cache-Control "no-store, no-cache, must-revalidate"; + } + + location /health { + access_log off; + return 200 'healthy\n'; + } + + gzip on; + gzip_vary on; + gzip_min_length 10240; + gzip_proxied expired no-cache no-store private auth; + gzip_types text/plain text/css text/xml text/javascript application/x-javascript application/xml; + gzip_disable "MSIE [1-6]\."; +} diff --git a/cmd/template/docker/files/docker-compose/mongo.tmpl b/cmd/template/docker/files/docker-compose/mongo.tmpl index 9da016df..526f88f3 100644 --- a/cmd/template/docker/files/docker-compose/mongo.tmpl +++ b/cmd/template/docker/files/docker-compose/mongo.tmpl @@ -31,7 +31,7 @@ services: depends_on: - app ports: - - 5173:5173 + - 80:80 networks: - blueprint {{- end }} diff --git a/cmd/template/docker/files/docker-compose/mysql.tmpl b/cmd/template/docker/files/docker-compose/mysql.tmpl index ad748567..47020a80 100644 --- a/cmd/template/docker/files/docker-compose/mysql.tmpl +++ b/cmd/template/docker/files/docker-compose/mysql.tmpl @@ -32,7 +32,7 @@ services: depends_on: - app ports: - - 5173:5173 + - 80:80 networks: - blueprint {{- end }} diff --git a/cmd/template/docker/files/docker-compose/postgres.tmpl b/cmd/template/docker/files/docker-compose/postgres.tmpl index 638f31a3..e536125f 100644 --- a/cmd/template/docker/files/docker-compose/postgres.tmpl +++ b/cmd/template/docker/files/docker-compose/postgres.tmpl @@ -33,7 +33,7 @@ services: depends_on: - app ports: - - 5173:5173 + - 80:80 networks: - blueprint {{- end }} diff --git a/cmd/template/docker/files/docker-compose/redis.tmpl b/cmd/template/docker/files/docker-compose/redis.tmpl index 73bdf48a..0444a230 100644 --- a/cmd/template/docker/files/docker-compose/redis.tmpl +++ b/cmd/template/docker/files/docker-compose/redis.tmpl @@ -31,7 +31,7 @@ services: depends_on: - app ports: - - 5173:5173 + - 80:80 networks: - blueprint {{- end }} diff --git a/cmd/template/docker/files/docker-compose/scylla.tmpl b/cmd/template/docker/files/docker-compose/scylla.tmpl index 682a0193..3cc4b368 100644 --- a/cmd/template/docker/files/docker-compose/scylla.tmpl +++ b/cmd/template/docker/files/docker-compose/scylla.tmpl @@ -34,7 +34,7 @@ services: depends_on: - app ports: - - 5173:5173 + - 80:80 networks: - blueprint {{- end }} @@ -67,4 +67,4 @@ volumes: {{- if .AdvancedOptions.docker }} networks: blueprint: -{{- end }} \ No newline at end of file +{{- end }} diff --git a/cmd/template/framework/files/routes/gin.go.tmpl b/cmd/template/framework/files/routes/gin.go.tmpl index 774c844c..dab11c48 100644 --- a/cmd/template/framework/files/routes/gin.go.tmpl +++ b/cmd/template/framework/files/routes/gin.go.tmpl @@ -18,7 +18,7 @@ func (s *Server) RegisterRoutes() http.Handler { r := gin.Default() r.Use(cors.New(cors.Config{ - AllowOrigins: []string{"http://localhost:5173"}, // Add your frontend URL + AllowOrigins: []string{"http://localhost"}, // Add your frontend URL AllowMethods: []string{"GET", "POST", "PUT", "DELETE", "OPTIONS", "PATCH"}, AllowHeaders: []string{"Accept", "Authorization", "Content-Type"}, AllowCredentials: true, // Enable cookies/auth diff --git a/contributors.yml b/contributors.yml index 166e9eec..b03898c0 100644 --- a/contributors.yml +++ b/contributors.yml @@ -15,8 +15,10 @@ - joshjms - brijesh-amin - briancbarrow +- arafays - LrsK - juleszs +- Sakelig - vadhe - Patel-Raj - PrajvalBadiger @@ -24,13 +26,13 @@ - pellizzetti - Owbird - Jamlie +- alexandear - NimishKashyap - narasaka - mubashiroliyantakath -- abhishekmj303 -- Sakelig - reavessm - young-steveo +- sibteali786 - tomasohCHOM - vinitparekh17 - vsnaichuk @@ -39,6 +41,7 @@ - nhlmg93 - rustafariandev - s0up4200 +- abhishekmj303 - alexanderilyin - Yoquec - jexroid @@ -52,6 +55,7 @@ - Echo5678 - EinarLogi - eric-jacobson +- KennyMwendwaX - KibuuleNoah - LarsArtmann - mdelapenya diff --git a/docs/docs/advanced-flag/docker.md b/docs/docs/advanced-flag/docker.md index 3f250ef5..9201354b 100644 --- a/docs/docs/advanced-flag/docker.md +++ b/docs/docs/advanced-flag/docker.md @@ -59,11 +59,10 @@ RUN npm install COPY frontend/. . RUN npm run build -FROM node:20-slim AS frontend -RUN npm install -g serve -COPY --from=frontend_builder /frontend/dist /app/dist -EXPOSE 5173 -CMD ["serve", "-s", "/app/dist", "-l", "5173"] +FROM nginx:alpine AS frontend +COPY --from=frontend_builder /frontend/dist /usr/share/nginx/html +COPY nginx.conf /etc/nginx/conf.d/default.conf +EXPOSE 80 ``` ## Docker compose Docker and docker-compose.yml pull environment variables from the .env file. diff --git a/docs/docs/advanced-flag/react-vite.md b/docs/docs/advanced-flag/react-vite.md index e1f59485..b74dad1d 100644 --- a/docs/docs/advanced-flag/react-vite.md +++ b/docs/docs/advanced-flag/react-vite.md @@ -56,7 +56,7 @@ npm install npm run dev ``` - You should now be able to access the React application by opening a browser and navigating to `http://localhost:5173`. + You should now be able to access the React application by opening a browser and navigating to `http://localhost`. You can extend the `vite.config.ts` to include additional configurations as needed, such as adding plugins for optimizing the build process, enabling TypeScript support, or configuring Tailwind CSS. @@ -113,11 +113,10 @@ RUN npm install COPY frontend/. . RUN npm run build -FROM node:20-slim AS frontend -RUN npm install -g serve -COPY --from=frontend_builder /frontend/dist /app/dist -EXPOSE 5173 -CMD ["serve", "-s", "/app/dist", "-l", "5173"] +FROM nginx:alpine AS frontend +COPY --from=frontend_builder /frontend/dist /usr/share/nginx/html +COPY nginx.conf /etc/nginx/conf.d/default.conf +EXPOSE 80 ``` ### Docker compose without db @@ -142,7 +141,7 @@ services: target: frontend restart: unless-stopped ports: - - 5173:5173 + - 80:80 depends_on: - app ``` @@ -182,7 +181,7 @@ services: depends_on: - app ports: - - 5173:5173 + - 80:80 networks: - blueprint psql_bp: @@ -213,4 +212,43 @@ networks: ## Environment Variables -The `VITE_PORT` in .env refers `PORT` from .env in project root ( for backend ). If value of `PORT` is changed than `VITE_PORT` must also be changed so that requests to backend work fine and have no conflicts. \ No newline at end of file +The `VITE_PORT` in .env refers `PORT` from .env in project root ( for backend ). If value of `PORT` is changed than `VITE_PORT` must also be changed so that requests to backend work fine and have no conflicts. + +## Nginx configuration + +In our second iteration, we moved from [serve](https://www.npmjs.com/package/serve) to using Nginx configuration for serving the Vite React frontend when the React advanced flag is paired with Docker. + +[Nginx](https://nginx.org/en/) is a highly efficient, fast, secure, and production-ready web server. +The frontend and backend are separated, which provides granular control over resources, autoscaling, rolling updates, and fault isolation. This separation also simplifies scaling specific components and removes the need to redeploy the backend if only the frontend changes, and vice versa. + +```bash +server { + listen 80; + server_name _; + root /usr/share/nginx/html; + index index.html; + + location ~* \.(?:css|js|jpg|jpeg|gif|png|ico|cur|gz|svg|svgz|mp4|ogg|ogv|webm|htc)$ { + expires 1M; + access_log off; + add_header Cache-Control "public"; + } + + location / { + try_files $uri $uri/ /index.html; + add_header Cache-Control "no-store, no-cache, must-revalidate"; + } + + location /health { + access_log off; + return 200 'healthy\n'; + } + + gzip on; + gzip_vary on; + gzip_min_length 10240; + gzip_proxied expired no-cache no-store private auth; + gzip_types text/plain text/css text/xml text/javascript application/x-javascript application/xml; + gzip_disable "MSIE [1-6]\."; +} +``` diff --git a/docs/docs/index.md b/docs/docs/index.md index 39e0fd00..2b57052a 100644 --- a/docs/docs/index.md +++ b/docs/docs/index.md @@ -88,6 +88,7 @@ Here's an overview of the project structure created by Go Blueprint when all opt ├── go.sum # Go module file containing checksums for dependencies. ├── Makefile # Makefile for defining and running commands. ├── tailwind.config.js # Tailwind CSS configuration file for HTMX. +├── nginx.conf # Nginx configuration for serving a React frontend when used with the Docker advanced flag. └── README.md # Project's README file containing essential information about the project. ```