Skip to content

Commit

Permalink
Fix demo with dream (#150)
Browse files Browse the repository at this point in the history
  • Loading branch information
davesnx authored Jul 30, 2024
1 parent 5f4c7eb commit e584585
Show file tree
Hide file tree
Showing 23 changed files with 431 additions and 662 deletions.
8 changes: 6 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@ build: ## Build the project, including non installable libraries and executables
build-prod: ## Build for production (--profile=prod)
$(DUNE) build packages --profile=prod

.PHONY: build-demo
build-demo: ## Build the project, including non installable libraries and executables
$(DUNE) build packages --profile=dev @install @client

.PHONY: dev
dev: ## Build in watch mode
$(DUNE) build -w --profile=dev @all
Expand Down Expand Up @@ -87,11 +91,11 @@ lib-test: ## Run library tests
$(DUNE) exec test/test.exe

.PHONY: demo
demo: build ## Run demo executable
demo: build-demo ## Run demo executable
$(DUNE) exec demo/server/server.exe --display-separate-messages --no-print-directory --profile=dev

.PHONY: demo-watch
demo-watch: build ## Run demo executable in watch mode
demo-watch: build-demo ## Run demo executable in watch mode
$(DUNE) exec demo/server/server.exe --display-separate-messages --no-print-directory --display=quiet --watch --profile=dev

.PHONY: subst
Expand Down
51 changes: 51 additions & 0 deletions demo/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
# server-reason-react demo

The app consist of 3 folders: `shared`, `server` and `client`, which encapsulates each compilation target defined by dune.

## `client/`

A folder that contains the code executed in the client only. It's defined in dune as a `melange.emit` to emit JavaScript from Reason via Melange. It uses all the ReScript goodies: Belt, Js, etc. Currently is tiny: client only renders the `Shared_js.App` component:

```re
switch (ReactDOM.querySelector("#root")) {
| Some(el) => ReactDOM.render(<Shared_js.App />, el)
| None => ()
};
```

## `server/`

An executable that expose a dream app with a home route which serves an HTML page. Written in [server-reason-react](https://github.com/ml-in-barcelona/server-reason-react) and send it as a string with `ReactDOM.renderToString`

## `universal/`

The folder contains the library for shared code between `client` and `server`. dune generates two libraries `Shared_js` and `Shared_native` (by using `copy_files#`) with separate dependencies for each:

```dune
; universal/js/dune
(library
(name shared_js)
(modes melange)
(libraries reason-react)
(preprocess (pps reason-react-ppx)))
(copy_files# "../*.re")
```

```dune
; universal/native/dune
(library
(name shared_native)
(modes native)
(libraries
server-reason-react.react
server-reason-react.reactDom)
(preprocess
(pps server-reason-react.ppx)))
(copy_files# "../*.re")
```

`Shared_js` is compiled by Melange to JavaScript while `Shared_native` compiled by OCaml to native.

<!-- Link to documentation -->
11 changes: 10 additions & 1 deletion demo/server/Page.re → demo/server/Document.re
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ let globalStyles = {js|
padding: 0;
width: 100vw;
height: 100vh;
background-color: #161615; /* Theme.Color.black; */
}
* {
Expand All @@ -12,6 +13,15 @@ let globalStyles = {js|
-moz-osx-font-smoothing: grayscale;
box-sizing: border-box;
}
@keyframes spin {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}
|js};

[@react.component]
Expand All @@ -30,7 +40,6 @@ let make = (~children, ~script=?) => {
dangerouslySetInnerHTML={"__html": globalStyles}
/>
<script src="https://cdn.tailwindcss.com" />
<div id="randomId" />
{switch (script) {
| None => React.null
| Some(src) => <script type_="module" src />
Expand Down
3 changes: 2 additions & 1 deletion demo/server/Esbuild.re
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
let build_folder = "_build/default/demo/client/app";

let build = (~entry_point, ~outfile, ()) => {
let build_folder = "_build/default/demo/client/app";
let output = Filename.concat(build_folder, outfile);
let entry = Filename.concat(build_folder, entry_point);
let command =
Expand Down
101 changes: 38 additions & 63 deletions demo/server/comments.re
Original file line number Diff line number Diff line change
Expand Up @@ -18,25 +18,6 @@ module Spinner = {
};
};

module Sidebar = {
let make = () => {
<aside>
<h3> {React.string("Archive")} </h3>
<ul>
<li> {React.string("May 2021")} </li>
<li> {React.string("April 2021")} </li>
<li> {React.string("March 2021")} </li>
<li> {React.string("February 2021")} </li>
<li> {React.string("January 2021")} </li>
<li> {React.string("December 2020")} </li>
<li> {React.string("November 2020")} </li>
<li> {React.string("October 2020")} </li>
<li> {React.string("September 2020")} </li>
</ul>
</aside>;
};
};

module Post = {
let make = () => {
<section>
Expand All @@ -61,6 +42,9 @@ module Data = {
"Wait, it doesn't wait for React to load?",
"How does this even work?",
"I like marshmallows",
"!1!1!1! This is a comment",
"This is actually static from the server",
"But, imagine it's dynamic",
];

let cached = ref(false);
Expand All @@ -84,60 +68,51 @@ module Comments = {
/* Sincronous data: let comments = Data.get(); */
let comments = React.Experimental.use(Data.promise());

<>
<div className="flex gap-4 flex-col">
{comments
|> List.mapi((i, comment) =>
<p
key={Int.to_string(i)}
style={ReactDOM.Style.make(
~border="2px solid #facedd",
~borderRadius="4px",
~padding="8px 8px",
~margin="2px",
(),
)}>
className="font-semibold border-2 border-yellow-200 rounded-lg p-2 bg-yellow-600 text-slate-900">
{React.string(comment)}
</p>
)
|> React.list}
</>;
};
};

module Layout = {
[@react.component]
let make = (~children) => {
<div style={ReactDOM.Style.make(~padding="20px", ~height="100%", ())}>
children
</div>;
};
};

module App = {
let make = () => {
<Layout>
<nav> <a href="/"> {React.string("Home")} </a> </nav>
<main
style={ReactDOM.Style.make(~display="flex", ~marginTop="16px", ())}>
<aside
className="sidebar"
style={ReactDOM.Style.make(~marginRight="16px", ())}>
<Sidebar />
</aside>
<React.Suspense fallback={<Spinner />}>
<article className="post">
<h1> {React.string("Hello world")} </h1>
<Post />
<section className="comments">
<h3> {React.string("Comments")} </h3>
<React.Suspense fallback={<Spinner />}>
<Comments />
</React.Suspense>
</section>
<h2> {React.string("Thanks for reading!")} </h2>
</article>
</React.Suspense>
</main>
</Layout>;
};
[@react.component]
let make = () => {
<Layout background=Theme.Color.black>
<main
className={Theme.text(Theme.Color.white)}
style={ReactDOM.Style.make(~display="flex", ~marginTop="16px", ())}>
<React.Suspense fallback={<Spinner />}>
<article className="flex gap-4 flex-col">
<h1
className={Cx.make([
"text-4xl font-bold ",
Theme.text(Theme.Color.white),
])}>
{React.string("Hello world")}
</h1>
<Post />
<section>
<h3
className={Cx.make([
"text-2xl font-bold mb-4",
Theme.text(Theme.Color.white),
])}>
{React.string("Comments")}
</h3>
<React.Suspense fallback={<Spinner />}>
<Comments />
</React.Suspense>
</section>
<h2> {React.string("Thanks for reading!")} </h2>
</article>
</React.Suspense>
</main>
</Layout>;
};
11 changes: 1 addition & 10 deletions demo/server/dune
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,6 @@
(enabled_if
(= %{profile} "dev"))
(flags :standard -w -26-27) ; browser_only removes code form the server, making this warning necessary
(libraries
tiny_httpd
tiny_httpd.core
tiny_httpd.unix
shared_native
react
reactDOM
js
lwt.unix
unix)
(libraries dream shared_native react reactDOM js lwt.unix unix belt)
(preprocess
(pps server_reason_react_ppx melange_native_ppx browser_ppx lwt_ppx)))
Loading

0 comments on commit e584585

Please sign in to comment.