├── .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 | [](https://david-dm.org/cironunes/reasonreact-starter)
6 | [](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 |
11 | {switch (url.path) {
12 | | [] => Pages.home
13 | | ["signup"] => Pages.signUp
14 | | _ => Pages.notFound
15 | }}
16 |
;
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 | ;
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 |
21 | ;
--------------------------------------------------------------------------------