serve frontend + backend as a one binary

This commit is contained in:
Ankit Patial 2024-11-19 17:16:36 +05:30
parent 5954ec2501
commit e378db58b8
14 changed files with 87 additions and 26 deletions

View File

@ -7,13 +7,15 @@ package main
import ( import (
"fmt" "fmt"
"net/http" "net/http"
"strings"
"gitserver.in/patialtech/mux" "gitserver.in/patialtech/mux"
"gitserver.in/patialtech/mux/middleware" "gitserver.in/patialtech/mux/middleware"
"gitserver.in/patialtech/rano/cmd/server/handler" "gitserver.in/patialtech/rano/bin/server/handler"
"gitserver.in/patialtech/rano/config" "gitserver.in/patialtech/rano/config"
"gitserver.in/patialtech/rano/graph" "gitserver.in/patialtech/rano/graph"
"gitserver.in/patialtech/rano/util/logger" "gitserver.in/patialtech/rano/util/logger"
"gitserver.in/patialtech/rano/web"
) )
func main() { func main() {
@ -24,6 +26,7 @@ func main() {
// CORS // CORS
r.Use(middleware.CORS(middleware.CORSOption{ r.Use(middleware.CORS(middleware.CORSOption{
AllowedHeaders: []string{"Content-Type"}, AllowedHeaders: []string{"Content-Type"},
AllowedOrigins: []string{config.Read().WebURL},
MaxAge: 60, MaxAge: 60,
})) }))
// Secure Headers // Secure Headers
@ -40,7 +43,37 @@ func main() {
// catch all // catch all
r.GET("/", func(w http.ResponseWriter, r *http.Request) { r.GET("/", func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("hello there")) var (
resourcePath string
path = r.URL.Path
)
if strings.HasPrefix(path, "/_app") {
resourcePath = "public/build" + path
} else if strings.HasSuffix(path, ".png") ||
strings.HasSuffix(path, ".ico") ||
strings.HasSuffix(path, ".svg") ||
strings.HasSuffix(path, "robot.txt") ||
strings.HasSuffix(path, "site.webmanifest") {
resourcePath = "public" + path
} else {
resourcePath = "public/build/fallback.html"
}
if b, err := web.Public.ReadFile(resourcePath); err != nil {
_, _ = w.Write([]byte("hello there"))
} else {
if strings.HasSuffix(path, ".js") {
w.Header().Set("Content-Type", "text/javascript")
} else if strings.HasSuffix(path, ".css") {
w.Header().Set("Content-Type", "text/css")
} else {
w.Header().Set("Content-Type", http.DetectContentType(b))
}
w.WriteHeader(http.StatusOK)
_, _ = w.Write(b)
}
}) })
r.Serve(func(srv *http.Server) error { r.Serve(func(srv *http.Server) error {

View File

@ -19,16 +19,12 @@ import (
const ( const (
// projDir need to be same as project code root dir name // projDir need to be same as project code root dir name
projDir = "rano" projDir = "rano"
EnvDev = "development"
EnvProd = "production"
EnvStage = "staging"
AuthUserCtxKey = "AuthUser" AuthUserCtxKey = "AuthUser"
) )
var ( var (
conf *Config conf *Config
AppEnv Env = EnvDev AppEnv = "development" // production | staging
) )
type ( type (
@ -47,7 +43,7 @@ type (
func init() { func init() {
var base string var base string
if AppEnv == EnvDev { if AppEnv == "development" { // AppEnv will be changed on build time using ldflags -X
wd, _ := os.Getwd() wd, _ := os.Getwd()
idx := strings.Index(wd, projDir) idx := strings.Index(wd, projDir)
if idx > -1 { if idx > -1 {
@ -57,6 +53,8 @@ func init() {
base, _ = os.Executable() base, _ = os.Executable()
} }
logger.Info("*** %s", AppEnv)
envVar, err := dotenv.Read(base, fmt.Sprintf(".env.%s", AppEnv)) envVar, err := dotenv.Read(base, fmt.Sprintf(".env.%s", AppEnv))
if err != nil { if err != nil {
panic(err) panic(err)

View File

@ -1,7 +1,5 @@
import path from 'node:path';
import adapter from '@sveltejs/adapter-static'; import adapter from '@sveltejs/adapter-static';
const webDir = path.resolve('.', 'web');
/** @type {import('@sveltejs/kit').Config} */ /** @type {import('@sveltejs/kit').Config} */
const config = { const config = {
@ -9,16 +7,15 @@ const config = {
// adapter-auto only supports some environments, see https://kit.svelte.dev/docs/adapter-auto for a list. // adapter-auto only supports some environments, see https://kit.svelte.dev/docs/adapter-auto for a list.
// If your environment is not supported, or you settled on a specific environment, switch out the adapter. // If your environment is not supported, or you settled on a specific environment, switch out the adapter.
// See https://kit.svelte.dev/docs/adapters for more information about adapters. // See https://kit.svelte.dev/docs/adapters for more information about adapters.
adapter: adapter(),
files: { files: {
appTemplate: path.resolve(webDir, 'app.html'), appTemplate: "web/app.html" ,
routes: path.resolve(webDir, 'routes'), routes: "web/routes",
lib: path.resolve(webDir, 'lib'), lib: "web/lib",
assets: path.resolve(webDir, 'public') assets: "public/lib"
}, },
alias: { alias: {
$image: path.resolve(webDir, 'assets', 'image'), $image: "web/assets/image",
$svg: path.resolve(webDir, 'assets', 'svg') $svg: "web/assets/svg"
}, },
paths: { paths: {
assets: process.env.ASSETS_HOST ?? '' assets: process.env.ASSETS_HOST ?? ''
@ -28,8 +25,8 @@ const config = {
pollInterval: 1000 * 60 * 1 // 5 minutes pollInterval: 1000 * 60 * 1 // 5 minutes
}, },
adapter: adapter({ adapter: adapter({
pages: path.resolve(webDir, 'public', 'build'), pages: "web/public/build",
assets: path.resolve(webDir, 'public', 'build'), assets: "web/public/build",
fallback: 'fallback.html', fallback: 'fallback.html',
strict: true strict: true
}) })

View File

@ -1,9 +1,12 @@
version: '3' version: '3'
dotenv: ['.env.{{.ENV}}']
env: env:
ENV: development ENV: development
dotenv: ['.env.{{.ENV}}'] vars:
MOD_NAME: gitserver.in/patialtech/rano
tasks: tasks:
install: install:
@ -14,7 +17,7 @@ tasks:
start-graph: start-graph:
desc: run graph server desc: run graph server
cmds: cmds:
- cmd: go run ./cmd/server - cmd: go run ./bin/server
start-web: start-web:
desc: run web in dev mode desc: run web in dev mode
@ -44,11 +47,11 @@ tasks:
- cmd: deno task codegen - cmd: deno task codegen
ent-new: ent-new:
desc: create new db Emtity desc: create new db Entity
cmd: cd ./db && go run -mod=mod entgo.io/ent/cmd/ent new {{.name}} cmd: cd ./db && go run -mod=mod entry.io/ent/cmd/ent new {{.name}}
ent-gen: ent-gen:
desc: genertate from ent schema desc: generate from ent schema
cmds: cmds:
- go generate ./db/ent - go generate ./db/ent
@ -61,4 +64,17 @@ tasks:
desc: apply automatically migration using Ent schema desc: apply automatically migration using Ent schema
cmds: cmds:
- task: ent-gen - task: ent-gen
- go run ./cmd/migrate-up - go run ./bin/migrate-up
build-web-prod:
desc: apply automatically migration using Ent schema
cmds:
- deno task build
env:
ASSETS_HOST:
build-prod:
desc: apply automatically migration using Ent schema
cmds:
- task: build-web-prod
- CGO_ENABLED=0 go build -trimpath -ldflags "-s -w" -ldflags "-X '{{.MOD_NAME}}/config.AppEnv=production'" -o ./server ./bin/server

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 262 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 548 B

BIN
web/public/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

View File

@ -0,0 +1,11 @@
{
"name": "",
"short_name": "",
"icons": [
{ "src": "/android-chrome-192x192.png", "sizes": "192x192", "type": "image/png" },
{ "src": "/android-chrome-512x512.png", "sizes": "512x512", "type": "image/png" }
],
"theme_color": "#ffffff",
"background_color": "#ffffff",
"display": "standalone"
}

6
web/web.go Normal file
View File

@ -0,0 +1,6 @@
package web
import "embed"
//go:embed public public/build/_app
var Public embed.FS