Skip to content

feat: added new community content page #980

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 13 commits into from
Mar 11, 2025
2 changes: 2 additions & 0 deletions data/resources.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[{"title":"JavaScript schema library from the Future 🧬","description":"ReScript Schema - The fastest parser in the entire JavaScript ecosystem with a focus on small bundle... Tagged with schema, typescript, rescript, opensource.","image":"https://media2.dev.to/dynamic/image/width=1000,height=500,fit=cover,gravity=auto,format=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fn102ksd9w1xo5ysgxbur.png","url":"https://dev.to/dzakh/javascript-schema-library-from-the-future-5420"},{"title":"ReScript: A Better Typed JavaScript? (with Gabriel Nordeborn)","description":"ReScript is a strongly-typed programming language that compiles to JavaScript, and that puts it squarely in competition with TypeScript. So why would a JavaS...","image":"https://i.ytimg.com/vi/yKl2fSdnw7w/maxresdefault.jpg","url":"https://www.youtube.com/watch?v=yKl2fSdnw7w"},{"title":"GitHub - rescript-lang/awesome-rescript: A collection of materials about the ReScript programming language and toolchain.","description":"A collection of materials about the ReScript programming language and toolchain. - rescript-lang/awesome-rescript","image":"https://repository-images.githubusercontent.com/395642331/9d6aaef3-c81c-4156-8f65-45c3dbd011ac","url":"https://github.com/rescript-lang/awesome-rescript"},{"title":"An early look at @rescript/webapi","description":"Here's an early look at the new ReScript Web API bindings I've been working on.For more information, visit https://rescript-lang.github.io/experimental-rescr...","image":"https://i.ytimg.com/vi/MC-dbM-GEuw/maxresdefault.jpg","url":"https://www.youtube.com/watch?v=MC-dbM-GEuw"},{"title":"ReScript has come a long way, maybe it's time to switch from TypeScript?","description":"ReScript, the \"Fast, Simple, Fully Typed JavaScript from the Future\", has been around for awhile now.... Tagged with rescript, javascript, typescript, webdev.","image":"https://media2.dev.to/dynamic/image/width=1000,height=500,fit=cover,gravity=auto,format=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5jrqcbteob11bc7nvwz9.jpg","url":"https://dev.to/jderochervlk/rescript-has-come-a-long-way-maybe-its-time-to-switch-from-typescript-29he"},{"title":"Create a Snake Game in ReScript","description":"Let's create a simple snake game in ReScript without using any framework.Full code here https://github.com/Exegetech/snake-rescript00:00 Getting started03:20...","image":"https://i.ytimg.com/vi/f0gDMjuaCZo/maxresdefault.jpg","url":"https://www.youtube.com/watch?v=f0gDMjuaCZo"},{"title":"ReScript and EdgeDB | Gel Blog","description":"Learn how together ReScript and EdgeDB achieve full type safety with less busy work. This post shows you the benefits and how you can get started with this pairing today!","image":"https://www.geldata.com/_images/_blog/ab9848d310c94bb25e21f219ee74b7f24ca16baa.jpg","url":"https://www.geldata.com/blog/rescript-and-edgedb"},{"title":"Building and consuming REST API in ReScript with rescript-rest and Fastify","description":"In the video, I show how you can use my ReScript Rest library to create an HTTP server with Fastify, generate OpenAPI for it, and then consume it on the clie...","image":"https://i.ytimg.com/vi/37FY6a-zY20/maxresdefault.jpg?sqp=-oaymwEmCIAKENAF8quKqQMa8AEB-AH-CYAC0AWKAgwIABABGEsgXShlMA8=&rs=AOn4CLBrz-ZJf8pcr_1_YZCfiMUwFKqj6A","url":"https://www.youtube.com/watch?v=37FY6a-zY20"},{"title":"When and Where to use ReScript? The ReScript happy path","description":"Are you ever hesitant about adopting ReScript, or have you tried it and been frustrated? I will give you a realistic guide for adopting ReScript in the project. (Hint: Review your project architecture first). Tagged with rescript, typescript, architecture.","image":"https://media2.dev.to/dynamic/image/width=1000,height=500,fit=cover,gravity=auto,format=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fool4835vdaqw8vueb9b5.png","url":"https://dev.to/cometkim/when-and-where-to-use-rescript-the-rescript-happy-path-47ni"},{"title":"From TypeScript To ReScript | Serhii Potapov (greyblake)","description":"A blog about software development.","image":"https://www.greyblake.com/greyblake.jpeg","url":"https://www.greyblake.com/blog/from-typescript-to-rescript/"},{"title":"Getting rid of your dead code in ReScript","description":"Exploring ReScript's tools for eliminating dead code, keeping your repository clean and without... Tagged with rescript.","image":"https://media2.dev.to/dynamic/image/width=1000,height=500,fit=cover,gravity=auto,format=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F12lsasc06v1a355i6rfk.jpeg","url":"https://dev.to/zth/getting-rid-of-your-dead-code-in-rescript-3mba"},{"title":"Rescript React Error boundary usage","description":"Hi I was trying to capture the react errors. I had to write the bindings for the ErrorBoundary and... Tagged with rescript, react.","image":"https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3otvb2z646ytpt1hl2rv.jpg","url":"https://dev.to/srikanthkyatham/rescript-react-error-boundary-usage-3b05"},{"title":"Full-stack ReScript. Architecture Overview","description":"Can ReScript be used to create a full-featured back-end? In this article, I’d try to prove it can and does it with success.\n","image":"","url":"https://fullsteak.dev/posts/fullstack-rescript-architecture-overview"},{"title":"ReScript for React Development","description":"Looking for ReScript for React Development information? In this article, I highlight the development & business advantages of ReScript.","image":"https://scalac.io/wp-content/uploads/2021/08/ReScript-for-React-Development-FB.png","url":"https://scalac.io/blog/rescript-for-react-development/"},{"title":"Rewriting a Project in ReScript","description":"My experience reimplementing a small project in ReScript","image":"","url":"https://yangdanny97.github.io/blog/2021/07/09/Migrating-to-Rescript"},{"title":"Responsive Images and Cumulative Layout Shift","description":"Solving cumulative layout shift issue caused by responsive images in layouts.","image":"https://d20bjcorj7xdk.cloudfront.net/eyJidWNrZXQiOiJpbWFnZXMuYWxleGZlZG9zZWV2LmNvbSIsImtleSI6Im1ldGEtYmxvZy5wbmciLCJlZGl0cyI6eyJyZXNpemUiOnsid2lkdGgiOjEyMDAsImhlaWdodCI6NjMwLCJmaXQiOiJjb3ZlciJ9LCJqcGVnIjp7InF1YWxpdHkiOjkwfX19?signature=d8e6c0ac1ff03d0f5ee04d128b96a7701b998952a38ba96e9a16e4414cd05ed0&version=58cfd6f8abdefeca2195a6a1f1108596","url":"https://alexfedoseev.com/blog/post/responsive-images-and-cumulative-layout-shift"},{"title":"ReScript records, NextJS, undefined and getStaticProps","description":"NextJS, a pretty solid framework for building React based websites and web-applications, offers a nic... Tagged with rescript, javascript, nextjs.","image":"https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3otvb2z646ytpt1hl2rv.jpg","url":"https://dev.to/ryyppy/rescript-records-nextjs-undefined-and-getstaticprops-4890"}]

3 changes: 2 additions & 1 deletion data/sidebar_community.json
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
{
"Resources": [
"overview",
"content",
"roadmap",
"code-of-conduct",
"translations"
]
}
}
5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,8 @@
"test": "node scripts/test-examples.mjs && node scripts/test-hrefs.mjs",
"reanalyze": "reanalyze -all-cmt .",
"update-index": "npm run generate-llms && node scripts/extract-indices.mjs && node scripts/extract-tocs.mjs && node scripts/extract-syntax.mjs && node scripts/generate_feed.mjs > public/blog/feed.xml",
"generate-llms": "node scripts/generate_llms.mjs"
"generate-llms": "node scripts/generate_llms.mjs",
"generate-resources": "node scripts/generate_resources.mjs"
},
"devDependencies": {
"@mdx-js/react": "^2.3.0",
Expand All @@ -78,4 +79,4 @@
"simple-functional-loader": "^1.2.1",
"tailwindcss": "^3.3.3"
}
}
}
10 changes: 10 additions & 0 deletions pages/community/content.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
---
title: "Content"
description: "Community Content"
canonical: "/community/content"
---


import CommunityContent from 'src/CommunityContent.mjs';

<CommunityContent />
10 changes: 1 addition & 9 deletions pages/community/overview.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ description: "Community Resources Overview"
canonical: "/community/overview"
---

# Community
# Community Overview

## Official Channels

Expand All @@ -14,19 +14,11 @@ canonical: "/community/overview"
- [Forum](https://forum.rescript-lang.org)
- [ReScript GitHub Org](https://github.com/rescript-lang/)
- [ReScript YouTube Channel](https://www.youtube.com/@rescriptlang)
- [ReScript Online Meetup on Guild](https://guild.host/rescript-online-meetup)
- [ReScript Online Meetup YouTube Channel](https://www.youtube.com/@ReScriptOnlineMeetup)

News are broadcasted on this site's blog, on Bluesky and X. Some extra, less important news are also posted on the forum's [Announcements category](https://forum.rescript-lang.org/c/announcements/).

**We don't use any other channel to communicate officially**. Any announcement made by users on Reddit, Discord, Medium and others don't necessarily represent our intent.

## Articles

- [Getting rid of your dead code in ReScript](https://dev.to/zth/getting-rid-of-your-dead-code-in-rescript-3mba)
- [Speeding up ReScript compilation using interface files](https://dev.to/zth/speeding-up-rescript-compilation-using-interface-files-4fgn)
- Articles in [awesome-rescript](https://github.com/fhammerschmidt/awesome-rescript#readme)

## Questions

Your questions can go on:
Expand Down
6 changes: 5 additions & 1 deletion pages/docs/manual/v11.0.0/faq.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,11 @@ Our focus is a solid JS story right now. In the future, if there’s strong dema

**What’s the current state of ReScript?**

Currently, we're actively working on the editor support.
We're working on the v12.0 release (see [v12 milestone](https://github.com/rescript-lang/rescript/milestone/16)).

- Move the [Rescript Core](https://github.com/rescript-lang/rescript-core) standard library into the compiler / remove the OCaml standard library
- A new build system tailored to ReScript's needs ([rewatch](https://github.com/teamwalnut/rewatch)) for better monorepo support and even faster compilation speed
- Make it easier to create libraries for consumption from TypeScript with GenType

**When will we get the `async/await` keywords?**

Expand Down
6 changes: 5 additions & 1 deletion pages/docs/manual/v12.0.0/faq.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,11 @@ Our focus is a solid JS story right now. In the future, if there’s strong dema

**What’s the current state of ReScript?**

Currently, we're actively working on the editor support.
We're working on the v12.0 release (see [v12 milestone](https://github.com/rescript-lang/rescript/milestone/16)).

- Move the [Rescript Core](https://github.com/rescript-lang/rescript-core) standard library into the compiler / remove the OCaml standard library
- A new build system tailored to ReScript's needs ([rewatch](https://github.com/teamwalnut/rewatch)) for better monorepo support and even faster compilation speed
- Make it easier to create libraries for consumption from TypeScript with GenType

**When will we get the `async/await` keywords?**

Expand Down
50 changes: 50 additions & 0 deletions scripts/generate_resources.res
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/** This is the list of community content we want to generate. */
/** If you have content you would like to add, please open up a PR adding the link to this list and then run `npm run generate-resources` */
let urls = [
// 2025
"https://dev.to/dzakh/javascript-schema-library-from-the-future-5420",
"https://www.youtube.com/watch?v=yKl2fSdnw7w",
"https://github.com/rescript-lang/awesome-rescript", // regardless of age this seems like it should always be near the top
// 2024
"https://www.youtube.com/watch?v=MC-dbM-GEuw",
"https://dev.to/jderochervlk/rescript-has-come-a-long-way-maybe-its-time-to-switch-from-typescript-29he",
"https://www.youtube.com/watch?v=f0gDMjuaCZo",
"https://www.geldata.com/blog/rescript-and-edgedb",
"https://www.youtube.com/watch?v=37FY6a-zY20",
// 2023
"https://dev.to/cometkim/when-and-where-to-use-rescript-the-rescript-happy-path-47ni",
// 2022
"https://www.greyblake.com/blog/from-typescript-to-rescript/",
"https://dev.to/zth/getting-rid-of-your-dead-code-in-rescript-3mba",
"https://www.youtube.com/watch?v=KDL-kRgilkQ",
"https://dev.to/srikanthkyatham/rescript-react-error-boundary-usage-3b05",
// "https://www.daggala.com/belt_vs_js_array_in_rescript/" I think we should exclude this one since it's related to API we are deprecating
// 2021
"https://fullsteak.dev/posts/fullstack-rescript-architecture-overview",
"https://scalac.io/blog/rescript-for-react-development/",
"https://yangdanny97.github.io/blog/2021/07/09/Migrating-to-Rescript",
"https://alexfedoseev.com/blog/post/responsive-images-and-cumulative-layout-shift",
"https://dev.to/ryyppy/rescript-records-nextjs-undefined-and-getstaticprops-4890",
]

let generate = async () => {
let filePath = "data/resources.json"
let metaData = await MetaTagsApi.getMetaTags(urls)

let fileContent = `${metaData
->Array.map(i =>
{
"title": `${i.title->Option.getOr("")}`,
"description": `${i.description->Option.getOr("")}`,
"image": `${i.image->Option.getOr("")}`,
"url": `${i.url}`,
}
)
->JSON.stringifyAny
->Option.getOr("[]")}
`

Node.Fs.writeFileSync(filePath, fileContent)
}

await generate()
68 changes: 68 additions & 0 deletions src/CommunityContent.res
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
type link = {
url: string,
title: string,
description: string,
image: string,
}

@module("../data/resources.json")
external resources: array<link> = "default"

let simplifyUrl = url =>
url
->String.replace("https://", "")
->String.replace("http://", "")
->String.split("/")
->Array.at(0)

module LinkCard = {
@react.component
let make = (~link) => {
<div className="rounded-lg hover:text-fire overflow-hidden bg-gray-10 border-2 border-gray-30">
<a href=link.url className="flex flex-col h-full">
<img className="object-cover w-full lg:h-40 max-h-[345px]" src=link.image alt="" />
<div className="p-3 md:p-5 grow">
<h3 className="font-semibold text-16 grow-0 mb-2"> {React.string(link.title)} </h3>
<p className="mb-2 text-14 grow text-gray-80"> {React.string(link.description)} </p>
</div>
<p className="text-14 p-3 md:p-5 grow-0 text-gray-70">
{React.string(link.url->simplifyUrl->Option.getOr(""))}
</p>
</a>
</div>
}
}

module LinkCards = {
@react.component
let make = () => {
<div className="grid lg:grid-cols-2 gap-6">
{resources
->Array.map(link =>
switch link.image {
| "" => {...link, image: "/static/Art-3-rescript-launch.jpg"}
| _ => link
}
)
->Array.map(link => <LinkCard link key=link.title />)
->React.array}
</div>
}
}

@react.component
let make = () => {
<div>
<h1 className="hl-1 mb-6"> {"Community Content"->React.string} </h1>
<p className="md-p md:leading-5 tracking-[-0.015em] text-gray-80 md:text-16 mb-16">
{React.string(
"These articles, videos, and resources are created by the amazing ReScript community.",
)}
<br />
{React.string("If you have a resource you'd like to share, please feel free to submit a PR!")}
</p>
<LinkCards />
</div>
}

let default = make
5 changes: 5 additions & 0 deletions src/bindings/Jsdom.res
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
type window = {document: Dom.document}
type t = {window: window}

@module("jsdom") @new
external make: string => t = "JSDOM"
6 changes: 6 additions & 0 deletions src/bindings/Webapi.res
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,11 @@ module Document = {
@val external document: Dom.element = "document"
@scope("document") @val external createElement: string => Dom.element = "createElement"
@scope("document") @val external createTextNode: string => Dom.element = "createTextNode"
@send
external querySelector: (Dom.document, string) => Nullable.t<Dom.element> = "querySelector"
@send
external querySelectorAll: (Dom.document, string) => Js.Array2.array_like<Dom.element> =
"querySelectorAll"
}

module ClassList = {
Expand All @@ -17,6 +22,7 @@ module Element = {
@get external classList: Dom.element => ClassList.t = "classList"
@send external getBoundingClientRect: Dom.element => {..} = "getBoundingClientRect"
@send external addEventListener: (Dom.element, string, unit => unit) => unit = "addEventListener"
@send external getAttribute: (Dom.element, string) => Nullable.t<string> = "getAttribute"

@send
external getElementById: (Dom.element, string) => Nullable.t<Dom.element> = "getElementById"
Expand Down
93 changes: 93 additions & 0 deletions src/common/MetaTagsApi.res
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
type t = {
title: option<string>,
description: option<string>,
image: option<string>,
}

/**
This function uses JSDOM to fetch a webpage and extract the meta tags from it.
JSDOM is required since this runs on Node.
*/
let extractMetaTags = async (url: string) => {
open Webapi
try {
let response = await Fetch.fetch(url)

let html = await response->Fetch.Response.text
let dom = Jsdom.make(html)
let document = dom.window.document

let metaTags =
document
->Document.querySelectorAll("meta")
->Array.fromArrayLike
->Array.reduce(Dict.fromArray([]), (tags, meta) => {
let name = meta->Element.getAttribute("name")->Nullable.toOption
let property = meta->Element.getAttribute("property")->Nullable.toOption
let itemprop = meta->Element.getAttribute("itemprop")->Nullable.toOption

let name = switch (name, property, itemprop) {
| (Some(name), _, _) => Some(name)
| (_, Some(property), _) => Some(property)
| (_, _, Some(itemprop)) => Some(itemprop)
| _ => None
}

let content = meta->Element.getAttribute("content")->Nullable.toOption

switch (name, content) {
| (Some(name), Some(content)) => tags->Dict.set(name, content)
| _ => ()
}

tags
})

let title = metaTags->Dict.get("og:title")
let description = metaTags->Dict.get("og:description")
let image = metaTags->Dict.get("og:image")

Some({
title,
description,
image,
})
} catch {
| _ => {
Console.error(`Error fetching Open Graph details for ${url}`)
None
}
}
}

type tags = {
...t,
url: string,
}

/*
Pass an array of URLs and get back an array of meta tags for each URL.
*/
let getMetaTags = async (urls: array<string>) => {
let metaTags: array<tags> = []
for i in 0 to Array.length(urls) - 1 {
let url = urls[i]
switch url {
| Some(url) => {
let tags = await extractMetaTags(url)
switch tags {
| Some(tags) =>
metaTags->Array.push({
title: tags.title,
description: tags.description,
image: tags.image,
url,
})
| None => ()
}
}
| None => ()
}
}
metaTags
}
8 changes: 7 additions & 1 deletion src/components/Button.res
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,12 @@ type size = Small | Large
/* type theme = Light | Dark */

@react.component
let make = (~kind: kind=PrimaryRed, ~size: size=Large, ~children) => {
let make = (
~kind: kind=PrimaryRed,
~size: size=Large,
~children,
~onClick: option<JsxEventU.Mouse.t => unit>=?,
) => {
let bgColor = switch kind {
| PrimaryRed => "bg-fire hover:bg-fire-70 text-white"
| PrimaryBlue => "bg-sky hover:bg-sky-70 text-white"
Expand All @@ -16,6 +21,7 @@ let make = (~kind: kind=PrimaryRed, ~size: size=Large, ~children) => {
}

<button
?onClick
role="button"
className={`select-none hover:cursor-pointer transition-colors duration-200 body-button focus:outline-none ${bgColor} ${padding}`}>
children
Expand Down
7 changes: 6 additions & 1 deletion src/components/Button.resi
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,9 @@ type kind = PrimaryRed | PrimaryBlue | SecondaryRed
type size = Small | Large

@react.component
let make: (~kind: kind=?, ~size: size=?, ~children: React.element) => React.element
let make: (
~kind: kind=?,
~size: size=?,
~children: React.element,
~onClick: JsxEventU.Mouse.t => unit=?,
) => React.element