logo My Digital Garden

Astro + MDX + Tailwind + Preact.

By James Kolean on Dec 30, 2022
Source repository: https://gitlab.com/jameskolean/astro-mdx-tailwind
Demo: https://jameskolean.gitlab.io/astro-mdx-tailwind
PreactAstroCSS
banner

I recently ported this site from Gatsby to Astro + MDX + Tailwind and can not be happier. Gatsby is Great but it’s more than I need here.

Astro is a tool that allows you to easily set up a static site with MDX and Tailwind CSS. MDX is a syntax that lets you mix JSX and Markdown in the same file, which makes it easy to write and style components that include both rich text and code. Tailwind CSS is a utility-based CSS framework that provides a set of low-level classes that you can use to style your components.

Using Astro with MDX and Tailwind can be a good choice for building static sites because it allows you to easily create complex, interactive components that include both rich text and code. It also gives you the flexibility to style your components using a variety of low-level classes, rather than having to write custom CSS for each component. This can save you time and effort when building your site, and make it easier to maintain and update in the future.

Preact is a lightweight JavaScript library that is designed to be a fast and lightweight alternative to React, with a similar API. It can be used in place of React in any application, including an application that uses MDX.

To use Preact in an application that uses MDX, you will need to install the Preact library and the @preact/compat package, which provides compatibility with the React API. You can then import the Preact components and functions that you need, just as you would in a regular React application.

For example, you might import the h function and the Component class from Preact, and use them to create a custom component that can be rendered in an MDX document:

import {
    h,
    Component
} from 'preact';

export class MyComponent extends Component {
    render() {
        return <div > Hello, Preact! </div>;
    }
}

You can then use this component in an MDX document like this:

---
import {MyComponent} from './my-component';
---

<MyComponent / >

This will render the MyComponent component in the MDX document, using Preact to manage the component’s state and rendering.

Setup

Let’s set up a sample project and deploy it to GitLab pages. I assume you can create a GitLab project and us Git.

npm create astro@latest

Deploy to GitLab pages

mv public static
// astro.config.mjs
import {
    defineConfig
} from 'astro/config';

export default defineConfig({
    site: 'https://jameskolean.gitlab.io',
    base: import.meta.env.MODE === 'development' ? '/' : '/astro-mdx-tailwind',
    // GitLab Pages requires exposed files to be located in a folder called "public".
    // So we're instructing Astro to put the static build output in a folder of that name.
    outDir: 'public',

    // The folder name Astro uses for static files (`public`) is already reserved
    // for the build output. So in deviation from the defaults we're using a folder
    // called `static` instead.
    publicDir: 'static',
});

Note: Change site to your own site and change base to your own base.

# .gitlab-ci.yml
# This folder is cached between builds
# https://docs.gitlab.com/ce/ci/yaml/README.html#cache
cache:
  paths:
    - node_modules/
    # Enables git-lab CI caching. Both .cache and public must be cached, otherwise builds will fail.
    - .cache/
    - public/

pages:
  script:
    - npm install
    - npm run build
  artifacts:
    paths:
      - public
  only:
    - main

🧞 Commands

All commands are run from the root of the project, from a terminal:

CommandAction
npm installInstalls dependencies
npm run devStarts local dev server at localhost:3000
npm run buildBuild your production site to ./public/
npm run previewPreview your build locally, before deploying
npm run astro ...Run CLI commands like astro add , astro preview
npm run astro --helpGet help using the Astro CLI

Add MDX and Preact

npx astro add mdx

VS Code supports Markdown by default. However, for MDX editor support, you may wish to add the following setting in your VSCode config. This ensures authoring MDX files provides a Markdown-like editor experience.

"files.associations": {
    "*.mdx": "markdown"
}

Now lets add some markdown files we can extend later

---
// src/layouts/LayoutMarkdown.astro
import Layout from "./Layout.astro";
export interface Props {
  title: string;
}

const props = Astro.props;
---

<Layout title={props.title}>
  <h2>Markdown Template</h2>
  <p>Markdown content is below</p>
  <slot />
</Layout>
---

# src/pages/md-page.md

layout: '../layouts/LayoutMarkdown.astro'
title: Markdown Example
---

# Markdown

This Markdown file creates a page at `your-domain.com/md-page/`

It probably isn't styled much, but Markdown does support:
* **bold** and _italics._
* lists
* [links](https://astro.build)
* and more!
---

# src/pages/mdx-page.mdx

layout: '../layouts/LayoutMarkdown.astro'
title: MDX Example
---

# MDX

This MDX file creates a page at `your-domain.com/mdx-page/`

Now Let’s add a Preact component

npx astro add preact

Add Compat

// astro.config.mjs
import {
    defineConfig
} from 'astro/config';
import mdx from '@astrojs/mdx';
import preact from "@astrojs/preact";
const MODE =
    import.meta.env.MODE;

// https://astro.build/config
export default defineConfig({
    site: 'https://jameskolean.gitlab.io',
    base: MODE === 'development' ? '/' : '/astro-mdx-tailwind',
    // GitLab Pages requires exposed files to be located in a folder called "public".
    // So we're instructing Astro to put the static build output in a folder of that name.
    outDir: 'public',
    // The folder name Astro uses for static files (`public`) is already reserved
    // for the build output. So in deviation from the defaults we're using a folder
    // called `static` instead.
    publicDir: 'static',
    markdown: {
        drafts: true
    },
    integrations: [mdx({
        drafts: true
    }), preact({
        compat: true
    })]
});
// src/components/Counter.jsx
import { useState } from 'preact/hooks';
import "./Counter.css";

export default function Counter({ children }) {
	const [count, setCount] = useState(0);
	const add = () => setCount((i) => i + 1);
	const subtract = () => setCount((i) => i - 1);

	return (
		<>
			<div class="counter">
				<button onClick={subtract}>-</button>
				<pre>{count}</pre>
				<button onClick={add}>+</button>
			</div>
			<div class="counter-message">{children}</div>
		</>
	);
}
/* src/components/Counter.css */
.counter {
    display: grid;
    font-size: 2em;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    margin-top: 2em;
    place-items: center;
}

.counter-message {
    text-align: center;
}
---
layout: '../layouts/LayoutMarkdown.astro'
title: MDX Example

---
import Counter from '../components/Counter'    

# MDX

This MDX file creates a page at `your-domain.com/mdx-page/`

<Counter client:idle>
	<h1>Hello, Preact 1!</h1>
</Counter>

Add Tailwind

npx astro add tailwind
---
// src/layouts/LayoutMarkdown.astro
import Layout from "./Layout.astro";
export interface Props {
  title: string;
}

const props = Astro.props;
---

<Layout title={props.title}>
  <div class="mx-auto max-w-3xl">
    <h2>Markdown Template</h2>
    <p>Markdown content is below</p>
    <div class="mt-5 max-w-prose bg-slate-300">
      <slot />
    </div>
  </div>
</Layout>
© Copyright 2023 Digital Garden cultivated by James Kolean.