generated from indoorvivants/scala-cli-smithy4s-fullstack-template
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 2cb368c
Showing
37 changed files
with
3,459 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
**/.scala-build | ||
**/.bsp | ||
*.class | ||
**/.bloop | ||
**/.metals | ||
.vscode | ||
Dockerfile | ||
fly.toml | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
name: CI | ||
on: | ||
push: | ||
branches: ["main"] | ||
tags: ["v*"] | ||
pull_request: | ||
branches: ["*"] | ||
|
||
jobs: | ||
build: | ||
strategy: | ||
fail-fast: false | ||
runs-on: ubuntu-latest | ||
steps: | ||
- uses: actions/checkout@v4 | ||
with: | ||
fetch-depth: 0 | ||
- uses: coursier/cache-action@v6 | ||
- uses: VirtusLab/scala-cli-setup@main | ||
with: | ||
power: true | ||
|
||
- name: Check formatting | ||
run: make code-check || echo "Run `make pre-ci`" | ||
|
||
# Smithy4s is not idempotent unfortunately :( | ||
# - name: Check generated code is up to date | ||
# run: make smithy4s && git diff --exit-code | ||
|
||
- name: Check Docker build | ||
run: make docker | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
# Logs | ||
logs | ||
*.log | ||
npm-debug.log* | ||
yarn-debug.log* | ||
yarn-error.log* | ||
pnpm-debug.log* | ||
lerna-debug.log* | ||
|
||
node_modules | ||
dist | ||
dist-ssr | ||
*.local | ||
|
||
# Editor directories and files | ||
.vscode/* | ||
!.vscode/extensions.json | ||
.idea | ||
.DS_Store | ||
*.suo | ||
*.ntvs* | ||
*.njsproj | ||
*.sln | ||
*.sw? | ||
|
||
.class | ||
.scala-build | ||
.metals | ||
.bsp | ||
scalajs-frontend.js | ||
*.semanticdb | ||
db.json | ||
*.map |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
version = "3.8.1" | ||
runner.dialect = scala3 | ||
rewrite.scala3.insertEndMarkerMinLines = 10 | ||
rewrite.scala3.removeOptionalBraces = true | ||
rewrite.scala3.convertToNewSyntax = true | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
FROM node:22 as build | ||
|
||
WORKDIR /usr/local/bin | ||
|
||
RUN wget https://raw.githubusercontent.com/VirtusLab/scala-cli/main/scala-cli.sh && \ | ||
mv scala-cli.sh scala-cli && \ | ||
chmod +x scala-cli && \ | ||
scala-cli config power true && \ | ||
scala-cli version && \ | ||
echo '@main def hello = println(42)' | scala-cli run _ --js -S 3.5.0-RC2 | ||
|
||
WORKDIR /source | ||
COPY shared shared | ||
|
||
WORKDIR /source/frontend | ||
COPY frontend/ . | ||
RUN npm install && npm run build | ||
|
||
WORKDIR /source/backend | ||
COPY backend/ . | ||
RUN scala-cli package . --assembly -f -o ./backend-assembly | ||
|
||
FROM nginx | ||
|
||
RUN apt update && apt install -y gpg wget && \ | ||
wget -qO - https://packages.adoptium.net/artifactory/api/gpg/key/public | gpg --dearmor | tee /etc/apt/trusted.gpg.d/adoptium.gpg > /dev/null && \ | ||
echo "deb https://packages.adoptium.net/artifactory/deb $(awk -F= '/^VERSION_CODENAME/{print$2}' /etc/os-release) main" | tee /etc/apt/sources.list.d/adoptium.list && \ | ||
apt update && apt install -y temurin-22-jdk | ||
|
||
COPY ./nginx/nginx.conf /etc/nginx/conf.d/default.conf | ||
COPY ./nginx/entrypoint.sh /app/entrypoint.sh | ||
COPY --from=build /source/backend/backend-assembly /app/backend | ||
COPY --from=build /source/frontend/dist /app/frontend | ||
|
||
EXPOSE 80 | ||
|
||
CMD ["/app/entrypoint.sh"] | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
docker: | ||
docker build . -t my-fullstack-scala:latest | ||
|
||
smithy4s: | ||
cd shared && \ | ||
rm -rf fullstack_scala/protocol && \ | ||
cs launch smithy4s --contrib -- generate protocol.smithy --skip resource --skip openapi && \ | ||
scala-cli --power compile . -O -rewrite -O -source -O 3.4-migration | ||
|
||
setup-ide: | ||
rm -rf .scala-build .bsp .metals | ||
cd shared && scala-cli --power setup-ide . | ||
cd frontend && scala-cli --power setup-ide . | ||
cd backend && scala-cli --power setup-ide . | ||
|
||
code-check: | ||
cd backend && scala-cli --power fmt . --check | ||
cd frontend && scala-cli --power fmt . --check | ||
|
||
pre-ci: | ||
cd backend && scala-cli --power fmt . | ||
cd frontend && scala-cli --power fmt . | ||
|
||
run-backend: | ||
cd backend && scala-cli --power run -w . --restart -- 9999 | ||
|
||
run-frontend: | ||
cd frontend && npm run dev |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
# Full stack Scala 3 | ||
|
||
<!--toc:start--> | ||
- [Full stack Scala 3](#full-stack-scala-3) | ||
- [Pre-requisites](#pre-requisites) | ||
- [Development workflow](#development-workflow) | ||
- [Setting up build definitions for Metals](#setting-up-build-definitions-for-metals) | ||
- [Updating protocol definitions](#updating-protocol-definitions) | ||
- [Frontend live server](#frontend-live-server) | ||
- [Backend live server](#backend-live-server) | ||
- [Packaging as docker container](#packaging-as-docker-container) | ||
<!--toc:end--> | ||
|
||
**Frontend**: [Scala.js](https://www.scala-js.org/) and [Laminar](https://laminar.dev) | **Backend**: [Scala JVM](https://www.scala-lang.org/) and [Http4s](https://http4s.org/) | **Protocol**: [Smithy4s](https://disneystreaming.github.io/smithy4s/) | **Build system**: [Scala CLI](https://scala-cli.virtuslab.org/) and [Vite](https://vitejs.dev/) | **Packaging**: [Docker](https://hub.docker.com/) | **Web server**: [NGINX](https://nginx.org/) | ||
|
||
This is an opinionated fullstack scala template: | ||
|
||
- The frontend-backend interaction layer is handled through **Smithy4s** protocol definition – this ensures shared modelling and keeps all definitions in sync, additionally allowing for code sharing between frontend and backend | ||
- **Scala CLI** is used everywhere. While it doesn't have multi-module support | ||
- **NGINX** is used as a web server. Using a very configurable and battle-tested server from the very beginning can help implementing more complicated features later as the app grows. We also use it to serve static assets separately from the JVM backend. | ||
- **Vite and TailwindCSS** are used on the frontend. Bundling a CSS framework can be helpful to get the styling off the ground for people not usually involved in frontend design work. | ||
|
||
## Pre-requisites | ||
|
||
1. **Frontend**: Node.js and NPM, Scala CLI | ||
2. **Backend**: Scala CLI | ||
3. **Protocol code**: [Coursier](https://get-coursier.io/docs/overview), Scala CLI | ||
|
||
## Development workflow | ||
|
||
### Setting up build definitions for Metals | ||
|
||
Scala CLI doesn't have any support for multi-module projects, so to make sure we can work with this codebase in Metals we need to generate BSP definitions manually. | ||
|
||
1. Run `make setup-ide` and then cross your fingers that Metals will pick everything up correctly | ||
|
||
### Updating protocol definitions | ||
|
||
1. Make changes to `shared/protocol.smithy` | ||
2. Run `make smithy4s` | ||
3. This will regenerate all the code that can be used by both backend and frontend | ||
|
||
### Frontend live server | ||
|
||
1. Run `make run-frontend` | ||
2. Note that to perform any actions that execute API calls, you need to have backend running as well | ||
|
||
### Backend live server | ||
|
||
1. Run `make run-backend` | ||
2. This will run the backend server on port 9999 – which is where Vite's frontend tooling expects it to be | ||
|
||
### Packaging as docker container | ||
|
||
1. Run `make docker` | ||
2. Note that this project is organised as a self-contained docker image - just running `docker build .` will produce a working docker image. This is particularly useful for services like [Fly.io](https://fly.io/) which detect a Dockerfile and can build and deploy app directly from it |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
../.scalafmt.conf |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
package fullstack_scala | ||
package backend | ||
|
||
import cats.data.Kleisli | ||
import cats.effect.IO | ||
import fullstack_scala.protocol.* | ||
import org.http4s.HttpApp | ||
import scribe.Scribe | ||
import smithy4s.http4s.SimpleRestJsonBuilder | ||
import cats.effect.std.Random | ||
import cats.effect.Ref | ||
|
||
def handleErrors(logger: Scribe[IO], routes: HttpApp[IO]): HttpApp[IO] = | ||
import cats.syntax.all.* | ||
routes.onError { exc => | ||
Kleisli(request => logger.error("Request failed", request.toString, exc)) | ||
} | ||
|
||
class TestServiceImpl(ref: Ref[IO, List[Test]]) extends TestService[IO]: | ||
override def listTests(): IO[ListTestsOutput] = | ||
ref.get.map(ListTestsOutput(_)) | ||
|
||
override def createTest(attributes: TestAttributes) = | ||
Random | ||
.scalaUtilRandom[IO] | ||
.flatMap(_.nextInt) | ||
.map(id => Test(id = TestId(id), attributes = attributes)) | ||
.flatTap(test => ref.update(_ :+ test)) | ||
.map(CreateTestOutput(_)) | ||
|
||
end TestServiceImpl | ||
|
||
def routesResource(service: TestService[IO]) = | ||
import org.http4s.implicits.* | ||
SimpleRestJsonBuilder | ||
.routes(service) | ||
.resource | ||
.map(_.orNotFound) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
//> using file ../shared/ | ||
//> using dep com.disneystreaming.smithy4s::smithy4s-http4s::0.18.23 | ||
//> using dep org.http4s::http4s-ember-server::0.23.27 | ||
//> using dep io.circe::circe-jawn::0.14.9 | ||
//> using dep com.outr::scribe-cats::3.15.0 | ||
//> using resourceDir ../frontend/dist | ||
//> using scala 3.5.0-RC2 | ||
//> using option -experimental -Wunused:all | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
package fullstack_scala | ||
package backend | ||
|
||
import cats.effect.* | ||
import com.comcast.ip4s.Port | ||
import com.comcast.ip4s.host | ||
import org.http4s.ember.server.EmberServerBuilder | ||
|
||
import scala.concurrent.duration.* | ||
import fullstack_scala.protocol.* | ||
|
||
object Server extends IOApp: | ||
|
||
override def run(args: List[String]) = | ||
val port = args.headOption | ||
.flatMap(_.toIntOption) | ||
.flatMap(Port.fromInt) | ||
.getOrElse(sys.error("port missing or invalid")) | ||
|
||
val server = | ||
for | ||
ref <- IO.ref(DUMMY_DATA).toResource | ||
routes <- routesResource(TestServiceImpl(ref)) | ||
server <- EmberServerBuilder | ||
.default[IO] | ||
.withPort(port) | ||
.withHost(host"0.0.0.0") | ||
.withHttpApp(handleErrors(scribe.cats.io, routes)) | ||
.withShutdownTimeout(0.seconds) | ||
.build | ||
.map(_.baseUri) | ||
.evalTap(uri => IO.println(s"Server running on $uri")) | ||
yield server | ||
|
||
server.useForever | ||
.as(ExitCode.Success) | ||
|
||
end run | ||
|
||
val DUMMY_DATA = | ||
List( | ||
Test( | ||
TestId(1), | ||
TestAttributes( | ||
TestTitle("yass"), | ||
description = Some(TestDescription("qween")) | ||
) | ||
), | ||
Test( | ||
TestId(2), | ||
TestAttributes( | ||
TestTitle("bless"), | ||
description = None | ||
) | ||
) | ||
) | ||
|
||
end Server |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
../.scalafmt.conf |
Oops, something went wrong.