2 | # About
3 |
4 | This project shows off Remix's new MDX capabilities when using the [Vite plugin][remix-future-vite].
5 | It also uses [Tailwind][tailwind] and the [typography plugin][tailwind-typography] for styling.
6 |
7 | Inspired by [Rajesh Babu's MDX template][remix-mdx-blog] ❤️
8 |
9 | [remix-future-vite]: https://remix.run/docs/en/main/future/vite
10 | [tailwind]: https://tailwindcss.com/
11 | [tailwind-typography]: https://tailwindcss.com/docs/typography-plugin
12 | [remix-mdx-blog]: https://github.com/rajeshdavidbabu/remix-mdx-blog
13 |
14 |
--------------------------------------------------------------------------------
/app/routes/blog.first.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | title: First post
3 | description: Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
4 | published: 2023-02-15
5 | ---
6 |
7 | # {frontmatter.title}
8 |
9 |
10 | Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
11 | Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
12 | Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.
13 | Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
14 |
--------------------------------------------------------------------------------
/app/routes/blog.how-this-site-is-built.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | title: How this site is built
3 | description: Explanation of how Vite features and plugins work together to power Remix + MDX
4 | published: 2023-10-30
5 | featured: true
6 | ---
7 |
8 | # {frontmatter.title}
9 |
10 | This site uses [Vite][vite] and [Remark][remark] plugins that let you write MDX routes in your Remix app.
11 | These MDX routes are transformed to JS at build-time.
12 |
13 | Server-side utilities query the frontmatter of each MDX file so that pages can display lists of posts.
14 |
15 | The best part is that Remix has your back as your app gets more complex.
16 | Need to grab data your database?
17 | It's just Remix, so use a `loader`.
18 | Remix let's you use the _same_ mental model and the _same_ tools all the way from a simple blog to a complex app.
19 | No rearchitecting is required.
20 |
21 | ## Plugins
22 |
23 | MDX support in Vite is provided by [`@mdx-js/rollup`][mdx-js-rollup].
24 | [Frontmatter][frontmatter] support in Remark is provided by [`remark-frontmatter`][remark-frontmatter] and [`remark-mdx-frontmatter`][remark-mdx-frontmatter].
25 |
26 | Check out [`vite.config.ts`][vite-config] to see how these are wired together.
27 |
28 | ## MDX routes
29 |
30 | To take advantage of [nested routes][nested-routes], posts are under `/blog/`
31 | so that the `blog.tsx` parent route can handle layout and styling uniformly for all posts.
32 |
33 | The about page is a one-off route so it handles its own styling.
34 | There are probably other ways to handle styling without needing a surrounding ``, but that seemed the simplest for now.
35 | It is still a nested route relative to the root route, so it gets the site layout for free.
36 |
37 | ## Querying MDX routes
38 |
39 | The home page (`/`) and blog archive (`/blog`) each want to display a subset of the posts.
40 | Specifically, they want to display metadata about each included post.
41 |
42 | The naive solution would be to read the files directly, say with `fs.readFileSync` and then parse the frontmatter.
43 | There are a couple issues with this approach.
44 | For one, the MDX routes are _routes_ not content and they will be built to a different location.
45 | Also, if you were using any other plugins for MDX or frontmatter, you'd have to duplicate that setup to parse the posts.
46 |
47 | Luckily, Vite's [glob imports][import-meta-glob] makes this easy.
48 | But relying on Vite, it handles transforming the MDX routes with the same transformation pipeline that is setup in `vite.config.ts`.
49 |
50 | Importantly, all frontmatter queries run behind a `loader` so that only the data needed by each page is sent over the network.
51 | Otherwise, chunks for _all_ posts would get sent to the browser even if a route like the home page only wanted to display metadata for a subset of the posts.
52 |
53 | ## Alternatives
54 |
55 | This approach handles MDX at build-time.
56 | For some use-cases, you might prefer to handle MDX at runtime.
57 | It's a bit more work since you have to setup a [Unified][unified] pipeline yourself,
58 | but it let's you model posts as _content_ rather than routes.
59 | That is, you would have a `blog.$slug.tsx` route that would dynamically load the MDX content for that post.
60 |
61 | There are different trade-offs here, so its up to you to decide which one is better.
62 | But the approach this site takes is often a simpler starting point.
63 |
64 | [vite]: https://vitejs.dev/
65 | [remark]: https://github.com/remarkjs/remark
66 | [vite-config]: https://github.com/pcattori/remix-blog-mdx/blob/main/vite.config.ts
67 | [mdx-js-rollup]: https://mdxjs.com/packages/rollup/
68 | [frontmatter]: https://mdxjs.com/guides/frontmatter/
69 | [remark-frontmatter]: https://github.com/remarkjs/remark-frontmatter
70 | [remark-mdx-frontmatter]: https://github.com/remcohaszing/remark-mdx-frontmatter
71 | [nested-routes]: https://remix.run/docs/en/main/discussion/routes
72 | [import-meta-glob]: https://vitejs.dev/guide/features.html#glob-import
73 | [unified]: https://unifiedjs.com/
74 |
--------------------------------------------------------------------------------
/app/routes/blog.markdown-and-mdx.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | title: Markdown and MDX
3 | description: Demo of Markdown syntax and React components in MDX
4 | published: 2023-10-08
5 | featured: true
6 | ---
7 |
8 | # {frontmatter.title}
9 |
10 | This is an MDX test page that showcases various MDX elements and code blocks.
11 |
12 | ## MDX
13 |
14 | Let's try using a component!
15 |
16 | import { Counter } from "../components/counter.tsx";
17 |
18 |
19 |
20 | ## Headings
21 |
22 | ### Level 3 Heading
23 |
24 | #### Level 4 Heading
25 |
26 | ##### Level 5 Heading
27 |
28 | ###### Level 6 Heading
29 |
30 | ## Paragraphs
31 |
32 | This is a paragraph. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam luctus felis vel risus lacinia, eu fringilla urna mattis. Sed maximus urna eu arcu blandit pulvinar.
33 |
34 | Etiam lobortis volutpat ligula, a facilisis purus. Sed vel felis blandit, sodales urna ac, varius mi. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas.
35 |
36 | ## Lists
37 |
38 | ### Unordered List
39 |
40 | - Item 1
41 | - Item 2
42 | - Item 3
43 |
44 | ### Ordered List
45 |
46 | 1. Item 1
47 | 2. Item 2
48 | 3. Item 3
49 |
50 | ## Images
51 |
52 | 
53 |
54 | ## Links
55 |
56 | [Link text](https://example.com)
57 |
58 | ## Blockquote
59 |
60 | > Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam luctus felis vel risus lacinia, eu fringilla urna mattis.
61 |
62 | ## Horizontal Rule
63 |
64 | ---
65 |
66 | ## Code Blocks
67 |
68 | ### Inline Code
69 |
70 | This is an example of `inline code`.
71 |
72 | ### Fenced Code Blocks
73 |
74 | ```javascript
75 | const add = (a, b) => a + b;
76 | console.log(add(2, 3)); // Output: 5
77 | ```
78 |
--------------------------------------------------------------------------------
/app/routes/blog.second.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | title: Second post
3 | description: Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
4 | published: 2023-08-31
5 | ---
6 |
7 | # {frontmatter.title}
8 |
9 | Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
10 | Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
11 | Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.
12 | Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
13 |
--------------------------------------------------------------------------------
/app/routes/blog.tsx:
--------------------------------------------------------------------------------
1 | import { Outlet } from "@remix-run/react";
2 |
3 | export default function Component() {
4 | return (
5 |