Skip to content
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

feat: add built-in PostCSS and Tailwind support #5229

Merged
merged 18 commits into from
Jan 25, 2023
Merged
Show file tree
Hide file tree
Changes from 17 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions .changeset/gorgeous-meals-rescue.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
"@remix-run/dev": minor
"@remix-run/react": minor
"@remix-run/server-runtime": minor
"@remix-run/testing": minor
---

Add unstable built-in support for PostCSS via the `future.unstable_postcss` feature flag
8 changes: 8 additions & 0 deletions .changeset/lemon-humans-yell.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
"@remix-run/dev": minor
"@remix-run/react": minor
"@remix-run/server-runtime": minor
"@remix-run/testing": minor
---

Add unstable built-in support for Tailwind via the `future.unstable_tailwind` feature flag
141 changes: 136 additions & 5 deletions docs/guides/styling.md
Original file line number Diff line number Diff line change
Expand Up @@ -400,7 +400,80 @@ export function links() {

## Tailwind CSS

Perhaps the most popular way to style a Remix application in the community is to use Tailwind CSS. It has the benefits of inline-style collocation for developer ergonomics and is able to generate a CSS file for Remix to import. The generated CSS file generally caps out around 8-10kb, even for large applications. Load that file into the `root.tsx` links and be done with it. If you don't have any CSS opinions, this is a great approach.
Perhaps the most popular way to style a Remix application in the community is to use [Tailwind CSS][tailwind]. It has the benefits of inline-style collocation for developer ergonomics and is able to generate a CSS file for Remix to import. The generated CSS file generally caps out around 8-10kb, even for large applications. Load that file into the `root.tsx` links and be done with it. If you don't have any CSS opinions, this is a great approach.

There are a couple of options for integrating Tailwind into your Remix application. You can use Remix's built-in support, or integrate Tailwind manually using their CLI.

### Built-in Tailwind Support

<docs-warning>This feature is unstable and currently only available behind a feature flag. We're confident in the use cases it solves but the API and implementation may change in the future.</docs-warning>

First, to enable built-in Tailwind support, set the `future.unstable_tailwind` feature flag in `remix.config.js`.

```js filename=remix.config.js
/** @type {import('@remix-run/dev').AppConfig} */
module.exports = {
future: {
unstable_tailwind: true,
},
// ...
};
```

Then install Tailwind:

```sh
npm install -D tailwind
```
MichaelDeBoey marked this conversation as resolved.
Show resolved Hide resolved

Initialize a config file:

```sh
npx tailwindcss init
```

Now we can tell it which files to generate classes from:

```js filename=tailwind.config.js lines=[3]
/** @type {import('tailwindcss').Config} */
module.exports = {
content: ["./app/**/*.{ts,tsx,jsx,js}"],
theme: {
extend: {},
},
plugins: [],
};
```

Then include the `@tailwind` directives in your CSS. For example, you could create a `tailwind.css` file at the root of your app:

```css filename=app/tailwind.css
@tailwind base;
@tailwind components;
@tailwind utilities;
```

MichaelDeBoey marked this conversation as resolved.
Show resolved Hide resolved
Then add `tailwind.css` to your root route's `links` function:

```tsx filename=app/root.tsx
import type { LinksFunction } from "@remix-run/node"; // or cloudflare/deno

// ...

import styles from "./tailwind.css";

export const links: LinksFunction = () => [
{ rel: "stylesheet", href: styles },
];
```

With this setup in place, you can also use [Tailwind's functions and directives][tailwind-functions-and-directives] anywhere in your CSS.

Note that if you're also using Remix's [built-in PostCSS support](#built-in-postcss-support), the Tailwind PostCSS plugin will be automatically included if it's missing.

### Manual Tailwind Integration

It's also possible to use Tailwind without leveraging the built-in support by using the `tailwindcss` CLI directly.
markdalgleish marked this conversation as resolved.
Show resolved Hide resolved

First install a couple dev dependencies:

Expand Down Expand Up @@ -527,21 +600,75 @@ export const links: LinksFunction = () => {

## PostCSS

While not built into Remix's compiler, it is straight forward to use PostCSS and add whatever syntax sugar you'd like to your stylesheets, here's the gist of it:
[PostCSS][postcss] is a popular tool with a rich plugin ecosystem, commonly used to prefix CSS for older browsers, transpile future CSS syntax, inline images, lint your styles and more.

There are a couple of options for integrating PostCSS into your Remix application. You can use Remix's built-in support, or integrate PostCSS manually using their CLI.

### Built-in PostCSS Support

<docs-warning>This feature is unstable and currently only available behind a feature flag. We're confident in the use cases it solves but the API and implementation may change in the future.</docs-warning>

When a PostCSS config is detected, Remix will automatically run PostCSS across all CSS in your project. For example, to use [Autoprefixer][autoprefixer]:

1. Enable built-in PostCSS support by setting the the `future.unstable_postcss` feature flag in `remix.config.js`.

```js filename=remix.config.js
/** @type {import('@remix-run/dev').AppConfig} */
module.exports = {
future: {
unstable_postcss: true,
},
// ...
};
```

2. Install any desired PostCSS plugins.

```sh
npm install -D autoprefixer
```

3. Add `postcss.config.js` in the Remix root with configuration for your plugins.

```js filename=postcss.config.js
module.exports = {
plugins: {
autoprefixer: {},
},
};
```

If you're using [Vanilla Extract](#vanilla-extract), since it's already playing the role of CSS preprocessor, you may want to apply a different set of PostCSS plugins relative to other styles. To support this, you can export a function from `postcss.config.js` which is given a context object that lets you know when Remix is processing a Vanilla Extract file.

```js filename=postcss.config.js
module.exports = (ctx) => {
return ctx.remix?.vanillaExtract
markdalgleish marked this conversation as resolved.
Show resolved Hide resolved
? {
// PostCSS plugins for Vanilla Extract styles...
}
: {
// PostCSS plugins for other styles...
};
};
```

### Manual PostCSS Integration

It's also possible to use PostCSS without leveraging the built-in support. Here's the gist of it:

1. Use `postcss` cli directly alongside Remix
1. Use the `postcss` CLI directly alongside Remix
2. Build CSS into the Remix app directory from a styles source directory
3. Import your stylesheet to your modules like any other stylesheet

Here's how to set it up:

1. Install the dev dependencies in your app:
1. Install PostCSS along with its CLI and any desired plugins in your app.

```sh
npm install -D postcss-cli postcss autoprefixer
```

2. Add `postcss.config.js` in the Remix root.
2. Add `postcss.config.js` in the Remix root with configuration for your plugins.

```js filename=postcss.config.js
module.exports = {
Expand Down Expand Up @@ -942,7 +1069,11 @@ module.exports = {
[examples]: https://github.com/remix-run/examples
[styled-components-issue]: https://github.com/styled-components/styled-components/issues/3660
[tailwind]: https://tailwindcss.com
[tailwind-functions-and-directives]: https://tailwindcss.com/docs/functions-and-directives
[tailwind-intelli-sense-extension]: https://marketplace.visualstudio.com/items?itemName=bradlc.vscode-tailwindcss
[postcss]: https://postcss.org
[autoprefixer]: https://github.com/postcss/autoprefixer
[postcss-preset-env]: https://preset-env.cssdb.org
[css modules]: https://github.com/css-modules/css-modules
[regular-stylesheet-imports]: #regular-stylesheets
[server-dependencies-to-bundle]: ../file-conventions/remix-config#serverdependenciestobundle
Expand Down
2 changes: 2 additions & 0 deletions integration/css-modules-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ test.describe("CSS Modules", () => {
// ensure features don't clash
unstable_cssModules: true,
unstable_cssSideEffectImports: true,
unstable_postcss: true,
unstable_tailwind: true,
unstable_vanillaExtract: true,
},
};
Expand Down
2 changes: 2 additions & 0 deletions integration/css-side-effect-imports-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ test.describe("CSS side-effect imports", () => {
// ensure features don't clash
unstable_cssModules: true,
unstable_cssSideEffectImports: true,
unstable_postcss: true,
unstable_tailwind: true,
unstable_vanillaExtract: true,
},
};
Expand Down
1 change: 1 addition & 0 deletions integration/deterministic-build-output-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ test("builds deterministically under different paths", async () => {
future: {
unstable_cssModules: true,
unstable_cssSideEffectImports: true,
unstable_postcss: true,
unstable_vanillaExtract: true,
},
};
Expand Down
Loading