Skip to content

Commit

Permalink
feat(dev): support PostCSS and Tailwind by default (#6909)
Browse files Browse the repository at this point in the history
  • Loading branch information
markdalgleish authored Jul 24, 2023
1 parent f3beabb commit c5e9050
Show file tree
Hide file tree
Showing 15 changed files with 32 additions and 263 deletions.
16 changes: 16 additions & 0 deletions .changeset/enable-css-features-by-default.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
---
"@remix-run/dev": major
---

Enable built-in PostCSS and Tailwind support by default.

These tools are now automatically used within the Remix compiler if PostCSS and/or Tailwind configuration files are present in your project.

If you have a custom PostCSS and/or Tailwind setup outside of Remix, you can disable these features in your `remix.config.js`.

```js
module.exports = {
postcss: false,
tailwind: false,
};
```
4 changes: 2 additions & 2 deletions docs/file-conventions/remix-config.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ The URL prefix of the browser build with a trailing slash. Defaults to

## postcss

Whether to process CSS using [PostCSS][postcss] if `postcss.config.js` is present. Defaults to `false`.
Whether to process CSS using [PostCSS][postcss] if `postcss.config.js` is present. Defaults to `true`.

## routes

Expand Down Expand Up @@ -249,7 +249,7 @@ The platform the server build is targeting, which can either be `"neutral"` or

## tailwind

Whether to support [Tailwind functions and directives][tailwind-functions-and-directives] in CSS files if `tailwindcss` is installed. Defaults to `false`.
Whether to support [Tailwind functions and directives][tailwind-functions-and-directives] in CSS files if `tailwindcss` is installed. Defaults to `true`.

## watchPaths

Expand Down
13 changes: 0 additions & 13 deletions docs/guides/migrating-react-router-app.md
Original file line number Diff line number Diff line change
Expand Up @@ -615,18 +615,6 @@ You'll notice on line 32 that we've rendered a `<Links />` component that replac

If you currently inject `<link />` tags into your page client-side in your existing route components, either directly or via an abstraction like [`react-helmet`][react-helmet], you can stop doing that and instead use the `links` export. You get to delete a lot of code and possibly a dependency or two!

### PostCSS

To enable [PostCSS] support, set the `postcss` option to `true` in `remix.config.js`. Remix will then automatically process your styles with PostCSS if a `postcss.config.js` file is present.

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

### CSS bundling

Remix has built-in support for [CSS Modules][css-modules], [Vanilla Extract][vanilla-extract] and [CSS side effect imports][css-side-effect-imports]. In order to make use of these features, you'll need to set up CSS bundling in your application.
Expand Down Expand Up @@ -757,7 +745,6 @@ Now then, go off and _remix your app_. We think you'll like what you build along
[styling-in-remix]: ./styling
[frequently-asked-questions]: ../pages/faq
[common-gotchas]: ../pages/gotchas
[postcss]: ./styling#postcss
[css-modules]: ./styling#css-modules
[vanilla-extract]: ./styling#vanilla-extract
[css-side-effect-imports]: ./styling#css-side-effect-imports
Expand Down
28 changes: 6 additions & 22 deletions docs/guides/styling.md
Original file line number Diff line number Diff line change
Expand Up @@ -404,17 +404,7 @@ export const links: LinksFunction = () => {

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.

To use the built-in Tailwind support, first enable the `tailwind` option in `remix.config.js`:

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

Install Tailwind as a dev dependency:
To use Tailwind, first install it as a dev dependency:

```sh
npm install -D tailwindcss
Expand Down Expand Up @@ -470,6 +460,8 @@ If you're using VS Code, it's recommended you install the [Tailwind IntelliSense

<docs-warning>It's recommended that you avoid Tailwind's `@import` syntax (e.g. `@import 'tailwindcss/base'`) in favor of Tailwind directives (e.g. `@tailwind base`). Tailwind replaces its import statements with inlined CSS but this can result in the interleaving of styles and import statements. This clashes with the restriction that all import statements must be at the start of the file. Alternatively, you can use [PostCSS][built-in-post-css-support] with the [postcss-import] plugin to process imports before passing them to esbuild.</docs-warning>

<docs-info>Built-in Tailwind support can be disabled by setting the `tailwind` option to `false` in `remix.config.js`.</docs-info>

## Remote Stylesheets

You can load stylesheets from any server, here's an example of loading a modern css reset from unpkg.
Expand All @@ -491,17 +483,7 @@ export const links: LinksFunction = () => {

[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. When a PostCSS config is detected, Remix will automatically run PostCSS across all CSS in your project.

For example, to use [Autoprefixer][autoprefixer], first enable the `postcss` option in `remix.config.js`:

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

Install the PostCSS plugin.
For example, to use [Autoprefixer][autoprefixer], first install the PostCSS plugin.

```sh
npm install -D autoprefixer
Expand Down Expand Up @@ -531,6 +513,8 @@ module.exports = (ctx) => {
};
```
<docs-info>Built-in PostCSS support can be disabled by setting the `postcss` option to `false` in `remix.config.js`.</docs-info>
## CSS Preprocessors
You can use CSS preprocessors like LESS and SASS. Doing so requires running an additional build process to convert these files to CSS files. This can be done via the command line tools provided by the preprocessor or any equivalent tool.
Expand Down
1 change: 0 additions & 1 deletion integration/deterministic-build-output-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ test("builds deterministically under different paths", async () => {
// * vanillaExtractPlugin (via app/routes/foo.tsx' .css.ts file import)
let init: FixtureInit = {
config: {
postcss: true,
future: {
v2_routeConvention: true,
},
Expand Down
1 change: 0 additions & 1 deletion integration/hmr-log-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ test.setTimeout(120_000);
let fixture = (options: { appPort: number; devPort: number }): FixtureInit => ({
config: {
serverModuleFormat: "cjs",
tailwind: true,
future: {
v2_dev: {
port: options.devPort,
Expand Down
1 change: 0 additions & 1 deletion integration/hmr-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ test.setTimeout(150_000);
let fixture = (options: { appPort: number; devPort: number }): FixtureInit => ({
config: {
serverModuleFormat: "cjs",
postcss: true,
future: {
v2_dev: {
port: options.devPort,
Expand Down
88 changes: 0 additions & 88 deletions integration/postcss-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,6 @@ test.describe("PostCSS enabled", () => {
test.beforeAll(async () => {
fixture = await createFixture({
config: {
postcss: true,
tailwind: true,
future: {
v2_routeConvention: true,
},
Expand Down Expand Up @@ -350,92 +348,6 @@ test.describe("PostCSS enabled", () => {
});
});

test.describe("PostCSS enabled via unstable future flag", () => {
let fixture: Fixture;
let appFixture: AppFixture;

test.beforeAll(async () => {
fixture = await createFixture({
config: {
future: {
unstable_postcss: true,
},
},
files: {
"postcss.config.js": js`
module.exports = (ctx) => ({
plugins: [
{
postcssPlugin: 'replace',
Declaration (decl) {
decl.value = decl.value
.replace(
/TEST_PADDING_VALUE/g,
${JSON.stringify(TEST_PADDING_VALUE)},
);
},
},
],
});
`,
"app/root.jsx": js`
import { Links, Outlet } from "@remix-run/react";
export default function Root() {
return (
<html>
<head>
<Links />
</head>
<body>
<Outlet />
</body>
</html>
)
}
`,
"app/routes/postcss-unstable-future-flag-test.jsx": js`
import { Test, links as testLinks } from "~/test-components/postcss-unstable-future-flag";
export function links() {
return [...testLinks()];
}
export default function() {
return <Test />;
}
`,
"app/test-components/postcss-unstable-future-flag/index.jsx": js`
import stylesHref from "./styles.css";
export function links() {
return [{ rel: 'stylesheet', href: stylesHref }];
}
export function Test() {
return (
<div data-testid="postcss-unstable-future-flag" className="postcss-unstable-future-flag-test">
<p>PostCSS unstable future flag test.</p>
</div>
);
}
`,
"app/test-components/postcss-unstable-future-flag/styles.css": css`
.postcss-unstable-future-flag-test {
padding: TEST_PADDING_VALUE;
}
`,
},
});
appFixture = await createAppFixture(fixture);
});

test.afterAll(() => appFixture.close());

test("uses PostCSS config", async ({ page }) => {
let app = new PlaywrightFixture(appFixture, page);
await app.goto("/postcss-unstable-future-flag-test");
let locator = await page.getByTestId("postcss-unstable-future-flag");
let padding = await locator.evaluate((el) => getComputedStyle(el).padding);
expect(padding).toBe(TEST_PADDING_VALUE);
});
});

test.describe("PostCSS disabled", () => {
let fixture: Fixture;
let appFixture: AppFixture;
Expand Down
78 changes: 0 additions & 78 deletions integration/tailwind-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,6 @@ function runTests(ext: typeof extensions[number]) {
test.beforeAll(async () => {
fixture = await createFixture({
config: {
tailwind: true,
future: {
v2_routeConvention: true,
},
Expand Down Expand Up @@ -329,83 +328,6 @@ test.describe("Tailwind enabled", () => {
}
});

test.describe("Tailwind enabled via unstable future flag", () => {
let fixture: Fixture;
let appFixture: AppFixture;

test.beforeAll(async () => {
fixture = await createFixture({
config: {
future: {
unstable_tailwind: true,
},
},
files: {
"tailwind.config.js": js`
module.exports = {
content: ["./app/**/*.{ts,tsx,jsx,js}"],
theme: {
spacing: {
'test': ${JSON.stringify(TEST_PADDING_VALUE)}
},
},
}
`,
"app/tailwind.css": css`
@tailwind base;
@tailwind components;
@tailwind utilities;
`,
"app/root.jsx": js`
import { Links, Outlet } from "@remix-run/react";
import { cssBundleHref } from "@remix-run/css-bundle";
import tailwindHref from "./tailwind.css"
export function links() {
return [
{ rel: "stylesheet", href: tailwindHref },
{ rel: "stylesheet", href: cssBundleHref }
];
}
export default function Root() {
return (
<html>
<head>
<Links />
</head>
<body>
<Outlet />
</body>
</html>
)
}
`,
"app/routes/unstable-future-flag-test.jsx": js`
export default function() {
return (
<div data-testid="unstable-future-flag" className="p-test">
Unstable future flag test
</div>
);
}
`,
},
});
appFixture = await createAppFixture(fixture);
});

test.afterAll(() => appFixture.close());

test("uses Tailwind config", async ({ page }) => {
let app = new PlaywrightFixture(appFixture, page);
await app.goto("/unstable-future-flag-test");
let locator = page.getByTestId("unstable-future-flag");
let padding = await locator.evaluate(
(element) => window.getComputedStyle(element).padding
);
expect(padding).toBe(TEST_PADDING_VALUE);
});
});

test.describe("Tailwind disabled", () => {
let fixture: Fixture;
let appFixture: AppFixture;
Expand Down
8 changes: 2 additions & 6 deletions packages/remix-dev/__tests__/readConfig-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,6 @@ describe("readConfig", () => {
entryServerFilePath: expect.any(String),
tsconfigPath: expect.any(String),
future: {
unstable_postcss: expect.any(Boolean),
unstable_tailwind: expect.any(Boolean),
v2_headers: expect.any(Boolean),
v2_meta: expect.any(Boolean),
v2_routeConvention: expect.any(Boolean),
Expand All @@ -44,15 +42,13 @@ describe("readConfig", () => {
"entryServerFile": "entry.server.tsx",
"entryServerFilePath": Any<String>,
"future": Object {
"unstable_postcss": Any<Boolean>,
"unstable_tailwind": Any<Boolean>,
"v2_dev": false,
"v2_headers": Any<Boolean>,
"v2_meta": Any<Boolean>,
"v2_routeConvention": Any<Boolean>,
},
"mdx": undefined,
"postcss": false,
"postcss": true,
"publicPath": "/build/",
"relativeAssetsBuildDirectory": Any<String>,
"rootDirectory": Any<String>,
Expand All @@ -77,7 +73,7 @@ describe("readConfig", () => {
"serverModuleFormat": "cjs",
"serverNodeBuiltinsPolyfill": undefined,
"serverPlatform": "node",
"tailwind": false,
"tailwind": true,
"tsconfigPath": Any<String>,
"watchPaths": Array [],
}
Expand Down
Loading

0 comments on commit c5e9050

Please sign in to comment.