Skip to content

Commit

Permalink
feat: add CSS Modules support (#4852)
Browse files Browse the repository at this point in the history
Co-authored-by: Chance Strickland <hi@chance.dev>
  • Loading branch information
markdalgleish and chaance committed Jan 4, 2023
1 parent 768db36 commit 3d58b0a
Show file tree
Hide file tree
Showing 31 changed files with 1,434 additions and 39 deletions.
9 changes: 9 additions & 0 deletions .changeset/little-avocados-fetch.md
@@ -0,0 +1,9 @@
---
"@remix-run/css-bundle": minor
"@remix-run/dev": minor
"@remix-run/react": minor
"@remix-run/server-runtime": minor
"@remix-run/testing": minor
---

Add unstable support for CSS Modules via `future.unstable_cssModules` feature flag
5 changes: 3 additions & 2 deletions docs/guides/migrating-react-router-app.md
Expand Up @@ -492,7 +492,7 @@ The answer to all of these questions is up to your bundler, _not you_. We think

**Note:** Remix does not currently support CSS processing directly. If you use preprocessors like Sass, Less, or PostCSS, you can run those as a separate process in development.

We also do not yet support CSS Modules, as that requires compiler integration and current approaches are not aligned with our design philosophy. We are actively working on a solution and plan to have an API for CSS Modules very soon.
We do process [CSS Modules][css-modules], but support is currently [opt-in behind a feature flag][css-modules].

</docs-info>

Expand Down Expand Up @@ -642,4 +642,5 @@ Now then, go off and _remix your app_. We think you'll like what you build along
[routing-in-remix]: ./routing
[styling-in-remix]: ./styling
[frequently-asked-questions]: ../pages/faq
[common-gotchas]: ../pages/gotchas
[common-gotchas]: ../pages/currently
[css-modules]: ./styling#css-modules
68 changes: 68 additions & 0 deletions docs/guides/styling.md
Expand Up @@ -766,6 +766,73 @@ Other CSS-in-JS libraries will have a similar setup. If you've got a CSS framewo

NOTE: You may run into hydration warnings when using Styled Components. Hopefully [this issue][styled-components-issue] will be fixed soon.

## CSS Modules

<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>

To enable [CSS Modules], set the `future.unstable_cssModules` feature flag in `remix.config.js`.

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

With this feature flag enabled, the Remix compiler will now generate a single CSS file containing all CSS Modules styles in your application. Note that any [regular stylesheet imports](#regular-stylesheets) will remain as separate files.

Unlike many other tools in the React ecosystem, we do not insert the CSS bundle into the page automatically. Instead, we ensure that you always have control over the link tags on your page. This lets you decide where the CSS file is loaded relative to other stylesheets in your app.

To get access to the CSS bundle, first install the `@remix-run/css-bundle` package.

```sh
npm install @remix-run/css-bundle

This comment has been minimized.

Copy link
@robbtraister

robbtraister Feb 14, 2023

Contributor

@markdalgleish do you know if there is any plan to change this to a devDependency in the future?

It turns out that @remix-run/css-bundle depends on @remix-run/dev (in order to read the asset manifest at runtime), which in turn depends on things like @babel/core, esbuild, lodash, @vanilla-extract/integration, etc.

I looked into my production Docker image recently and was able to shave 70+MB by simply moving @remix-run/css-bundle to a devDependency. As far as I can tell, everything still works as expected. It seems as though the cssBundleHref value is inlined into the build artifact (at least, for now, on my machine).

```

Then, import `cssBundleHref` and add it to a link descriptor—most likely in `root.tsx` so that it applies to your entire application.

```tsx filename=root.tsx lines=[2,6]
import type { LinksFunction } from "@remix-run/node"; // or cloudflare/deno
import { cssBundleHref } from "@remix-run/css-bundle";

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

You're all set! You can now opt into CSS Modules via the `.module.css` file name convention. For example:

```css filename=app/components/button/styles.module.css
.root {
border: solid 1px;
background: white;
color: #454545;
}
```

```tsx filename=app/components/button/index.js lines=[1,9]
import styles from "./styles.module.css";

export const Button = React.forwardRef(
({ children, ...props }, ref) => {
return (
<button
{...props}
ref={ref}
className={styles.root}
/>
);
}
);
Button.displayName = "Button";
```

[custom-properties]: https://developer.mozilla.org/en-US/docs/Web/CSS/--*
[link]: ../components/link
[route-module-links]: ../route/links
Expand All @@ -774,3 +841,4 @@ NOTE: You may run into hydration warnings when using Styled Components. Hopefull
[styled-components-issue]: https://github.com/styled-components/styled-components/issues/3660
[tailwind]: https://tailwindcss.com
[tailwind-intelli-sense-extension]: https://marketplace.visualstudio.com/items?itemName=bradlc.vscode-tailwindcss
[css modules]: https://github.com/css-modules/css-modules

0 comments on commit 3d58b0a

Please sign in to comment.