├── .gitignore ├── .npmignore ├── .vim └── coc-settings.json ├── .vscode └── extensions.json ├── LICENSE ├── README.md ├── bsconfig.json ├── package.json ├── public ├── favicon.ico ├── index.html └── robots.txt ├── snowpack.config.mjs └── src ├── App.css ├── App.res ├── Index.res ├── bindings ├── ReactDomExperimental.res ├── ReactDomExperimental.resi └── ReactExperimental.res ├── index.css ├── index.js └── logo.svg /.gitignore: -------------------------------------------------------------------------------- 1 | *.DS_Store 2 | *.log* 3 | 4 | .merlin 5 | .bsb.lock 6 | *.bs.js 7 | 8 | node_modules/ 9 | /lib/ 10 | /build/ 11 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | *.bs.js 2 | -------------------------------------------------------------------------------- /.vim/coc-settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "coc.preferences.formatOnSaveFiletypes": [ 3 | "rescript" 4 | ], 5 | "languageserver": { 6 | "rescript": { 7 | "enable": true, 8 | "module": "~/.vim/plugged/vim-rescript/rescript-vscode/extension/server/out/server.js", 9 | "args": ["--node-ipc"], 10 | "filetypes": ["rescript"], 11 | "rootPatterns": ["bsconfig.json"] 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": [ 3 | "chenglou92.rescript-vscode", 4 | "jaredly.reason-vscode" 5 | ], 6 | "unwantedRecommendations": [ 7 | "vscode.typescript-language-features" 8 | ] 9 | } 10 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Reason Seoul 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # snowpack-rescript-react 2 | 3 | [![npm](https://img.shields.io/npm/v/snowpack-rescript-react)](https://npm.im/snowpack-rescript-react) 4 | [![npm](https://img.shields.io/npm/dm/snowpack-rescript-react)](https://npm.im/snowpack-rescript-react) 5 | 6 | A project template to start [ReScript React](https://rescript-lang.org/docs/react/latest/introduction) with [Snowpack](https://www.snowpack.dev/) 7 | 8 | ## Usage 9 | 10 | Bootstrap a project using [create-snowpack-app](https://github.com/snowpackjs/snowpack/tree/main/create-snowpack-app/cli) 11 | 12 | ```bash 13 | # Using Yarn 14 | yarn create snowpack-app my-rescript-project --template snowpack-rescript-react --use-yarn 15 | 16 | # Or using pnpm 17 | pnpx create-snowpack-app my-rescript-project --template snowpack-rescript-react --use-pnpm 18 | ``` 19 | -------------------------------------------------------------------------------- /bsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "app", 3 | "reason": { 4 | "react-jsx": 3 5 | }, 6 | "refmt": 3, 7 | "suffix": ".bs.js", 8 | "sources": { 9 | "dir" : "src", 10 | "subdirs" : true 11 | }, 12 | "bsc-flags": [ 13 | "-bs-super-errors", 14 | "-bs-no-version-header" 15 | ], 16 | "package-specs": [ 17 | { 18 | "module": "es6", 19 | "in-source": true 20 | } 21 | ], 22 | "bs-dependencies": [ 23 | "@rescript/react", 24 | "bs-webapi" 25 | ], 26 | "bs-dev-dependencies": [ 27 | ] 28 | } 29 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "snowpack-rescript-react", 3 | "version": "0.1.0", 4 | "license": "MIT", 5 | "repository": { 6 | "type": "git", 7 | "url": "git+https://github.com/reason-seoul/snowpack-rescript-react.git" 8 | }, 9 | "keywords": [ 10 | "csa-template", 11 | "snowpack", 12 | "rescript", 13 | "react" 14 | ], 15 | "scripts": { 16 | "prepack": "git clean -fdx", 17 | "postinstall": "rescript build -with-deps", 18 | "start:re": "rescript build -w", 19 | "start:snowpack": "snowpack dev", 20 | "start": "run-p start:**", 21 | "build:re": "rescript build", 22 | "build:snowpack": "snowpack build", 23 | "build": "run-s build:**", 24 | "format": "rescript format", 25 | "test": "echo \"This template does not include a test runner by default.\" && exit 1" 26 | }, 27 | "files": [ 28 | ".gitignore", 29 | "bsconfig.json", 30 | "README.md", 31 | "snowpack.config.mjs", 32 | "public", 33 | "src" 34 | ], 35 | "resolutions": { 36 | "react": "0.0.0-experimental-2d8d133e1", 37 | "react-dom": "0.0.0-experimental-2d8d133e1" 38 | }, 39 | "dependencies": { 40 | "@rescript/react": "^0.10.3", 41 | "bs-webapi": "^0.19.1", 42 | "react": "experimental", 43 | "react-dom": "experimental", 44 | "rescript": "^9.1.2" 45 | }, 46 | "devDependencies": { 47 | "@snowpack/plugin-react-refresh": "^2.5.0", 48 | "npm-run-all": "^4.1.5", 49 | "snowpack": "^3.5.1" 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/reason-seoul/snowpack-rescript-react/07a59a6871e64b5589697c10c73f33fc1380aad8/public/favicon.ico -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Snowpack ReScript React Starter 9 | 10 | 11 | 12 |
13 | 14 | 15 | -------------------------------------------------------------------------------- /public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /snowpack.config.mjs: -------------------------------------------------------------------------------- 1 | /** @type {import("snowpack").SnowpackUserConfig } */ 2 | export default { 3 | mount: { 4 | 'public': { url: '/', static: true }, 5 | 'src': { url: '/dist' }, 6 | }, 7 | exclude: [ 8 | '**/*.{res,resi}', 9 | ], 10 | plugins: [ 11 | '@snowpack/plugin-react-refresh', 12 | ], 13 | routes: [ 14 | /* Enable an SPA Fallback in development: */ 15 | // {"match": "routes", "src": ".*", "dest": "/index.html"}, 16 | ], 17 | optimize: { 18 | /* Example: Bundle your final build: */ 19 | // "bundle": true, 20 | }, 21 | packageOptions: { 22 | /* ... */ 23 | }, 24 | devOptions: { 25 | /* ... */ 26 | }, 27 | buildOptions: { 28 | /* ... */ 29 | }, 30 | }; 31 | -------------------------------------------------------------------------------- /src/App.css: -------------------------------------------------------------------------------- 1 | .App { 2 | text-align: center; 3 | } 4 | 5 | .App-logo { 6 | height: 40vmin; 7 | pointer-events: none; 8 | } 9 | 10 | @media (prefers-reduced-motion: no-preference) { 11 | .App-logo { 12 | animation: App-logo-spin infinite 20s linear; 13 | } 14 | } 15 | 16 | .App-header { 17 | background-color: #282c34; 18 | min-height: 100vh; 19 | display: flex; 20 | flex-direction: column; 21 | align-items: center; 22 | justify-content: center; 23 | font-size: calc(10px + 2vmin); 24 | color: white; 25 | } 26 | 27 | .App-button { 28 | font-size: 2rem; 29 | margin-bottom: 1rem; 30 | } 31 | 32 | .App-link { 33 | color: #e6484f; 34 | } 35 | 36 | @keyframes App-logo-spin { 37 | from { 38 | transform: rotate(0deg); 39 | } 40 | to { 41 | transform: rotate(360deg); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/App.res: -------------------------------------------------------------------------------- 1 | %%raw(`import './App.css';`) 2 | 3 | @module("./logo.svg") external logo: string = "default" 4 | 5 | @react.component 6 | let make = () => { 7 | let (count, setCount) = React.useState(() => 0) 8 | 9 |
10 |
11 | logo 12 |

13 | {React.string("Edit ")} 14 | {React.string("src/App.js")} 15 | {React.string(" and save to reload.")} 16 |

17 | 20 | 26 | {React.string("Learn ReScript React")} 27 | 28 |
29 |
30 | } 31 | -------------------------------------------------------------------------------- /src/Index.res: -------------------------------------------------------------------------------- 1 | open ReactDomExperimental 2 | 3 | switch createRootWithId("root") { 4 | | Some(root) => root->render( ) 5 | | None => () 6 | } 7 | -------------------------------------------------------------------------------- /src/bindings/ReactDomExperimental.res: -------------------------------------------------------------------------------- 1 | type root 2 | 3 | @val @return(nullable) 4 | external getElementById: string => option = "document.getElementById" 5 | 6 | @module("react-dom") 7 | external createRoot: Dom.element => root = "createRoot" 8 | 9 | let createRootWithId = id => 10 | switch getElementById(id) { 11 | | None => None 12 | | Some(element) => Some(createRoot(element)) 13 | } 14 | 15 | @send external render: (root, React.element) => unit = "render" 16 | -------------------------------------------------------------------------------- /src/bindings/ReactDomExperimental.resi: -------------------------------------------------------------------------------- 1 | type root 2 | 3 | @module("react-dom") 4 | external createRoot: Dom.element => root = "createRoot" 5 | 6 | let createRootWithId: string => option 7 | 8 | @send external render: (root, React.element) => unit = "render" 9 | -------------------------------------------------------------------------------- /src/bindings/ReactExperimental.res: -------------------------------------------------------------------------------- 1 | @module("react") 2 | external useOpaqueIdentifier: unit => string = "unstable_useOpaqueIdentifer" 3 | 4 | module MutableSource = { 5 | module type Config = { 6 | type source 7 | type version 8 | type snapshot 9 | } 10 | 11 | module Make = (Config: Config) => { 12 | include Config 13 | 14 | type t 15 | 16 | type getVersion = source => version 17 | type getSnapshot = source => snapshot 18 | type subscribe = (source, unit => unit) => option unit> 19 | 20 | @module("react") 21 | external make: (source, getVersion) => t = "unstable_createMutableSource" 22 | 23 | @module("react") 24 | external use: (t, getSnapshot, subscribe) => snapshot = "unstable_useMutableSource" 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 4 | 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', 5 | sans-serif; 6 | -webkit-font-smoothing: antialiased; 7 | -moz-osx-font-smoothing: grayscale; 8 | } 9 | 10 | code { 11 | font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', 12 | monospace; 13 | } 14 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import './index.css'; 2 | import './Index.bs'; 3 | 4 | if (import.meta.hot) { 5 | import.meta.hot.accept(); 6 | } 7 | -------------------------------------------------------------------------------- /src/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | --------------------------------------------------------------------------------