Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Generate boostrap.js file with client component refs #193

Draft
wants to merge 19 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -140,5 +140,5 @@ bench-watch: build-bench ## Run benchmark in watch mode
@$(DUNE) exec bench/main.exe --profile=release --display-separate-messages --no-print-directory --watch

.PHONY: once
once: build-bench ## Run benchmark once
@time _build/default/bench/once.exe
once: ## Run benchmark once
@$(DUNE) exec _build/default/bench/once.exe
2 changes: 1 addition & 1 deletion bench/once.re
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
Printf.printf("Rendering app to stdout\n");
Printf.printf("Rendering a Hello world component to stdout\n\n");
let start = Unix.gettimeofday();
print_endline(ReactDOM.renderToStaticMarkup(<HelloWorld />));
let end_time = Unix.gettimeofday();
Expand Down
47 changes: 47 additions & 0 deletions demo/client/build.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import esbuild from 'esbuild';

async function build(input, output) {
let outdir = undefined;
let outfile = undefined;
let splitting = false;

/* shitty way to check if output is a directory or a file */
if (output.endsWith('/')) {
outdir = output;
splitting = true;
} else {
outfile = output;
splitting = false;
}
try {
const result = await esbuild.build({
entryPoints: [input],
bundle: true,
platform: 'browser',
format: 'esm',
splitting,
logLevel: 'error',
outdir: outdir,
outfile: outfile,
plugins: [],
write: true,
metafile: true,
});

console.log('Build completed successfully for "' + input + '"');
return result;
} catch (error) {
console.error('\nBuild failed:', error);
process.exit(1);
}
}

const input = process.argv[2];
const output = process.argv[3];

if (!input) {
console.error('Please provide an input file path');
process.exit(1);
}

build(input, output);
64 changes: 26 additions & 38 deletions demo/client/dune
Original file line number Diff line number Diff line change
@@ -1,62 +1,50 @@
(melange.emit
(alias melange-app)
(target app)
(enabled_if
(= %{profile} "dev"))
(modules index)
(libraries melange demo_shared_js reason-react melange.dom melange-webapi)
(preprocess
(pps reason-react-ppx browser_ppx -js melange.ppx))
(module_systems es6))
(pps browser_ppx -js reason-react-ppx melange.ppx))
(module_systems
(es6 js))
(enabled_if
(= %{profile} "dev")))

(rule
(alias client)
; Make the client rule depend on the generated file by melange.emit, so it needs to wait to be built and it's rebuilt when the file changes.
(deps
(alias_rec melange-app))
(enabled_if
(= %{profile} "dev"))
(alias_rec melange-app)
(:script build.mjs))
(target app.js)
(action
(progn
(run
esbuild
app/demo/client/index.js
--format=cjs
--bundle
--platform=browser
--log-level=error
--outfile=app/demo/client/app.js))))
(run node %{script} app/demo/client/index.js %{target})))
(enabled_if
(= %{profile} "dev")))

(rule
(alias client)
(deps
(:file create-from-fetch.jsx)
(alias_rec melange-app))
(alias_rec melange-app)
(:input create-from-fetch.jsx)
(:script build.mjs))
(action
(progn
(run
esbuild
%{file}
--bundle
--platform=browser
--splitting
--outdir=app/demo/client
--format=esm
--log-level=error))))
(run node %{script} %{input} "app/demo/client/")))
(enabled_if
(= %{profile} "dev")))

(rule
(alias client)
(deps
(:file runtime-with-client.jsx)
(alias_rec melange-app))
(alias_rec melange-app)
(:input runtime-with-client.jsx)
(:script build.mjs)
(:mapper
%{workspace_root}/packages/melange-file-mapper/client_components_mapper.exe))
(action
(progn
(run
esbuild
%{file}
--bundle
--platform=browser
--format=esm
--splitting
--log-level=error
--outdir=app/demo/client))))
(run %{mapper} bootstrap.js)
(run node %{script} %{input} "app/demo/client/")))
(enabled_if
(= %{profile} "dev")))
26 changes: 1 addition & 25 deletions demo/client/runtime-with-client.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,31 +11,7 @@ const React = require("react");
const ReactDOM = require("react-dom/client");
const ReactServerDOM = require("react-server-dom-webpack/client");

/* bootstrap.js */

window.__client_manifest_map = {};

const register = (name, render) => {
console.log("Client ref registered:", name);
window.__client_manifest_map[name] = render;
};

register(
"Counter",
React.lazy(() => import("./app/demo/universal/js/Counter.js").then(module => ({ default: module.make })))
);

register(
"Note_editor",
React.lazy(() => import("./app/demo/universal/js/Note_editor.js").then(module => ({ default: module.make }))),
);

/* register(
"Promise_renderer",
React.lazy(() => import("./app/demo/universal/js/Promise_renderer.js")),
); */

/* end bootstrap.js */
require("./bootstrap.js");

class ErrorBoundary extends React.Component {
constructor(props) {
Expand Down
3 changes: 0 additions & 3 deletions demo/dune
Original file line number Diff line number Diff line change
@@ -1,6 +1,3 @@
;(flags
; (-alert ++browser_only -alert ++not_implemented -warn-error +A-d))

(rule
(alias demo)
(enabled_if
Expand Down
20 changes: 17 additions & 3 deletions demo/server/server.re
Original file line number Diff line number Diff line change
Expand Up @@ -89,10 +89,24 @@ module Page = {
])}>
{React.string("This is a small form")}
</p>
/* TODO: payload is wrong in client components */
<Note_editor title="Hello" body="World" />
<Hr />
<Counter initial=123 />
<div className="text-white">
<Counter
string="Title"
int=1
float=1.1
bool_true=true
bool_false=false
string_array=[|"Item 1", "Item 2"|]
string_list=["Item 1", "Item 2"]
object_={
`Assoc([
("name", `String("John")),
("age", `Int(30)),
])
}
/>
</div>
<Hr />
</Stack>
</Layout>,
Expand Down
89 changes: 89 additions & 0 deletions demo/universal/js/Counter.re
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
open Ppx_deriving_json_runtime.Primitives;

[@react.component]
let make =
(
~string: string,
~int: int,
~float: float,
~bool_true: bool,
~bool_false: bool,
~string_array: [@deriving json] array(string),
~string_list: [@deriving json] list(string),
~object_: Js.Json.t,
) => {
<div>
<code>
<pre> {React.string("string - ")} {React.string(string)} </pre>
<pre> {React.string("int - ")} {React.int(int)} </pre>
<pre> {React.string("float - ")} {React.float(float)} </pre>
<pre>
{React.string("bool_true - ")}
{React.string(bool_true ? "true" : "false")}
</pre>
<pre>
{React.string("bool_false - ")}
{React.string(bool_false ? "true" : "false")}
</pre>
<pre>
{React.string("string_list - ")}
{string_list
|> Array.of_list
|> Array.map(item =>
<span key=item>
{React.string(item)}
{React.string(" ")}
</span>
)
|> React.array}
</pre>
<pre>
{React.string("string_array - ")}
{string_array
|> Array.map(item =>
<span key=item>
{React.string(item)}
{React.string(" ")}
</span>
)
|> React.array}
</pre>
<pre>
{React.string("object_ - ")}
{React.string(Js.Json.stringify(object_))}
</pre>
</code>
</div>;
};

let make_client = props => {
make({
"string": string_of_json(props##string),
"int": int_of_json(props##int),
"float": float_of_json(props##float),
"bool_true": bool_of_json(props##bool_true),
"bool_false": bool_of_json(props##bool_false),
"string_array": array_of_json(string_of_json, props##string_array),
"string_list": list_of_json(string_of_json, props##string_list),
"object_": props##object_,
});
};

/*
let make_client = props => {
React.jsx(
make,
makeProps(
~string=string_of_json(props##string),
~int=int_of_json(props##int),
~float=float_of_json(props##float),
~bool_true=bool_of_json(props##bool_true),
~bool_false=bool_of_json(props##bool_false),
~string_array=array_of_json(string_of_json, props##string_array),
~string_list=list_of_json(string_of_json, props##string_list),
~object_=props##object_,
(),
),
);
};
*/
10 changes: 8 additions & 2 deletions demo/universal/js/dune
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,15 @@
(name demo_shared_js)
(modes melange)
(wrapped false)
(libraries reason-react melange-webapi melange.belt melange.js melange.dom)
(libraries
reason-react
melange-webapi
melange.belt
melange.js
melange.dom
melange-json)
(preprocess
(pps melange.ppx reason-react-ppx browser_ppx -js)))
(pps melange.ppx reason-react-ppx browser_ppx -js melange-json.ppx)))

(copy_files
(mode fallback)
Expand Down
6 changes: 5 additions & 1 deletion demo/universal/native/dune
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,8 @@
(libraries react reactDOM js belt dom webapi yojson lwt)
(wrapped false)
(preprocess
(pps melange_native_ppx server_reason_react_ppx browser_ppx)))
(pps
melange_native_ppx
server_reason_react_ppx
browser_ppx
melange-json-native.ppx)))
6 changes: 1 addition & 5 deletions demo/universal/native/lib/App.re
Original file line number Diff line number Diff line change
Expand Up @@ -87,10 +87,6 @@ let make = () => {
});

<Layout background=Theme.Color.black>
<Stack gap=8 justify=`start>
<Title />
<Hr />
<Counter initial=22 />
</Stack>
<Stack gap=8 justify=`start> <Title /> </Stack>
</Layout>;
};
Loading
Loading