├── .gitignore ├── README.md ├── __tests__ ├── Calculator_test.bs.js └── Calculator_test.re ├── bsconfig.json ├── index.html ├── package.json ├── src ├── App.bs.js ├── App.re ├── Calculator │ ├── Calculator.bs.js │ ├── Calculator.re │ └── Calculator.rei ├── Index.bs.js ├── Index.re ├── components │ ├── Hero.bs.js │ ├── Hero.re │ ├── Nav.bs.js │ ├── Nav.re │ └── README.md └── pages │ ├── Home.bs.js │ ├── Home.re │ ├── NotFound.bs.js │ ├── NotFound.re │ ├── Pages.bs.js │ ├── Pages.re │ ├── README.md │ ├── SignUp.bs.js │ └── SignUp.re └── yarn.lock /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .merlin 3 | .bsb.lock 4 | npm-debug.log 5 | /lib/bs/ 6 | /node_modules/ 7 | .cache 8 | dist 9 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ReasonReact Starter 2 | 3 | > Minimal yet powerful ReasonReact template with batteries included. 🔋 4 | 5 | [![dependencies Status](https://david-dm.org/cironunes/reasonreact-starter/status.svg)](https://david-dm.org/cironunes/reasonreact-starter) 6 | [![devDependencies Status](https://david-dm.org/cironunes/reasonreact-starter/dev-status.svg)](https://david-dm.org/cironunes/reasonreact-starter?type=dev) 7 | 8 | [Full ReasonReact docs](https://reasonml.github.io/reason-react/) 9 | 10 | ## 🎬 Get started 11 | 12 | 1. Clone this repository without any history `git clone --depth 1 https://github.com/cironunes/reasonreact-starter.git` 13 | 2. Run it and jump into the browser to start developing 14 | 15 | ## 🏃‍♂️ How to run it? 16 | 17 | ```sh 18 | yarn 19 | yarn dev 20 | # in another tab, run the tests in watch mode 21 | yarn test 22 | ``` 23 | 24 | Open a new web page to `http://localhost:1234/`. Change any `.re` file in `src` to see the page auto-reload. 25 | 26 | ## 📦 What's included? 27 | 28 | | Feature | Description | 29 | | ------------------- | --------------------------------------------------------------------------------------------- | 30 | | Folder Structure | We included a scalable folder structure. Make sure to check the README files for more details | 31 | | Routes | ReasonReact comes with a Router. The template comes with two examples | 32 | | Tests | Unit & Integration Testing with Jest and React Testing Library | 33 | | Styles | CSS-in-JS with bs-css and re-classnames | 34 | | Web APIs | _comming soon_ | 35 | | Themes | _coming soon_ | 36 | | Forms | _coming soon_ | 37 | | GraphQL integration | _coming soon_ React Apollo (GraphQL) | 38 | | Authentication | _coming soon_ Auth0, Firebase? | 39 | | Websockets | _coming soon_ | 40 | 41 | ## 🚀 Bundle for Production 42 | 43 | `yarn build` 44 | -------------------------------------------------------------------------------- /__tests__/Calculator_test.bs.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var Jest = require("@glennsl/bs-jest/src/jest.js"); 4 | var Calculator$ReasonreactStarter = require("../src/Calculator/Calculator.bs.js"); 5 | 6 | Jest.describe("Calculator", (function (param) { 7 | Jest.test("should add three numbers", (function (param) { 8 | return Jest.Expect.toBe(8, Jest.Expect.expect(Calculator$ReasonreactStarter.sum(/* :: */[ 9 | 2, 10 | /* :: */[ 11 | 3, 12 | /* :: */[ 13 | 3, 14 | /* [] */0 15 | ] 16 | ] 17 | ]))); 18 | })); 19 | return Jest.test("should add four numbers", (function (param) { 20 | return Jest.Expect.toBe(9, Jest.Expect.expect(Calculator$ReasonreactStarter.sum(/* :: */[ 21 | 2, 22 | /* :: */[ 23 | 3, 24 | /* :: */[ 25 | 3, 26 | /* :: */[ 27 | 1, 28 | /* [] */0 29 | ] 30 | ] 31 | ] 32 | ]))); 33 | })); 34 | })); 35 | 36 | /* Not a pure module */ 37 | -------------------------------------------------------------------------------- /__tests__/Calculator_test.re: -------------------------------------------------------------------------------- 1 | open Jest; 2 | open Expect; 3 | 4 | open Calculator; 5 | 6 | describe("Calculator", () => { 7 | test("should add three numbers", () => { 8 | expect(sum([2, 3, 3])) |> toBe(8) 9 | }); 10 | test("should add four numbers", () => { 11 | expect(sum([2, 3, 3, 1])) |> toBe(9) 12 | }); 13 | }); -------------------------------------------------------------------------------- /bsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "reasonreact-starter", 3 | "reason": { 4 | "react-jsx": 3 5 | }, 6 | "sources": [ 7 | { 8 | "dir": "src", 9 | "subdirs": true 10 | }, 11 | { "dir": "__tests__", "type": "dev" } 12 | ], 13 | "bsc-flags": ["-bs-super-errors", "-bs-no-version-header"], 14 | "package-specs": [ 15 | { 16 | "module": "commonjs", 17 | "in-source": true 18 | } 19 | ], 20 | "suffix": ".bs.js", 21 | "namespace": true, 22 | "bs-dev-dependencies": ["@glennsl/bs-jest", "bs-react-testing-library"], 23 | "bs-dependencies": ["reason-react", "bs-css", "bs-css-emotion"], 24 | "refmt": 3 25 | } 26 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | ReasonReact Starter 6 | 7 |
8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "reasonreact-starter", 3 | "private": true, 4 | "version": "0.1.0", 5 | "scripts": { 6 | "dev": "parcel index.html", 7 | "build": "parcel build index.html", 8 | "bsb:build": "bsb -make-world", 9 | "bsb:build:watch": "bsb -make-world -w -ws _ ", 10 | "bsb:clean": "bsb -clean-world", 11 | "test:ci": "jest", 12 | "test": "jest --watchAll" 13 | }, 14 | "keywords": [ 15 | "BuckleScript", 16 | "ReasonReact", 17 | "reason-react" 18 | ], 19 | "author": "", 20 | "license": "MIT", 21 | "dependencies": { 22 | "bs-css": "12.2.0", 23 | "bs-css-emotion": "1.2.0", 24 | "react": "16.13.1", 25 | "react-dom": "16.13.1", 26 | "reason-react": "0.8.0" 27 | }, 28 | "devDependencies": { 29 | "@glennsl/bs-jest": "0.5.1", 30 | "bs-platform": "7.2.2", 31 | "bs-react-testing-library": "0.7.2", 32 | "bsb-js": "^1.1.7", 33 | "parcel-bundler": "^1.12.4" 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/App.bs.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var React = require("react"); 4 | var ReasonReactRouter = require("reason-react/src/ReasonReactRouter.js"); 5 | var Nav$ReasonreactStarter = require("./components/Nav.bs.js"); 6 | var Pages$ReasonreactStarter = require("./pages/Pages.bs.js"); 7 | 8 | function App(Props) { 9 | var url = ReasonReactRouter.useUrl(undefined, /* () */0); 10 | var match = url.path; 11 | var tmp; 12 | tmp = match ? ( 13 | match[0] === "signup" && !match[1] ? Pages$ReasonreactStarter.signUp : Pages$ReasonreactStarter.notFound 14 | ) : Pages$ReasonreactStarter.home; 15 | return React.createElement("div", undefined, React.createElement(Nav$ReasonreactStarter.make, { 16 | items: /* :: */[ 17 | { 18 | url: "/", 19 | label: "Home" 20 | }, 21 | /* :: */[ 22 | { 23 | url: "/signup", 24 | label: "Sign up" 25 | }, 26 | /* [] */0 27 | ] 28 | ] 29 | }), tmp); 30 | } 31 | 32 | var make = App; 33 | 34 | exports.make = make; 35 | /* react Not a pure module */ 36 | -------------------------------------------------------------------------------- /src/App.re: -------------------------------------------------------------------------------- 1 | [@react.component] 2 | let make = () => { 3 | let url = ReasonReactRouter.useUrl(); 4 | let navItems: list(Nav.item) = [ 5 | {url: "/", label: "Home"}, 6 | {url: "/signup", label: "Sign up"}, 7 | ]; 8 | 9 |
10 |
; 17 | }; -------------------------------------------------------------------------------- /src/Calculator/Calculator.bs.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var List = require("bs-platform/lib/js/list.js"); 4 | 5 | function sum(numbers) { 6 | return List.fold_right((function (a, b) { 7 | return a + b | 0; 8 | }), numbers, 0); 9 | } 10 | 11 | exports.sum = sum; 12 | /* No side effect */ 13 | -------------------------------------------------------------------------------- /src/Calculator/Calculator.re: -------------------------------------------------------------------------------- 1 | let sum = (numbers: list(int)) => 2 | List.fold_right((a, b) => a + b, numbers, 0); -------------------------------------------------------------------------------- /src/Calculator/Calculator.rei: -------------------------------------------------------------------------------- 1 | let sum: list(int) => int; -------------------------------------------------------------------------------- /src/Index.bs.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var Css = require("bs-css-emotion/src/Css.js"); 4 | var Curry = require("bs-platform/lib/js/curry.js"); 5 | var React = require("react"); 6 | var ReactDOMRe = require("reason-react/src/ReactDOMRe.js"); 7 | var App$ReasonreactStarter = require("./App.bs.js"); 8 | 9 | Curry._2(Css.$$global, "body", /* :: */[ 10 | Css.fontFamily(/* `custom */[ 11 | 1066567601, 12 | "sans-serif" 13 | ]), 14 | /* [] */0 15 | ]); 16 | 17 | var Styles = { }; 18 | 19 | ReactDOMRe.renderToElementWithId(React.createElement(App$ReasonreactStarter.make, { }), "app"); 20 | 21 | exports.Styles = Styles; 22 | /* Not a pure module */ 23 | -------------------------------------------------------------------------------- /src/Index.re: -------------------------------------------------------------------------------- 1 | module Styles = { 2 | open Css; 3 | global("body", [fontFamily("sans-serif"->`custom)]); 4 | }; 5 | 6 | ReactDOMRe.renderToElementWithId(, "app"); -------------------------------------------------------------------------------- /src/components/Hero.bs.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var Css = require("bs-css-emotion/src/Css.js"); 4 | var Curry = require("bs-platform/lib/js/curry.js"); 5 | var React = require("react"); 6 | 7 | var container = Curry._1(Css.style, /* :: */[ 8 | Css.backgroundColor(Css.hex("f3f3f3")), 9 | /* :: */[ 10 | Css.padding(Css.px(24)), 11 | /* [] */0 12 | ] 13 | ]); 14 | 15 | var Styles = { 16 | container: container 17 | }; 18 | 19 | function Hero(Props) { 20 | var children = Props.children; 21 | return React.createElement("div", { 22 | className: container 23 | }, children); 24 | } 25 | 26 | var make = Hero; 27 | 28 | exports.Styles = Styles; 29 | exports.make = make; 30 | /* container Not a pure module */ 31 | -------------------------------------------------------------------------------- /src/components/Hero.re: -------------------------------------------------------------------------------- 1 | module Styles = { 2 | open Css; 3 | 4 | let container = 5 | style([backgroundColor(hex("f3f3f3")), padding(px(24))]); 6 | }; 7 | 8 | [@react.component] 9 | let make = (~children) => { 10 |
children
; 11 | }; -------------------------------------------------------------------------------- /src/components/Nav.bs.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var Css = require("bs-css-emotion/src/Css.js"); 4 | var List = require("bs-platform/lib/js/list.js"); 5 | var $$Array = require("bs-platform/lib/js/array.js"); 6 | var Curry = require("bs-platform/lib/js/curry.js"); 7 | var React = require("react"); 8 | 9 | var container = Curry._1(Css.style, /* :: */[ 10 | Css.selector("> *", /* :: */[ 11 | Css.marginRight(Css.px(12)), 12 | /* [] */0 13 | ]), 14 | /* :: */[ 15 | Css.selector("> *:last-child", /* :: */[ 16 | Css.marginRight(Css.zero), 17 | /* [] */0 18 | ]), 19 | /* [] */0 20 | ] 21 | ]); 22 | 23 | var Styles = { 24 | container: container 25 | }; 26 | 27 | function Nav(Props) { 28 | var items = Props.items; 29 | return React.createElement("div", { 30 | className: container 31 | }, $$Array.of_list(List.mapi((function (index, item) { 32 | return React.createElement("a", { 33 | key: String(index), 34 | href: item.url 35 | }, item.label); 36 | }), items))); 37 | } 38 | 39 | var make = Nav; 40 | 41 | exports.Styles = Styles; 42 | exports.make = make; 43 | /* container Not a pure module */ 44 | -------------------------------------------------------------------------------- /src/components/Nav.re: -------------------------------------------------------------------------------- 1 | type item = { 2 | url: string, 3 | label: string, 4 | }; 5 | 6 | module Styles = { 7 | open Css; 8 | 9 | let container = 10 | style([ 11 | selector("> *", [marginRight(12 |> px)]), 12 | selector("> *:last-child", [marginRight(zero)]), 13 | ]); 14 | }; 15 | 16 | [@react.component] 17 | let make = (~items) => { 18 |
19 | {items 20 | |> List.mapi((index, item) => { 21 | string_of_int} href={item.url}> 22 | item.label->React.string 23 | 24 | }) 25 | |> Array.of_list 26 | |> React.array} 27 |
; 28 | }; -------------------------------------------------------------------------------- /src/components/README.md: -------------------------------------------------------------------------------- 1 | # Components 2 | 3 | **Only put in this folder presentational/dumb reusable components** 4 | -------------------------------------------------------------------------------- /src/pages/Home.bs.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var React = require("react"); 4 | var Hero$ReasonreactStarter = require("../components/Hero.bs.js"); 5 | 6 | function Home(Props) { 7 | return React.createElement(Hero$ReasonreactStarter.make, { 8 | children: React.createElement("h1", undefined, "ReasonReact Starter") 9 | }); 10 | } 11 | 12 | var make = Home; 13 | 14 | exports.make = make; 15 | /* react Not a pure module */ 16 | -------------------------------------------------------------------------------- /src/pages/Home.re: -------------------------------------------------------------------------------- 1 | [@react.component] 2 | let make = () => { 3 |

"ReasonReact Starter"->React.string

; 4 | }; -------------------------------------------------------------------------------- /src/pages/NotFound.bs.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | 4 | function NotFound(Props) { 5 | return "Not Found"; 6 | } 7 | 8 | var make = NotFound; 9 | 10 | exports.make = make; 11 | /* No side effect */ 12 | -------------------------------------------------------------------------------- /src/pages/NotFound.re: -------------------------------------------------------------------------------- 1 | [@react.component] 2 | let make = () => "Not Found"->React.string; -------------------------------------------------------------------------------- /src/pages/Pages.bs.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var React = require("react"); 4 | var Home$ReasonreactStarter = require("./Home.bs.js"); 5 | var SignUp$ReasonreactStarter = require("./SignUp.bs.js"); 6 | var NotFound$ReasonreactStarter = require("./NotFound.bs.js"); 7 | 8 | var notFound = React.createElement(NotFound$ReasonreactStarter.make, { }); 9 | 10 | var home = React.createElement(Home$ReasonreactStarter.make, { }); 11 | 12 | var signUp = React.createElement(SignUp$ReasonreactStarter.make, { }); 13 | 14 | exports.notFound = notFound; 15 | exports.home = home; 16 | exports.signUp = signUp; 17 | /* notFound Not a pure module */ 18 | -------------------------------------------------------------------------------- /src/pages/Pages.re: -------------------------------------------------------------------------------- 1 | let notFound = ; 2 | let home = ; 3 | let signUp = ; -------------------------------------------------------------------------------- /src/pages/README.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cironunes/reasonreact-starter/7d2dabcda7817ec90c8e65ed6c5c896be49b57cc/src/pages/README.md -------------------------------------------------------------------------------- /src/pages/SignUp.bs.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var Css = require("bs-css-emotion/src/Css.js"); 4 | var Curry = require("bs-platform/lib/js/curry.js"); 5 | var React = require("react"); 6 | var Hero$ReasonreactStarter = require("../components/Hero.bs.js"); 7 | 8 | var label = Curry._1(Css.style, /* :: */[ 9 | Css.display(Css.block), 10 | /* [] */0 11 | ]); 12 | 13 | var Styles = { 14 | label: label 15 | }; 16 | 17 | function SignUp(Props) { 18 | return React.createElement(Hero$ReasonreactStarter.make, { 19 | children: null 20 | }, React.createElement("h1", undefined, "Sign Up"), React.createElement("form", undefined, React.createElement("div", undefined, React.createElement("label", { 21 | className: label 22 | }, "Name"), React.createElement("input", { 23 | type: "text" 24 | })), React.createElement("div", undefined, React.createElement("label", { 25 | className: label 26 | }, "Email"), React.createElement("input", { 27 | type: "text" 28 | })), React.createElement("button", undefined, "Sign Up"))); 29 | } 30 | 31 | var make = SignUp; 32 | 33 | exports.Styles = Styles; 34 | exports.make = make; 35 | /* label Not a pure module */ 36 | -------------------------------------------------------------------------------- /src/pages/SignUp.re: -------------------------------------------------------------------------------- 1 | module Styles = { 2 | open Css; 3 | let label = style([display(block)]); 4 | }; 5 | 6 | [@react.component] 7 | let make = () => 8 | 9 |

"Sign Up"->React.string

10 |
11 |
12 | 13 | 14 |
15 |
16 | 17 | 18 |
19 | 20 |
21 |
; --------------------------------------------------------------------------------