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(dev): support PostCSS and Tailwind by default #6909

Merged
merged 3 commits into from
Jul 24, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
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 @@ -68,7 +68,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 @@ -245,7 +245,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_errorBoundary: expect.any(Boolean),
v2_headers: expect.any(Boolean),
v2_meta: expect.any(Boolean),
Expand All @@ -45,16 +43,14 @@ describe("readConfig", () => {
"entryServerFile": "entry.server.tsx",
"entryServerFilePath": Any<String>,
"future": Object {
"unstable_postcss": Any<Boolean>,
"unstable_tailwind": Any<Boolean>,
"v2_dev": false,
"v2_errorBoundary": Any<Boolean>,
"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 @@ -79,7 +75,7 @@ describe("readConfig", () => {
"serverModuleFormat": "cjs",
"serverNodeBuiltinsPolyfill": undefined,
"serverPlatform": "node",
"tailwind": false,
"tailwind": true,
"tsconfigPath": Any<String>,
"watchPaths": Array [],
}
Expand Down
Loading