Skip to content

Commit

Permalink
Add tailwindcss nesting support (#9529)
Browse files Browse the repository at this point in the history
* Add tailwindcss nesting support

* Update lockfile
  • Loading branch information
bluwy committed Dec 27, 2023
1 parent cf993bc commit d252fc6
Show file tree
Hide file tree
Showing 9 changed files with 121 additions and 4 deletions.
5 changes: 5 additions & 0 deletions .changeset/rude-deers-turn.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@astrojs/tailwind': minor
---

Adds `nesting` option to enable `tailwindcss/nesting` support
5 changes: 4 additions & 1 deletion packages/integrations/tailwind/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@
"scripts": {
"build": "astro-scripts build \"src/**/*.ts\" && tsc",
"build:ci": "astro-scripts build \"src/**/*.ts\"",
"dev": "astro-scripts dev \"src/**/*.ts\""
"dev": "astro-scripts dev \"src/**/*.ts\"",
"test": "mocha --exit --timeout 20000 test/"
},
"dependencies": {
"autoprefixer": "^10.4.15",
Expand All @@ -39,6 +40,8 @@
"devDependencies": {
"astro": "workspace:*",
"astro-scripts": "workspace:*",
"chai": "^4.3.7",
"mocha": "^10.2.0",
"tailwindcss": "^3.3.5",
"vite": "^5.0.10"
},
Expand Down
26 changes: 23 additions & 3 deletions packages/integrations/tailwind/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { fileURLToPath } from 'node:url';
import type { AstroIntegration } from 'astro';
import autoprefixerPlugin from 'autoprefixer';
import tailwindPlugin from 'tailwindcss';
Expand All @@ -23,15 +24,22 @@ async function getPostCssConfig(

async function getViteConfiguration(
tailwindConfigPath: string | undefined,
viteConfig: UserConfig
nesting: boolean,
root: string,
postcssInlineOptions: CSSOptions['postcss']
): Promise<Partial<UserConfig>> {
// We need to manually load postcss config files because when inlining the tailwind and autoprefixer plugins,
// that causes vite to ignore postcss config files
const postcssConfigResult = await getPostCssConfig(viteConfig.root, viteConfig.css?.postcss);
const postcssConfigResult = await getPostCssConfig(root, postcssInlineOptions);

const postcssOptions = postcssConfigResult?.options ?? {};
const postcssPlugins = postcssConfigResult?.plugins?.slice() ?? [];

if (nesting) {
const tailwindcssNestingPlugin = (await import('tailwindcss/nesting/index.js')).default;
postcssPlugins.push(tailwindcssNestingPlugin());
}

postcssPlugins.push(tailwindPlugin(tailwindConfigPath));
postcssPlugins.push(autoprefixerPlugin());

Expand Down Expand Up @@ -59,18 +67,30 @@ type TailwindOptions = {
* @default true
*/
applyBaseStyles?: boolean;
/**
* Add CSS nesting support using `tailwindcss/nesting`. See {@link https://tailwindcss.com/docs/using-with-preprocessors#nesting Tailwind's docs}
* for how this works with `postcss-nesting` and `postcss-nested`.
*/
nesting?: boolean;
};

export default function tailwindIntegration(options?: TailwindOptions): AstroIntegration {
const applyBaseStyles = options?.applyBaseStyles ?? true;
const customConfigPath = options?.configFile;
const nesting = options?.nesting ?? false;

return {
name: '@astrojs/tailwind',
hooks: {
'astro:config:setup': async ({ config, updateConfig, injectScript }) => {
// Inject the Tailwind postcss plugin
updateConfig({
vite: await getViteConfiguration(customConfigPath, config.vite),
vite: await getViteConfiguration(
customConfigPath,
nesting,
fileURLToPath(config.root),
config.vite.css?.postcss
),
});

if (applyBaseStyles) {
Expand Down
33 changes: 33 additions & 0 deletions packages/integrations/tailwind/test/basic.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { expect } from 'chai';
import { loadFixture } from '../../../astro/test/test-utils.js';

describe('Basic', () => {
let fixture;

before(async () => {
fixture = await loadFixture({
root: new URL('./fixtures/basic/', import.meta.url),
});
});

describe('build', () => {
before(async () => {
await fixture.build();
});

it('works', async () => {
const astroChunkDir = await fixture.readdir('/_astro');

let css = '';
for (const file of astroChunkDir) {
if (file.endsWith('.css')) {
css += await fixture.readFile(`/_astro/${file}`);
}
}

expect(css).to.include('box-sizing:border-box;'); // base css
expect(css).to.include('text-red-500'); // class css
expect(css).to.match(/\.a\[data-astro-cid-.*?\] \.b\[data-astro-cid-.*?\]/); // nesting
});
});
});
12 changes: 12 additions & 0 deletions packages/integrations/tailwind/test/fixtures/basic/astro.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { fileURLToPath } from 'node:url';
import { defineConfig } from 'astro/config';
import tailwind from '@astrojs/tailwind';

export default defineConfig({
integrations: [
tailwind({
configFile: fileURLToPath(new URL('./tailwind.config.js', import.meta.url)),
nesting: true
}),
]
});
10 changes: 10 additions & 0 deletions packages/integrations/tailwind/test/fixtures/basic/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"name": "@test/tailwind-basic",
"version": "0.0.0",
"private": true,
"type": "module",
"dependencies": {
"astro": "workspace:*",
"@astrojs/tailwind": "workspace:*"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<div class="text-red-500">red</div>

<div class="a">
<div class="b">nested blue</div>
</div>

<style>
.a {
.b {
color: blue;
}
}
</style>
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import path from 'node:path';

/** @type {import('tailwindcss').Config} */
export default {
content: [path.join(__dirname, 'src/**/*.{astro,html,js,jsx,md,mdx,svelte,ts,tsx,vue}')],
};
15 changes: 15 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit d252fc6

Please sign in to comment.