<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Paul Bacchus</title>
    <description>The latest articles on DEV Community by Paul Bacchus (@psb).</description>
    <link>https://dev.to/psb</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1113938%2Ff40e3008-4725-4177-ae76-4b5566a66a1f.jpeg</url>
      <title>DEV Community: Paul Bacchus</title>
      <link>https://dev.to/psb</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/psb"/>
    <language>en</language>
    <item>
      <title>Reason and React Meta-Frameworks</title>
      <dc:creator>Paul Bacchus</dc:creator>
      <pubDate>Tue, 17 Oct 2023 13:49:48 +0000</pubDate>
      <link>https://dev.to/psb/reason-and-react-meta-frameworks-d7n</link>
      <guid>https://dev.to/psb/reason-and-react-meta-frameworks-d7n</guid>
      <description>&lt;p&gt;In &lt;a href="https://dev.to/psb/nextjs-the-app-router-and-reasonreact-2c0j"&gt;my previous post&lt;/a&gt; on trying to use the NextJS App Router and Reason I described some of the problems and limitations of their compatibility with one another. With the &lt;a href="https://github.com/melange-re/melange/releases/tag/2.0.0"&gt;release of Melange 2&lt;/a&gt; I decided to see if the new features of Melange 2 could help to increase the compatibility of Reason and the NextJS App Router. I have also documented some of the things learnt after trying Melange (v1) with Astro and Remix.&lt;/p&gt;

&lt;h2&gt;
  
  
  Melange 2
&lt;/h2&gt;

&lt;p&gt;Melange 2 introduces a couple of new features that help to make Reason and ReasonReact more compatible with the NextJS App Router.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;@mel.as&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;@mel.as&lt;/code&gt; attribute allows us to redefine a name in the output JavaScript. Using &lt;code&gt;@mel.as&lt;/code&gt; we can solve one of the previous problems with NextJS API route functions and Reason. NextJS expects API route functions to export a function with the name of a HTTP method. With &lt;code&gt;@mel.as&lt;/code&gt; we can rename our Reason API function to the HTTP method we want in the output JS and get no export related errors from NextJS:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight reasonml"&gt;&lt;code&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;mel&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="s2"&gt;"POST"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;handler&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="o"&gt;...&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Will be compiled to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;POST&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;param&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;POST&lt;/span&gt; &lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Astro API endpoints also require the route function to be named after a HTTP method, so this will be useful for Astro as well.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;$$default&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Another previous compatibility problem was the export of &lt;code&gt;$$default&lt;/code&gt; whenever &lt;code&gt;default&lt;/code&gt; was used as the function name in ReasonReact instead of &lt;code&gt;make&lt;/code&gt;. The export of &lt;code&gt;$$default&lt;/code&gt; would cause NextJS to complain and not compile. In Melange 2 &lt;code&gt;$$default&lt;/code&gt; is still present but it is exported properly in the output JS:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight reasonml"&gt;&lt;code&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;react&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;component&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;default&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="o"&gt;...&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Compiles to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;Page$default&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Props&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;$$default&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Page$default&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;$$default&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;@mel.as&lt;/code&gt; and the changes to &lt;code&gt;$$default&lt;/code&gt; make Reason and ReasonReact much more compatible with the NextJS App Router.&lt;/p&gt;

&lt;h2&gt;
  
  
  Structuring a Reason and React meta-framework app
&lt;/h2&gt;

&lt;p&gt;After experimenting with Reason plus Astro, NextJS, and Remix, I think there are two main ways to structure a React meta-framework app for use with Reason, and it depends upon how much Reason you want to use and how you are deploying your app. If you want to write a few components in ReasonReact then it is best to promote (i.e., copy) the output JS back into the &lt;code&gt;src&lt;/code&gt; folder of your app. If you want to write most of your app in Reason then it is best to add the meta-framework files as Melange dependencies and then promote all the output JS out of the &lt;code&gt;_build&lt;/code&gt; folder and back into the root.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why promote
&lt;/h3&gt;

&lt;p&gt;Developing in the OCaml way can be done by copying all of the meta-framework files to the &lt;code&gt;_build&lt;/code&gt; folder as Melange dependencies and then serving the app from the JavaScript output folder in &lt;code&gt;_build&lt;/code&gt;. However, I have found that this doesn't always go smoothly and can cause the meta-framework development tooling to behave in unexpected ways. You could try and debug these unexpected behaviours, but ...&lt;/p&gt;

&lt;p&gt;&lt;a href="https://i.giphy.com/media/bWM2eWYfN3r20/giphy.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://i.giphy.com/media/bWM2eWYfN3r20/giphy.gif" alt="no time for that" width="245" height="245"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I have found that the meta-framework dev tooling works much better if you promote the output JS into a folder that the meta-framework dev tooling expects to be used.&lt;/p&gt;

&lt;p&gt;Promoting the output code also makes it much easier to deploy an application via linking a Git repository to a platform like Vercel or Netlify and deploying on push.&lt;/p&gt;

&lt;h3&gt;
  
  
  Promoting components
&lt;/h3&gt;

&lt;p&gt;If your are only using ReasonReact to create a few components then it is best to promote the output JS of those components back into the &lt;code&gt;src&lt;/code&gt; folder. For example, if you have an Astro app like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;/
├── _build/
├── public/
├── src/
│   ├── dune
│   ├── layouts/
│   │   └── Layout.astro
│   ├── pages/
│   │   ├── dogs.astro
│   │   ├── jokes.astro
│   │   └── index.astro
│   └── reason_components/
│       ├── Dog.re
│       ├── Dog.rei
│       ├── Joke.re
│       ├── Joke.rei
│       └── dune
├── package.json
├── astro-reason.cfg.mjs
├── &amp;lt;project_name&amp;gt;.opam
├── dune
├── dune-project
└── Makefile
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After promoting the output of the &lt;code&gt;reason_components&lt;/code&gt; folder you will end up with:&lt;/p&gt;

&lt;pre&gt;
&lt;code&gt;
/
├── _build/
├── public/
├── src/
│   ├── dune
│   ├── layouts/
│   │   └── Layout.astro
│   ├── pages/
│   │   ├── dogs.astro
│   │   ├── jokes.astro
│   │   └── index.astro
│   ├── reason_components/
│   │   ├── Dog.re
│   │   ├── Dog.rei
│   │   ├── Joke.re
│   │   ├── Joke.rei
│   │   └── dune&lt;span&gt;
│   └── reason_components_output/
│       ├── node_modules/
│       └── src/
│           └── reason_components/
│               ├── Dog.js
│               └── Joke.js&lt;/span&gt;
├── package.json
├── astro-reason.cfg.mjs
├── .opam
├── dune
├── dune-project
└── Makefile
&lt;/code&gt;
&lt;/pre&gt;

&lt;p&gt;No doubt, the path to the components in the promoted output folder is ugly and cumbersome, but you can remedy this by adding a path alias in a &lt;code&gt;tsconfig.json&lt;/code&gt; or &lt;code&gt;jsconfig.json&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"compilerOptions"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"baseUrl"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"paths"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"@components/*"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"src/reason_components_output/src/reason_components/*"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Promoting serverless functions
&lt;/h3&gt;

&lt;p&gt;How you promote serverless functions depends on where you are deploying them. If you are using something like Netlify, where functions can be configured independently of the frontend, then promoting the serverless functions folder might be the best option.&lt;/p&gt;

&lt;p&gt;Expanding on the Astro example above we can add serverless functions:&lt;/p&gt;

&lt;pre&gt;
&lt;code&gt;
/
├── _build/
├── public/
├── reason_netlify_functions/
│   ├── dune
│   └── joke.re&lt;span&gt;
├── reason_netlify_functions_output/
│   ├── node_modules/
│   └── reason_netlify_functions/
│       └── joke.js&lt;/span&gt;
├── src/
...
└── Makefile
&lt;/code&gt;
&lt;/pre&gt;

&lt;p&gt;We can then tell Netlify the location of our functions (&lt;code&gt;./reason_netlify_functions_output/reason_netlify_functions&lt;/code&gt;) in a &lt;code&gt;netlify.toml&lt;/code&gt; file. &lt;a href="https://github.com/psb/astro-reason"&gt;See this basic Astro, Reason and Netlify application for an example&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If you are using something like Vercel, where the serverless functions are expected to be in a certain folder, then it might be best to promote the whole app.&lt;/p&gt;

&lt;h3&gt;
  
  
  Promoting the whole app
&lt;/h3&gt;

&lt;p&gt;When promoting only certain folders extra paths are created when the output JS files are copied back next to the Reason source files. If we were to do this for applications that require serverless function routes to be in an &lt;code&gt;api&lt;/code&gt; folder then the path for that route would be long and ugly; for example, you could end up with something like &lt;code&gt;api/output/reason_serverless_functions/joke/route.js&lt;/code&gt;. You could use some hacks to get around such a path, e.g., redirects or a &lt;code&gt;.env&lt;/code&gt; value to shorten the path, but...&lt;/p&gt;

&lt;p&gt;&lt;a href="https://i.giphy.com/media/bWM2eWYfN3r20/giphy.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://i.giphy.com/media/bWM2eWYfN3r20/giphy.gif" alt="no time for that" width="245" height="245"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A better and cleaner solution is to promote the whole app. What does it mean to promote the whole app? Promoting the whole app involves adding all the meta-framework files to a &lt;code&gt;melange.runtime_deps&lt;/code&gt; stanza as dependencies so that they are copied to the &lt;code&gt;_build&lt;/code&gt; folder and next to the output JS files. We can then promote all the meta-framework files back out of the &lt;code&gt;_build&lt;/code&gt; folder along with the output JS.&lt;/p&gt;

&lt;p&gt;A typical TypeScript NextJS App Router application will be structured something like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;├── README.md
├── app/
│   ├── api/
│   │   └── joke/
│   │       └── route.ts
│   ├── jokes/
│   │   └── page.tsx
│   ├── favicon.ico
│   ├── globals.css
│   ├── layout.tsx
│   └── page.tsx
├── next-env.d.ts
├── next.config.js
├── node_modules/
├── package-lock.json
├── package.json
├── postcss.config.js
├── public/
├── tailwind.config.ts
└── tsconfig.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can then convert it to a Reason application:&lt;/p&gt;

&lt;pre&gt;
&lt;code&gt;
├── README.md
├── &lt;span&gt;reason_app/&lt;/span&gt;
│   ├── api/
│   │   └── joke/
│   │       ├── &lt;span&gt;dune&lt;/span&gt;
│   │       └── &lt;span&gt;route.re&lt;/span&gt;
│   ├── jokes/
│   │   ├── &lt;span&gt;dune&lt;/span&gt;
│   │   ├── &lt;span&gt;page.re&lt;/span&gt;
│   │   └── &lt;span&gt;page.rei&lt;/span&gt;
│   ├── favicon.ico
│   ├── globals.css
│   ├── layout.tsx
│   ├── page.tsx
│   └── &lt;span&gt;dune&lt;/span&gt;
├── next-env.d.ts
├── next.config.js
├── node_modules/
├── package-lock.json
├── package.json
├── postcss.config.js
├── public/
├── tailwind.config.ts
├── tsconfig.json&lt;span&gt;
├── &amp;lt;project_name&amp;gt;.opam
├── dune
├── dune-project
└── Makefile&lt;/span&gt;
&lt;/code&gt;
&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;It is important to note that we are not using a &lt;code&gt;src&lt;/code&gt; folder (i.e., ./src/app/) for our application structure and Reason source code.&lt;/strong&gt; We will be using the &lt;code&gt;src&lt;/code&gt; folder eventually because it is important when promoting the output JS.&lt;/p&gt;

&lt;p&gt;We have to rename the &lt;code&gt;app&lt;/code&gt; folder to &lt;code&gt;reason_app&lt;/code&gt; because an &lt;code&gt;app&lt;/code&gt; folder at the root level will take priority over a &lt;code&gt;src/app&lt;/code&gt; folder.&lt;/p&gt;

&lt;p&gt;In &lt;code&gt;./app/dune&lt;/code&gt; we add the NextJS files to the &lt;code&gt;melange.runtime_deps&lt;/code&gt; stanza:&lt;/p&gt;

&lt;pre&gt;
&lt;code&gt;
(library
 (name app)
 (modes melange)
 (libraries reason-react jokes)&lt;span&gt;
 (melange.runtime_deps
  favicon.ico
  globals.css
  (glob_files *.tsx))&lt;/span&gt;
 (preprocess
  (pps reason-react-ppx melange.ppx)))
&lt;/code&gt;
&lt;/pre&gt;

&lt;p&gt;We can then add a &lt;code&gt;reason_bindings&lt;/code&gt; folder at the root level for any bindings we want, and when we build the app the output in the &lt;code&gt;_build&lt;/code&gt; folder will be:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;./_build/default/output/
├── reason_app/
│   ├── api/
│   │   └── joke/
│   │       └── route.js
│   ├── jokes/
│   │   └── page.js
│   ├── favicon.ico
│   ├── globals.css
│   ├── layout.tsx
│   └── page.tsx
├── reason_bindings/
└── node_modules/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note the &lt;code&gt;node_modules&lt;/code&gt; folder. This &lt;code&gt;node_modules&lt;/code&gt; folder contains the output JS for the Melange libraries used in the application. It is not the contents of the &lt;code&gt;node_modules&lt;/code&gt; folder created from &lt;code&gt;package.json&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Using dune &lt;code&gt;directory-targets&lt;/code&gt; (add &lt;code&gt;(using directory-targets 0.1)&lt;/code&gt; to the &lt;code&gt;./dune-project&lt;/code&gt; file) we can promote the output JS in the &lt;code&gt;_build&lt;/code&gt; folder how we like. In &lt;code&gt;./dune&lt;/code&gt; we can add a rule for the promotion of the output code to the all important &lt;code&gt;./src&lt;/code&gt; folder, thus creating a typical NextJS application structure that uses &lt;code&gt;./src/app&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;(rule
 (alias promote-app)
 (mode
  (promote (until-clean)))
 (deps
  (alias_rec nextjs))
 (targets
  (dir src))
 (action
  (bash
   "mkdir src &amp;amp;&amp;amp; cp -r output/reason_app src/app &amp;amp;&amp;amp; cp -r output/reason_bindings src &amp;amp;&amp;amp; cp -r output/node_modules src")))
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;alias promote_app&lt;/code&gt; is an alias we can use in our Makefile so that the rule is run after every build. &lt;code&gt;deps (alias_rec nextjs)&lt;/code&gt; is a dependency on the recursive construction of our main application code which has the alias of &lt;code&gt;nextjs&lt;/code&gt;. &lt;code&gt;dir src&lt;/code&gt; sets the target for the promotion of the output JS as &lt;code&gt;src&lt;/code&gt;. In the action stanza we use bash to copy &lt;code&gt;output/reason_app&lt;/code&gt; to &lt;code&gt;src/app&lt;/code&gt;, making it recognisable to NextJS. We also copy &lt;code&gt;reason_bindings&lt;/code&gt; and the Melange &lt;code&gt;node_modules&lt;/code&gt; to &lt;code&gt;src&lt;/code&gt; so that they are at the same directory level as &lt;code&gt;app&lt;/code&gt;, which is important for maintaining import paths defined in the application when it was built and put into the &lt;code&gt;build&lt;/code&gt; folder. What we end up with is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/
├── _build/
...
├── public/
├── reason_app/
├── reason_bindings/
├── src/
│   ├── app/
│   ├── node_modules/
│   └── reason_bindings/
├── package.json
├── next.config.js
...
├── &amp;lt;project_name&amp;gt;.opam
├── dune
├── dune-project
└── Makefile
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And the app should work perfectly with the NextJS dev tooling. &lt;a href="https://github.com/psb/nextjs-approuter-melange2"&gt;See this basic NextJS App Router, Reason and Melange 2 application for an example&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Miscellaneous
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Melange &lt;code&gt;node_modules&lt;/code&gt; and deployment
&lt;/h3&gt;

&lt;p&gt;If you want to deploy your app by connecting a Git repo to a service like Vercel or Netlify then you need to include the Melange &lt;code&gt;node_modules&lt;/code&gt; folder in the repository. If you don't you will likely get errors about being unable to find certain Melange libraries during the build process.&lt;/p&gt;

&lt;p&gt;If you don't want to commit the Melange &lt;code&gt;node_modules&lt;/code&gt; folder to your repo then you can build the app locally using the Vercel/Netlify CLI and deploy using the CLI as well.&lt;/p&gt;

&lt;p&gt;Another option is to use a CI/CD workflow to spin up a Linux container, install opam and build everything from scratch, but...&lt;/p&gt;

&lt;p&gt;&lt;a href="https://i.giphy.com/media/bWM2eWYfN3r20/giphy.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://i.giphy.com/media/bWM2eWYfN3r20/giphy.gif" alt="no time for that" width="245" height="245"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Directives
&lt;/h3&gt;

&lt;p&gt;To use the directives &lt;code&gt;"use client"&lt;/code&gt; and &lt;code&gt;"use server"&lt;/code&gt; in a NextJS App Router application add &lt;code&gt;[@mel.config {flags: [|"--preamble", "\"use client\";"|]}];&lt;/code&gt; to the top of a file.&lt;/p&gt;

&lt;h3&gt;
  
  
  React Server Components
&lt;/h3&gt;

&lt;p&gt;React Server Components are not yet supported by ReasonReact. You can work around this by creating a standard &lt;code&gt;page.tsx&lt;/code&gt; file. If you need a React component then you can write one in ReasonReact and import it into the page file.&lt;/p&gt;

&lt;h3&gt;
  
  
  Editor errors when importing components from ReasonReact
&lt;/h3&gt;

&lt;p&gt;If you structure your application so that the whole app is going to be promoted out of the &lt;code&gt;_build&lt;/code&gt; folder and you import a ReasonReact component from a &lt;code&gt;.re&lt;/code&gt; file into a &lt;code&gt;page.tsx&lt;/code&gt; file you will get an editor error about the import. This error occurs because you have to import the component as if the &lt;code&gt;.re&lt;/code&gt; file was a JS component file. Once compiled the &lt;code&gt;.re&lt;/code&gt; file will be converted to a &lt;code&gt;.js&lt;/code&gt; file in the &lt;code&gt;_build&lt;/code&gt; folder and it will be in the correct location for the import to work properly after promotion. This is another reason to ensure that the folder structure of the output JS in the &lt;code&gt;_build&lt;/code&gt; folder is maintained when promoting the code.&lt;/p&gt;

&lt;h3&gt;
  
  
  Special characters in file names
&lt;/h3&gt;

&lt;p&gt;Dune will allow some special characters in folder names but it does not allow them in file names (&lt;a href="https://github.com/ocaml/ocaml.org/issues/1635"&gt;in my limited experience&lt;/a&gt;). Remix uses file name based routing and the file names can have special characters in them, e.g., &lt;code&gt;concerts.$city.js&lt;/code&gt;. When a file name with special characters in it fails to compile we can use a Dune rule stanza to create an output JS file with special characters in it:&lt;/p&gt;

&lt;pre&gt;
&lt;code&gt;
; ./src/routes/dune

(library
 (name app)
 (libraries reason-react routes bindings)
 (modes melange)
 (melange.runtime_deps tailwind.css &lt;span&gt;concerts_city.js&lt;/span&gt;)
 (preprocess
  (pps reactjs-jsx-ppx melange.ppx)))

(rule
 (target &lt;span&gt;concerts.$city.js&lt;/span&gt;)
 (deps %{project_root}/remix/app/routes/&lt;span&gt;concerts_city.js&lt;/span&gt;)
 (action
  (copy %{deps} %{target})))
&lt;/code&gt;
&lt;/pre&gt;

&lt;p&gt;In the above dune file we add &lt;code&gt;concerts_city.js&lt;/code&gt; to the &lt;code&gt;melange.runtime_deps&lt;/code&gt; - this is the output JS file name created from the Reason source code file &lt;code&gt;concerts_city.re&lt;/code&gt;. In the rule stanza we set the target as the special character containing file name we want and the dependency (&lt;code&gt;deps&lt;/code&gt;) as the path to &lt;code&gt;concerts_city.js&lt;/code&gt; in the &lt;code&gt;_build&lt;/code&gt; folder. The rule then copies &lt;code&gt;concerts_city.js&lt;/code&gt; to &lt;code&gt;concerts.$city.js&lt;/code&gt;, which should then work perfectly in a Remix application. &lt;a href="https://github.com/psb/remix-reason"&gt;Here is a broken and unfinished Remix app&lt;/a&gt; that may be of some limited use.&lt;/p&gt;

&lt;h3&gt;
  
  
  Hot Module Replacement (HMR)
&lt;/h3&gt;

&lt;p&gt;If you find that HMR is not working properly it might help to add a delay to the meta-framework file watcher. For NextJS you could add the following to &lt;code&gt;next.config.js&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;nextConfig&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="p"&gt;...&lt;/span&gt;
  &lt;span class="na"&gt;webpack&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;watchOptions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;poll&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;aggregateTimeout&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;300&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Ignore &lt;code&gt;_build&lt;/code&gt; and &lt;code&gt;_opam&lt;/code&gt; folders
&lt;/h3&gt;

&lt;p&gt;A meta-frameworks file watcher will watch for any changes in any of the files and folders in root. The presence the OCaml &lt;code&gt;_build&lt;/code&gt; and &lt;code&gt;_opam&lt;/code&gt; folders can cause the meta-frameworks file watcher to behave in unexpected ways, so it is best to configure the meta-frameworks file watcher to ignore the &lt;code&gt;_build&lt;/code&gt; and &lt;code&gt;_opam&lt;/code&gt; folders. For Astro you can add the following to &lt;code&gt;astro.config.mjs&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;defineConfig&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="p"&gt;...&lt;/span&gt;
  &lt;span class="na"&gt;vite&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;server&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;watch&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;ignored&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;**/_build/**&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;**/_opam/**&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Melange 2 and the capabilities of Dune allow Reason and ReasonReact to work very well with React meta-frameworks. There maybe a few aspects of the meta-framework and their development tools that you have to work around, but hopefully the information above should help to make development go smoothly.&lt;/p&gt;




&lt;p&gt;Thank you to &lt;a href="https://twitter.com/javierwchavarri"&gt;Javier Chávarri&lt;/a&gt; for the help with Dune.&lt;/p&gt;

</description>
      <category>reason</category>
      <category>nextjs</category>
      <category>astro</category>
      <category>remix</category>
    </item>
    <item>
      <title>NextJS, the App Router and ReasonReact</title>
      <dc:creator>Paul Bacchus</dc:creator>
      <pubDate>Mon, 21 Aug 2023 14:36:47 +0000</pubDate>
      <link>https://dev.to/psb/nextjs-the-app-router-and-reasonreact-2c0j</link>
      <guid>https://dev.to/psb/nextjs-the-app-router-and-reasonreact-2c0j</guid>
      <description>&lt;h2&gt;
  
  
  &lt;em&gt;TLDR&lt;/em&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjml6mamzjlhhbdula6x7.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjml6mamzjlhhbdula6x7.gif" alt="VyVyan cricket bat"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After creating a &lt;a href="https://github.com/psb/astro-reason" rel="noopener noreferrer"&gt;demo application&lt;/a&gt; with Astro and ReasonReact I thought I would try and recreate the app using NextJS and the App Router. In the Astro app components were written using ReasonReact and then imported into an Astro file from the output JS files created by Melange. This time I wanted to try and use no JS at all and write the whole thing in Reason. The code can be found &lt;a href="https://github.com/psb/nextjs-approuter-reason" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Dune way
&lt;/h2&gt;

&lt;h3&gt;
  
  
  The &lt;code&gt;_build&lt;/code&gt; folder
&lt;/h3&gt;

&lt;p&gt;When Dune builds a projects the output is placed into the &lt;code&gt;_build&lt;/code&gt; directory. For the Astro application mentioned above ReasonReact components were promoted out of the &lt;code&gt;_build&lt;/code&gt; folder and back into the &lt;code&gt;src&lt;/code&gt; folder, which made it easier to import the components into &lt;code&gt;.astro&lt;/code&gt; files. Because NextJS uses folder based routing I wanted to try and keep the directory structure as clean as possible and without promoted folders, thus making the directory structure the same as a regular JavaScript NextJS app.&lt;/p&gt;

&lt;p&gt;For the NextJS app to work properly from the &lt;code&gt;_build&lt;/code&gt; directory, files and folders required by the app have to be copied into the output directory using the &lt;code&gt;runtime_deps&lt;/code&gt; stanza in a &lt;code&gt;dune&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ocaml"&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;melange&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;emit&lt;/span&gt;
 &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;target&lt;/span&gt; &lt;span class="n"&gt;nextjs&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;folder&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;reason&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
 &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;alias&lt;/span&gt; &lt;span class="n"&gt;nextjs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
 &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;module_systems&lt;/span&gt; &lt;span class="n"&gt;es6&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
 &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;libraries&lt;/span&gt; &lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="n"&gt;api&lt;/span&gt; &lt;span class="n"&gt;components&lt;/span&gt; &lt;span class="n"&gt;bindings&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
 &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;runtime_deps&lt;/span&gt;
  &lt;span class="n"&gt;jsconfig&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;json&lt;/span&gt;
  &lt;span class="n"&gt;next&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ts&lt;/span&gt;
  &lt;span class="n"&gt;next&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;js&lt;/span&gt;
  &lt;span class="n"&gt;package&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;json&lt;/span&gt;
  &lt;span class="n"&gt;postcss&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;js&lt;/span&gt;
  &lt;span class="n"&gt;tailwind&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;js&lt;/span&gt;
  &lt;span class="n"&gt;tsconfig&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;json&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;source_tree&lt;/span&gt; &lt;span class="n"&gt;public&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This effectively replicates the standard app directory structure in the &lt;code&gt;_build&lt;/code&gt; folder, and on compilation the Reason files will be compiled to JS files:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fw6koi710tq2jy3ai7ypy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fw6koi710tq2jy3ai7ypy.png" alt="build folder structure"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To run the app from the root directory the commands in &lt;code&gt;package.json&lt;/code&gt; have to be updated, e.g., &lt;code&gt;"cd _build/default/nextjs &amp;amp;&amp;amp; next dev"&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;dune&lt;/code&gt; files
&lt;/h3&gt;

&lt;p&gt;In the image above you can see that there are a lot of &lt;code&gt;dune&lt;/code&gt; files. The &lt;code&gt;dune&lt;/code&gt; files contain stanzas that, among other things, can define libraries, specify what libraries this library relies on, and how the library should be processed. For example, the &lt;code&gt;dune&lt;/code&gt; file in the &lt;code&gt;api&lt;/code&gt; folder is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ocaml"&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;library&lt;/span&gt;
 &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="n"&gt;api&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
 &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;libraries&lt;/span&gt; &lt;span class="n"&gt;melange&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;json&lt;/span&gt; &lt;span class="n"&gt;melange&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;fetch&lt;/span&gt; &lt;span class="n"&gt;bindings&lt;/span&gt; &lt;span class="n"&gt;joke&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
 &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;modes&lt;/span&gt; &lt;span class="n"&gt;melange&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
 &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;preprocess&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pps&lt;/span&gt; &lt;span class="n"&gt;melange&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ppx&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Every subfolder of &lt;code&gt;api/&lt;/code&gt; is a route, e.g., &lt;code&gt;api/joke/&lt;/code&gt;, and requires its own &lt;code&gt;dune&lt;/code&gt; file, which is then referenced in the &lt;code&gt;api/dune&lt;/code&gt; file.&lt;br&gt;
Writing a &lt;code&gt;dune&lt;/code&gt; file for each route (and page) is not hard, but it could get tedious really quickly if there are a lot of them.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7bi9gl402i87xlean1lu.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7bi9gl402i87xlean1lu.jpeg" alt="dune files everywhere"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;One way to get around this is to modify the &lt;code&gt;api/dune&lt;/code&gt; file with &lt;code&gt;(include_subdirs qualified)&lt;/code&gt;; this means that every subdirectory of &lt;code&gt;api/&lt;/code&gt; can be referenced by module namespacing and we don't have to write &lt;code&gt;dune&lt;/code&gt; files for every route (or pages) folder. However, the &lt;a href="https://github.com/ocaml/dune/issues/8297" rel="noopener noreferrer"&gt;OCaml LSP does not like it&lt;/a&gt; and red squiggles will show up in the editor (although the app with still compile without errors). Trying to develop the app knowing those red squiggles cannot be vanquished would drive me nuts, so instead of using &lt;code&gt;(include_subdirs qualified)&lt;/code&gt; I just wrote &lt;code&gt;dune&lt;/code&gt; files for every route (and page) which gets rid of the red squiggles.&lt;/p&gt;

&lt;p&gt;Dune and the NextJS dev server are completely fine with this application and directory structure, and everything works during development; but when trying to build the app NextJS turns cantankerous.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://i.giphy.com/media/XhcSIUIkgbmuY/giphy.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://i.giphy.com/media/XhcSIUIkgbmuY/giphy.gif" alt="shocked gopher"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  &lt;a href="https://www.youtube.com/watch?v=x0YGZPycMEU" rel="noopener noreferrer"&gt;Computer Says No&lt;/a&gt;
&lt;/h2&gt;
&lt;h3&gt;
  
  
  &lt;code&gt;make&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;When creating a React component with Reason it is typical to use the word &lt;code&gt;make&lt;/code&gt; as the name of the function that will create the component. So the dogs page, for example, might look something like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight reasonml"&gt;&lt;code&gt;&lt;span class="c1"&gt;// src/app/dogs/page.re&lt;/span&gt;

&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;react&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;component&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;make&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Dog&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Dog component from src/app/components/Dog.re&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the output JS file created by Melange the export will be:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;make&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Dog&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;make&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But &lt;code&gt;next build&lt;/code&gt; will give a type error:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Type error: Page &lt;span class="s2"&gt;"src/app/dogs/page.js"&lt;/span&gt; does not match the required types of a Next.js Page.
&lt;span class="s2"&gt;"make"&lt;/span&gt; is not a valid Page &lt;span class="nb"&gt;export &lt;/span&gt;field.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Okay. Let's try changing &lt;code&gt;make&lt;/code&gt; to &lt;code&gt;default&lt;/code&gt;. Now the output JS has a default export:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;$$default&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Page$default&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;$$default&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;$$default&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But still &lt;code&gt;next build&lt;/code&gt; will give a type error:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Type error: Page &lt;span class="s2"&gt;"src/app/dogs/page.js"&lt;/span&gt; does not match the required types of a Next.js Page.
&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$$&lt;/span&gt;&lt;span class="s2"&gt;default"&lt;/span&gt; is not a valid Page &lt;span class="nb"&gt;export &lt;/span&gt;field.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Deleting the extra &lt;code&gt;$$default&lt;/code&gt; from the export in the output JS file, so that the the export is just &lt;code&gt;export { $$default as default };&lt;/code&gt;, seems to fix the problem, but editing the output JS is a bad idea and not practical. I'm not sure why Melange adds the extra &lt;code&gt;$$default&lt;/code&gt; to the export but NextJS does not like it.&lt;/p&gt;

&lt;h3&gt;
  
  
  Routes
&lt;/h3&gt;

&lt;p&gt;According to the NextJS docs routes have to export a function with the name of the HTTP method you want to use, e.g., &lt;code&gt;export async function POST(request) {...};&lt;/code&gt;. In Reason/OCaml we cannot use &lt;code&gt;POST&lt;/code&gt; as the name of a function because a word beginning with an uppercase letter is a &lt;a href="https://ocaml.org/docs/data-types#a-simple-custom-type" rel="noopener noreferrer"&gt;constructor for a data type&lt;/a&gt;. To get around this we can we use &lt;code&gt;bs.raw&lt;/code&gt; to write some raw JavaScript in the Reason code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight reasonml"&gt;&lt;code&gt;&lt;span class="c1"&gt;// src/app/api/joke/route.re&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;handler&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="c1"&gt;/// ...&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;%%&lt;/span&gt;&lt;span class="n"&gt;bs&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;raw&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;export&lt;/span&gt; &lt;span class="n"&gt;const&lt;/span&gt; &lt;span class="nc"&gt;POST&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;handler&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="p"&gt;}];&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And the output JS will be:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;POST&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;handler&lt;/span&gt;
&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;decodeJokeCount&lt;/span&gt; &lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// JSON decoder function&lt;/span&gt;
  &lt;span class="nx"&gt;decodeJoke&lt;/span&gt; &lt;span class="p"&gt;,&lt;/span&gt;      &lt;span class="c1"&gt;// JSON decoder function&lt;/span&gt;
  &lt;span class="nx"&gt;handler&lt;/span&gt; &lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Will &lt;code&gt;next build&lt;/code&gt; let us pass??? No.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Type error: Route &lt;span class="s2"&gt;"src/app/api/joke/route.js"&lt;/span&gt; does not match the required types of a Next.js Route.
&lt;span class="s2"&gt;"decodeJokeCount"&lt;/span&gt; is not a valid Route &lt;span class="nb"&gt;export &lt;/span&gt;field.

Type error: Route &lt;span class="s2"&gt;"src/app/api/joke/route.js"&lt;/span&gt; does not match the required types of a Next.js Route.
&lt;span class="s2"&gt;"decodeJoke"&lt;/span&gt; is not a valid Route &lt;span class="nb"&gt;export &lt;/span&gt;field.

Type error: Route &lt;span class="s2"&gt;"src/app/api/joke/route.js"&lt;/span&gt; does not match the required types of a Next.js Route.
&lt;span class="s2"&gt;"handler"&lt;/span&gt; is not a valid Route &lt;span class="nb"&gt;export &lt;/span&gt;field.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once again NextJS does not like the extra export fields. Using an interface file can restrict the exports and make &lt;code&gt;decodeJokeCount&lt;/code&gt; and &lt;code&gt;decodeJoke&lt;/code&gt; private; however, trying to make &lt;code&gt;handler&lt;/code&gt; private so that the only export is &lt;code&gt;export const POST = handler;&lt;/code&gt; is not possible, and trying to do so causes Melange to output an empty JS file.&lt;/p&gt;

&lt;h2&gt;
  
  
  Refactoring
&lt;/h2&gt;

&lt;p&gt;To stop &lt;code&gt;next build&lt;/code&gt; from slapping us with type errors we have to wrap the Reason code with JavaScript, which means creating &lt;code&gt;page.js&lt;/code&gt; and &lt;code&gt;route.js&lt;/code&gt; files and importing the Reason code (the output JS code) into them. This is now a situation that is similar to the Astro project, and so now, rather than having many folders and many &lt;code&gt;dune&lt;/code&gt; files, all of the Reason code can be put into one folder. Because of this it also makes sense to promote the output JavaScript out of the &lt;code&gt;_build&lt;/code&gt; folder and back into the &lt;code&gt;src&lt;/code&gt; folder, which means that project files no longer have to be copied to the &lt;code&gt;_build&lt;/code&gt; folder.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyoqls5wu1q7xhmqx0x6t.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyoqls5wu1q7xhmqx0x6t.png" alt="Refactored folder structure"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Directives and bindings
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;"use client"&lt;/code&gt; directive binding:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight reasonml"&gt;&lt;code&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;bs&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;config&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;flags&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="s2"&gt;"--preamble"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;use client&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;;"&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="p"&gt;]}];&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Font and metadata bindings for the root layout:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight reasonml"&gt;&lt;code&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;%%&lt;/span&gt;&lt;span class="n"&gt;bs&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;raw&lt;/span&gt; &lt;span class="s2"&gt;"import './globals.css'"&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;%%&lt;/span&gt;&lt;span class="n"&gt;bs&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;raw&lt;/span&gt; &lt;span class="s2"&gt;"import { Inter } from 'next/font/google'"&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;%%&lt;/span&gt;&lt;span class="n"&gt;bs&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;raw&lt;/span&gt; &lt;span class="s2"&gt;"const inter = Inter({ subsets: ['latin'] })"&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;font&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;metadata&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;bs&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="k"&gt;val&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;external&lt;/span&gt; &lt;span class="n"&gt;inter&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;font&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"inter"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;bs&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;external&lt;/span&gt; &lt;span class="n"&gt;fontClassName&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;font&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"className"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Since the Reason code is now wrapped in JS less bindings are required because they can just be written in the JavaScript file; therefore, bindings like those above are no longer needed.&lt;/p&gt;

&lt;p&gt;The refactored code is the code in the main branch. The all Reason code version of the app can be found on the &lt;code&gt;include-subdirs-qualified&lt;/code&gt; branch.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Replacing all of the JavaScript in a NextJS App Router application with Reason is currently not possible. Reason can be used for the majority of the code but it will need to be wrapped in JS for it to be compatible with NextJS. I'm not sure why NextJS is so strict on what fields are exported. As long the fields NextJS needs are exported I don't see why other export fields are a problem, especially since they cause no problem during development. I also wish these problems would have showed up sooner during development instead of during building. There may be some Dune or NextJS configuration options that I have missed, but at this point I'm too tired and &lt;a href="https://www.youtube.com/watch?v=0VH-tJSpkjA" rel="noopener noreferrer"&gt;bored&lt;/a&gt; to try and figure it out.&lt;/p&gt;

</description>
      <category>nextjs</category>
      <category>reason</category>
      <category>react</category>
      <category>webdev</category>
    </item>
    <item>
      <title>ReasonReact, Auth0 and 3rd Party React Components</title>
      <dc:creator>Paul Bacchus</dc:creator>
      <pubDate>Sun, 16 Jul 2023 12:17:56 +0000</pubDate>
      <link>https://dev.to/psb/reasonreact-auth0-and-3rd-party-react-components-31kp</link>
      <guid>https://dev.to/psb/reasonreact-auth0-and-3rd-party-react-components-31kp</guid>
      <description>&lt;p&gt;One of the ways I like to test a technology is to try and implement something that could be required in a real world app, and authentication is one of those things. I have also been wanting to see how easy it is to use a third-party JS React component with &lt;a href="https://reasonml.github.io/reason-react/en"&gt;ReasonReact&lt;/a&gt;. So, to kill two birds with one stone I created a simple app that uses the &lt;a href="https://auth0.com/"&gt;Auth0&lt;/a&gt; React component. You can view the app &lt;a href="https://reason-auth.netlify.app/"&gt;here&lt;/a&gt;, and the code is &lt;a href="https://github.com/psb/reason-auth"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Using the &lt;code&gt;Auth0Provider&lt;/code&gt; component
&lt;/h2&gt;

&lt;p&gt;The login for the app is based on the &lt;a href="https://auth0.com/docs/quickstart/spa/react/interactive"&gt;Auth0 quick start tutorial&lt;/a&gt; for React, and the first thing we have to do is wrap our &lt;code&gt;App&lt;/code&gt; in the &lt;code&gt;Auth0Provider&lt;/code&gt;. In JavaScript we would do &lt;code&gt;import { Auth0Provider } from '@auth0/auth0-react';&lt;/code&gt; and wrap our &lt;code&gt;App&lt;/code&gt; component with the imported &lt;code&gt;Auth0Provider&lt;/code&gt; component, but in ReasonReact we need to write some bindings to the component using &lt;a href="https://melange.re/v1.0.0/communicate-with-javascript/#list-of-attributes-and-extension-nodes"&gt;Melange attributes&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight reasonml"&gt;&lt;code&gt;&lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="nc"&gt;Auth0Provider&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;auth_param&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;redirect_uri&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;

  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;bs&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="s2"&gt;"@auth0/auth0-react"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;react&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;component&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="k"&gt;external&lt;/span&gt; &lt;span class="n"&gt;make&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="n"&gt;domain&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
      &lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="n"&gt;clientId&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
      &lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="n"&gt;authorizationParams&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;auth_param&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
      &lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="n"&gt;children&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nn"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;element&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
    &lt;span class="nn"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;element&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
    &lt;span class="s2"&gt;"Auth0Provider"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;@bs.module&lt;/code&gt; is a Melange attribute that lets us bind to a value from a JS module. The &lt;code&gt;= "Auth0Provider"&lt;/code&gt; at the end is the JavaScript name of the value/component we are binding to. The &lt;code&gt;external&lt;/code&gt; before the &lt;code&gt;make&lt;/code&gt; is used for JS interop/FFI and is like an FFI &lt;code&gt;let&lt;/code&gt; binding. Everything else in between is the type signature of a React component in ReasonReact.&lt;/p&gt;

&lt;p&gt;In Reason each file is a module, and it is common to have one ReasonReact component per file with the filename being the name of the component. We can also define modules within files which is what we have done for the &lt;code&gt;Auth0Provider&lt;/code&gt; in the snippet above, and we use the component like so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight reasonml"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Auth0Provider&lt;/span&gt;
  &lt;span class="n"&gt;domain&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"dev-dj37pygvjwvaxjde.us.auth0.com"&lt;/span&gt;
  &lt;span class="n"&gt;clientId&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"e6mvq0WBov5jSBW0clTFdAIXgbyyK4gv"&lt;/span&gt;
  &lt;span class="n"&gt;authorizationParams&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;redirect_uri&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;origin&lt;/span&gt; &lt;span class="o"&gt;++&lt;/span&gt; &lt;span class="s2"&gt;"/profile"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;App&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;Auth0Provider&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Using the &lt;code&gt;useAuth0()&lt;/code&gt; hook
&lt;/h2&gt;

&lt;p&gt;Now that we have wrapped our &lt;code&gt;App&lt;/code&gt; with the &lt;code&gt;Auth0Provider&lt;/code&gt; we can start using the &lt;code&gt;useAuth0()&lt;/code&gt; hook in our components, and to do so we must write some bindings to the hook.&lt;/p&gt;

&lt;p&gt;Because in JavaScript we would &lt;code&gt;import&lt;/code&gt; the hook we again have to use the &lt;code&gt;@bs.module&lt;/code&gt; attribute to bind to it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight reasonml"&gt;&lt;code&gt;&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;hook&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;bs&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="s2"&gt;"@auth0/auth0-react"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;external&lt;/span&gt; &lt;span class="n"&gt;useAuth0&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;unit&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;hook&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"useAuth0"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;|--------------------&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;-------------------|&lt;/span&gt; &lt;span class="o"&gt;|---&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="o"&gt;---|&lt;/span&gt; &lt;span class="o"&gt;|-&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="o"&gt;-|&lt;/span&gt;  &lt;span class="o"&gt;|-&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="o"&gt;-|&lt;/span&gt;   &lt;span class="o"&gt;|----&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="o"&gt;----|&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here we are telling Reason that we are binding to an external something in the module &lt;code&gt;"@auth0/auth0-react"&lt;/code&gt;(1) and that something is called &lt;code&gt;"useAuth0"&lt;/code&gt;(5) in JS land; we are binding &lt;code&gt;"useAuth0"&lt;/code&gt;(5) to the name &lt;code&gt;useAuth0&lt;/code&gt;(2) in Reason land; and &lt;code&gt;useAuth&lt;/code&gt;(2) takes a &lt;code&gt;unit&lt;/code&gt;(3) (i.e., takes no arguments; equivalent to &lt;code&gt;useAuth0()&lt;/code&gt; in JS) and returns a &lt;code&gt;hook&lt;/code&gt;(4). We have to give the return value a type (&lt;code&gt;type hook&lt;/code&gt;) so that the type system knows what we have just "imported"/bound to, and which we need when we want to bind to the values and methods of the hook.&lt;/p&gt;

&lt;p&gt;(You don't have to use the same JS name in Reason for a binding. For example, you could do something like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight reasonml"&gt;&lt;code&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;bs&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="s2"&gt;"@auth0/auth0-react"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;external&lt;/span&gt; &lt;span class="n"&gt;useAuth0Reason&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;unit&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;hook&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"useAuth0"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You would then just use &lt;code&gt;useAuth0Reason&lt;/code&gt; in your ReasonReact code. In fact, you may need to rename bindings if they clash with reserved key words in Reason.)&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;useAuth0&lt;/code&gt; hook provides various &lt;a href="https://auth0.github.io/auth0-react/functions/useAuth0.html"&gt;state values and methods&lt;/a&gt;, and to use them we need more bindings.&lt;/p&gt;

&lt;p&gt;To call a method we use the &lt;code&gt;bs.send&lt;/code&gt; attribute:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight reasonml"&gt;&lt;code&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;bs&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;send&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;external&lt;/span&gt; &lt;span class="n"&gt;loginWithRedirect&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;hook&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;unit&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"loginWithRedirect"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To get a value we use the &lt;code&gt;bs.get&lt;/code&gt; attribute:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight reasonml"&gt;&lt;code&gt;&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;bs&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;external&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;hook&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"user"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once defined we can use the bindings in our ReasonReact components:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight reasonml"&gt;&lt;code&gt;&lt;span class="c1"&gt;// LoginButton.re&lt;/span&gt;
&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;react&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;component&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;make&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;ua&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Bindings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nn"&gt;Auth0&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;useAuth0&lt;/span&gt;&lt;span class="bp"&gt;()&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;button&lt;/span&gt;
    &lt;span class="n"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"py-2 px-4 rounded-md bg-blue-500 text-white"&lt;/span&gt;
    &lt;span class="n"&gt;onClick&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nn"&gt;Bindings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nn"&gt;Auth0&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;loginWithRedirect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ua&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nn"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"Log In"&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;
  &lt;span class="o"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="n"&gt;button&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And the very readable output JavaScript of the LoginButton ReasonReact component:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Generated by Melange&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;Auth0React&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@auth0/auth0-react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;LoginButton&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Props&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;ua&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Auth0React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;useAuth0&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;createElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;button&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;py-2 px-4 rounded-md bg-blue-500 text-white&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;param&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;ua&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;loginWithRedirect&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Log In&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;make&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;LoginButton&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;make&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="cm"&gt;/* react Not a pure module */&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://i.giphy.com/media/1jkV5ifEE5EENHESRa/giphy.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://i.giphy.com/media/1jkV5ifEE5EENHESRa/giphy.gif" alt="nice" width="240" height="184"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Bindings can be written as they are needed, and once written completing the Auth0 quick start guide is pretty straight forward.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Third-party JS React components can be successfully used in any ReasonReact project. Bindings may look complicated, but once you've written a couple of them you quickly get the hang of it.&lt;/p&gt;




&lt;p&gt;Cover image by &lt;a href="https://www.pexels.com/photo/close-up-shot-of-keyboard-buttons-2882566/"&gt;Miguel Á. Padriñán from Pexels&lt;/a&gt;&lt;/p&gt;

</description>
      <category>reason</category>
      <category>melange</category>
      <category>react</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Getting started with ReasonReact and Melange</title>
      <dc:creator>Paul Bacchus</dc:creator>
      <pubDate>Fri, 07 Jul 2023 13:01:35 +0000</pubDate>
      <link>https://dev.to/psb/getting-started-with-reasonreact-and-melange-13hd</link>
      <guid>https://dev.to/psb/getting-started-with-reasonreact-and-melange-13hd</guid>
      <description>&lt;h2&gt;
  
  
  A bit of background
&lt;/h2&gt;

&lt;p&gt;To quote the official docs:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Melange is a backend for the OCaml compiler that emits JavaScript. Melange strives to provide the best integration with both the OCaml and JavaScript ecosystems.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Basically, &lt;a href="https://melange.re/v1.0.0/"&gt;Melange&lt;/a&gt; lets you generate JS code from OCaml code. &lt;a href="https://reasonml.github.io/en"&gt;Reason&lt;/a&gt; (aka ReasonML) is an alternative syntax for OCaml that looks more like JS. &lt;a href="https://reasonml.github.io/reason-react/en"&gt;Reason React&lt;/a&gt; are Reason bindings to React so that you can create React apps with Reason.&lt;/p&gt;

&lt;p&gt;You may have heard of BuckleScript and you may be wondering if there is a relationship between Melange and BuckleScript. To quote the docs again:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;... at some point the goals of both BuckleScript and Reason projects become harder to reconcile. In August 2020, the BuckleScript team decides to rename to ReScript, stops adding support for the latest versions of the Reason parser, and replaces it with a new parser that changes the syntax. The reasons for the rebranding are explained in &lt;a href="https://rescript-lang.org/blog/bucklescript-is-rebranding"&gt;the official ReScript blog post&lt;/a&gt;.&lt;br&gt;
...&lt;br&gt;
This is where Melange comes in. A few weeks after the rebranding of BuckleScript to ReScript, António Monteiro starts working on a fork of BuckleScript with a simple (not easy) goal: replace the Ninja build system, which BuckleScript had been using from its creation, with Dune, which is the most used build system for OCaml projects.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Melange has reached a &lt;a href="https://anmonteiro.substack.com/p/melange-10-is-here"&gt;1.0 release&lt;/a&gt;, and it is &lt;a href="https://tech.ahrefs.com/ahrefs-is-now-built-with-melange-b14f5ec56df4"&gt;used in production&lt;/a&gt; at &lt;a href="https://ahrefs.com"&gt;Ahrefs&lt;/a&gt;. &lt;a href="https://sancho.dev/blog/server-side-rendering-react-in-ocaml"&gt;server-reason-react&lt;/a&gt;, which was discussed by &lt;a href="https://www.youtube.com/watch?v=j9Vn6PC2u8k"&gt;ThePrimeagen&lt;/a&gt;, is a great article that shows what Melange, Reason/OCaml and ReasonReact can do.&lt;/p&gt;

&lt;h2&gt;
  
  
  Reading
&lt;/h2&gt;

&lt;p&gt;If you know nothing about OCaml and its ecosystem the &lt;a href="https://ocaml.org/docs/up-and-running"&gt;new(ish) docs&lt;/a&gt; are a great place to start. I would then spend some time going over the &lt;a href="https://melange.re/v1.0.0/"&gt;Melange docs&lt;/a&gt; which explain how to set everything up and JS interop. If you know JS then the syntax in the &lt;a href="https://ocaml.org/docs/up-and-running"&gt;Reason docs&lt;/a&gt; should not be too alien. And if you know React then it should not take long to go over the &lt;a href="https://reasonml.github.io/reason-react/docs/en/installation"&gt;ReasonReact docs&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Quick start templates
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;A template using both OCaml and Reason syntax, ReasonReact and webpack: &lt;a href="https://github.com/melange-re/melange-opam-template"&gt;https://github.com/melange-re/melange-opam-template&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;A template using both OCaml and Reason syntax, ReasonReact and Vite: &lt;a href="https://github.com/pdelacroix/melange-vite-template"&gt;https://github.com/pdelacroix/melange-vite-template&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;A template using only Reason syntax, ReasonReact, Tailwind and Vite: &lt;a href="https://github.com/psb/melange-opam-template"&gt;https://github.com/psb/melange-opam-template&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Example apps
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/psb/reason-react-hn-melange"&gt;Here&lt;/a&gt; is a Hacker News app that uses ReasonReact and Tailwind. It is a port of the original app that used BuckleScript. A good exercise for the reader would be to update the app to use the official HN API.&lt;/p&gt;

&lt;p&gt;Because Melange outputs JS you can sprinkle Reason and ReasonReact into existing JS apps. &lt;a href="https://github.com/psb/astro-reason"&gt;Here&lt;/a&gt; is an example &lt;a href="https://docs.astro.build/"&gt;Astro&lt;/a&gt; application that uses ReasonReact components and Reason lambda functions on &lt;a href="https://www.netlify.com/"&gt;Netlify&lt;/a&gt;. I'll admit that it did take a while to figure out how to get everything setup properly so that everything worked together, but now you don't have to 😄. Check out the open and closed issues in the repo to see what kind of problems I was having.&lt;/p&gt;

&lt;h2&gt;
  
  
  Getting help
&lt;/h2&gt;

&lt;p&gt;Hopefully the docs and example apps can get you up and running with Melange, Reason and ReasonReact, but if you need further help then the &lt;a href="https://discord.gg/reasonml"&gt;Reason Discord channel&lt;/a&gt; is a great place to get help. I owe thanks to &lt;a href="https://twitter.com/_anmonteiro"&gt;António Monteiro&lt;/a&gt;, &lt;a href="https://twitter.com/javierwchavarri"&gt;Javier Chávarri&lt;/a&gt;, &lt;a href="https://twitter.com/davesnx"&gt;David Sancho&lt;/a&gt; and &lt;a href="https://medium.com/@mostrous"&gt;Dimitris Mostrous&lt;/a&gt; for helping me. Pop in and say hi 👋. There is also the &lt;a href="https://reasonml.chat/"&gt;Reason forum&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;You can get help with OCaml and OCaml tooling in the Reason Discord but there are more OCaml people in the &lt;a href="https://discord.gg/cCYQbqN"&gt;OCaml Discord channel&lt;/a&gt; and &lt;a href="https://discuss.ocaml.org/"&gt;OCaml forum&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Next
&lt;/h2&gt;

&lt;p&gt;So far I have really enjoyed working with this stack. The compiler is incredibly fast, the type system and tooling are great, and Reason can fit in to the typical JS workflow. I still have some experiments I want to do with ReasonReact (e.g., using third party React components), but I hope to be able to play with &lt;a href="https://aantron.github.io/dream/"&gt;Dream&lt;/a&gt; soon and build some full stack applications. Type safety from the DB to the frontend would be great!&lt;/p&gt;

</description>
      <category>reason</category>
      <category>melange</category>
      <category>react</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
