From 68f8ce0f3151451fc2d744331cf661ff945fceeb Mon Sep 17 00:00:00 2001 From: Philipp Spiess Date: Tue, 5 Nov 2024 13:17:26 +0100 Subject: [PATCH 1/6] vite-third-party-plugins --- integrations/vite/other-transforms.test.ts | 153 +++++++++++++++++++++ packages/@tailwindcss-vite/src/index.ts | 39 +++--- pnpm-lock.yaml | 27 +--- 3 files changed, 178 insertions(+), 41 deletions(-) create mode 100644 integrations/vite/other-transforms.test.ts diff --git a/integrations/vite/other-transforms.test.ts b/integrations/vite/other-transforms.test.ts new file mode 100644 index 000000000000..f897b4171358 --- /dev/null +++ b/integrations/vite/other-transforms.test.ts @@ -0,0 +1,153 @@ +import { describe, expect } from 'vitest' +import { css, fetchStyles, html, retryAssertion, test, ts, txt } from '../utils' + +function createSetup(transformer: 'postcss' | 'lightningcss') { + return { + fs: { + 'package.json': txt` + { + "type": "module", + "dependencies": { + "@tailwindcss/vite": "workspace:^", + "tailwindcss": "workspace:^" + }, + "devDependencies": { + ${transformer === 'lightningcss' ? `"lightningcss": "^1.26.0",` : ''} + "vite": "^5.3.5" + } + } + `, + 'vite.config.ts': ts` + import tailwindcss from '@tailwindcss/vite' + import { defineConfig } from 'vite' + + export default defineConfig({ + css: ${transformer === 'postcss' ? '{}' : "{ transformer: 'lightningcss' }"}, + build: { cssMinify: false }, + plugins: [ + tailwindcss(), + { + name: 'recolor', + transform(code, id) { + if (id.includes('.css')) { + return code.replace(/red/g, 'blue') + } + }, + }, + ], + }) + `, + 'index.html': html` + + + + +
Hello, world!
+ + `, + 'src/index.css': css` + @import 'tailwindcss/theme' theme(reference); + @import 'tailwindcss/utilities'; + + .foo { + color: red; + } + `, + }, + } +} + +for (let transformer of ['postcss', 'lightningcss'] as const) { + describe(transformer, () => { + test(`production build`, createSetup(transformer), async ({ fs, exec }) => { + await exec('pnpm vite build') + + let files = await fs.glob('dist/**/*.css') + expect(files).toHaveLength(1) + let [filename] = files[0] + + await fs.expectFileToContain(filename, [ + css` + .foo { + color: blue; + } + `, + ]) + }) + + test(`dev mode`, createSetup(transformer), async ({ spawn, getFreePort, fs }) => { + let port = await getFreePort() + await spawn(`pnpm vite dev --port ${port}`) + + await retryAssertion(async () => { + let styles = await fetchStyles(port, '/index.html') + expect(styles).toContain(css` + .foo { + color: blue; + } + `) + }) + + await retryAssertion(async () => { + await fs.write( + 'src/index.css', + css` + @import 'tailwindcss/theme' theme(reference); + @import 'tailwindcss/utilities'; + + .foo { + background-color: red; + } + `, + ) + + let styles = await fetchStyles(port) + expect(styles).toContain(css` + .foo { + background-color: blue; + } + `) + }) + }) + + test('watch mode', createSetup(transformer), async ({ spawn, fs }) => { + await spawn(`pnpm vite build --watch`) + + await retryAssertion(async () => { + let files = await fs.glob('dist/**/*.css') + expect(files).toHaveLength(1) + let [, styles] = files[0] + + expect(styles).toContain(css` + .foo { + color: blue; + } + `) + }) + + await retryAssertion(async () => { + await fs.write( + 'src/index.css', + css` + @import 'tailwindcss/theme' theme(reference); + @import 'tailwindcss/utilities'; + + .foo { + background-color: red; + } + `, + ) + + let files = await fs.glob('dist/**/*.css') + expect(files).toHaveLength(1) + let [, styles] = files[0] + + expect(styles).toContain(css` + .foo { + background-color: blue; + } + `) + }) + }) + }) +} diff --git a/packages/@tailwindcss-vite/src/index.ts b/packages/@tailwindcss-vite/src/index.ts index 4f02e60f290c..a0b4f27e3781 100644 --- a/packages/@tailwindcss-vite/src/index.ts +++ b/packages/@tailwindcss-vite/src/index.ts @@ -15,11 +15,6 @@ export default function tailwindcss(): Plugin[] { let isSSR = false let minify = false - // A list of css plugins defined in the Vite config. We need to retain these - // so that we can rerun the right transformations in build mode where we have - // to manually rebuild the css file after the compilation is done. - let cssPlugins: readonly Plugin[] = [] - // The Vite extension has two types of sources for candidates: // // 1. The module graph: These are all modules that vite transforms and we want @@ -109,8 +104,26 @@ export default function tailwindcss(): Plugin[] { }, } - for (let plugin of cssPlugins) { + for (let plugin of config!.plugins) { if (!plugin.transform) continue + + if (plugin.name.startsWith('@tailwindcss/')) { + // We do not run any Tailwind transforms anymore + continue + } else if ( + plugin.name.startsWith('vite:') && + // Apply the vite:css plugin to generated CSS for transformations like + // URL path rewriting and image inlining. + plugin.name !== 'vite:css' && + // In build mode, since `renderStart` runs after all transformations, we + // need to also apply vite:css-post. + plugin.name !== 'vite:css-post' && + // The vite:vue plugin handles CSS specific post-processing for Vue + plugin.name !== 'vite:vue' + ) { + continue + } + let transformHandler = 'handler' in plugin.transform! ? plugin.transform.handler : plugin.transform! @@ -147,20 +160,6 @@ export default function tailwindcss(): Plugin[] { config = _config minify = config.build.cssMinify !== false isSSR = config.build.ssr !== false && config.build.ssr !== undefined - - let allowedPlugins = [ - // Apply the vite:css plugin to generated CSS for transformations like - // URL path rewriting and image inlining. - 'vite:css', - - // In build mode, since renderChunk runs after all transformations, we - // need to also apply vite:css-post. - ...(config.command === 'build' ? ['vite:css-post'] : []), - ] - - cssPlugins = config.plugins.filter((plugin) => { - return allowedPlugins.includes(plugin.name) - }) }, // Scan all non-CSS files for candidates diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 4545fe4cddc4..7b80bf01c83f 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1093,7 +1093,6 @@ packages: '@parcel/watcher-darwin-arm64@2.4.2-alpha.0': resolution: {integrity: sha512-2xH4Ve7OKjIh+4YRfTN3HGJa2W8KTPLOALHZj5fxcbTPwaVxdpIRItDrcikUx2u3AzGAFme7F+AZZXHnf0F15Q==} engines: {node: '>= 10.0.0'} - cpu: [arm64] os: [darwin] '@parcel/watcher-darwin-x64@2.4.1': @@ -1105,7 +1104,6 @@ packages: '@parcel/watcher-darwin-x64@2.4.2-alpha.0': resolution: {integrity: sha512-xtjmXUH4YZVah5+7Q0nb+fpRP5qZn9cFfuPuZ4k77UfUGVwhacgZyIRQgIOwMP3GkgW4TsrKQaw1KIe7L1ZqcQ==} engines: {node: '>= 10.0.0'} - cpu: [x64] os: [darwin] '@parcel/watcher-freebsd-x64@2.4.1': @@ -1129,7 +1127,6 @@ packages: '@parcel/watcher-linux-arm64-glibc@2.4.2-alpha.0': resolution: {integrity: sha512-vIIOcZf+fgsRReIK3Fw0WINvGo9UwiXfisnqYRzfpNByRZvkEPkGTIVe8iiDp72NhPTVmwIvBqM6yKDzIaw8GQ==} engines: {node: '>= 10.0.0'} - cpu: [arm64] os: [linux] '@parcel/watcher-linux-arm64-musl@2.4.1': @@ -1141,7 +1138,6 @@ packages: '@parcel/watcher-linux-arm64-musl@2.4.2-alpha.0': resolution: {integrity: sha512-gXqEAoLG9bBCbQNUgqjSOxHcjpmCZmYT9M8UvrdTMgMYgXgiWcR8igKlPRd40mCIRZSkMpN2ScSy2WjQ0bQZnQ==} engines: {node: '>= 10.0.0'} - cpu: [arm64] os: [linux] '@parcel/watcher-linux-x64-glibc@2.4.1': @@ -1153,7 +1149,6 @@ packages: '@parcel/watcher-linux-x64-glibc@2.4.2-alpha.0': resolution: {integrity: sha512-/WJJ3Y46ubwQW+Z+mzpzK3pvqn/AT7MA63NB0+k9GTLNxJQZNREensMtpJ/FJ+LVIiraEHTY22KQrsx9+DeNbw==} engines: {node: '>= 10.0.0'} - cpu: [x64] os: [linux] '@parcel/watcher-linux-x64-musl@2.4.1': @@ -1165,7 +1160,6 @@ packages: '@parcel/watcher-linux-x64-musl@2.4.2-alpha.0': resolution: {integrity: sha512-1dz4fTM5HaANk3RSRmdhALT+bNqTHawVDL1D77HwV/FuF/kSjlM3rGrJuFaCKwQ5E8CInHCcobqMN8Jh8LYaRg==} engines: {node: '>= 10.0.0'} - cpu: [x64] os: [linux] '@parcel/watcher-win32-arm64@2.4.1': @@ -1189,7 +1183,6 @@ packages: '@parcel/watcher-win32-x64@2.4.2-alpha.0': resolution: {integrity: sha512-U2abMKF7JUiIxQkos19AvTLFcnl2Xn8yIW1kzu+7B0Lux4Gkuu/BUDBroaM1s6+hwgK63NOLq9itX2Y3GwUThg==} engines: {node: '>= 10.0.0'} - cpu: [x64] os: [win32] '@parcel/watcher@2.4.1': @@ -1618,7 +1611,6 @@ packages: bun@1.1.29: resolution: {integrity: sha512-SKhpyKNZtgxrVel9ec9xon3LDv8mgpiuFhARgcJo1YIbggY2PBrKHRNiwQ6Qlb+x3ivmRurfuwWgwGexjpgBRg==} - cpu: [arm64, x64] os: [darwin, linux, win32] hasBin: true @@ -2508,13 +2500,11 @@ packages: lightningcss-darwin-arm64@1.26.0: resolution: {integrity: sha512-n4TIvHO1NY1ondKFYpL2ZX0bcC2y6yjXMD6JfyizgR8BCFNEeArINDzEaeqlfX9bXz73Bpz/Ow0nu+1qiDrBKg==} engines: {node: '>= 12.0.0'} - cpu: [arm64] os: [darwin] lightningcss-darwin-x64@1.26.0: resolution: {integrity: sha512-Rf9HuHIDi1R6/zgBkJh25SiJHF+dm9axUZW/0UoYCW1/8HV0gMI0blARhH4z+REmWiU1yYT/KyNF3h7tHyRXUg==} engines: {node: '>= 12.0.0'} - cpu: [x64] os: [darwin] lightningcss-freebsd-x64@1.26.0: @@ -2532,25 +2522,21 @@ packages: lightningcss-linux-arm64-gnu@1.26.0: resolution: {integrity: sha512-iJmZM7fUyVjH+POtdiCtExG+67TtPUTer7K/5A8DIfmPfrmeGvzfRyBltGhQz13Wi15K1lf2cPYoRaRh6vcwNA==} engines: {node: '>= 12.0.0'} - cpu: [arm64] os: [linux] lightningcss-linux-arm64-musl@1.26.0: resolution: {integrity: sha512-XxoEL++tTkyuvu+wq/QS8bwyTXZv2y5XYCMcWL45b8XwkiS8eEEEej9BkMGSRwxa5J4K+LDeIhLrS23CpQyfig==} engines: {node: '>= 12.0.0'} - cpu: [arm64] os: [linux] lightningcss-linux-x64-gnu@1.26.0: resolution: {integrity: sha512-1dkTfZQAYLj8MUSkd6L/+TWTG8V6Kfrzfa0T1fSlXCXQHrt1HC1/UepXHtKHDt/9yFwyoeayivxXAsApVxn6zA==} engines: {node: '>= 12.0.0'} - cpu: [x64] os: [linux] lightningcss-linux-x64-musl@1.26.0: resolution: {integrity: sha512-yX3Rk9m00JGCUzuUhFEojY+jf/6zHs3XU8S8Vk+FRbnr4St7cjyMXdNjuA2LjiT8e7j8xHRCH8hyZ4H/btRE4A==} engines: {node: '>= 12.0.0'} - cpu: [x64] os: [linux] lightningcss-win32-arm64-msvc@1.26.0: @@ -2562,7 +2548,6 @@ packages: lightningcss-win32-x64-msvc@1.26.0: resolution: {integrity: sha512-pYS3EyGP3JRhfqEFYmfFDiZ9/pVNfy8jVIYtrx9TVNusVyDK3gpW1w/rbvroQ4bDJi7grdUtyrYU6V2xkY/bBw==} engines: {node: '>= 12.0.0'} - cpu: [x64] os: [win32] lightningcss@1.26.0: @@ -4950,7 +4935,7 @@ snapshots: debug: 4.3.7 enhanced-resolve: 5.17.1 eslint: 9.11.1(jiti@2.3.3) - eslint-module-utils: 2.8.1(@typescript-eslint/parser@6.21.0(eslint@9.11.1(jiti@2.3.3))(typescript@5.5.4))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1)(eslint@9.11.1(jiti@2.3.3)) + eslint-module-utils: 2.8.1(@typescript-eslint/parser@6.21.0(eslint@9.11.1(jiti@2.3.3))(typescript@5.5.4))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@6.21.0(eslint@9.11.1(jiti@2.3.3))(typescript@5.5.4))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1(eslint@9.11.1(jiti@2.3.3)))(eslint@9.11.1(jiti@2.3.3)))(eslint@9.11.1(jiti@2.3.3)) eslint-plugin-import: 2.29.1(@typescript-eslint/parser@6.21.0(eslint@9.11.1(jiti@2.3.3))(typescript@5.5.4))(eslint-import-resolver-typescript@3.6.1)(eslint@9.11.1(jiti@2.3.3)) fast-glob: 3.3.2 get-tsconfig: 4.7.6 @@ -4968,7 +4953,7 @@ snapshots: debug: 4.3.7 enhanced-resolve: 5.17.1 eslint: 9.13.0(jiti@2.3.3) - eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.11.0(eslint@9.13.0(jiti@2.3.3))(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3)(eslint@9.13.0(jiti@2.3.3)) + eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.11.0(eslint@9.13.0(jiti@2.3.3))(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@8.11.0(eslint@9.13.0(jiti@2.3.3))(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0)(eslint@9.13.0(jiti@2.3.3)))(eslint@9.13.0(jiti@2.3.3)) fast-glob: 3.3.2 get-tsconfig: 4.8.1 is-bun-module: 1.2.1 @@ -4981,7 +4966,7 @@ snapshots: - eslint-import-resolver-webpack - supports-color - eslint-module-utils@2.12.0(@typescript-eslint/parser@8.11.0(eslint@9.13.0(jiti@2.3.3))(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3)(eslint@9.13.0(jiti@2.3.3)): + eslint-module-utils@2.12.0(@typescript-eslint/parser@8.11.0(eslint@9.13.0(jiti@2.3.3))(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@8.11.0(eslint@9.13.0(jiti@2.3.3))(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0)(eslint@9.13.0(jiti@2.3.3)))(eslint@9.13.0(jiti@2.3.3)): dependencies: debug: 3.2.7 optionalDependencies: @@ -4992,7 +4977,7 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-module-utils@2.8.1(@typescript-eslint/parser@6.21.0(eslint@9.11.1(jiti@2.3.3))(typescript@5.5.4))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1)(eslint@9.11.1(jiti@2.3.3)): + eslint-module-utils@2.8.1(@typescript-eslint/parser@6.21.0(eslint@9.11.1(jiti@2.3.3))(typescript@5.5.4))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@6.21.0(eslint@9.11.1(jiti@2.3.3))(typescript@5.5.4))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1(eslint@9.11.1(jiti@2.3.3)))(eslint@9.11.1(jiti@2.3.3)))(eslint@9.11.1(jiti@2.3.3)): dependencies: debug: 3.2.7 optionalDependencies: @@ -5013,7 +4998,7 @@ snapshots: doctrine: 2.1.0 eslint: 9.11.1(jiti@2.3.3) eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.8.1(@typescript-eslint/parser@6.21.0(eslint@9.11.1(jiti@2.3.3))(typescript@5.5.4))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1)(eslint@9.11.1(jiti@2.3.3)) + eslint-module-utils: 2.8.1(@typescript-eslint/parser@6.21.0(eslint@9.11.1(jiti@2.3.3))(typescript@5.5.4))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@6.21.0(eslint@9.11.1(jiti@2.3.3))(typescript@5.5.4))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1(eslint@9.11.1(jiti@2.3.3)))(eslint@9.11.1(jiti@2.3.3)))(eslint@9.11.1(jiti@2.3.3)) hasown: 2.0.2 is-core-module: 2.15.0 is-glob: 4.0.3 @@ -5041,7 +5026,7 @@ snapshots: doctrine: 2.1.0 eslint: 9.13.0(jiti@2.3.3) eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.11.0(eslint@9.13.0(jiti@2.3.3))(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3)(eslint@9.13.0(jiti@2.3.3)) + eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.11.0(eslint@9.13.0(jiti@2.3.3))(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@8.11.0(eslint@9.13.0(jiti@2.3.3))(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0)(eslint@9.13.0(jiti@2.3.3)))(eslint@9.13.0(jiti@2.3.3)) hasown: 2.0.2 is-core-module: 2.15.1 is-glob: 4.0.3 From f5cef93c3fc93b2fe73f0be56f6176e99c87c22f Mon Sep 17 00:00:00 2001 From: Jordan Pittman Date: Thu, 31 Oct 2024 15:37:39 -0400 Subject: [PATCH 2/6] =?UTF-8?q?Add=20test=20for=20`:deep(=E2=80=A6)`=20in?= =?UTF-8?q?=20Vue=20scoped=20style=20blocks?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- integrations/vite/vue.test.ts | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/integrations/vite/vue.test.ts b/integrations/vite/vue.test.ts index 4f582a99fcdc..35ed5de77ba6 100644 --- a/integrations/vite/vue.test.ts +++ b/integrations/vite/vue.test.ts @@ -51,9 +51,15 @@ test( @apply text-red-500; } - + `, }, @@ -65,5 +71,7 @@ test( expect(files).toHaveLength(1) await fs.expectFileToContain(files[0][0], [candidate`underline`, candidate`foo`]) + + await fs.expectFileNotToContain(files[0][0], [':deep(.bar)']) }, ) From d02ca1d5baae8d8360ffec447598d0a8821339e3 Mon Sep 17 00:00:00 2001 From: Philipp Spiess Date: Tue, 5 Nov 2024 18:04:44 +0100 Subject: [PATCH 3/6] Handle Nuxt SSR --- integrations/vite/nuxt.test.ts | 111 +++++++++++++----------- packages/@tailwindcss-vite/src/index.ts | 5 ++ 2 files changed, 65 insertions(+), 51 deletions(-) diff --git a/integrations/vite/nuxt.test.ts b/integrations/vite/nuxt.test.ts index 21876d2c7adf..8c7eedc386d7 100644 --- a/integrations/vite/nuxt.test.ts +++ b/integrations/vite/nuxt.test.ts @@ -1,65 +1,74 @@ import { expect } from 'vitest' import { candidate, css, fetchStyles, html, json, retryAssertion, test, ts } from '../utils' -test( - 'dev mode', - { - fs: { - 'package.json': json` - { - "type": "module", - "dependencies": { - "@tailwindcss/vite": "workspace:^", - "nuxt": "^3.13.1", - "tailwindcss": "workspace:^", - "vue": "latest" - } +const SETUP = { + fs: { + 'package.json': json` + { + "type": "module", + "dependencies": { + "@tailwindcss/vite": "workspace:^", + "nuxt": "^3.13.1", + "tailwindcss": "workspace:^", + "vue": "latest" } - `, - 'nuxt.config.ts': ts` - import tailwindcss from '@tailwindcss/vite' + } + `, + 'nuxt.config.ts': ts` + import tailwindcss from '@tailwindcss/vite' - // https://nuxt.com/docs/api/configuration/nuxt-config - export default defineNuxtConfig({ - vite: { - plugins: [tailwindcss()], - }, + // https://nuxt.com/docs/api/configuration/nuxt-config + export default defineNuxtConfig({ + vite: { + plugins: [tailwindcss()], + }, - css: ['~/assets/css/main.css'], - devtools: { enabled: true }, - compatibilityDate: '2024-08-30', - }) - `, - 'app.vue': html` + css: ['~/assets/css/main.css'], + devtools: { enabled: true }, + compatibilityDate: '2024-08-30', + }) + `, + 'app.vue': html` +
Hello world!
+ `, - 'assets/css/main.css': css`@import 'tailwindcss';`, - }, + 'assets/css/main.css': css`@import 'tailwindcss';`, }, - async ({ fs, spawn, getFreePort }) => { - let port = await getFreePort() - await spawn(`pnpm nuxt dev --port ${port}`) +} + +test('dev mode', SETUP, async ({ fs, spawn, getFreePort }) => { + let port = await getFreePort() + await spawn(`pnpm nuxt dev --port ${port}`) - await retryAssertion(async () => { - let css = await fetchStyles(port) - expect(css).toContain(candidate`underline`) - }) + await retryAssertion(async () => { + let css = await fetchStyles(port) + expect(css).toContain(candidate`underline`) + }) - await retryAssertion(async () => { - await fs.write( - 'app.vue', - html` + await retryAssertion(async () => { + await fs.write( + 'app.vue', + html` +
Hello world!
+ `, - ) + ) - let css = await fetchStyles(port) - expect(css).toContain(candidate`underline`) - expect(css).toContain(candidate`font-bold`) - }) - }, -) + let css = await fetchStyles(port) + expect(css).toContain(candidate`underline`) + expect(css).toContain(candidate`font-bold`) + }) +}) + +test('build', SETUP, async ({ spawn, getFreePort, exec }) => { + let port = await getFreePort() + await exec(`pnpm nuxt build`) + await spawn(`PORT=${port} pnpm nuxt preview`) + + await retryAssertion(async () => { + let css = await fetchStyles(port) + expect(css).toContain(candidate`underline`) + }) +}) diff --git a/packages/@tailwindcss-vite/src/index.ts b/packages/@tailwindcss-vite/src/index.ts index a0b4f27e3781..644c1382180c 100644 --- a/packages/@tailwindcss-vite/src/index.ts +++ b/packages/@tailwindcss-vite/src/index.ts @@ -122,6 +122,11 @@ export default function tailwindcss(): Plugin[] { plugin.name !== 'vite:vue' ) { continue + } else if (plugin.name === 'ssr-styles') { + // The Nuxt ssr-styles plugin emits styles from server-side rendered + // components, we can't run it in the `renderStart` phase so we're + // skipping it. + continue } let transformHandler = From 94f6a9649d2ad7bc7b2b9f1e83caca5bda6234f5 Mon Sep 17 00:00:00 2001 From: Philipp Spiess Date: Wed, 6 Nov 2024 14:31:22 +0100 Subject: [PATCH 4/6] Add changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index bee7ca749dad..fd9f6d9d51e5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -27,6 +27,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Ensure `--inset-ring=*` and `--inset-shadow-*` variables are ignored by `inset-*` utilities ([#14855](https://github.com/tailwindlabs/tailwindcss/pull/14855)) - Ensure `url(…)` containing special characters such as `;` or `{}` end up in one declaration ([#14879](https://github.com/tailwindlabs/tailwindcss/pull/14879)) - Ensure adjacent rules are merged together after handling nesting when generating optimized CSS ([#14873](https://github.com/tailwindlabs/tailwindcss/pull/14873)) +- Ensure that CSS transforms from other Vite plugins correctly work in full builds (e.g. `:deep()` in Vue) ([#14871](https://github.com/tailwindlabs/tailwindcss/pull/14871)) - _Upgrade (experimental)_: Install `@tailwindcss/postcss` next to `tailwindcss` ([#14830](https://github.com/tailwindlabs/tailwindcss/pull/14830)) - _Upgrade (experimental)_: Remove whitespace around `,` separator when print arbitrary values ([#14838](https://github.com/tailwindlabs/tailwindcss/pull/14838)) - _Upgrade (experimental)_: Fix crash during upgrade when content globs escape root of project ([#14896](https://github.com/tailwindlabs/tailwindcss/pull/14896)) From fa25b2128652e3526f427f7315a7df4cf949bf61 Mon Sep 17 00:00:00 2001 From: Philipp Spiess Date: Thu, 7 Nov 2024 12:13:55 +0100 Subject: [PATCH 5/6] Improvements --- integrations/vite/other-transforms.test.ts | 25 +++++++++++++++++++--- integrations/vite/vue.test.ts | 3 +-- 2 files changed, 23 insertions(+), 5 deletions(-) diff --git a/integrations/vite/other-transforms.test.ts b/integrations/vite/other-transforms.test.ts index f897b4171358..53a0cc9e0b9b 100644 --- a/integrations/vite/other-transforms.test.ts +++ b/integrations/vite/other-transforms.test.ts @@ -1,3 +1,4 @@ +import dedent from 'dedent' import { describe, expect } from 'vitest' import { css, fetchStyles, html, retryAssertion, test, ts, txt } from '../utils' @@ -30,7 +31,7 @@ function createSetup(transformer: 'postcss' | 'lightningcss') { name: 'recolor', transform(code, id) { if (id.includes('.css')) { - return code.replace(/red/g, 'blue') + return code.replace(/red;/g, 'blue;') } }, }, @@ -42,7 +43,7 @@ function createSetup(transformer: 'postcss' | 'lightningcss') { -
Hello, world!
+
Hello, world!
`, 'src/index.css': css` @@ -59,7 +60,7 @@ function createSetup(transformer: 'postcss' | 'lightningcss') { for (let transformer of ['postcss', 'lightningcss'] as const) { describe(transformer, () => { - test(`production build`, createSetup(transformer), async ({ fs, exec }) => { + test.only(`production build`, createSetup(transformer), async ({ fs, exec }) => { await exec('pnpm vite build') let files = await fs.glob('dist/**/*.css') @@ -72,6 +73,12 @@ for (let transformer of ['postcss', 'lightningcss'] as const) { color: blue; } `, + // Running the transforms on utilities generated by Tailwind might change in the future + dedent` + .\[background-color\:red\] { + background-color: blue; + } + `, ]) }) @@ -86,6 +93,12 @@ for (let transformer of ['postcss', 'lightningcss'] as const) { color: blue; } `) + // Running the transforms on utilities generated by Tailwind might change in the future + expect(styles).toContain(dedent` + .\[background-color\:red\] { + background-color: blue; + } + `) }) await retryAssertion(async () => { @@ -123,6 +136,12 @@ for (let transformer of ['postcss', 'lightningcss'] as const) { color: blue; } `) + // Running the transforms on utilities generated by Tailwind might change in the future + expect(styles).toContain(dedent` + .\[background-color\:red\] { + background-color: blue; + } + `) }) await retryAssertion(async () => { diff --git a/integrations/vite/vue.test.ts b/integrations/vite/vue.test.ts index 35ed5de77ba6..53f079499dd0 100644 --- a/integrations/vite/vue.test.ts +++ b/integrations/vite/vue.test.ts @@ -71,7 +71,6 @@ test( expect(files).toHaveLength(1) await fs.expectFileToContain(files[0][0], [candidate`underline`, candidate`foo`]) - - await fs.expectFileNotToContain(files[0][0], [':deep(.bar)']) + await fs.expectFileToContain(files[0][0], ['.bar{']) }, ) From e923a38e48c7bb27088b05292fb9a70dd8d9fc24 Mon Sep 17 00:00:00 2001 From: Adam Wathan Date: Thu, 7 Nov 2024 09:47:02 -0500 Subject: [PATCH 6/6] Update integrations/vite/other-transforms.test.ts --- integrations/vite/other-transforms.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/integrations/vite/other-transforms.test.ts b/integrations/vite/other-transforms.test.ts index 53a0cc9e0b9b..71749f21c229 100644 --- a/integrations/vite/other-transforms.test.ts +++ b/integrations/vite/other-transforms.test.ts @@ -60,7 +60,7 @@ function createSetup(transformer: 'postcss' | 'lightningcss') { for (let transformer of ['postcss', 'lightningcss'] as const) { describe(transformer, () => { - test.only(`production build`, createSetup(transformer), async ({ fs, exec }) => { + test(`production build`, createSetup(transformer), async ({ fs, exec }) => { await exec('pnpm vite build') let files = await fs.glob('dist/**/*.css')