-
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.
configured with: - solid-js - elysia - bun - nvm - typescript - vitest - eslint - prettier - docker - github actions
- Loading branch information
0 parents
commit 801b587
Showing
36 changed files
with
2,112 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,7 @@ | ||
**/node_modules/ | ||
**/dist | ||
**/__tests__ | ||
**/coverage/ | ||
.git | ||
.env | ||
mockServiceWorker.js |
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,26 @@ | ||
{ | ||
"parser": "@typescript-eslint/parser", | ||
"plugins": ["simple-import-sort", "solid"], | ||
"extends": [ | ||
"eslint:recommended", | ||
"plugin:@typescript-eslint/eslint-recommended", | ||
"plugin:@typescript-eslint/recommended", | ||
"plugin:solid/typescript" | ||
], | ||
"env": { | ||
"browser": true, | ||
"node": true, | ||
"es6": true, | ||
"jest": true | ||
}, | ||
"parserOptions": { | ||
"sourceType": "module" | ||
}, | ||
"rules": { | ||
"@typescript-eslint/no-unused-vars": ["error", { "varsIgnorePattern": "^_" }], | ||
"no-unused-vars": "off", | ||
"simple-import-sort/imports": "error", | ||
"simple-import-sort/exports": "error" | ||
}, | ||
"ignorePatterns": ["dist", "node_modules"] | ||
} |
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 @@ | ||
thedanchez |
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 @@ | ||
name: CI | ||
|
||
on: | ||
push: | ||
branches: | ||
- main | ||
pull_request: | ||
branches: | ||
- main | ||
|
||
jobs: | ||
quality-checks: | ||
name: Quality Checks | ||
runs-on: ubuntu-latest | ||
steps: | ||
- name: Checkout | ||
uses: actions/checkout@v4 | ||
- name: Setup Bun | ||
uses: oven-sh/setup-bun@v1 | ||
with: | ||
bun-version: 1.1.42 | ||
- name: Install Dependencies | ||
run: bun install --frozen-lockfile | ||
- name: Type Check | ||
run: bun typecheck | ||
- name: Lint Check | ||
run: bun lint | ||
- name: Format Check | ||
run: bun format | ||
- name: Test Coverage Check (UI) | ||
run: bun test:ui | ||
- name: Test Coverage Check (Server) | ||
run: bun test: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,80 @@ | ||
name: Deploy | ||
|
||
on: | ||
push: | ||
branches: | ||
- main | ||
workflow_dispatch: | ||
inputs: | ||
environment: | ||
description: "Select the environment" | ||
required: true | ||
default: "qa" | ||
type: choice | ||
options: | ||
- qa | ||
- prod | ||
git_hash: | ||
description: "Optional git commit hash or branch (defaults to latest in main)" | ||
required: false | ||
default: "" | ||
|
||
jobs: | ||
build: | ||
name: Build and Push Image | ||
runs-on: ubuntu-latest | ||
steps: | ||
- name: Checkout Code | ||
uses: actions/checkout@v4 | ||
with: | ||
ref: ${{ github.event.inputs.git_hash || 'main' }} | ||
- name: Set Variables | ||
id: vars | ||
run: | | ||
if [ "${{ github.event.inputs.git_hash }}" == "" ]; then | ||
echo "No git_hash input provided, using latest commit in main branch" | ||
GIT_HASH=${{ github.sha }} | ||
else | ||
echo "Using provided git hash" | ||
GIT_HASH=${{ github.event.inputs.git_hash }} | ||
fi | ||
echo "GIT_HASH=$GIT_HASH" >> $GITHUB_OUTPUT | ||
- name: Build Image | ||
run: | | ||
podman build -t app:${{ steps.vars.outputs.GIT_HASH }} \ | ||
--build-arg VERSION=$(echo ${{ steps.vars.outputs.GIT_HASH }} | cut -c1-7) \ | ||
. | ||
# NOTE: The last two steps are only for template purposes. Post building the image, you should be pushing it to an | ||
# image registry/repository which could be public facing or internal if you are a private organization. | ||
# When you use this template, make sure to replace these steps with the appropriate ones for your use case. | ||
- name: Save Image | ||
run: | | ||
podman save app:${{ steps.vars.outputs.GIT_HASH }} -o app_${{ steps.vars.outputs.GIT_HASH }}.tar | ||
- name: Upload Image Artifact | ||
uses: actions/upload-artifact@v4 | ||
with: | ||
name: app_${{ steps.vars.outputs.GIT_HASH }} | ||
path: app_${{ steps.vars.outputs.GIT_HASH }}.tar | ||
# NOTE: Post building the image, you should be pulling it from where you pushed it to using whatever tool you use to | ||
# deploy your application to your infrastructure (i.e. Kubernetes). This is just a template to show you where the deploy | ||
# job would go. | ||
deploy: | ||
name: Deploy Image | ||
runs-on: ubuntu-latest | ||
needs: build | ||
steps: | ||
- name: Set Variables | ||
id: vars | ||
run: | | ||
if [ "${{ github.event.inputs.git_hash }}" == "" ]; then | ||
echo "No git_hash input provided, using latest commit in main branch" | ||
GIT_HASH=${{ github.sha }} | ||
else | ||
echo "Using provided git hash" | ||
GIT_HASH=${{ github.event.inputs.git_hash }} | ||
fi | ||
echo "GIT_HASH=$GIT_HASH" >> $GITHUB_OUTPUT | ||
- name: Download Image Artifact | ||
uses: actions/download-artifact@v4 | ||
with: | ||
name: app_${{ steps.vars.outputs.GIT_HASH }} |
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,44 @@ | ||
# Sandbox workflow to build and push ephemeral sandbox deployments on every pull request to the main branch. | ||
# This is useful for testing changes in a production-like environment before merging them into the main branch. | ||
name: Sandbox | ||
|
||
on: | ||
pull_request: | ||
branches: | ||
- main | ||
|
||
jobs: | ||
build: | ||
name: Build and Push Image | ||
runs-on: ubuntu-latest | ||
steps: | ||
- name: Checkout Code | ||
uses: actions/checkout@v4 | ||
- name: Build Image | ||
run: | | ||
podman build -t app:sandbox-${{ github.event.pull_request.number }} \ | ||
--build-arg VERSION=sandbox-${{ github.event.pull_request.number }} \ | ||
. | ||
# NOTE: The last two steps are only for template purposes. Post building the image, you should be pushing it to an | ||
# image registry/repository which could be public facing or internal if you are a private organization. | ||
# When you use this template, make sure to replace these steps with the appropriate ones for your use case. | ||
- name: Save Image | ||
run: | | ||
podman save app:sandbox-${{ github.event.pull_request.number }} -o app_sandbox_${{ github.event.pull_request.number }}.tar | ||
- name: Upload Image Artifact | ||
uses: actions/upload-artifact@v4 | ||
with: | ||
name: app_sandbox_${{ github.event.pull_request.number }} | ||
path: app_sandbox_${{ github.event.pull_request.number }}.tar | ||
# NOTE: Post building the image, you should be pulling it from where you pushed it to using whatever tool you use to | ||
# deploy your application to your infrastructure (i.e. Kubernetes). This is just a template to show you where the deploy | ||
# job would go. | ||
deploy: | ||
name: Deploy Image | ||
runs-on: ubuntu-latest | ||
needs: build | ||
steps: | ||
- name: Download Image Artifact | ||
uses: actions/download-artifact@v4 | ||
with: | ||
name: app_sandbox_${{ github.event.pull_request.number }} |
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,8 @@ | ||
coverage | ||
dist | ||
node_modules | ||
|
||
.DS_Store | ||
.env | ||
.env.local | ||
/*.tgz |
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 @@ | ||
22.11.0 |
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,4 @@ | ||
coverage | ||
dist | ||
node_modules | ||
mockServiceWorker.js |
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,3 @@ | ||
{ | ||
"printWidth": 100 | ||
} |
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 @@ | ||
{ | ||
"editor.codeActionsOnSave": { | ||
"source.fixAll": "always" | ||
}, | ||
"editor.formatOnSave": true, | ||
"editor.rulers": [100], | ||
"files.autoSave": "onFocusChange", | ||
"files.insertFinalNewline": 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,24 @@ | ||
FROM oven/bun:1.1.42-alpine | ||
|
||
WORKDIR /app | ||
|
||
COPY package.json bun.lock ./ | ||
RUN bun install --frozen-lockfile | ||
|
||
ARG VERSION | ||
ENV VITE_VERSION=$VERSION | ||
|
||
COPY public ./public | ||
RUN echo "{ \"version\": \"${VERSION}\" }" > ./public/version.json | ||
|
||
COPY index.html ./ | ||
COPY tsconfig.json ./ | ||
COPY vite.config.ts ./ | ||
COPY src ./src | ||
COPY backend ./backend | ||
|
||
RUN bun run build | ||
|
||
EXPOSE 8000 | ||
|
||
CMD ["bun", "start: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,118 @@ | ||
# Template: SolidJS + Elysia | ||
|
||
Template for [SolidJS](https://www.solidjs.com/) SPA with [Elysia](https://elysiajs.com/at-glance.html) BFF (Backend-for-Frontend) layer. Elysia was chosen because it is performant, uses TypeScript thus creating language symmetry on both ends of the stack and, provides end-to-end type safety between the server (BFF) and the client (SPA) via [Eden Treaty](https://elysiajs.com/eden/treaty/overview.html). Furthermore, Elysia has a healthy and growing plugin ecosystem that provides first-party support for popular tools like [Swagger](https://elysiajs.com/plugins/swagger.html) for API documentation and [OpenTelemetry](https://elysiajs.com/plugins/opentelemetry.html) that provides observability, metrics and tracing to identify bottlenecks and general server performance which are important when productionizing applications. | ||
|
||
With all of the above said, this additional BFF layer serves the following purposes: | ||
|
||
- It is the primary source of data for the SolidJS frontend (`/api`). It will do the work of interfacing with external data sources for the sake of the frontend. | ||
- It is responsible for serving the production built frontend assets generated from `bun run build`. | ||
- Building on first point, issues related to CORS are gone as the frontend and backend BFF share the same origin URL. | ||
- Can enrich or massage data for the frontend if/when desired. | ||
|
||
Other things configured include: | ||
|
||
- TypeScript (for both SPA and BFF) | ||
- [Solid Query](https://tanstack.com/query/latest/docs/framework/solid/overview#motivation) (for data fetching / caching against BFF layer) | ||
- [MSW](https://mswjs.io/docs/getting-started) + [Solid Testing Library](https://github.com/solidjs/solid-testing-library) + Vitest (for SPA testing) | ||
- Bun Test (for BFF testing) | ||
- ESLint / Prettier | ||
- Dockerfile (for containerized deployments) | ||
- GitHub Actions | ||
- `ci.yaml`: Workflow for running code quality checks (linting, formatting, typechecks, tests). | ||
- `sandbox.yaml`: Workflow for building and pushing ephemeral deployments on every pull request to `main`. (_Developer Note: make sure to create a separate cleanup sandbox workflow that tears down the ephemeral deployment once the pull request has been merged to `main`_) | ||
- `deploy.yaml`: Workflow for building and pushing deployments on merge to `main`. Has a manual `workflow_dispatch` configured to support manual pushes as well. You can imagine the workflow being set where, on every merge to `main` you continuously deploy your app to some `qa` or `staging` environment. When you are satisfied with the changes, you can then manually trigger the workflow to push either the latest in `main` or git hash to your production environment. | ||
- _Developer Notes: For the `sandbox.yaml` and `deploy.yaml` workflows, there are placeholder jobs that store the production image artifacts of the application. It is expected that when using this template, you remove those placeholder jobs and update the workflows to reflect your deployment use-case (e.g. push images to an image repository of some kind followed by deploying the image to Kubernetes or elsewhere)._ | ||
|
||
### Comments | ||
|
||
Ideally, we would use `bun` for everything (frontend + backend) but there are gaps, specifically for the frontend, in the following two areas which force us to use Vite + Vitest: **bundling** and **testing**. | ||
|
||
On the bundling side, Bun does not support bundling `index.html` nor injecting any bundled JS asset into the `index.html` file. We can probably work around this via doing some manual scripting but that is not worth doing for what is already a solved problem using other tools. | ||
|
||
This is why we use Vite for bundling the frontend as there is the official `vite-plugin-solid` which does all the work under the hood for helping Vite to work with Solid. Furthermore, that same Vite plugin is what helps us to write tests against the SolidJS frontend using Vitest. | ||
|
||
On the day when Bun provides an official plugin for Solid where it can bundle the web app and allow for writing tests against it, we can then deprecate Vite/Vitest and rely on Bun as the primary toolchain for the entire repository. | ||
|
||
## Getting Started | ||
|
||
Some pre-requisites before install dependencies: | ||
|
||
- Install Node Version Manager (NVM) | ||
```bash | ||
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash | ||
``` | ||
- Install Bun | ||
```bash | ||
curl -fsSL https://bun.sh/install | bash | ||
``` | ||
|
||
### Installing Dependencies | ||
|
||
```bash | ||
nvm use | ||
bun install | ||
``` | ||
|
||
### Local Development Build | ||
|
||
```bash | ||
# Note: UI dev server running on port 3000 proxies API requests to port 8000 | ||
bun start # http://localhost:3000 | ||
bun start:server --watch # http://localhost:8000 | ||
|
||
bun start:msw # start UI with mock server | ||
``` | ||
|
||
### Local Production Build | ||
|
||
```bash | ||
bun run build # Build production frontend static assets | ||
bun start:server # Backend serves assets at http://localhost:8000 | ||
|
||
docker-compose up -d # Or alternatively using docker-compose | ||
``` | ||
|
||
### Linting & Formatting | ||
|
||
```bash | ||
bun lint # checks source for lint violations | ||
bun format # checks source for format violations | ||
|
||
bun lint:fix # fixes lint violations | ||
bun format:fix # fixes format violations | ||
``` | ||
|
||
### Unit Testing | ||
|
||
> We use [Solid Testing Library](https://github.com/solidjs/solid-testing-library) for integration style unit tests | ||
```bash | ||
bun test:ui | ||
bun test:server # or `bun test` | ||
|
||
bun test:ui --coverage # with test coverage | ||
bun test:server --coverage # with test coverage | ||
``` | ||
|
||
### Docker / Podman Image | ||
|
||
The provided `Dockerfile` includes all the things needed to build the SPA and BFF to support a containerized deployment model. | ||
Recommended to use `podman` as it is daemon-less and does not require root privileges which offers better security, especially in shared environments. | ||
|
||
```bash | ||
# Using Podman (recommended) | ||
podman build -t [tag_name] . | ||
|
||
# Using Docker | ||
docker build -t [tag_name] . | ||
``` | ||
|
||
### Contributing | ||
|
||
The only requirements when contributing are: | ||
|
||
- You keep a clean git history in your branch | ||
- rebasing `main` instead of making merge commits. | ||
- Using proper commit message formats that adhere to [conventional commits](https://www.conventionalcommits.org/en/v1.0.0/) | ||
- Additionally, squashing (via rebase) commits that are not [conventional commits](https://www.conventionalcommits.org/en/v1.0.0/) | ||
- CI checks pass before merging into `main` |
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,13 @@ | ||
import { treaty } from "@elysiajs/eden"; | ||
import { describe, expect, it } from "vitest"; | ||
|
||
import { app } from "../server"; | ||
|
||
const api = treaty(app); | ||
|
||
describe("Elysia", () => { | ||
it("return a response", async () => { | ||
const { data } = await api.api.hello.get(); | ||
expect(data).toEqual({ message: "Hello World API!" }); | ||
}); | ||
}); |
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,5 @@ | ||
import { Elysia } from "elysia"; | ||
|
||
const api = new Elysia({ prefix: "/api" }).get("/hello", () => ({ message: "Hello World API!" })); | ||
|
||
export default api; |
Oops, something went wrong.