diff --git a/data/resources.json b/data/resources.json
new file mode 100644
index 000000000..9da497fee
--- /dev/null
+++ b/data/resources.json
@@ -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"}]
+
\ No newline at end of file
diff --git a/data/sidebar_community.json b/data/sidebar_community.json
index 9f40e27f2..83d693cfd 100644
--- a/data/sidebar_community.json
+++ b/data/sidebar_community.json
@@ -1,8 +1,9 @@
{
"Resources": [
"overview",
+ "content",
"roadmap",
"code-of-conduct",
"translations"
]
-}
+}
\ No newline at end of file
diff --git a/package.json b/package.json
index ef6303763..d6b9a9fdf 100644
--- a/package.json
+++ b/package.json
@@ -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",
@@ -78,4 +79,4 @@
"simple-functional-loader": "^1.2.1",
"tailwindcss": "^3.3.3"
}
-}
+}
\ No newline at end of file
diff --git a/pages/community/content.mdx b/pages/community/content.mdx
new file mode 100644
index 000000000..84c68f3f6
--- /dev/null
+++ b/pages/community/content.mdx
@@ -0,0 +1,10 @@
+---
+title: "Content"
+description: "Community Content"
+canonical: "/community/content"
+---
+
+
+import CommunityContent from 'src/CommunityContent.mjs';
+
+
diff --git a/pages/community/overview.mdx b/pages/community/overview.mdx
index debfbe2c7..cfdd6cf03 100644
--- a/pages/community/overview.mdx
+++ b/pages/community/overview.mdx
@@ -4,7 +4,7 @@ description: "Community Resources Overview"
canonical: "/community/overview"
---
-# Community
+# Community Overview
## Official Channels
@@ -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:
diff --git a/pages/docs/manual/v11.0.0/faq.mdx b/pages/docs/manual/v11.0.0/faq.mdx
index 5400024fc..a2c6ec366 100644
--- a/pages/docs/manual/v11.0.0/faq.mdx
+++ b/pages/docs/manual/v11.0.0/faq.mdx
@@ -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?**
diff --git a/pages/docs/manual/v12.0.0/faq.mdx b/pages/docs/manual/v12.0.0/faq.mdx
index 60f7f39c6..d7efd476e 100644
--- a/pages/docs/manual/v12.0.0/faq.mdx
+++ b/pages/docs/manual/v12.0.0/faq.mdx
@@ -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?**
diff --git a/scripts/generate_resources.res b/scripts/generate_resources.res
new file mode 100644
index 000000000..d504c14dd
--- /dev/null
+++ b/scripts/generate_resources.res
@@ -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()
diff --git a/src/CommunityContent.res b/src/CommunityContent.res
new file mode 100644
index 000000000..0f9ff49ac
--- /dev/null
+++ b/src/CommunityContent.res
@@ -0,0 +1,68 @@
+type link = {
+ url: string,
+ title: string,
+ description: string,
+ image: string,
+}
+
+@module("../data/resources.json")
+external resources: array = "default"
+
+let simplifyUrl = url =>
+ url
+ ->String.replace("https://", "")
+ ->String.replace("http://", "")
+ ->String.split("/")
+ ->Array.at(0)
+
+module LinkCard = {
+ @react.component
+ let make = (~link) => {
+
+ {React.string(
+ "These articles, videos, and resources are created by the amazing ReScript community.",
+ )}
+
+ {React.string("If you have a resource you'd like to share, please feel free to submit a PR!")}
+
+
+
+}
+
+let default = make
diff --git a/src/bindings/Jsdom.res b/src/bindings/Jsdom.res
new file mode 100644
index 000000000..5021bab42
--- /dev/null
+++ b/src/bindings/Jsdom.res
@@ -0,0 +1,5 @@
+type window = {document: Dom.document}
+type t = {window: window}
+
+@module("jsdom") @new
+external make: string => t = "JSDOM"
diff --git a/src/bindings/Webapi.res b/src/bindings/Webapi.res
index 0cbc09f93..ab53ceb41 100644
--- a/src/bindings/Webapi.res
+++ b/src/bindings/Webapi.res
@@ -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 = "querySelector"
+ @send
+ external querySelectorAll: (Dom.document, string) => Js.Array2.array_like =
+ "querySelectorAll"
}
module ClassList = {
@@ -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 = "getAttribute"
@send
external getElementById: (Dom.element, string) => Nullable.t = "getElementById"
diff --git a/src/common/MetaTagsApi.res b/src/common/MetaTagsApi.res
new file mode 100644
index 000000000..01a3dbc90
--- /dev/null
+++ b/src/common/MetaTagsApi.res
@@ -0,0 +1,93 @@
+type t = {
+ title: option,
+ description: option,
+ image: option,
+}
+
+/**
+ 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) => {
+ let metaTags: array = []
+ 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
+}
diff --git a/src/components/Button.res b/src/components/Button.res
index 06110fe09..6f034a1a1 100644
--- a/src/components/Button.res
+++ b/src/components/Button.res
@@ -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 unit>=?,
+) => {
let bgColor = switch kind {
| PrimaryRed => "bg-fire hover:bg-fire-70 text-white"
| PrimaryBlue => "bg-sky hover:bg-sky-70 text-white"
@@ -16,6 +21,7 @@ let make = (~kind: kind=PrimaryRed, ~size: size=Large, ~children) => {
}