Skip to content

Commit

Permalink
Merge pull request #446 from danilaplee/websocket-realtime-updates
Browse files Browse the repository at this point in the history
feat: websocket realtime updates and added dockerfile
  • Loading branch information
steida authored Jul 16, 2024
2 parents 5a2a8a7 + ab24e09 commit 21698ae
Show file tree
Hide file tree
Showing 26 changed files with 552 additions and 56 deletions.
7 changes: 7 additions & 0 deletions .changeset/lovely-buckets-argue.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
"@evolu/common": major
"@evolu/server": major
"server": major
---

websocket integration and realtime updates
15 changes: 15 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
.turbo
node_modules
db.sqlite
**/node_modules
**/**/node_modules
apps/native
apps/web
packages/evolu-react
packages/evolu-react-native
packages/evolu-common-react
packages/evolu-common-web
pnpm-lock.yaml
dist
**/dist
**/**/dist
42 changes: 42 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -64,3 +64,45 @@ jobs:
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
push_to_registry:
name: Push Docker image to Docker Hub
runs-on: ubuntu-latest
permissions:
packages: write
contents: read
attestations: write
id-token: write
steps:
- name: Check out the repo
uses: actions/checkout@v4

- name: Set up QEMU
uses: docker/setup-qemu-action@v3

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3

- name: Log in to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}

- name: Extract metadata (tags, labels) for Docker
id: meta
uses: docker/metadata-action@9ec57ed1fcdbf14dcef7dfbe97b2010124a938b7
with:
images: evoluhq/evolu

- name: Build and push Docker image
id: push
uses: docker/build-push-action@v6
with:
platforms: linux/amd64,linux/arm64
context: .
file: ./apps/server/Dockerfile
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}


16 changes: 16 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,22 @@

Local-first apps allow users to own their data by storing them on their devices. Modern browsers provide API designed precisely for that. How is it different from keeping files on disk? Files are not the right abstraction for apps and cannot synchronize among devices. That's why traditional apps use the client-server architecture. But using client-server architecture also means that users' ability to use an app depends on some server that can be offline, temporarily or forever, if a company decides to ban a user or even goes bankrupt. That's unfortunate. Luckily, a way to restore data ownership exists. It's Evolu.

## Running the server

Currently the easiest solution to run an evolu server would be to use the docker image:

1. Pull the docker image

`docker pull evoluhq/evolu:main`

2. Create an empty sqlite file for mounting the database

`touch db.sqlite`

3. startup the evolu server on `port` `4000` and `mount` database file on `./db.sqlite` that we created previously

`docker run --name evolu -p 4000:4000 -v $(pwd)/db.sqlite:/home/node/app/apps/server/db.sqlite -d evoluhq/evolu:main`

## Documentation

For detailed information and usage examples, please visit [evolu.dev](https://www.evolu.dev).
Expand Down
1 change: 1 addition & 0 deletions apps/native/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
"@evolu/react-native": "workspace:*",
"@expo/metro-runtime": "~3.2.1",
"@react-native-community/netinfo": "11.3.1",
"@types/react-native": "^0.73.0",
"babel-plugin-module-resolver": "^5.0.2",
"crypto-browserify": "^3.12.0",
"effect": "^3.2.1",
Expand Down
1 change: 1 addition & 0 deletions apps/native/src/db/db.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ export const createDatabase = () =>
indexes,
...(process.env.NODE_ENV === "development" && {
syncUrl: "http://localhost:4000",
enableWebsocketConnection: true,
}),
initialData: (evolu) => {
const { id: categoryId } = evolu.create("todoCategory", {
Expand Down
3 changes: 2 additions & 1 deletion apps/server/.dockerignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
.turbo
node_modules
db.sqlite
db.sqlite
dist
141 changes: 141 additions & 0 deletions apps/server/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
FROM node:20-alpine AS builder

RUN mkdir -p /home/node/app

ENV NPM_CONFIG_PREFIX=/home/node/.npm-global

ENV PATH=$PATH:/home/node/.npm-global/bin

WORKDIR /home/node/app

RUN npm i -g pnpm

RUN ls -l /home/node/.npm-global

COPY . /home/node/app/

RUN ls -l /home/node/app/

RUN pnpm i --shamefully-hoist

RUN pnpm build

RUN rm -rf /home/node/app/apps/server/.dockerignore

RUN ls /home/node/app/node_modules/

#MANUALLY LINK PACKAGES TO REDUCE THE DOCKER IMAGE SIZE
RUN mkdir /home/node/app/packages/evolu-server/node_modules/effect/
RUN mkdir /home/node/app/packages/evolu-common/node_modules/effect/
RUN mkdir /home/node/app/packages/evolu-common/node_modules/@effect/
RUN cp -r /home/node/app/node_modules/effect/* /home/node/app/packages/evolu-server/node_modules/effect/
RUN cp -r /home/node/app/node_modules/effect/* /home/node/app/packages/evolu-common/node_modules/effect/
RUN cp -r /home/node/app/node_modules/@effect/* /home/node/app/packages/evolu-common/node_modules/@effect/

RUN mkdir /home/node/app/packages/evolu-common/node_modules/@noble/
RUN mv /home/node/app/node_modules/@noble/* /home/node/app/packages/evolu-common/node_modules/@noble/

RUN mkdir /home/node/app/packages/evolu-common/node_modules/@protobuf-ts/
RUN mv /home/node/app/node_modules/@protobuf-ts/* /home/node/app/packages/evolu-common/node_modules/@protobuf-ts/

RUN mkdir /home/node/app/packages/evolu-common/node_modules/@scure/
RUN mv /home/node/app/node_modules/@scure/* /home/node/app/packages/evolu-common/node_modules/@scure/

RUN mkdir /home/node/app/packages/evolu-common/node_modules/fast-check/
RUN mv /home/node/app/node_modules/fast-check/* /home/node/app/packages/evolu-common/node_modules/fast-check/

RUN mkdir /home/node/app/packages/evolu-common/node_modules/find-my-way-ts/
RUN mv /home/node/app/node_modules/find-my-way-ts/* /home/node/app/packages/evolu-common/node_modules/find-my-way-ts/

RUN mkdir /home/node/app/packages/evolu-common/node_modules/path-browserify/
RUN mv /home/node/app/node_modules/path-browserify/* /home/node/app/packages/evolu-common/node_modules/path-browserify/

RUN mkdir /home/node/app/packages/evolu-common/node_modules/multipasta/
RUN mv /home/node/app/node_modules/multipasta/* /home/node/app/packages/evolu-common/node_modules/multipasta/

RUN mkdir /home/node/app/packages/evolu-common/node_modules/pure-rand/
RUN mv /home/node/app/node_modules/pure-rand/* /home/node/app/packages/evolu-common/node_modules/pure-rand/

RUN mkdir /home/node/app/packages/evolu-common/node_modules/fast-querystring/
RUN mv /home/node/app/node_modules/fast-querystring/* /home/node/app/packages/evolu-common/node_modules/fast-querystring/

RUN mkdir /home/node/app/packages/evolu-common/node_modules/fast-decode-uri-component/
RUN mv /home/node/app/node_modules/fast-decode-uri-component/* /home/node/app/packages/evolu-common/node_modules/fast-decode-uri-component/
RUN mkdir /home/node/app/packages/evolu-server/node_modules/kysely/
RUN mkdir /home/node/app/packages/evolu-common/node_modules/kysely/
RUN cp -r /home/node/app/node_modules/kysely/* /home/node/app/packages/evolu-server/node_modules/kysely/
RUN cp -r /home/node/app/node_modules/kysely/* /home/node/app/packages/evolu-common/node_modules/kysely/

RUN mkdir /home/node/app/packages/evolu-server/node_modules/better-sqlite3/
RUN mv /home/node/app/node_modules/better-sqlite3/* /home/node/app/packages/evolu-server/node_modules/better-sqlite3/

RUN mkdir /home/node/app/packages/evolu-server/node_modules/express/
RUN mv /home/node/app/node_modules/express/* /home/node/app/packages/evolu-server/node_modules/express/

RUN mkdir /home/node/app/packages/evolu-server/node_modules/body-parser/
RUN mv /home/node/app/node_modules/body-parser/* /home/node/app/packages/evolu-server/node_modules/body-parser/

RUN mkdir /home/node/app/packages/evolu-server/node_modules/depd/
RUN mv /home/node/app/node_modules/depd/* /home/node/app/packages/evolu-server/node_modules/depd/

RUN mkdir /home/node/app/packages/evolu-server/node_modules/vary/
RUN mv /home/node/app/node_modules/vary/* /home/node/app/packages/evolu-server/node_modules/vary/

RUN mkdir /home/node/app/packages/evolu-server/node_modules/cors/
RUN mv /home/node/app/node_modules/cors/* /home/node/app/packages/evolu-server/node_modules/cors/

RUN mkdir /home/node/app/packages/evolu-server/node_modules/ws/
RUN mv /home/node/app/node_modules/ws/* /home/node/app/packages/evolu-server/node_modules/ws/

RUN mkdir /home/node/app/packages/evolu-server/node_modules/object-assign/
RUN mv /home/node/app/node_modules/object-assign/* /home/node/app/packages/evolu-server/node_modules/object-assign/

RUN mkdir /home/node/app/packages/evolu-server/node_modules/bindings/
RUN mv /home/node/app/node_modules/bindings/* /home/node/app/packages/evolu-server/node_modules/bindings/

RUN mkdir /home/node/app/packages/evolu-server/node_modules/prebuild-install/
RUN mv /home/node/app/node_modules/prebuild-install/* /home/node/app/packages/evolu-server/node_modules/prebuild-install/

RUN mkdir /home/node/app/packages/evolu-server/node_modules/file-uri-to-path/
RUN mv /home/node/app/node_modules/file-uri-to-path/* /home/node/app/packages/evolu-server/node_modules/file-uri-to-path/

#EXPRESS LINKING FIX
RUN npm i -g express

RUN ls -l /home/node/.npm-global/lib/node_modules/

RUN rm -rf /home/node/app/packages/evolu-server/node_modules/express

RUN cp -r /home/node/.npm-global/lib/node_modules/express /home/node/app/packages/evolu-server/node_modules/

WORKDIR /home/node/.npm-global/lib/node_modules/express

RUN yarn

WORKDIR /home/node/app

RUN cp -r /home/node/.npm-global/lib/node_modules/express/node_modules/* /home/node/app/packages/evolu-server/node_modules/

FROM node:20-alpine

ENV PORT=4000

COPY --from=builder /home/node/app/apps/server /home/node/app/apps/server

COPY --from=builder /home/node/app/packages/evolu-server /home/node/app/packages/evolu-server

COPY --from=builder /home/node/app/packages/evolu-common /home/node/app/packages/evolu-common

RUN cd /home/node/app/apps/server

WORKDIR /home/node/app/

RUN ls -l /home/node/app/packages/evolu-server/node_modules

RUN cat /home/node/app/apps/server/package.json

WORKDIR /home/node/app/apps/server

EXPOSE $PORT

CMD [ "npm", "start" ]
13 changes: 2 additions & 11 deletions apps/server/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,3 @@
import { createExpressApp } from "@evolu/server";
import { Effect } from "effect";
import { createExpressAppWithWebsocket } from "@evolu/server";

Effect.runPromise(createExpressApp).then((app) => {
// eslint-disable-next-line turbo/no-undeclared-env-vars
const port = process.env.PORT || 4000;

app.listen(port, () => {
// eslint-disable-next-line no-console
console.log(`Server is listening at http://localhost:${port}`);
});
});
createExpressAppWithWebsocket();
9 changes: 5 additions & 4 deletions examples/remix/app/entry.client.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
/**
* By default, Remix will handle hydrating your app on the client for you.
* You are free to delete this file if you'd like to, but if you ever want it revealed again, you can run `npx remix reveal` ✨
* For more information, see https://remix.run/file-conventions/entry.client
* By default, Remix will handle hydrating your app on the client for you. You
* are free to delete this file if you'd like to, but if you ever want it
* revealed again, you can run `npx remix reveal` ✨ For more information, see
* https://remix.run/file-conventions/entry.client
*/

import { RemixBrowser } from "@remix-run/react";
Expand All @@ -13,6 +14,6 @@ startTransition(() => {
document,
<StrictMode>
<RemixBrowser />
</StrictMode>
</StrictMode>,
);
});
25 changes: 13 additions & 12 deletions examples/remix/app/entry.server.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
/**
* By default, Remix will handle generating the HTTP Response for you.
* You are free to delete this file if you'd like to, but if you ever want it revealed again, you can run `npx remix reveal` ✨
* For more information, see https://remix.run/file-conventions/entry.server
* By default, Remix will handle generating the HTTP Response for you. You are
* free to delete this file if you'd like to, but if you ever want it revealed
* again, you can run `npx remix reveal` ✨ For more information, see
* https://remix.run/file-conventions/entry.server
*/

import { PassThrough } from "node:stream";
Expand All @@ -22,28 +23,28 @@ export default function handleRequest(
// This is ignored so we can keep it in the template for visibility. Feel
// free to delete this parameter in your app if you're not using it!
// eslint-disable-next-line @typescript-eslint/no-unused-vars
loadContext: AppLoadContext
loadContext: AppLoadContext,
) {
return isbot(request.headers.get("user-agent") || "")
? handleBotRequest(
request,
responseStatusCode,
responseHeaders,
remixContext
remixContext,
)
: handleBrowserRequest(
request,
responseStatusCode,
responseHeaders,
remixContext
remixContext,
);
}

function handleBotRequest(
request: Request,
responseStatusCode: number,
responseHeaders: Headers,
remixContext: EntryContext
remixContext: EntryContext,
) {
return new Promise((resolve, reject) => {
let shellRendered = false;
Expand All @@ -65,7 +66,7 @@ function handleBotRequest(
new Response(stream, {
headers: responseHeaders,
status: responseStatusCode,
})
}),
);

pipe(body);
Expand All @@ -82,7 +83,7 @@ function handleBotRequest(
console.error(error);
}
},
}
},
);

setTimeout(abort, ABORT_DELAY);
Expand All @@ -93,7 +94,7 @@ function handleBrowserRequest(
request: Request,
responseStatusCode: number,
responseHeaders: Headers,
remixContext: EntryContext
remixContext: EntryContext,
) {
return new Promise((resolve, reject) => {
let shellRendered = false;
Expand All @@ -115,7 +116,7 @@ function handleBrowserRequest(
new Response(stream, {
headers: responseHeaders,
status: responseStatusCode,
})
}),
);

pipe(body);
Expand All @@ -132,7 +133,7 @@ function handleBrowserRequest(
console.error(error);
}
},
}
},
);

setTimeout(abort, ABORT_DELAY);
Expand Down
Loading

0 comments on commit 21698ae

Please sign in to comment.