Today, we're thrilled to announce that this very website is now open source! We invite you to explore and learn from the source code and maybe even consider contributing.
Over 2 years ago Remix the framework went open source. For 10 years now Ryan and Michael have been working on open source software. Even reactrouter.com is a public repo. Needless to say, we're big believers in open source.
So why doesn't everyone open source their website? For good reasons:
Well, we're gonna open source it anyway.
We believe the pros outweigh the cons. Open sourcing our website allows us to provide a real-world Remix site to learn from. It also gives us an opportunity to more easily get feedback and contributions from kind-hearted devs in the community (thanks Ryan Leichty for polishing our docs). Plus, while our website is mostly pretty straightforward, there are some pretty cool things we're doing.
I still don't know.
Ryan Florence wrote it and now you can read the 1500 line ScrollExperience
component source code. Or you can just scroll through it multiple times to see all the cool animations like I do.
One of the unique features of our website is that we Server-Side Render our docs at request time, instead of using the more common strategy of Static Site Generation (prerendering the HTML during build).
The main reason we do this is so we don't have to rebuild our entire site every time we fix a typo. In fact, the Remix docs don't exist in this repo at all. You can find them in the Remix codebase right next to the Remix source code. We keep the docs here:
This last point is the other main reason we SSR our docs instead of SSG-ing them. We are able to keep the docs for each version of Remix forever. We can even render the most up-to-date version of the dev docs without redeploying. Imagine rebuilding every single doc for every single Remix version every time someone commits a change. That would be a lot.
We're able to accomplish this by fetching the markdown from GitHub in the loader
and server rendering the requested doc page in the route. Since this content doesn't change frequently, we leverage a LRU cache to cache the results on the server for 5 minutes. We also send a Cache-Control
header with the stale-while-revalidate
directive along with the response, that way when there is a fresh doc, the old one will be served while the new one renders and populates in the CDN for the next request.
return json(
{ doc },
{
headers: {
"Cache-Control": "max-age=300, stale-while-revalidate=604800",
},
},
);
If you hate occasionally being 5 minutes behind the bleeding edge, you can just read the source docs themselves, or maybe see a therapist.
You may have noticed that we recently started adding a few more pages to the website:
We have many plans to continue improving these pages, as well as add more resources to help serve the community. However, up until now contributing examples to these pages has only been possible by hoping the core team notices your project and adds it. We're excited to flip that around and make Showcase and Resource contributions just a PR away.
Remix.run already uses the new Vite plugin. We upgraded to Vite mostly to dogfood the new plugin and make sure it works for a real, production site. Open sourcing remix.run means that when we dogfood new features, it's that much easier to show them off on a production website and share that knowledge.
Here are some (simplified) examples where we removed clunky patterns Remix forced us into and Vite made incredibly simple.
Loading markdown for blog posts
- import path from "path";
- import fs from "fs";
- const dataPath = path.join(__dirname, "..", "data");
- const blogPath = path.join(dataPath, "posts");
+ const postContentsBySlug = Object.fromEntries(
+ Object.entries(
+ import.meta.glob("../../data/posts/*.md", { as: "raw", eager: true }),
+ ).map(([filePath, contents]) => [
+ filePath.replace("../../data/posts/", "").replace(/\.md$/, ""),
+ contents,
+ ]),
+ );
export async function getBlogPost(slug: string): Promise<BlogPost> {
let cached = postsCache.get(slug);
- if (cached) return cached;
- let filePath = path.join(blogPath, slug + ".md");
- let contents: string;
- try {
- contents = (await fs.promises.readFile(filePath)).toString();
- } catch (e) {
+ let contents = postContentsBySlug[slug];
+ if (!contents) {
throw new Response("Not Found", { status: 404, statusText: "Not Found" });
}
}
Loading Author data from a yaml file
import yaml from "yaml";
+ import authorsYamlFileContents from "../../data/authors.yml?raw";
- const AUTHORS: BlogAuthor[] = yaml.parse(
- fs.readFileSync(path.join(dataPath, "authors.yml")).toString(),
- )
+ const AUTHORS: BlogAuthor[] = yaml.parse(authorsYamlFileContents);
Checkout the Vite migration PR, and while you're there, checkout how easy it was to swap our server from CJS to ESM.
This is the part I'm most excited about.
Personally, I wanted to make open source contributions years before I worked up the courage. While this says more about me than anything, one thing I know that would have made it easier is if I contributed to an open source website vs a library. Why? Because I worked on websites all day long at my job, it's what I already knew. I didn't write libraries. In fact, far fewer web developers write libraries than write websites.
That's why I'm excited to be open sourcing our website. I strongly believe the shift to contributing to a website with a public repository is much simpler than contributing to a library for many developers. I hope this announcement offers an easier opportunity for many of you to make your first ever open source contribution.
In fact, we've gone ahead and curated a number of good first issues to make it easy to get started. These are issues we have specifically marked as being friendly for new contributors. So whether you're a seasoned OSS contributor or just trying to break in, we're excited to see your GitHub profile pop up in the "Pull request" tab.
Happy contributing, can't wait to build a better remix.run together.