Skip to content

React starter template #4010

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Dec 6, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions jscomp/bsb/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,23 @@ Bsb is BuckleScript's build system. User-facing documentations are [here](https:
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.

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`.

## Add/edit a template

The content of `templates` is packed into `bsb_templates.ml` automatically when running `pack-templates.sh`, located in this directory.

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:

```sh
opam install ocp-ocamlres
```

## Testing a template locally

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).

The built binaries will end up under `lib` where you can run local `bsb`:

```sh
./bsb -init test-theme -theme new_theme
```
204 changes: 204 additions & 0 deletions jscomp/bsb/bsb_templates.ml
Original file line number Diff line number Diff line change
Expand Up @@ -995,6 +995,210 @@ let root = OCamlRes.Res.([
</body>\n\
</html>\n\
")]) ;
Dir ("react-starter", [
Dir ("src", [
File ("Index.re",
"[%bs.raw {|require(\"./index.css\")|}];\n\
\n\
ReactDOMRe.renderToElementWithId(<App />, \"root\");\n\
") ;
File ("index.css",
"body {\n\
\ margin: 0;\n\
\ font-family: -apple-system, system-ui, \"Segoe UI\", Helvetica, Arial,\n\
\ sans-serif, \"Apple Color Emoji\", \"Segoe UI Emoji\", \"Segoe UI Symbol\";\n\
}\n\
\n\
main {\n\
\ padding: 20px;\n\
}\n\
\n\
.counter {\n\
\ padding: 20px;\n\
\ display: inline-block;\n\
}\n\
") ;
File ("App.re",
"type state = {count: int};\n\
\n\
type action =\n\
\ | Increment\n\
\ | Decrement;\n\
\n\
let initialState = {count: 0};\n\
\n\
let reducer = (state, action) =>\n\
\ switch (action) {\n\
\ | Increment => {count: state.count + 1}\n\
\ | Decrement => {count: state.count - 1}\n\
\ };\n\
\n\
[@react.component]\n\
let make = () => {\n\
\ let (state, dispatch) = React.useReducer(reducer, initialState);\n\
\n\
\ <main>\n\
\ {React.string(\"Simple counter with reducer\")}\n\
\ <div>\n\
\ <button onClick={_ => dispatch(Decrement)}>\n\
\ {React.string(\"Decrement\")}\n\
\ </button>\n\
\ <span className=\"counter\">\n\
\ {state.count |> string_of_int |> React.string}\n\
\ </span>\n\
\ <button onClick={_ => dispatch(Increment)}>\n\
\ {React.string(\"Increment\")}\n\
\ </button>\n\
\ </div>\n\
\ </main>;\n\
};\n\
") ;
File ("index.html",
"<!DOCTYPE html>\n\
<html lang=\"en\">\n\
\ <head>\n\
\ <meta charset=\"UTF-8\" />\n\
\ <title>Reason react starter</title>\n\
\ </head>\n\
\ <body>\n\
\ <div id=\"root\"></div>\n\
\ <script src=\"/Index.js\"></script>\n\
\ </body>\n\
</html>\n\
")]) ;
File ("bsconfig.json",
"{\n\
\ \"name\": \"reason-react-starter\",\n\
\ \"reason\": {\n\
\ \"react-jsx\": 3\n\
\ },\n\
\ \"sources\": {\n\
\ \"dir\": \"src\",\n\
\ \"subdirs\": true\n\
\ },\n\
\ \"bsc-flags\": [\"-bs-super-errors\", \"-bs-no-version-header\"],\n\
\ \"package-specs\": [\n\
\ {\n\
\ \"module\": \"commonjs\",\n\
\ \"in-source\": true\n\
\ }\n\
\ ],\n\
\ \"suffix\": \".bs.js\",\n\
\ \"namespace\": true,\n\
\ \"bs-dependencies\": [\"reason-react\"],\n\
\ \"refmt\": 3\n\
}\n\
") ;
File ("package.json",
"{\n\
\ \"name\": \"${bsb:name}\",\n\
\ \"version\": \"${bsb:proj-version}\",\n\
\ \"scripts\": {\n\
\ \"build\": \"bsb -make-world\",\n\
\ \"start\": \"bsb -make-world -w -ws _ \",\n\
\ \"clean\": \"bsb -clean-world\",\n\
\ \"webpack\": \"webpack -w\",\n\
\ \"webpack:production\": \"NODE_ENV=production webpack\",\n\
\ \"server\": \"webpack-dev-server\",\n\
\ \"test\": \"echo \\\"Error: no test specified\\\" && exit 1\"\n\
\ },\n\
\ \"keywords\": [\n\
\ \"BuckleScript\",\n\
\ \"ReasonReact\",\n\
\ \"reason-react\"\n\
\ ],\n\
\ \"author\": \"\",\n\
\ \"license\": \"MIT\",\n\
\ \"dependencies\": {\n\
\ \"react\": \"^16.8.1\",\n\
\ \"react-dom\": \"^16.8.1\",\n\
\ \"reason-react\": \">=0.7.0\"\n\
\ },\n\
\ \"devDependencies\": {\n\
\ \"bs-platform\": \"^${bsb:bs-version}\",\n\
\ \"webpack\": \"^4.0.1\",\n\
\ \"webpack-cli\": \"^3.1.1\",\n\
\ \"webpack-dev-server\": \"^3.1.8\",\n\
\ \"html-webpack-plugin\": \"^3.2.0\",\n\
\ \"style-loader\": \"^1.0.0\",\n\
\ \"css-loader\": \"^3.2.0\"\n\
\ }\n\
}\n\
") ;
File (".gitignore",
".DS_Store\n\
.merlin\n\
.bsb.lock\n\
npm-debug.log\n\
/lib/bs/\n\
/node_modules/\n\
*.bs.js\n\
") ;
File ("README.md",
"# Reason react starter\n\
\n\
## Run Project\n\
\n\
```sh\n\
npm install\n\
npm start\n\
# in another tab\n\
npm run server\n\
```\n\
\n\
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\
\n\
To use a port other than 8000 set the `PORT` environment variable (`PORT=8080 npm run server`).\n\
\n\
## Build for Production\n\
\n\
```sh\n\
npm run clean\n\
npm run build\n\
npm run webpack:production\n\
```\n\
\n\
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\
\n\
**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\
") ;
File ("webpack.config.js",
"const path = require(\"path\")\n\
const HtmlWebpackPlugin = require(\"html-webpack-plugin\")\n\
const outputDir = path.join(__dirname, \"build/\")\n\
\n\
const isProd = process.env.NODE_ENV === \"production\"\n\
\n\
module.exports = {\n\
\ entry: \"./src/Index.bs.js\",\n\
\ mode: isProd ? \"production\" : \"development\",\n\
\ devtool: \"source-map\",\n\
\ output: {\n\
\ path: outputDir,\n\
\ filename: \"Index.js\"\n\
\ },\n\
\ plugins: [\n\
\ new HtmlWebpackPlugin({\n\
\ template: \"src/index.html\",\n\
\ inject: false\n\
\ })\n\
\ ],\n\
\ devServer: {\n\
\ compress: true,\n\
\ contentBase: outputDir,\n\
\ port: process.env.PORT || 8000,\n\
\ historyApiFallback: true\n\
\ },\n\
\ module: {\n\
\ rules: [\n\
\ {\n\
\ test: /\\.css$/,\n\
\ use: [\"style-loader\", \"css-loader\"]\n\
\ }\n\
\ ]\n\
\ }\n\
}\n\
")]) ;
Dir ("tea", [
Dir ("src", [
File ("main.ml",
Expand Down
7 changes: 7 additions & 0 deletions jscomp/bsb/templates/react-starter/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
.DS_Store
.merlin
.bsb.lock
npm-debug.log
/lib/bs/
/node_modules/
*.bs.js
26 changes: 26 additions & 0 deletions jscomp/bsb/templates/react-starter/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# Reason react starter

## Run Project

```sh
npm install
npm start
# in another tab
npm run server
```

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.

To use a port other than 8000 set the `PORT` environment variable (`PORT=8080 npm run server`).

## Build for Production

```sh
npm run clean
npm run build
npm run webpack:production
```

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`).

**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.
21 changes: 21 additions & 0 deletions jscomp/bsb/templates/react-starter/bsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"name": "reason-react-starter",
"reason": {
"react-jsx": 3
},
"sources": {
"dir": "src",
"subdirs": true
},
"bsc-flags": ["-bs-super-errors", "-bs-no-version-header"],
"package-specs": [
{
"module": "commonjs",
"in-source": true
}
],
"suffix": ".bs.js",
"namespace": true,
"bs-dependencies": ["reason-react"],
"refmt": 3
}
34 changes: 34 additions & 0 deletions jscomp/bsb/templates/react-starter/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
{
"name": "${bsb:name}",
"version": "${bsb:proj-version}",
"scripts": {
"build": "bsb -make-world",
"start": "bsb -make-world -w -ws _ ",
"clean": "bsb -clean-world",
"webpack": "webpack -w",
"webpack:production": "NODE_ENV=production webpack",
"server": "webpack-dev-server",
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [
"BuckleScript",
"ReasonReact",
"reason-react"
],
"author": "",
"license": "MIT",
"dependencies": {
"react": "^16.8.1",
"react-dom": "^16.8.1",
"reason-react": ">=0.7.0"
},
"devDependencies": {
"bs-platform": "^${bsb:bs-version}",
"webpack": "^4.0.1",
"webpack-cli": "^3.1.1",
"webpack-dev-server": "^3.1.8",
"html-webpack-plugin": "^3.2.0",
"style-loader": "^1.0.0",
"css-loader": "^3.2.0"
}
}
33 changes: 33 additions & 0 deletions jscomp/bsb/templates/react-starter/src/App.re
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
type state = {count: int};

type action =
| Increment
| Decrement;

let initialState = {count: 0};

let reducer = (state, action) =>
switch (action) {
| Increment => {count: state.count + 1}
| Decrement => {count: state.count - 1}
};

[@react.component]
let make = () => {
let (state, dispatch) = React.useReducer(reducer, initialState);

<main>
{React.string("Simple counter with reducer")}
<div>
<button onClick={_ => dispatch(Decrement)}>
{React.string("Decrement")}
</button>
<span className="counter">
{state.count |> string_of_int |> React.string}
</span>
<button onClick={_ => dispatch(Increment)}>
{React.string("Increment")}
</button>
</div>
</main>;
};
3 changes: 3 additions & 0 deletions jscomp/bsb/templates/react-starter/src/Index.re
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[%bs.raw {|require("./index.css")|}];

ReactDOMRe.renderToElementWithId(<App />, "root");
14 changes: 14 additions & 0 deletions jscomp/bsb/templates/react-starter/src/index.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
body {
margin: 0;
font-family: -apple-system, system-ui, "Segoe UI", Helvetica, Arial,
sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
}

main {
padding: 20px;
}

.counter {
padding: 20px;
display: inline-block;
}
11 changes: 11 additions & 0 deletions jscomp/bsb/templates/react-starter/src/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Reason react starter</title>
</head>
<body>
<div id="root"></div>
<script src="/Index.js"></script>
</body>
</html>
Loading