├── example ├── src │ ├── css │ │ └── normalize.css │ ├── commands │ │ ├── Build.re │ │ ├── BuildWithTerser.re │ │ ├── BuildWithEsbuildPlugin.re │ │ ├── BuildWithTerserPluginWithEsbuild.re │ │ ├── Start.re │ │ └── BuildHelper.re │ ├── images │ │ └── cat.jpeg │ ├── Link_Css.re │ ├── Link.re │ ├── content.css │ ├── Content_Css.re │ ├── Env.re │ ├── WrapperWithoutData.re │ ├── MetaTags.re │ ├── PageContext.re │ ├── Footer.re │ ├── WrapperWithData.re │ ├── PageWithoutData.re │ ├── PageWithoutHydration.re │ ├── Global_Css.re │ ├── PerPageGlobals.re │ ├── PageDynamic.re │ ├── PageWithPartialHydration.re │ ├── Header.re │ ├── Page.re │ ├── Content.re │ ├── PageWithData.re │ └── Pages.re └── dune ├── src ├── js │ └── bin.mjs ├── RenderedPage.re ├── EnvParams.re ├── bindings │ ├── Buffer.re │ ├── NodeOs.re │ ├── Performance.re │ ├── Base32Encode.re │ ├── Util.re │ ├── Jsesc.re │ ├── Set.re │ ├── Path.re │ ├── Process.re │ ├── ReactHelmet.re │ ├── Array.re │ ├── ChildProcess.re │ ├── Crypto.re │ ├── Chokidar.re │ ├── HashWasm.re │ ├── WorkerThreads.re │ ├── Fs.re │ ├── Emotion.re │ ├── Promise.re │ └── Esbuild.re ├── PagePath.re ├── GlobalValues.re ├── Debounce.re ├── GracefulShutdown.re ├── Log.re ├── Bin.re ├── PartialHydration.re ├── Bundler.re ├── BuildPageWorkerT.re ├── Utils.re ├── NodeLoader.re ├── BuildPageWorkerHelpers.re ├── BuildPageWorker.re ├── Commands.re ├── ProxyServer.re ├── FileWatcher.re ├── Webpack.re └── PageBuilder.re ├── tests ├── fixtures │ ├── TestPage.re │ ├── TestWrapper.re │ ├── TestPageWithData.re │ └── TestWrapperWithData.re └── Tests.re ├── .c8rc.json ├── .gitignore ├── .vscode └── settings.json ├── package.opam ├── .github └── workflows │ └── nodejs.yml ├── bsconfig.json ├── package.json ├── CHANGELOG.md ├── Makefile └── README.md /example/src/css/normalize.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | } 4 | -------------------------------------------------------------------------------- /example/src/commands/Build.re: -------------------------------------------------------------------------------- 1 | let () = BuildHelper.build(~webpackMinimizer=Terser); 2 | -------------------------------------------------------------------------------- /example/src/commands/BuildWithTerser.re: -------------------------------------------------------------------------------- 1 | let () = BuildHelper.build(~webpackMinimizer=Terser); 2 | -------------------------------------------------------------------------------- /src/js/bin.mjs: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | import { run } from '../Bin.bs.js'; 4 | 5 | run(); 6 | -------------------------------------------------------------------------------- /example/src/commands/BuildWithEsbuildPlugin.re: -------------------------------------------------------------------------------- 1 | let () = BuildHelper.build(~webpackMinimizer=EsbuildPlugin); 2 | -------------------------------------------------------------------------------- /example/src/images/cat.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/denis-ok/rescript-ssg/HEAD/example/src/images/cat.jpeg -------------------------------------------------------------------------------- /example/src/Link_Css.re: -------------------------------------------------------------------------------- 1 | open CssJs; 2 | 3 | let link = style(. [|color(blue), hover([|color(blueviolet)|])|]); 4 | -------------------------------------------------------------------------------- /example/src/commands/BuildWithTerserPluginWithEsbuild.re: -------------------------------------------------------------------------------- 1 | let () = BuildHelper.build(~webpackMinimizer=TerserPluginWithEsbuild); 2 | -------------------------------------------------------------------------------- /src/RenderedPage.re: -------------------------------------------------------------------------------- 1 | type t = { 2 | path: PagePath.t, 3 | entryPath: string, 4 | outputDir: string, 5 | htmlTemplatePath: string, 6 | }; 7 | -------------------------------------------------------------------------------- /tests/fixtures/TestPage.re: -------------------------------------------------------------------------------- 1 | let modulePath = Utils.getFilepath(); 2 | 3 | [@react.component] 4 | let make = () =>
"Hello"->React.string
; 5 | -------------------------------------------------------------------------------- /example/src/Link.re: -------------------------------------------------------------------------------- 1 | module Css = Link_Css; 2 | 3 | [@react.component] 4 | let make = (~href, ~children) => children ; 5 | -------------------------------------------------------------------------------- /example/src/content.css: -------------------------------------------------------------------------------- 1 | .customButton { 2 | display: block; 3 | background-color: white; 4 | border: 2px solid black; 5 | cursor: pointer; 6 | } 7 | -------------------------------------------------------------------------------- /src/EnvParams.re: -------------------------------------------------------------------------------- 1 | let assetPrefix = 2 | switch (Process.env->Js.Dict.get("RESCRIPT_SSG_ASSET_PREFIX")) { 3 | | None => "" 4 | | Some(assetPrefix) => assetPrefix 5 | }; 6 | -------------------------------------------------------------------------------- /.c8rc.json: -------------------------------------------------------------------------------- 1 | { 2 | "reporter": [ 3 | "text", 4 | "html" 5 | ], 6 | "include": [ 7 | "src/PageBuilder.bs.js", 8 | "src/Utils.bs.js" 9 | ] 10 | } 11 | -------------------------------------------------------------------------------- /tests/fixtures/TestWrapper.re: -------------------------------------------------------------------------------- 1 | [@react.component] 2 | let make = (~children) => 3 |
"Hello from page wrapper"->React.string children
; 4 | 5 | let modulePath = Utils.getFilepath(); 6 | -------------------------------------------------------------------------------- /example/dune: -------------------------------------------------------------------------------- 1 | (include_subdirs unqualified) 2 | 3 | (melange.emit 4 | (target example) 5 | (alias example) 6 | (preprocess 7 | (pps melange.ppx reason-react-ppx)) 8 | (libraries reason-react)) 9 | -------------------------------------------------------------------------------- /src/bindings/Buffer.re: -------------------------------------------------------------------------------- 1 | type t; 2 | 3 | [@bs.val] 4 | external fromString: (string, ~encoding: string) => t = "Buffer.from"; 5 | 6 | [@bs.send] external toString: (t, string) => string = "toString"; 7 | -------------------------------------------------------------------------------- /src/bindings/NodeOs.re: -------------------------------------------------------------------------------- 1 | // optional value for backwards compatibility with node <18.14.0 2 | [@bs.module "node:os"] 3 | external availableParallelism: option(unit => int) = "availableParallelism"; 4 | -------------------------------------------------------------------------------- /example/src/Content_Css.re: -------------------------------------------------------------------------------- 1 | open CssJs; 2 | 3 | let content = 4 | style(. [| 5 | backgroundColor(`hex("F9F1F0")), 6 | padding(`px(16)), 7 | display(`grid), 8 | gridGap(`px(16)), 9 | |]); 10 | -------------------------------------------------------------------------------- /example/src/Env.re: -------------------------------------------------------------------------------- 1 | [@val] external envVar: option(string) = "process.env.ENV_VAR"; 2 | 3 | let envVar = envVar->(Belt.Option.getWithDefault("ENV_VAR IS MISSING")); 4 | 5 | [@val] external globalVar: string = "GLOBAL_VAR"; 6 | -------------------------------------------------------------------------------- /example/src/WrapperWithoutData.re: -------------------------------------------------------------------------------- 1 | let modulePath = Utils.getFilepath(); 2 | 3 | [@react.component] 4 | let make = (~children) => 5 |
6 |

"Hello from simple page wrapper"->React.string

7 | children 8 |
; 9 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | /node_modules/ 3 | /lib/ 4 | .bsb.lock 5 | .merlin 6 | *.bs.js 7 | /dist 8 | /demo/bundle 9 | .trash 10 | /_opam 11 | /_opam_mel 12 | /_opam_bs 13 | _build 14 | example/build 15 | coverage 16 | tests/output 17 | -------------------------------------------------------------------------------- /example/src/MetaTags.re: -------------------------------------------------------------------------------- 1 | [@react.component] 2 | let make = (~title, ~description) => 3 | 4 | 5 | title->React.string 6 | 7 | ; 8 | -------------------------------------------------------------------------------- /src/bindings/Performance.re: -------------------------------------------------------------------------------- 1 | [@bs.module "node:perf_hooks"] [@bs.scope "performance"] 2 | external now: unit => float = "now"; 3 | 4 | let durationSinceStartTime = (~startTime) => 5 | (now() -. startTime)->Js.Float.toFixedWithPrecision(~digits=2) ++ " ms"; 6 | -------------------------------------------------------------------------------- /src/bindings/Base32Encode.re: -------------------------------------------------------------------------------- 1 | type padding = {padding: bool}; 2 | 3 | [@bs.module "base32-encode"] 4 | external base32Encode': (Buffer.t, string, padding) => string = "default"; 5 | 6 | let base32Encode = buffer => 7 | base32Encode'(buffer, "RFC4648", {padding: false}); 8 | -------------------------------------------------------------------------------- /example/src/PageContext.re: -------------------------------------------------------------------------------- 1 | type variant = 2 | | One 3 | | Two(string); 4 | 5 | type polyVariant = [ | `hello | `world]; 6 | 7 | type t = { 8 | string, 9 | int, 10 | float, 11 | variant, 12 | polyVariant, 13 | bool, 14 | option: option(string), 15 | }; 16 | -------------------------------------------------------------------------------- /example/src/Footer.re: -------------------------------------------------------------------------------- 1 | [@react.component] 2 | let make = () => 3 |

4 | "This page has been built with "->React.string 5 | 6 | "rescript-ssg"->React.string 7 | 8 | " library."->React.string 9 |

; 10 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "ocaml.sandbox": { 3 | "kind": "opam", 4 | "switch": "${workspaceFolder:rescript-ssg}" 5 | }, 6 | "github.copilot.enable": { 7 | "*": false, 8 | "reason": true, 9 | "ocaml": true, 10 | "rescript": true, 11 | "javascript": true 12 | }, 13 | } 14 | -------------------------------------------------------------------------------- /src/bindings/Util.re: -------------------------------------------------------------------------------- 1 | // https://nodejs.org/api/util.html#utilinspectobject-options 2 | 3 | type options = { 4 | depth: int, 5 | colors: bool, 6 | }; 7 | 8 | [@bs.module "node:util"] external inspect: ('a, options) => string = "inspect"; 9 | 10 | let inspect = value => inspect(value, {depth: 2, colors: true}); 11 | -------------------------------------------------------------------------------- /example/src/WrapperWithData.re: -------------------------------------------------------------------------------- 1 | let modulePath = Utils.getFilepath(); 2 | 3 | [@react.component] 4 | let make = (~data, ~children) => 5 |
6 |

"Hello from page wrapper with data"->React.string

7 |

"Data: "->React.string

8 |

data->React.string

9 | children 10 |
; 11 | -------------------------------------------------------------------------------- /src/bindings/Jsesc.re: -------------------------------------------------------------------------------- 1 | type jsesc; 2 | 3 | type options = { 4 | quotes: string, 5 | json: bool, 6 | wrap: bool, 7 | es6: bool, 8 | }; 9 | 10 | [@bs.module "jsesc"] external jsesc: ('a, options) => string = "default"; 11 | 12 | let jsesc = a => 13 | jsesc(a, {quotes: "double", json: false, wrap: true, es6: false}); 14 | -------------------------------------------------------------------------------- /example/src/PageWithoutData.re: -------------------------------------------------------------------------------- 1 | let modulePath = Utils.getFilepath(); 2 | 3 | [@react.component] 4 | let make = () => 5 | <> 6 | 10 |
11 | 12 |