<?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>Forem: Art Deineka</title>
    <description>The latest articles on Forem by Art Deineka (@darkest_ruby).</description>
    <link>https://forem.com/darkest_ruby</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%2F357114%2Faedfacc8-0346-49fc-8a69-3706a9caebd4.jpg</url>
      <title>Forem: Art Deineka</title>
      <link>https://forem.com/darkest_ruby</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/darkest_ruby"/>
    <language>en</language>
    <item>
      <title>How to use PureScript with React in 2020</title>
      <dc:creator>Art Deineka</dc:creator>
      <pubDate>Sun, 17 May 2020 19:37:13 +0000</pubDate>
      <link>https://forem.com/darkest_ruby/how-to-use-purescript-with-create-react-app-in-2020-20m8</link>
      <guid>https://forem.com/darkest_ruby/how-to-use-purescript-with-create-react-app-in-2020-20m8</guid>
      <description>&lt;p&gt;CRA (&lt;code&gt;create-react-app&lt;/code&gt;) is de facto standard for creating new React apps, but unless you &lt;code&gt;eject&lt;/code&gt; its build mechanisms remain quite inflexible and opinionated - so one cannot just plug in arbitrary 3rd party language to be used in an app. Currently only JavaScript and TypeScript are supported out of the box.&lt;/p&gt;

&lt;p&gt;What if I want to use PureScript - a  strongly-typed functional programming language that compiles to JavaScript for some mission critical parts of my React app. Turns out it can be done quite easily. This short article explains how.&lt;/p&gt;

&lt;p&gt;Start a new CRA project&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;~$ npx create-react-app purs-test &amp;amp;&amp;amp; cd purs-test
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Our project will live in a folder inelaborately called &lt;code&gt;purs-test&lt;/code&gt;. Verify by running &lt;code&gt;npm start&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Once inside that folder - initialize a PureScript project inside the same folder. PureScript uses &lt;code&gt;spago&lt;/code&gt; as its build companion. &lt;code&gt;spago&lt;/code&gt; for PureScript is what &lt;code&gt;npm&lt;/code&gt; is for JavaScript, and more!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;~/purs-test $ npm install -g spago purescript
~/purs-test $ spago init
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Spago will detect that &lt;code&gt;src&lt;/code&gt; folder and &lt;code&gt;.gitignore&lt;/code&gt; file exist and re-use them. Verify that initialization succeeded and run &lt;code&gt;spago bundle-module&lt;/code&gt; - this will build module &lt;code&gt;Main&lt;/code&gt; that came with &lt;code&gt;spago init&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Ok - we have two projects sharing the same folder structure unaware of one another - next step is to establish friendship between the two.&lt;/p&gt;

&lt;p&gt;As mentioned earlier CRA build mechanism is quite locked in (unless you &lt;code&gt;eject&lt;/code&gt; in which case you become responsible for all build scripts) - so we will try to fool it. Luckily &lt;code&gt;spago&lt;/code&gt; is capable of producing a &lt;code&gt;CommonJS&lt;/code&gt; compatible bundle. It is also capable of watching your files change and rebuilding on the fly, as well as taking a parameter of where to put the artifacts.&lt;/p&gt;

&lt;h3&gt;
  
  
  Attempt 0
&lt;/h3&gt;

&lt;p&gt;By default &lt;code&gt;spago&lt;/code&gt; places artifacts it to the current folder, but that's not very neat so let's ask it to place it some place special&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;~/purs-test $ bundle-module -w -x -t ./ps-output/index.js
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This will download dependencies if necessary, build the project as library, and place it to &lt;code&gt;ps-output&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;We can then refer to it from out React project by&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import Main from '../ps-output/'
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;but wait.. CRA yells at us with&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Failed to compile.

./src/App.js
You attempted to import ../ps-output/index.js which falls outside of the project src/ directory. Relative imports outside of src/ are not supported.
You can either move it inside src/, or add a symlink to it from project's node_modules/.
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Turns out that all JS files, even external need to live inside &lt;code&gt;src&lt;/code&gt;. Ok - we can do that:&lt;/p&gt;

&lt;h3&gt;
  
  
  Attempt 1
&lt;/h3&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;~/purs-test $ bundle-module -w -x -t ./src/ps-output/index.js
~/purs-test $ npm start
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Unfortunately this leads to an interesting situation where &lt;code&gt;spago&lt;/code&gt; puts a file inside &lt;code&gt;src&lt;/code&gt;, that's then picked up by CRA and triggers a rebuild which in turn triggers &lt;code&gt;spago&lt;/code&gt; rebuild (That's the &lt;code&gt;-w&lt;/code&gt; flag) and so it just goes in circles... forever.&lt;/p&gt;

&lt;h3&gt;
  
  
  Attempt 2
&lt;/h3&gt;

&lt;p&gt;One other place in out project where CRA pick's up 3rd party libraries is .. surprise surprise &lt;code&gt;node_modules&lt;/code&gt;. This also allows to import dependencies by specifying non-relative paths, as if it was installed via &lt;code&gt;npm&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Let's change our &lt;code&gt;package.json&lt;/code&gt; to reflect that:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;"scripts": {
    "start": "concurrently 'npm run ps-watch' 'react-scripts start'",
    "build": "npm run ps-build &amp;amp;&amp;amp; react-scripts build",
    "ps-build": "spago bundle-module -x -t ./node_modules/ps-interop/index.js",
    "ps-watch": "spago bundle-module -w -x -t ./node_modules/ps-interop/index.js",
...
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;And your imports now look like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import Main from "ps-interop";
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;A bit of explanation needed:&lt;br&gt;
&lt;code&gt;npm start&lt;/code&gt; - runs 2 build concurrently, and is used for development. PureScript library is seen as 3rd party, npm supplied library&lt;/p&gt;

&lt;p&gt;&lt;code&gt;npm build&lt;/code&gt; - runs two builds sequentially - PureScript first as it's used as dependency in CRA build&lt;/p&gt;
&lt;h2&gt;
  
  
  Let's build it
&lt;/h2&gt;

&lt;p&gt;Add a file to &lt;code&gt;src&lt;/code&gt; folder and call it &lt;code&gt;Main.purs&lt;/code&gt; - this will be our mission critical code written in a pure functional style.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;module Main where

import Prelude

double :: Number -&amp;gt; Number
double n = n * 2.0

hello :: String -&amp;gt; String
hello name = "Hello, " &amp;lt;&amp;gt; name

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



&lt;p&gt;Obviously this is just a simple example. Real PureScript code can be of arbitrary complexity, taking advantage of all the features of functional programming.&lt;/p&gt;

&lt;h4&gt;
  
  
  Use it in React
&lt;/h4&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import React from "react";
import Main from "ps-interop";

const App = () =&amp;gt; {
  return (
    &amp;lt;div className="App"&amp;gt;
      &amp;lt;strong&amp;gt;{Main.hello("from PureScript")}&amp;lt;/strong&amp;gt;
      &amp;lt;strong&amp;gt;3 time 2 is&amp;lt;/strong&amp;gt; {Main.double(3)}
    &amp;lt;/div&amp;gt;
  );
};

export default App;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Running &lt;code&gt;npm start&lt;/code&gt; rebuilds when either React or PureScript parts of your app change - and so you get seamless experience and hot reload.&lt;/p&gt;

&lt;p&gt;Running &lt;code&gt;npm build&lt;/code&gt; produces bundled app, with all PureScript and React integrated into single package.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;That's it folks!&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Should you do this?
&lt;/h2&gt;

&lt;h4&gt;
  
  
  No!
&lt;/h4&gt;

&lt;p&gt;Don't do it unless you're doing it for fun or experimentation like I was. If you want to use PureScript library in your React app for production build - have it as a separate library, and install via your favourite package manager.&lt;/p&gt;

</description>
      <category>react</category>
      <category>webdev</category>
      <category>functional</category>
      <category>javascript</category>
    </item>
  </channel>
</rss>
