Skip to content

Commit 9456c3e

Browse files
authored
Merge pull request #4010 from MargaretKrutikova/react-starter-template
React starter template
2 parents ab4e336 + 76f8a06 commit 9456c3e

File tree

11 files changed

+408
-0
lines changed

11 files changed

+408
-0
lines changed

jscomp/bsb/README.md

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,23 @@ Bsb is BuckleScript's build system. User-facing documentations are [here](https:
55
This directory hosts its implementation. It reads into `bsconfig.json`, uses some BS/OCaml/Reason-specific logic, and generates a [ninja](https://ninja-build.org) build file then calls `ninja` on it. So much of the incremental build and perf work is delegated to Ninja.
66

77
There's a `templates/` subdirectory. It's the thing shown when you do `bsb -themes`. To generate a template for the user, it basically picks the chosen template from `templates/` and copy pastes it into the destined user directory while substituting some strings in those templates, like `${bsb:proj-version}` in the `package.json`s. The copy-pasting of folders isn't actually done naively through a call to unix `cp`. It's cleverly achieved through something called ocamlres. Please see more descriptions in `pack-templates.sh`.
8+
9+
## Add/edit a template
10+
11+
The content of `templates` is packed into `bsb_templates.ml` automatically when running `pack-templates.sh`, located in this directory.
12+
13+
When adding/editing a template the script needs to be rerun to update the relevant parts in `bsb_templates.ml`. The script uses [`ocamlres`](https://github.com/OCamlPro/ocp-ocamlres), a tool for embedding files inside ocaml executables. You will need to install it with [`opam`](https://opam.ocaml.org/doc/Install.html), ocaml package manager. Follow the [instructions](https://opam.ocaml.org/doc/Install.html) to install `opam`, if you haven't installed it yet. To install `ocp-ocamlres` run:
14+
15+
```sh
16+
opam install ocp-ocamlres
17+
```
18+
19+
## Testing a template locally
20+
21+
Do the following setup steps to build the compiler: [build ocaml compiler](https://github.com/BuckleScript/bucklescript/blob/master/CONTRIBUTING.md#build-the-vendored-ocaml-compiler) and [build everything in dev mode](https://github.com/BuckleScript/bucklescript/blob/master/CONTRIBUTING.md#build-everything-in-dev-mode-using-vendored-compiler).
22+
23+
The built binaries will end up under `lib` where you can run local `bsb`:
24+
25+
```sh
26+
./bsb -init test-theme -theme new_theme
27+
```

jscomp/bsb/bsb_templates.ml

Lines changed: 204 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -995,6 +995,210 @@ let root = OCamlRes.Res.([
995995
</body>\n\
996996
</html>\n\
997997
")]) ;
998+
Dir ("react-starter", [
999+
Dir ("src", [
1000+
File ("Index.re",
1001+
"[%bs.raw {|require(\"./index.css\")|}];\n\
1002+
\n\
1003+
ReactDOMRe.renderToElementWithId(<App />, \"root\");\n\
1004+
") ;
1005+
File ("index.css",
1006+
"body {\n\
1007+
\ margin: 0;\n\
1008+
\ font-family: -apple-system, system-ui, \"Segoe UI\", Helvetica, Arial,\n\
1009+
\ sans-serif, \"Apple Color Emoji\", \"Segoe UI Emoji\", \"Segoe UI Symbol\";\n\
1010+
}\n\
1011+
\n\
1012+
main {\n\
1013+
\ padding: 20px;\n\
1014+
}\n\
1015+
\n\
1016+
.counter {\n\
1017+
\ padding: 20px;\n\
1018+
\ display: inline-block;\n\
1019+
}\n\
1020+
") ;
1021+
File ("App.re",
1022+
"type state = {count: int};\n\
1023+
\n\
1024+
type action =\n\
1025+
\ | Increment\n\
1026+
\ | Decrement;\n\
1027+
\n\
1028+
let initialState = {count: 0};\n\
1029+
\n\
1030+
let reducer = (state, action) =>\n\
1031+
\ switch (action) {\n\
1032+
\ | Increment => {count: state.count + 1}\n\
1033+
\ | Decrement => {count: state.count - 1}\n\
1034+
\ };\n\
1035+
\n\
1036+
[@react.component]\n\
1037+
let make = () => {\n\
1038+
\ let (state, dispatch) = React.useReducer(reducer, initialState);\n\
1039+
\n\
1040+
\ <main>\n\
1041+
\ {React.string(\"Simple counter with reducer\")}\n\
1042+
\ <div>\n\
1043+
\ <button onClick={_ => dispatch(Decrement)}>\n\
1044+
\ {React.string(\"Decrement\")}\n\
1045+
\ </button>\n\
1046+
\ <span className=\"counter\">\n\
1047+
\ {state.count |> string_of_int |> React.string}\n\
1048+
\ </span>\n\
1049+
\ <button onClick={_ => dispatch(Increment)}>\n\
1050+
\ {React.string(\"Increment\")}\n\
1051+
\ </button>\n\
1052+
\ </div>\n\
1053+
\ </main>;\n\
1054+
};\n\
1055+
") ;
1056+
File ("index.html",
1057+
"<!DOCTYPE html>\n\
1058+
<html lang=\"en\">\n\
1059+
\ <head>\n\
1060+
\ <meta charset=\"UTF-8\" />\n\
1061+
\ <title>Reason react starter</title>\n\
1062+
\ </head>\n\
1063+
\ <body>\n\
1064+
\ <div id=\"root\"></div>\n\
1065+
\ <script src=\"/Index.js\"></script>\n\
1066+
\ </body>\n\
1067+
</html>\n\
1068+
")]) ;
1069+
File ("bsconfig.json",
1070+
"{\n\
1071+
\ \"name\": \"reason-react-starter\",\n\
1072+
\ \"reason\": {\n\
1073+
\ \"react-jsx\": 3\n\
1074+
\ },\n\
1075+
\ \"sources\": {\n\
1076+
\ \"dir\": \"src\",\n\
1077+
\ \"subdirs\": true\n\
1078+
\ },\n\
1079+
\ \"bsc-flags\": [\"-bs-super-errors\", \"-bs-no-version-header\"],\n\
1080+
\ \"package-specs\": [\n\
1081+
\ {\n\
1082+
\ \"module\": \"commonjs\",\n\
1083+
\ \"in-source\": true\n\
1084+
\ }\n\
1085+
\ ],\n\
1086+
\ \"suffix\": \".bs.js\",\n\
1087+
\ \"namespace\": true,\n\
1088+
\ \"bs-dependencies\": [\"reason-react\"],\n\
1089+
\ \"refmt\": 3\n\
1090+
}\n\
1091+
") ;
1092+
File ("package.json",
1093+
"{\n\
1094+
\ \"name\": \"${bsb:name}\",\n\
1095+
\ \"version\": \"${bsb:proj-version}\",\n\
1096+
\ \"scripts\": {\n\
1097+
\ \"build\": \"bsb -make-world\",\n\
1098+
\ \"start\": \"bsb -make-world -w -ws _ \",\n\
1099+
\ \"clean\": \"bsb -clean-world\",\n\
1100+
\ \"webpack\": \"webpack -w\",\n\
1101+
\ \"webpack:production\": \"NODE_ENV=production webpack\",\n\
1102+
\ \"server\": \"webpack-dev-server\",\n\
1103+
\ \"test\": \"echo \\\"Error: no test specified\\\" && exit 1\"\n\
1104+
\ },\n\
1105+
\ \"keywords\": [\n\
1106+
\ \"BuckleScript\",\n\
1107+
\ \"ReasonReact\",\n\
1108+
\ \"reason-react\"\n\
1109+
\ ],\n\
1110+
\ \"author\": \"\",\n\
1111+
\ \"license\": \"MIT\",\n\
1112+
\ \"dependencies\": {\n\
1113+
\ \"react\": \"^16.8.1\",\n\
1114+
\ \"react-dom\": \"^16.8.1\",\n\
1115+
\ \"reason-react\": \">=0.7.0\"\n\
1116+
\ },\n\
1117+
\ \"devDependencies\": {\n\
1118+
\ \"bs-platform\": \"^${bsb:bs-version}\",\n\
1119+
\ \"webpack\": \"^4.0.1\",\n\
1120+
\ \"webpack-cli\": \"^3.1.1\",\n\
1121+
\ \"webpack-dev-server\": \"^3.1.8\",\n\
1122+
\ \"html-webpack-plugin\": \"^3.2.0\",\n\
1123+
\ \"style-loader\": \"^1.0.0\",\n\
1124+
\ \"css-loader\": \"^3.2.0\"\n\
1125+
\ }\n\
1126+
}\n\
1127+
") ;
1128+
File (".gitignore",
1129+
".DS_Store\n\
1130+
.merlin\n\
1131+
.bsb.lock\n\
1132+
npm-debug.log\n\
1133+
/lib/bs/\n\
1134+
/node_modules/\n\
1135+
*.bs.js\n\
1136+
") ;
1137+
File ("README.md",
1138+
"# Reason react starter\n\
1139+
\n\
1140+
## Run Project\n\
1141+
\n\
1142+
```sh\n\
1143+
npm install\n\
1144+
npm start\n\
1145+
# in another tab\n\
1146+
npm run server\n\
1147+
```\n\
1148+
\n\
1149+
View the app in the browser at http://localhost:8000. Running in this environment provides hot reloading and support for routing; just edit and save the file and the browser will automatically refresh.\n\
1150+
\n\
1151+
To use a port other than 8000 set the `PORT` environment variable (`PORT=8080 npm run server`).\n\
1152+
\n\
1153+
## Build for Production\n\
1154+
\n\
1155+
```sh\n\
1156+
npm run clean\n\
1157+
npm run build\n\
1158+
npm run webpack:production\n\
1159+
```\n\
1160+
\n\
1161+
This will replace the development artifact `build/Index.js` for an optimized version as well as copy `src/index.html` into `build/`. You can then deploy the contents of the `build` directory (`index.html` and `Index.js`).\n\
1162+
\n\
1163+
**To enable dead code elimination**, change `bsconfig.json`'s `package-specs` `module` from `\"commonjs\"` to `\"es6\"`. Then re-run the above 2 commands. This will allow Webpack to remove unused code.\n\
1164+
") ;
1165+
File ("webpack.config.js",
1166+
"const path = require(\"path\")\n\
1167+
const HtmlWebpackPlugin = require(\"html-webpack-plugin\")\n\
1168+
const outputDir = path.join(__dirname, \"build/\")\n\
1169+
\n\
1170+
const isProd = process.env.NODE_ENV === \"production\"\n\
1171+
\n\
1172+
module.exports = {\n\
1173+
\ entry: \"./src/Index.bs.js\",\n\
1174+
\ mode: isProd ? \"production\" : \"development\",\n\
1175+
\ devtool: \"source-map\",\n\
1176+
\ output: {\n\
1177+
\ path: outputDir,\n\
1178+
\ filename: \"Index.js\"\n\
1179+
\ },\n\
1180+
\ plugins: [\n\
1181+
\ new HtmlWebpackPlugin({\n\
1182+
\ template: \"src/index.html\",\n\
1183+
\ inject: false\n\
1184+
\ })\n\
1185+
\ ],\n\
1186+
\ devServer: {\n\
1187+
\ compress: true,\n\
1188+
\ contentBase: outputDir,\n\
1189+
\ port: process.env.PORT || 8000,\n\
1190+
\ historyApiFallback: true\n\
1191+
\ },\n\
1192+
\ module: {\n\
1193+
\ rules: [\n\
1194+
\ {\n\
1195+
\ test: /\\.css$/,\n\
1196+
\ use: [\"style-loader\", \"css-loader\"]\n\
1197+
\ }\n\
1198+
\ ]\n\
1199+
\ }\n\
1200+
}\n\
1201+
")]) ;
9981202
Dir ("tea", [
9991203
Dir ("src", [
10001204
File ("main.ml",
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
.DS_Store
2+
.merlin
3+
.bsb.lock
4+
npm-debug.log
5+
/lib/bs/
6+
/node_modules/
7+
*.bs.js
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
# Reason react starter
2+
3+
## Run Project
4+
5+
```sh
6+
npm install
7+
npm start
8+
# in another tab
9+
npm run server
10+
```
11+
12+
View the app in the browser at http://localhost:8000. Running in this environment provides hot reloading and support for routing; just edit and save the file and the browser will automatically refresh.
13+
14+
To use a port other than 8000 set the `PORT` environment variable (`PORT=8080 npm run server`).
15+
16+
## Build for Production
17+
18+
```sh
19+
npm run clean
20+
npm run build
21+
npm run webpack:production
22+
```
23+
24+
This will replace the development artifact `build/Index.js` for an optimized version as well as copy `src/index.html` into `build/`. You can then deploy the contents of the `build` directory (`index.html` and `Index.js`).
25+
26+
**To enable dead code elimination**, change `bsconfig.json`'s `package-specs` `module` from `"commonjs"` to `"es6"`. Then re-run the above 2 commands. This will allow Webpack to remove unused code.
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
{
2+
"name": "reason-react-starter",
3+
"reason": {
4+
"react-jsx": 3
5+
},
6+
"sources": {
7+
"dir": "src",
8+
"subdirs": true
9+
},
10+
"bsc-flags": ["-bs-super-errors", "-bs-no-version-header"],
11+
"package-specs": [
12+
{
13+
"module": "commonjs",
14+
"in-source": true
15+
}
16+
],
17+
"suffix": ".bs.js",
18+
"namespace": true,
19+
"bs-dependencies": ["reason-react"],
20+
"refmt": 3
21+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
{
2+
"name": "${bsb:name}",
3+
"version": "${bsb:proj-version}",
4+
"scripts": {
5+
"build": "bsb -make-world",
6+
"start": "bsb -make-world -w -ws _ ",
7+
"clean": "bsb -clean-world",
8+
"webpack": "webpack -w",
9+
"webpack:production": "NODE_ENV=production webpack",
10+
"server": "webpack-dev-server",
11+
"test": "echo \"Error: no test specified\" && exit 1"
12+
},
13+
"keywords": [
14+
"BuckleScript",
15+
"ReasonReact",
16+
"reason-react"
17+
],
18+
"author": "",
19+
"license": "MIT",
20+
"dependencies": {
21+
"react": "^16.8.1",
22+
"react-dom": "^16.8.1",
23+
"reason-react": ">=0.7.0"
24+
},
25+
"devDependencies": {
26+
"bs-platform": "^${bsb:bs-version}",
27+
"webpack": "^4.0.1",
28+
"webpack-cli": "^3.1.1",
29+
"webpack-dev-server": "^3.1.8",
30+
"html-webpack-plugin": "^3.2.0",
31+
"style-loader": "^1.0.0",
32+
"css-loader": "^3.2.0"
33+
}
34+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
type state = {count: int};
2+
3+
type action =
4+
| Increment
5+
| Decrement;
6+
7+
let initialState = {count: 0};
8+
9+
let reducer = (state, action) =>
10+
switch (action) {
11+
| Increment => {count: state.count + 1}
12+
| Decrement => {count: state.count - 1}
13+
};
14+
15+
[@react.component]
16+
let make = () => {
17+
let (state, dispatch) = React.useReducer(reducer, initialState);
18+
19+
<main>
20+
{React.string("Simple counter with reducer")}
21+
<div>
22+
<button onClick={_ => dispatch(Decrement)}>
23+
{React.string("Decrement")}
24+
</button>
25+
<span className="counter">
26+
{state.count |> string_of_int |> React.string}
27+
</span>
28+
<button onClick={_ => dispatch(Increment)}>
29+
{React.string("Increment")}
30+
</button>
31+
</div>
32+
</main>;
33+
};
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
[%bs.raw {|require("./index.css")|}];
2+
3+
ReactDOMRe.renderToElementWithId(<App />, "root");
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
body {
2+
margin: 0;
3+
font-family: -apple-system, system-ui, "Segoe UI", Helvetica, Arial,
4+
sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
5+
}
6+
7+
main {
8+
padding: 20px;
9+
}
10+
11+
.counter {
12+
padding: 20px;
13+
display: inline-block;
14+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8" />
5+
<title>Reason react starter</title>
6+
</head>
7+
<body>
8+
<div id="root"></div>
9+
<script src="/Index.js"></script>
10+
</body>
11+
</html>

0 commit comments

Comments
 (0)