├── .dockerignore ├── .gitignore ├── Dockerfile ├── Makefile ├── README.md ├── cmd ├── echo │ └── main.go ├── fiber │ └── main.go └── http │ └── main.go ├── frontend ├── .gitignore ├── .npmrc ├── README.md ├── frontend.go ├── package.json ├── pnpm-lock.yaml ├── src │ ├── app.html │ ├── global.css │ ├── lib │ │ └── index.js │ └── routes │ │ ├── +error.svelte │ │ ├── +layout.svelte │ │ ├── +page.svelte │ │ └── about │ │ └── +page.svelte ├── static │ └── favicon.png ├── svelte.config.js └── vite.config.js ├── go.mod └── go.sum /.dockerignore: -------------------------------------------------------------------------------- 1 | /* 2 | !/cmd 3 | !/frontend 4 | /frontend/.svelte-kit 5 | /frontend/build 6 | /frontend/node_modules 7 | /frontend/.gitignore 8 | /frontend/.npmrc 9 | /frontend/README.md 10 | !go.mod 11 | !go.sum -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # OS or Editor folders 2 | _* 3 | ._* 4 | *.test 5 | .cache 6 | .DS_Store 7 | nbproject 8 | Thumbs.db 9 | 10 | # Binary file 11 | http 12 | echo 13 | fiber -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | # syntax=docker/dockerfile:1.2 2 | 3 | # Stage 1: Build the static files 4 | FROM node:20.5.1-alpine3.18 AS frontend-builder 5 | WORKDIR /frontend 6 | COPY /frontend/package.json /frontend/pnpm-lock.yaml ./ 7 | RUN npm install -g pnpm 8 | RUN pnpm install --frozen-lockfile 9 | COPY /frontend . 10 | RUN npm run build 11 | 12 | # Stage 2: Build the binary 13 | FROM golang:1.21.0-alpine3.18 AS binary-builder 14 | ARG APP_NAME=http 15 | RUN apk update && apk upgrade && apk --update add git upx 16 | WORKDIR /builder 17 | COPY go.mod go.sum ./ 18 | RUN go mod download 19 | COPY . . 20 | COPY --from=frontend-builder /frontend/build ./frontend/build 21 | RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build \ 22 | -ldflags='-w -s -extldflags "-static"' -a \ 23 | -o engine ./cmd/${APP_NAME}/main.go && upx -9 engine 24 | 25 | # Stage 3: Run the binary 26 | FROM gcr.io/distroless/static 27 | ENV APP_PORT=5050 28 | WORKDIR /app 29 | COPY --from=binary-builder --chown=nonroot:nonroot /builder/engine . 30 | ENTRYPOINT ["./engine"] -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | FRONTEND_DIR=frontend 2 | BUILD_DIR=build 3 | APP_NAME=http 4 | APP_PORT=5050 5 | NETWORK=bridge 6 | 7 | clean: 8 | cd $(FRONTEND_DIR); \ 9 | if [ -d $(BUILD_DIR) ]; then rm -rf $(BUILD_DIR); fi 10 | 11 | static: clean 12 | cd $(FRONTEND_DIR); \ 13 | pnpm i; \ 14 | pnpm build 15 | 16 | build: clean 17 | DOCKER_BUILDKIT=1 docker build \ 18 | -t spa:$(APP_NAME) \ 19 | --build-arg APP_NAME=$(APP_NAME) \ 20 | . 21 | 22 | run: 23 | docker run -dp $(APP_PORT):$(APP_PORT) \ 24 | --network $(NETWORK) \ 25 | --name $(APP_NAME) \ 26 | --env APP_PORT=$(APP_PORT) \ 27 | --restart unless-stopped \ 28 | spa:$(APP_NAME) 29 | 30 | stop: 31 | docker rm -f $(APP_NAME) 32 | 33 | .PHONY: clean run build -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Go Embed Single-Page Application 2 | 3 | Although there are many alternatives to deploying a single-page application, you might find a situation where you need to deploy it in an isolated environment or just portability concern. 4 | 5 | The example is using SvelteKit to generate a single-page application and embed it with Golang with Docker multi-stage build for smaller image. 6 | 7 | ## Tech 8 | 9 | - [SvelteKit](https://kit.svelte.dev/ "SvelteKit") 10 | - [Go](https://go.dev/ "Golang") 11 | - [Echo](https://echo.labstack.com/ "Echo Framework") 12 | - [Fiber](https://gofiber.io/ "Fiber Framework") 13 | - [Docker](https://www.docker.com/ "Docker") 14 | 15 | ## Build the image 16 | 17 | Go HTTP standard library 18 | 19 | ```bash 20 | make build 21 | ``` 22 | 23 | Echo framework 24 | 25 | ```bash 26 | make build APP_NAME=echo 27 | ``` 28 | 29 | Fiber framework 30 | 31 | ```bash 32 | make build APP_NAME=fiber 33 | ``` 34 | 35 | ## Run the application 36 | 37 | The default port is `5050`, configure a runnable app port with `APP_PORT=xxxx`. 38 | 39 | Go HTTP standard library 40 | 41 | ```bash 42 | make run 43 | ``` 44 | 45 | Echo framework 46 | 47 | ```bash 48 | make run APP_NAME=echo APP_PORT=5051 49 | ``` 50 | 51 | Fiber framework 52 | 53 | ```bash 54 | make run APP_NAME=fiber APP_PORT=5052 55 | ``` 56 | 57 | ## Update 58 | Reduce the binary size around 50%-70% by using [UPX](https://upx.github.io/). 59 | 60 | Before: 61 | ``` 62 | REPOSITORY TAG IMAGE ID CREATED SIZE 63 | spa fiber ddbdf411532d 7 seconds ago 8.98MB 64 | spa echo f0f144aecd27 53 seconds ago 10.9MB 65 | spa http 1b4f9bd0632b About a minute ago 7.29MB 66 | ``` 67 | After: 68 | ``` 69 | REPOSITORY TAG IMAGE ID CREATED SIZE 70 | spa fiber 6a2d174a176b 6 minutes ago 5.23MB 71 | spa echo a82aa5113481 7 minutes ago 5.79MB 72 | spa http 4248e779a14f 8 minutes ago 4.49MB 73 | ``` -------------------------------------------------------------------------------- /cmd/echo/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "log" 6 | "net/http" 7 | "os" 8 | 9 | "github.com/aprakasa/go-embed-spa/frontend" 10 | "github.com/labstack/echo/v4" 11 | "github.com/labstack/echo/v4/middleware" 12 | ) 13 | 14 | func main() { 15 | app := echo.New() 16 | app.GET("/hello.json", handleHello) 17 | app.Use(middleware.StaticWithConfig(middleware.StaticConfig{ 18 | Filesystem: frontend.BuildHTTPFS(), 19 | HTML5: true, 20 | })) 21 | log.Fatal(app.Start(fmt.Sprintf(":%s", os.Getenv("APP_PORT")))) 22 | } 23 | 24 | func handleHello(c echo.Context) error { 25 | return c.JSON(http.StatusOK, echo.Map{ 26 | "message": "hello from the echo server", 27 | }) 28 | } 29 | -------------------------------------------------------------------------------- /cmd/fiber/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "log" 6 | "os" 7 | 8 | "github.com/aprakasa/go-embed-spa/frontend" 9 | "github.com/gofiber/fiber/v2" 10 | "github.com/gofiber/fiber/v2/middleware/filesystem" 11 | ) 12 | 13 | func main() { 14 | app := fiber.New() 15 | app.Get("/hello.json", handleHello) 16 | app.Use("/", filesystem.New(filesystem.Config{ 17 | Root: frontend.BuildHTTPFS(), 18 | NotFoundFile: "index.html", 19 | })) 20 | log.Fatal(app.Listen(fmt.Sprintf(":%s", os.Getenv("APP_PORT")))) 21 | } 22 | 23 | func handleHello(c *fiber.Ctx) error { 24 | return c.JSON(fiber.Map{"message": "hello from the fiber server"}) 25 | } 26 | -------------------------------------------------------------------------------- /cmd/http/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | "log" 7 | "net/http" 8 | "os" 9 | "path/filepath" 10 | 11 | "github.com/aprakasa/go-embed-spa/frontend" 12 | ) 13 | 14 | func main() { 15 | http.HandleFunc("/hello.json", handleHello) 16 | http.HandleFunc("/", handleSPA) 17 | log.Printf("the server is listening to port %s", os.Getenv("APP_PORT")) 18 | log.Fatal(http.ListenAndServe(fmt.Sprintf(":%s", os.Getenv("APP_PORT")), nil)) 19 | } 20 | 21 | func handleHello(w http.ResponseWriter, r *http.Request) { 22 | res, err := json.Marshal(map[string]string{ 23 | "message": "hello from the server", 24 | }) 25 | if err != nil { 26 | http.Error(w, err.Error(), http.StatusBadRequest) 27 | return 28 | } 29 | w.Header().Set("Content-Type", "application/json") 30 | w.Write(res) 31 | } 32 | 33 | func handleSPA(w http.ResponseWriter, r *http.Request) { 34 | buildPath := "build" 35 | f, err := frontend.BuildFs.Open(filepath.Join(buildPath, r.URL.Path)) 36 | if os.IsNotExist(err) { 37 | index, err := frontend.BuildFs.ReadFile(filepath.Join(buildPath, "index.html")) 38 | if err != nil { 39 | http.Error(w, err.Error(), http.StatusBadRequest) 40 | return 41 | } 42 | w.WriteHeader(http.StatusAccepted) 43 | w.Write(index) 44 | return 45 | } else if err != nil { 46 | http.Error(w, err.Error(), http.StatusInternalServerError) 47 | return 48 | } 49 | defer f.Close() 50 | http.FileServer(frontend.BuildHTTPFS()).ServeHTTP(w, r) 51 | } 52 | -------------------------------------------------------------------------------- /frontend/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /build 4 | /.svelte-kit 5 | /package 6 | .env 7 | .env.* 8 | !.env.example 9 | vite.config.js.timestamp-* 10 | vite.config.ts.timestamp-* 11 | -------------------------------------------------------------------------------- /frontend/.npmrc: -------------------------------------------------------------------------------- 1 | engine-strict=true 2 | resolution-mode=highest 3 | -------------------------------------------------------------------------------- /frontend/README.md: -------------------------------------------------------------------------------- 1 | # create-svelte 2 | 3 | Everything you need to build a Svelte project, powered by [`create-svelte`](https://github.com/sveltejs/kit/tree/master/packages/create-svelte). 4 | 5 | ## Creating a project 6 | 7 | If you're seeing this, you've probably already done this step. Congrats! 8 | 9 | ```bash 10 | # create a new project in the current directory 11 | npm create svelte@latest 12 | 13 | # create a new project in my-app 14 | npm create svelte@latest my-app 15 | ``` 16 | 17 | ## Developing 18 | 19 | Once you've created a project and installed dependencies with `npm install` (or `pnpm install` or `yarn`), start a development server: 20 | 21 | ```bash 22 | npm run dev 23 | 24 | # or start the server and open the app in a new browser tab 25 | npm run dev -- --open 26 | ``` 27 | 28 | ## Building 29 | 30 | To create a production version of your app: 31 | 32 | ```bash 33 | npm run build 34 | ``` 35 | 36 | You can preview the production build with `npm run preview`. 37 | 38 | > To deploy your app, you may need to install an [adapter](https://kit.svelte.dev/docs/adapters) for your target environment. 39 | -------------------------------------------------------------------------------- /frontend/frontend.go: -------------------------------------------------------------------------------- 1 | package frontend 2 | 3 | import ( 4 | "embed" 5 | "io/fs" 6 | "log" 7 | "net/http" 8 | ) 9 | 10 | // Embed the build directory from the frontend. 11 | // 12 | //go:embed all:build 13 | var BuildFs embed.FS 14 | 15 | // Get the subtree of the embedded files with `build` directory as a root. 16 | func BuildHTTPFS() http.FileSystem { 17 | build, err := fs.Sub(BuildFs, "build") 18 | if err != nil { 19 | log.Fatal(err) 20 | } 21 | return http.FS(build) 22 | } 23 | -------------------------------------------------------------------------------- /frontend/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "frontend", 3 | "version": "0.0.1", 4 | "private": true, 5 | "scripts": { 6 | "dev": "vite dev", 7 | "build": "vite build", 8 | "preview": "vite preview" 9 | }, 10 | "devDependencies": { 11 | "@sveltejs/adapter-static": "^2.0.3", 12 | "@sveltejs/kit": "^1.20.4", 13 | "svelte": "^4.0.5", 14 | "vite": "^4.4.2" 15 | }, 16 | "type": "module" 17 | } 18 | -------------------------------------------------------------------------------- /frontend/pnpm-lock.yaml: -------------------------------------------------------------------------------- 1 | lockfileVersion: '6.0' 2 | 3 | settings: 4 | autoInstallPeers: true 5 | excludeLinksFromLockfile: false 6 | 7 | devDependencies: 8 | '@sveltejs/adapter-static': 9 | specifier: ^2.0.3 10 | version: 2.0.3(@sveltejs/kit@1.22.6) 11 | '@sveltejs/kit': 12 | specifier: ^1.20.4 13 | version: 1.22.6(svelte@4.2.0)(vite@4.4.9) 14 | svelte: 15 | specifier: ^4.0.5 16 | version: 4.2.0 17 | vite: 18 | specifier: ^4.4.2 19 | version: 4.4.9 20 | 21 | packages: 22 | 23 | /@ampproject/remapping@2.2.1: 24 | resolution: {integrity: sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg==} 25 | engines: {node: '>=6.0.0'} 26 | dependencies: 27 | '@jridgewell/gen-mapping': 0.3.3 28 | '@jridgewell/trace-mapping': 0.3.19 29 | dev: true 30 | 31 | /@esbuild/android-arm64@0.18.20: 32 | resolution: {integrity: sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ==} 33 | engines: {node: '>=12'} 34 | cpu: [arm64] 35 | os: [android] 36 | requiresBuild: true 37 | dev: true 38 | optional: true 39 | 40 | /@esbuild/android-arm@0.18.20: 41 | resolution: {integrity: sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw==} 42 | engines: {node: '>=12'} 43 | cpu: [arm] 44 | os: [android] 45 | requiresBuild: true 46 | dev: true 47 | optional: true 48 | 49 | /@esbuild/android-x64@0.18.20: 50 | resolution: {integrity: sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg==} 51 | engines: {node: '>=12'} 52 | cpu: [x64] 53 | os: [android] 54 | requiresBuild: true 55 | dev: true 56 | optional: true 57 | 58 | /@esbuild/darwin-arm64@0.18.20: 59 | resolution: {integrity: sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA==} 60 | engines: {node: '>=12'} 61 | cpu: [arm64] 62 | os: [darwin] 63 | requiresBuild: true 64 | dev: true 65 | optional: true 66 | 67 | /@esbuild/darwin-x64@0.18.20: 68 | resolution: {integrity: sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ==} 69 | engines: {node: '>=12'} 70 | cpu: [x64] 71 | os: [darwin] 72 | requiresBuild: true 73 | dev: true 74 | optional: true 75 | 76 | /@esbuild/freebsd-arm64@0.18.20: 77 | resolution: {integrity: sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw==} 78 | engines: {node: '>=12'} 79 | cpu: [arm64] 80 | os: [freebsd] 81 | requiresBuild: true 82 | dev: true 83 | optional: true 84 | 85 | /@esbuild/freebsd-x64@0.18.20: 86 | resolution: {integrity: sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ==} 87 | engines: {node: '>=12'} 88 | cpu: [x64] 89 | os: [freebsd] 90 | requiresBuild: true 91 | dev: true 92 | optional: true 93 | 94 | /@esbuild/linux-arm64@0.18.20: 95 | resolution: {integrity: sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA==} 96 | engines: {node: '>=12'} 97 | cpu: [arm64] 98 | os: [linux] 99 | requiresBuild: true 100 | dev: true 101 | optional: true 102 | 103 | /@esbuild/linux-arm@0.18.20: 104 | resolution: {integrity: sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg==} 105 | engines: {node: '>=12'} 106 | cpu: [arm] 107 | os: [linux] 108 | requiresBuild: true 109 | dev: true 110 | optional: true 111 | 112 | /@esbuild/linux-ia32@0.18.20: 113 | resolution: {integrity: sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA==} 114 | engines: {node: '>=12'} 115 | cpu: [ia32] 116 | os: [linux] 117 | requiresBuild: true 118 | dev: true 119 | optional: true 120 | 121 | /@esbuild/linux-loong64@0.18.20: 122 | resolution: {integrity: sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg==} 123 | engines: {node: '>=12'} 124 | cpu: [loong64] 125 | os: [linux] 126 | requiresBuild: true 127 | dev: true 128 | optional: true 129 | 130 | /@esbuild/linux-mips64el@0.18.20: 131 | resolution: {integrity: sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ==} 132 | engines: {node: '>=12'} 133 | cpu: [mips64el] 134 | os: [linux] 135 | requiresBuild: true 136 | dev: true 137 | optional: true 138 | 139 | /@esbuild/linux-ppc64@0.18.20: 140 | resolution: {integrity: sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA==} 141 | engines: {node: '>=12'} 142 | cpu: [ppc64] 143 | os: [linux] 144 | requiresBuild: true 145 | dev: true 146 | optional: true 147 | 148 | /@esbuild/linux-riscv64@0.18.20: 149 | resolution: {integrity: sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A==} 150 | engines: {node: '>=12'} 151 | cpu: [riscv64] 152 | os: [linux] 153 | requiresBuild: true 154 | dev: true 155 | optional: true 156 | 157 | /@esbuild/linux-s390x@0.18.20: 158 | resolution: {integrity: sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ==} 159 | engines: {node: '>=12'} 160 | cpu: [s390x] 161 | os: [linux] 162 | requiresBuild: true 163 | dev: true 164 | optional: true 165 | 166 | /@esbuild/linux-x64@0.18.20: 167 | resolution: {integrity: sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w==} 168 | engines: {node: '>=12'} 169 | cpu: [x64] 170 | os: [linux] 171 | requiresBuild: true 172 | dev: true 173 | optional: true 174 | 175 | /@esbuild/netbsd-x64@0.18.20: 176 | resolution: {integrity: sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A==} 177 | engines: {node: '>=12'} 178 | cpu: [x64] 179 | os: [netbsd] 180 | requiresBuild: true 181 | dev: true 182 | optional: true 183 | 184 | /@esbuild/openbsd-x64@0.18.20: 185 | resolution: {integrity: sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg==} 186 | engines: {node: '>=12'} 187 | cpu: [x64] 188 | os: [openbsd] 189 | requiresBuild: true 190 | dev: true 191 | optional: true 192 | 193 | /@esbuild/sunos-x64@0.18.20: 194 | resolution: {integrity: sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ==} 195 | engines: {node: '>=12'} 196 | cpu: [x64] 197 | os: [sunos] 198 | requiresBuild: true 199 | dev: true 200 | optional: true 201 | 202 | /@esbuild/win32-arm64@0.18.20: 203 | resolution: {integrity: sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg==} 204 | engines: {node: '>=12'} 205 | cpu: [arm64] 206 | os: [win32] 207 | requiresBuild: true 208 | dev: true 209 | optional: true 210 | 211 | /@esbuild/win32-ia32@0.18.20: 212 | resolution: {integrity: sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g==} 213 | engines: {node: '>=12'} 214 | cpu: [ia32] 215 | os: [win32] 216 | requiresBuild: true 217 | dev: true 218 | optional: true 219 | 220 | /@esbuild/win32-x64@0.18.20: 221 | resolution: {integrity: sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ==} 222 | engines: {node: '>=12'} 223 | cpu: [x64] 224 | os: [win32] 225 | requiresBuild: true 226 | dev: true 227 | optional: true 228 | 229 | /@jridgewell/gen-mapping@0.3.3: 230 | resolution: {integrity: sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==} 231 | engines: {node: '>=6.0.0'} 232 | dependencies: 233 | '@jridgewell/set-array': 1.1.2 234 | '@jridgewell/sourcemap-codec': 1.4.15 235 | '@jridgewell/trace-mapping': 0.3.19 236 | dev: true 237 | 238 | /@jridgewell/resolve-uri@3.1.1: 239 | resolution: {integrity: sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==} 240 | engines: {node: '>=6.0.0'} 241 | dev: true 242 | 243 | /@jridgewell/set-array@1.1.2: 244 | resolution: {integrity: sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==} 245 | engines: {node: '>=6.0.0'} 246 | dev: true 247 | 248 | /@jridgewell/sourcemap-codec@1.4.15: 249 | resolution: {integrity: sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==} 250 | dev: true 251 | 252 | /@jridgewell/trace-mapping@0.3.19: 253 | resolution: {integrity: sha512-kf37QtfW+Hwx/buWGMPcR60iF9ziHa6r/CZJIHbmcm4+0qrXiVdxegAH0F6yddEVQ7zdkjcGCgCzUu+BcbhQxw==} 254 | dependencies: 255 | '@jridgewell/resolve-uri': 3.1.1 256 | '@jridgewell/sourcemap-codec': 1.4.15 257 | dev: true 258 | 259 | /@polka/url@1.0.0-next.21: 260 | resolution: {integrity: sha512-a5Sab1C4/icpTZVzZc5Ghpz88yQtGOyNqYXcZgOssB2uuAr+wF/MvN6bgtW32q7HHrvBki+BsZ0OuNv6EV3K9g==} 261 | dev: true 262 | 263 | /@sveltejs/adapter-static@2.0.3(@sveltejs/kit@1.22.6): 264 | resolution: {integrity: sha512-VUqTfXsxYGugCpMqQv1U0LIdbR3S5nBkMMDmpjGVJyM6Q2jHVMFtdWJCkeHMySc6mZxJ+0eZK3T7IgmUCDrcUQ==} 265 | peerDependencies: 266 | '@sveltejs/kit': ^1.5.0 267 | dependencies: 268 | '@sveltejs/kit': 1.22.6(svelte@4.2.0)(vite@4.4.9) 269 | dev: true 270 | 271 | /@sveltejs/kit@1.22.6(svelte@4.2.0)(vite@4.4.9): 272 | resolution: {integrity: sha512-SDKxI/QpsReCwIn5czjT53fKlPBybbmMk67d317gUqfeORroBAFN1Z6s/x0E1JYi+04i7kKllS+Sz9wVfmUkAQ==} 273 | engines: {node: ^16.14 || >=18} 274 | hasBin: true 275 | requiresBuild: true 276 | peerDependencies: 277 | svelte: ^3.54.0 || ^4.0.0-next.0 278 | vite: ^4.0.0 279 | dependencies: 280 | '@sveltejs/vite-plugin-svelte': 2.4.5(svelte@4.2.0)(vite@4.4.9) 281 | '@types/cookie': 0.5.1 282 | cookie: 0.5.0 283 | devalue: 4.3.2 284 | esm-env: 1.0.0 285 | kleur: 4.1.5 286 | magic-string: 0.30.2 287 | mime: 3.0.0 288 | sade: 1.8.1 289 | set-cookie-parser: 2.6.0 290 | sirv: 2.0.3 291 | svelte: 4.2.0 292 | undici: 5.23.0 293 | vite: 4.4.9 294 | transitivePeerDependencies: 295 | - supports-color 296 | dev: true 297 | 298 | /@sveltejs/vite-plugin-svelte-inspector@1.0.3(@sveltejs/vite-plugin-svelte@2.4.5)(svelte@4.2.0)(vite@4.4.9): 299 | resolution: {integrity: sha512-Khdl5jmmPN6SUsVuqSXatKpQTMIifoQPDanaxC84m9JxIibWvSABJyHpyys0Z+1yYrxY5TTEQm+6elh0XCMaOA==} 300 | engines: {node: ^14.18.0 || >= 16} 301 | peerDependencies: 302 | '@sveltejs/vite-plugin-svelte': ^2.2.0 303 | svelte: ^3.54.0 || ^4.0.0 304 | vite: ^4.0.0 305 | dependencies: 306 | '@sveltejs/vite-plugin-svelte': 2.4.5(svelte@4.2.0)(vite@4.4.9) 307 | debug: 4.3.4 308 | svelte: 4.2.0 309 | vite: 4.4.9 310 | transitivePeerDependencies: 311 | - supports-color 312 | dev: true 313 | 314 | /@sveltejs/vite-plugin-svelte@2.4.5(svelte@4.2.0)(vite@4.4.9): 315 | resolution: {integrity: sha512-UJKsFNwhzCVuiZd06jM/psscyNJNDwjQC+qIeb7GBJK9iWeQCcIyfcPWDvbCudfcJggY9jtxJeeaZH7uny93FQ==} 316 | engines: {node: ^14.18.0 || >= 16} 317 | peerDependencies: 318 | svelte: ^3.54.0 || ^4.0.0 319 | vite: ^4.0.0 320 | dependencies: 321 | '@sveltejs/vite-plugin-svelte-inspector': 1.0.3(@sveltejs/vite-plugin-svelte@2.4.5)(svelte@4.2.0)(vite@4.4.9) 322 | debug: 4.3.4 323 | deepmerge: 4.3.1 324 | kleur: 4.1.5 325 | magic-string: 0.30.2 326 | svelte: 4.2.0 327 | svelte-hmr: 0.15.3(svelte@4.2.0) 328 | vite: 4.4.9 329 | vitefu: 0.2.4(vite@4.4.9) 330 | transitivePeerDependencies: 331 | - supports-color 332 | dev: true 333 | 334 | /@types/cookie@0.5.1: 335 | resolution: {integrity: sha512-COUnqfB2+ckwXXSFInsFdOAWQzCCx+a5hq2ruyj+Vjund94RJQd4LG2u9hnvJrTgunKAaax7ancBYlDrNYxA0g==} 336 | dev: true 337 | 338 | /@types/estree@1.0.1: 339 | resolution: {integrity: sha512-LG4opVs2ANWZ1TJoKc937iMmNstM/d0ae1vNbnBvBhqCSezgVUOzcLCqbI5elV8Vy6WKwKjaqR+zO9VKirBBCA==} 340 | dev: true 341 | 342 | /acorn@8.10.0: 343 | resolution: {integrity: sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==} 344 | engines: {node: '>=0.4.0'} 345 | hasBin: true 346 | dev: true 347 | 348 | /aria-query@5.3.0: 349 | resolution: {integrity: sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==} 350 | dependencies: 351 | dequal: 2.0.3 352 | dev: true 353 | 354 | /axobject-query@3.2.1: 355 | resolution: {integrity: sha512-jsyHu61e6N4Vbz/v18DHwWYKK0bSWLqn47eeDSKPB7m8tqMHF9YJ+mhIk2lVteyZrY8tnSj/jHOv4YiTCuCJgg==} 356 | dependencies: 357 | dequal: 2.0.3 358 | dev: true 359 | 360 | /busboy@1.6.0: 361 | resolution: {integrity: sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==} 362 | engines: {node: '>=10.16.0'} 363 | dependencies: 364 | streamsearch: 1.1.0 365 | dev: true 366 | 367 | /code-red@1.0.4: 368 | resolution: {integrity: sha512-7qJWqItLA8/VPVlKJlFXU+NBlo/qyfs39aJcuMT/2ere32ZqvF5OSxgdM5xOfJJ7O429gg2HM47y8v9P+9wrNw==} 369 | dependencies: 370 | '@jridgewell/sourcemap-codec': 1.4.15 371 | '@types/estree': 1.0.1 372 | acorn: 8.10.0 373 | estree-walker: 3.0.3 374 | periscopic: 3.1.0 375 | dev: true 376 | 377 | /cookie@0.5.0: 378 | resolution: {integrity: sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==} 379 | engines: {node: '>= 0.6'} 380 | dev: true 381 | 382 | /css-tree@2.3.1: 383 | resolution: {integrity: sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw==} 384 | engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0} 385 | dependencies: 386 | mdn-data: 2.0.30 387 | source-map-js: 1.0.2 388 | dev: true 389 | 390 | /debug@4.3.4: 391 | resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==} 392 | engines: {node: '>=6.0'} 393 | peerDependencies: 394 | supports-color: '*' 395 | peerDependenciesMeta: 396 | supports-color: 397 | optional: true 398 | dependencies: 399 | ms: 2.1.2 400 | dev: true 401 | 402 | /deepmerge@4.3.1: 403 | resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==} 404 | engines: {node: '>=0.10.0'} 405 | dev: true 406 | 407 | /dequal@2.0.3: 408 | resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==} 409 | engines: {node: '>=6'} 410 | dev: true 411 | 412 | /devalue@4.3.2: 413 | resolution: {integrity: sha512-KqFl6pOgOW+Y6wJgu80rHpo2/3H07vr8ntR9rkkFIRETewbf5GaYYcakYfiKz89K+sLsuPkQIZaXDMjUObZwWg==} 414 | dev: true 415 | 416 | /esbuild@0.18.20: 417 | resolution: {integrity: sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA==} 418 | engines: {node: '>=12'} 419 | hasBin: true 420 | requiresBuild: true 421 | optionalDependencies: 422 | '@esbuild/android-arm': 0.18.20 423 | '@esbuild/android-arm64': 0.18.20 424 | '@esbuild/android-x64': 0.18.20 425 | '@esbuild/darwin-arm64': 0.18.20 426 | '@esbuild/darwin-x64': 0.18.20 427 | '@esbuild/freebsd-arm64': 0.18.20 428 | '@esbuild/freebsd-x64': 0.18.20 429 | '@esbuild/linux-arm': 0.18.20 430 | '@esbuild/linux-arm64': 0.18.20 431 | '@esbuild/linux-ia32': 0.18.20 432 | '@esbuild/linux-loong64': 0.18.20 433 | '@esbuild/linux-mips64el': 0.18.20 434 | '@esbuild/linux-ppc64': 0.18.20 435 | '@esbuild/linux-riscv64': 0.18.20 436 | '@esbuild/linux-s390x': 0.18.20 437 | '@esbuild/linux-x64': 0.18.20 438 | '@esbuild/netbsd-x64': 0.18.20 439 | '@esbuild/openbsd-x64': 0.18.20 440 | '@esbuild/sunos-x64': 0.18.20 441 | '@esbuild/win32-arm64': 0.18.20 442 | '@esbuild/win32-ia32': 0.18.20 443 | '@esbuild/win32-x64': 0.18.20 444 | dev: true 445 | 446 | /esm-env@1.0.0: 447 | resolution: {integrity: sha512-Cf6VksWPsTuW01vU9Mk/3vRue91Zevka5SjyNf3nEpokFRuqt/KjUQoGAwq9qMmhpLTHmXzSIrFRw8zxWzmFBA==} 448 | dev: true 449 | 450 | /estree-walker@3.0.3: 451 | resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==} 452 | dependencies: 453 | '@types/estree': 1.0.1 454 | dev: true 455 | 456 | /fsevents@2.3.2: 457 | resolution: {integrity: sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==} 458 | engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} 459 | os: [darwin] 460 | requiresBuild: true 461 | dev: true 462 | optional: true 463 | 464 | /is-reference@3.0.1: 465 | resolution: {integrity: sha512-baJJdQLiYaJdvFbJqXrcGv3WU3QCzBlUcI5QhbesIm6/xPsvmO+2CDoi/GMOFBQEQm+PXkwOPrp9KK5ozZsp2w==} 466 | dependencies: 467 | '@types/estree': 1.0.1 468 | dev: true 469 | 470 | /kleur@4.1.5: 471 | resolution: {integrity: sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==} 472 | engines: {node: '>=6'} 473 | dev: true 474 | 475 | /locate-character@3.0.0: 476 | resolution: {integrity: sha512-SW13ws7BjaeJ6p7Q6CO2nchbYEc3X3J6WrmTTDto7yMPqVSZTUyY5Tjbid+Ab8gLnATtygYtiDIJGQRRn2ZOiA==} 477 | dev: true 478 | 479 | /magic-string@0.30.2: 480 | resolution: {integrity: sha512-lNZdu7pewtq/ZvWUp9Wpf/x7WzMTsR26TWV03BRZrXFsv+BI6dy8RAiKgm1uM/kyR0rCfUcqvOlXKG66KhIGug==} 481 | engines: {node: '>=12'} 482 | dependencies: 483 | '@jridgewell/sourcemap-codec': 1.4.15 484 | dev: true 485 | 486 | /mdn-data@2.0.30: 487 | resolution: {integrity: sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==} 488 | dev: true 489 | 490 | /mime@3.0.0: 491 | resolution: {integrity: sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A==} 492 | engines: {node: '>=10.0.0'} 493 | hasBin: true 494 | dev: true 495 | 496 | /mri@1.2.0: 497 | resolution: {integrity: sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==} 498 | engines: {node: '>=4'} 499 | dev: true 500 | 501 | /mrmime@1.0.1: 502 | resolution: {integrity: sha512-hzzEagAgDyoU1Q6yg5uI+AorQgdvMCur3FcKf7NhMKWsaYg+RnbTyHRa/9IlLF9rf455MOCtcqqrQQ83pPP7Uw==} 503 | engines: {node: '>=10'} 504 | dev: true 505 | 506 | /ms@2.1.2: 507 | resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==} 508 | dev: true 509 | 510 | /nanoid@3.3.6: 511 | resolution: {integrity: sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==} 512 | engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} 513 | hasBin: true 514 | dev: true 515 | 516 | /periscopic@3.1.0: 517 | resolution: {integrity: sha512-vKiQ8RRtkl9P+r/+oefh25C3fhybptkHKCZSPlcXiJux2tJF55GnEj3BVn4A5gKfq9NWWXXrxkHBwVPUfH0opw==} 518 | dependencies: 519 | '@types/estree': 1.0.1 520 | estree-walker: 3.0.3 521 | is-reference: 3.0.1 522 | dev: true 523 | 524 | /picocolors@1.0.0: 525 | resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==} 526 | dev: true 527 | 528 | /postcss@8.4.27: 529 | resolution: {integrity: sha512-gY/ACJtJPSmUFPDCHtX78+01fHa64FaU4zaaWfuh1MhGJISufJAH4cun6k/8fwsHYeK4UQmENQK+tRLCFJE8JQ==} 530 | engines: {node: ^10 || ^12 || >=14} 531 | dependencies: 532 | nanoid: 3.3.6 533 | picocolors: 1.0.0 534 | source-map-js: 1.0.2 535 | dev: true 536 | 537 | /rollup@3.28.0: 538 | resolution: {integrity: sha512-d7zhvo1OUY2SXSM6pfNjgD5+d0Nz87CUp4mt8l/GgVP3oBsPwzNvSzyu1me6BSG9JIgWNTVcafIXBIyM8yQ3yw==} 539 | engines: {node: '>=14.18.0', npm: '>=8.0.0'} 540 | hasBin: true 541 | optionalDependencies: 542 | fsevents: 2.3.2 543 | dev: true 544 | 545 | /sade@1.8.1: 546 | resolution: {integrity: sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A==} 547 | engines: {node: '>=6'} 548 | dependencies: 549 | mri: 1.2.0 550 | dev: true 551 | 552 | /set-cookie-parser@2.6.0: 553 | resolution: {integrity: sha512-RVnVQxTXuerk653XfuliOxBP81Sf0+qfQE73LIYKcyMYHG94AuH0kgrQpRDuTZnSmjpysHmzxJXKNfa6PjFhyQ==} 554 | dev: true 555 | 556 | /sirv@2.0.3: 557 | resolution: {integrity: sha512-O9jm9BsID1P+0HOi81VpXPoDxYP374pkOLzACAoyUQ/3OUVndNpsz6wMnY2z+yOxzbllCKZrM+9QrWsv4THnyA==} 558 | engines: {node: '>= 10'} 559 | dependencies: 560 | '@polka/url': 1.0.0-next.21 561 | mrmime: 1.0.1 562 | totalist: 3.0.1 563 | dev: true 564 | 565 | /source-map-js@1.0.2: 566 | resolution: {integrity: sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==} 567 | engines: {node: '>=0.10.0'} 568 | dev: true 569 | 570 | /streamsearch@1.1.0: 571 | resolution: {integrity: sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==} 572 | engines: {node: '>=10.0.0'} 573 | dev: true 574 | 575 | /svelte-hmr@0.15.3(svelte@4.2.0): 576 | resolution: {integrity: sha512-41snaPswvSf8TJUhlkoJBekRrABDXDMdpNpT2tfHIv4JuhgvHqLMhEPGtaQn0BmbNSTkuz2Ed20DF2eHw0SmBQ==} 577 | engines: {node: ^12.20 || ^14.13.1 || >= 16} 578 | peerDependencies: 579 | svelte: ^3.19.0 || ^4.0.0 580 | dependencies: 581 | svelte: 4.2.0 582 | dev: true 583 | 584 | /svelte@4.2.0: 585 | resolution: {integrity: sha512-kVsdPjDbLrv74SmLSUzAsBGquMs4MPgWGkGLpH+PjOYnFOziAvENVzgJmyOCV2gntxE32aNm8/sqNKD6LbIpeQ==} 586 | engines: {node: '>=16'} 587 | dependencies: 588 | '@ampproject/remapping': 2.2.1 589 | '@jridgewell/sourcemap-codec': 1.4.15 590 | '@jridgewell/trace-mapping': 0.3.19 591 | acorn: 8.10.0 592 | aria-query: 5.3.0 593 | axobject-query: 3.2.1 594 | code-red: 1.0.4 595 | css-tree: 2.3.1 596 | estree-walker: 3.0.3 597 | is-reference: 3.0.1 598 | locate-character: 3.0.0 599 | magic-string: 0.30.2 600 | periscopic: 3.1.0 601 | dev: true 602 | 603 | /totalist@3.0.1: 604 | resolution: {integrity: sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==} 605 | engines: {node: '>=6'} 606 | dev: true 607 | 608 | /undici@5.23.0: 609 | resolution: {integrity: sha512-1D7w+fvRsqlQ9GscLBwcAJinqcZGHUKjbOmXdlE/v8BvEGXjeWAax+341q44EuTcHXXnfyKNbKRq4Lg7OzhMmg==} 610 | engines: {node: '>=14.0'} 611 | dependencies: 612 | busboy: 1.6.0 613 | dev: true 614 | 615 | /vite@4.4.9: 616 | resolution: {integrity: sha512-2mbUn2LlUmNASWwSCNSJ/EG2HuSRTnVNaydp6vMCm5VIqJsjMfbIWtbH2kDuwUVW5mMUKKZvGPX/rqeqVvv1XA==} 617 | engines: {node: ^14.18.0 || >=16.0.0} 618 | hasBin: true 619 | peerDependencies: 620 | '@types/node': '>= 14' 621 | less: '*' 622 | lightningcss: ^1.21.0 623 | sass: '*' 624 | stylus: '*' 625 | sugarss: '*' 626 | terser: ^5.4.0 627 | peerDependenciesMeta: 628 | '@types/node': 629 | optional: true 630 | less: 631 | optional: true 632 | lightningcss: 633 | optional: true 634 | sass: 635 | optional: true 636 | stylus: 637 | optional: true 638 | sugarss: 639 | optional: true 640 | terser: 641 | optional: true 642 | dependencies: 643 | esbuild: 0.18.20 644 | postcss: 8.4.27 645 | rollup: 3.28.0 646 | optionalDependencies: 647 | fsevents: 2.3.2 648 | dev: true 649 | 650 | /vitefu@0.2.4(vite@4.4.9): 651 | resolution: {integrity: sha512-fanAXjSaf9xXtOOeno8wZXIhgia+CZury481LsDaV++lSvcU2R9Ch2bPh3PYFyoHW+w9LqAeYRISVQjUIew14g==} 652 | peerDependencies: 653 | vite: ^3.0.0 || ^4.0.0 654 | peerDependenciesMeta: 655 | vite: 656 | optional: true 657 | dependencies: 658 | vite: 4.4.9 659 | dev: true 660 | -------------------------------------------------------------------------------- /frontend/src/app.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | %sveltekit.head% 8 | 9 | 10 |
%sveltekit.body%
11 | 12 | 13 | -------------------------------------------------------------------------------- /frontend/src/global.css: -------------------------------------------------------------------------------- 1 | body { 2 | background-color: aliceblue; 3 | font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, 4 | Ubuntu, Cantarell, "Open Sans", "Helvetica Neue", sans-serif; 5 | } -------------------------------------------------------------------------------- /frontend/src/lib/index.js: -------------------------------------------------------------------------------- 1 | // place files you want to import through the `$lib` alias in this folder. 2 | -------------------------------------------------------------------------------- /frontend/src/routes/+error.svelte: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | {$page.status} 7 | 8 | 9 |

{$page.status}

10 | 11 |

{$page.error.message}

12 | 13 | 18 | -------------------------------------------------------------------------------- /frontend/src/routes/+layout.svelte: -------------------------------------------------------------------------------- 1 | 4 | 5 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /frontend/src/routes/+page.svelte: -------------------------------------------------------------------------------- 1 | 2 | Homepage 3 | 4 | 5 |

Welcome to SvelteKit

6 |

7 | Visit kit.svelte.dev to read 8 | the documentation 9 |

10 | 11 | 16 | -------------------------------------------------------------------------------- /frontend/src/routes/about/+page.svelte: -------------------------------------------------------------------------------- 1 | 8 | 9 | 10 | About 11 | 12 | 13 |

About

14 | 15 |

16 | server respond: 17 | {#await status} 18 | loading 19 | {:then data} 20 | {data.message} 21 | {:catch err} 22 | failed to load data 23 | {/await} 24 |

25 | 26 |

This is about page

27 | 28 | 33 | -------------------------------------------------------------------------------- /frontend/static/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aprakasa/go-embed-spa/5302790a1f40f21acc60ae21a695c71db79581da/frontend/static/favicon.png -------------------------------------------------------------------------------- /frontend/svelte.config.js: -------------------------------------------------------------------------------- 1 | import adapter from '@sveltejs/adapter-static'; 2 | 3 | /** @type {import('@sveltejs/kit').Config} */ 4 | const config = { 5 | kit: { 6 | // adapter-auto only supports some environments, see https://kit.svelte.dev/docs/adapter-auto for a list. 7 | // If your environment is not supported or you settled on a specific environment, switch out the adapter. 8 | // See https://kit.svelte.dev/docs/adapters for more information about adapters. 9 | adapter: adapter({ 10 | fallback: "index.html" 11 | }) 12 | } 13 | }; 14 | 15 | export default config; 16 | -------------------------------------------------------------------------------- /frontend/vite.config.js: -------------------------------------------------------------------------------- 1 | import { sveltekit } from '@sveltejs/kit/vite'; 2 | import { defineConfig } from 'vite'; 3 | 4 | export default defineConfig({ 5 | plugins: [sveltekit()] 6 | }); 7 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/aprakasa/go-embed-spa 2 | 3 | go 1.19 4 | 5 | require ( 6 | github.com/gofiber/fiber/v2 v2.37.1 7 | github.com/labstack/echo/v4 v4.9.0 8 | ) 9 | 10 | require ( 11 | github.com/andybalholm/brotli v1.0.4 // indirect 12 | github.com/golang-jwt/jwt v3.2.2+incompatible // indirect 13 | github.com/klauspost/compress v1.15.10 // indirect 14 | github.com/labstack/gommon v0.3.1 // indirect 15 | github.com/mattn/go-colorable v0.1.13 // indirect 16 | github.com/mattn/go-isatty v0.0.16 // indirect 17 | github.com/valyala/bytebufferpool v1.0.0 // indirect 18 | github.com/valyala/fasthttp v1.40.0 // indirect 19 | github.com/valyala/fasttemplate v1.2.1 // indirect 20 | github.com/valyala/tcplisten v1.0.0 // indirect 21 | golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90 // indirect 22 | golang.org/x/net v0.0.0-20220909164309-bea034e7d591 // indirect 23 | golang.org/x/sys v0.0.0-20220915200043-7b5979e65e41 // indirect 24 | golang.org/x/text v0.3.7 // indirect 25 | golang.org/x/time v0.0.0-20220722155302-e5dcc9cfc0b9 // indirect 26 | ) 27 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/andybalholm/brotli v1.0.4 h1:V7DdXeJtZscaqfNuAdSRuRFzuiKlHSC/Zh3zl9qY3JY= 2 | github.com/andybalholm/brotli v1.0.4/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= 3 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 4 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 5 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 6 | github.com/gofiber/fiber/v2 v2.32.0 h1:lpgcGEq1UENv27uVuOaufAhU8wUKnX8yb9L7559Neec= 7 | github.com/gofiber/fiber/v2 v2.32.0/go.mod h1:CMy5ZLiXkn6qwthrl03YMyW1NLfj0rhxz2LKl4t7ZTY= 8 | github.com/gofiber/fiber/v2 v2.37.1 h1:QK2032gjv0ulegpv/qlTEBoXQD3eFFzCHXcNN12UZCs= 9 | github.com/gofiber/fiber/v2 v2.37.1/go.mod h1:j3UslgQeJQP3mNhBxHnLLE8TPqA1Fd/lrl4gD25rRUY= 10 | github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY= 11 | github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I= 12 | github.com/klauspost/compress v1.15.0/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= 13 | github.com/klauspost/compress v1.15.2 h1:3WH+AG7s2+T8o3nrM/8u2rdqUEcQhmga7smjrT41nAw= 14 | github.com/klauspost/compress v1.15.2/go.mod h1:PhcZ0MbTNciWF3rruxRgKxI5NkcHHrHUDtV4Yw2GlzU= 15 | github.com/klauspost/compress v1.15.10 h1:Ai8UzuomSCDw90e1qNMtb15msBXsNpH6gzkkENQNcJo= 16 | github.com/klauspost/compress v1.15.10/go.mod h1:QPwzmACJjUTFsnSHH934V6woptycfrDDJnH7hvFVbGM= 17 | github.com/labstack/echo/v4 v4.7.2 h1:Kv2/p8OaQ+M6Ex4eGimg9b9e6icoxA42JSlOR3msKtI= 18 | github.com/labstack/echo/v4 v4.7.2/go.mod h1:xkCDAdFCIf8jsFQ5NnbK7oqaF/yU1A1X20Ltm0OvSks= 19 | github.com/labstack/echo/v4 v4.9.0 h1:wPOF1CE6gvt/kmbMR4dGzWvHMPT+sAEUJOwOTtvITVY= 20 | github.com/labstack/echo/v4 v4.9.0/go.mod h1:xkCDAdFCIf8jsFQ5NnbK7oqaF/yU1A1X20Ltm0OvSks= 21 | github.com/labstack/gommon v0.3.1 h1:OomWaJXm7xR6L1HmEtGyQf26TEn7V6X88mktX9kee9o= 22 | github.com/labstack/gommon v0.3.1/go.mod h1:uW6kP17uPlLJsD3ijUYn3/M5bAxtlZhMI6m3MFxTMTM= 23 | github.com/mattn/go-colorable v0.1.11 h1:nQ+aFkoE2TMGc0b68U2OKSexC+eq46+XwZzWXHRmPYs= 24 | github.com/mattn/go-colorable v0.1.11/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= 25 | github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= 26 | github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= 27 | github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y= 28 | github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= 29 | github.com/mattn/go-isatty v0.0.16 h1:bq3VjFmv/sOjHtdEhmkEV4x1AJtvUvOJ2PFAZ5+peKQ= 30 | github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= 31 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 32 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 33 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 34 | github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= 35 | github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 36 | github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= 37 | github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= 38 | github.com/valyala/fasthttp v1.35.0/go.mod h1:t/G+3rLek+CyY9bnIE+YlMRddxVAAGjhxndDB4i4C0I= 39 | github.com/valyala/fasthttp v1.36.0 h1:NhqfO/cB7Ajn1czkKnWkMHyPYr5nyND14ZGPk23g0/c= 40 | github.com/valyala/fasthttp v1.36.0/go.mod h1:t/G+3rLek+CyY9bnIE+YlMRddxVAAGjhxndDB4i4C0I= 41 | github.com/valyala/fasthttp v1.40.0 h1:CRq/00MfruPGFLTQKY8b+8SfdK60TxNztjRMnH0t1Yc= 42 | github.com/valyala/fasthttp v1.40.0/go.mod h1:t/G+3rLek+CyY9bnIE+YlMRddxVAAGjhxndDB4i4C0I= 43 | github.com/valyala/fasttemplate v1.2.1 h1:TVEnxayobAdVkhQfrfes2IzOB6o+z4roRkPF52WA1u4= 44 | github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= 45 | github.com/valyala/tcplisten v1.0.0 h1:rBHj/Xf+E1tRGZyWIWwJDiRY0zc1Js+CV5DqwacVSA8= 46 | github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc= 47 | golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= 48 | golang.org/x/crypto v0.0.0-20220214200702-86341886e292 h1:f+lwQ+GtmgoY+A2YaQxlSOnDjXcQ7ZRLWOHbC6HtRqE= 49 | golang.org/x/crypto v0.0.0-20220214200702-86341886e292/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= 50 | golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90 h1:Y/gsMcFOcR+6S6f3YeMKl5g+dZMEWqcz5Czj/GWYbkM= 51 | golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= 52 | golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= 53 | golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= 54 | golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= 55 | golang.org/x/net v0.0.0-20220225172249-27dd8689420f h1:oA4XRj0qtSt8Yo1Zms0CUlsT3KG69V2UGQWPBxujDmc= 56 | golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= 57 | golang.org/x/net v0.0.0-20220909164309-bea034e7d591 h1:D0B/7al0LLrVC8aWF4+oxpv/m8bc7ViFfVS8/gXGdqI= 58 | golang.org/x/net v0.0.0-20220909164309-bea034e7d591/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= 59 | golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 60 | golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 61 | golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 62 | golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 63 | golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 64 | golang.org/x/sys v0.0.0-20211103235746-7861aae1554b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 65 | golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 66 | golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 67 | golang.org/x/sys v0.0.0-20220502124256-b6088ccd6cba h1:AyHWHCBVlIYI5rgEM3o+1PLd0sLPcIAoaUckGQMaWtw= 68 | golang.org/x/sys v0.0.0-20220502124256-b6088ccd6cba/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 69 | golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 70 | golang.org/x/sys v0.0.0-20220915200043-7b5979e65e41 h1:ohgcoMbSofXygzo6AD2I1kz3BFmW1QArPYTtwEM3UXc= 71 | golang.org/x/sys v0.0.0-20220915200043-7b5979e65e41/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 72 | golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= 73 | golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= 74 | golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 75 | golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 76 | golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= 77 | golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= 78 | golang.org/x/time v0.0.0-20201208040808-7e3f01d25324 h1:Hir2P/De0WpUhtrKGGjvSb2YxUgyZ7EFOSLIcSSpiwE= 79 | golang.org/x/time v0.0.0-20201208040808-7e3f01d25324/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= 80 | golang.org/x/time v0.0.0-20220722155302-e5dcc9cfc0b9 h1:ftMN5LMiBFjbzleLqtoBZk7KdJwhuybIU+FckUHgoyQ= 81 | golang.org/x/time v0.0.0-20220722155302-e5dcc9cfc0b9/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= 82 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 83 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 84 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 85 | gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= 86 | gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 87 | --------------------------------------------------------------------------------