diff --git a/integrations/vite/source-maps.test.ts b/integrations/vite/source-maps.test.ts
new file mode 100644
index 000000000..299cd1167
--- /dev/null
+++ b/integrations/vite/source-maps.test.ts
@@ -0,0 +1,96 @@
+import { candidate, css, fetchStyles, html, json, retryAssertion, test, ts } from '../utils'
+
+test(
+ `dev build`,
+ {
+ fs: {
+ 'package.json': json`
+ {
+ "type": "module",
+ "dependencies": {
+ "@tailwindcss/vite": "workspace:^",
+ "tailwindcss": "workspace:^"
+ },
+ "devDependencies": {
+ "lightningcss": "^1.26.0",
+ "vite": "^6"
+ }
+ }
+ `,
+ 'vite.config.ts': ts`
+ import tailwindcss from '@tailwindcss/vite'
+ import { defineConfig } from 'vite'
+
+ export default defineConfig({
+ plugins: [tailwindcss()],
+ css: {
+ devSourcemap: true,
+ },
+ build: {
+ sourcemap: true,
+ },
+ })
+ `,
+ 'index.html': html`
+
+
+
+
+ Hello, world!
+
+ `,
+ 'src/index.css': css`
+ @import 'tailwindcss/utilities';
+ /* */
+ `,
+ },
+ },
+ async ({ fs, spawn, expect, parseSourceMap }) => {
+ // Source maps only work in development mode in Vite
+ let process = await spawn('pnpm vite dev')
+ await process.onStdout((m) => m.includes('ready in'))
+
+ let url = ''
+ await process.onStdout((m) => {
+ let match = /Local:\s*(http.*)\//.exec(m)
+ if (match) url = match[1]
+ return Boolean(url)
+ })
+
+ let styles = await retryAssertion(async () => {
+ let styles = await fetchStyles(url, '/index.html')
+
+ // Wait until we have the right CSS
+ expect(styles).toContain(candidate`flex`)
+
+ return styles
+ })
+
+ // Make sure we can find a source map
+ let map = parseSourceMap(styles)
+
+ expect(map.at(1, 0)).toMatchObject({
+ source: null,
+ original: '(none)',
+ generated: '/*! tailwi...',
+ })
+
+ expect(map.at(2, 0)).toMatchObject({
+ source: expect.stringContaining('node_modules/tailwindcss/utilities.css'),
+ original: '@tailwind...',
+ generated: '.flex {...',
+ })
+
+ expect(map.at(3, 2)).toMatchObject({
+ source: expect.stringContaining('node_modules/tailwindcss/utilities.css'),
+ original: '@tailwind...',
+ generated: 'display: f...',
+ })
+
+ expect(map.at(4, 0)).toMatchObject({
+ source: null,
+ original: '(none)',
+ generated: '}...',
+ })
+ },
+)
diff --git a/packages/@tailwindcss-vite/src/index.ts b/packages/@tailwindcss-vite/src/index.ts
index 0a053291a..00ba92db4 100644
--- a/packages/@tailwindcss-vite/src/index.ts
+++ b/packages/@tailwindcss-vite/src/index.ts
@@ -1,4 +1,12 @@
-import { compile, env, Features, Instrumentation, normalizePath, optimize } from '@tailwindcss/node'
+import {
+ compile,
+ env,
+ Features,
+ Instrumentation,
+ normalizePath,
+ optimize,
+ toSourceMap,
+} from '@tailwindcss/node'
import { clearRequireCache } from '@tailwindcss/node/require-cache'
import { Scanner } from '@tailwindcss/oxide'
import fs from 'node:fs/promises'
@@ -37,6 +45,9 @@ export default function tailwindcss(): Plugin[] {
return new Root(
id,
config!.root,
+ // Currently, Vite only supports CSS source maps in development and they
+ // are off by default. Check to see if we need them or not.
+ config?.css.devSourcemap ?? false,
customCssResolver,
customJsResolver,
)
@@ -108,6 +119,7 @@ export default function tailwindcss(): Plugin[] {
DEBUG && I.start('[@tailwindcss/vite] Optimize CSS')
result = optimize(result.code, {
minify,
+ map: result.map,
})
DEBUG && I.end('[@tailwindcss/vite] Optimize CSS')
@@ -180,6 +192,7 @@ class Root {
private id: string,
private base: string,
+ private enableSourceMaps: boolean,
private customCssResolver: (id: string, base: string) => Promise,
private customJsResolver: (id: string, base: string) => Promise,
) {}
@@ -193,6 +206,7 @@ class Root {
): Promise<
| {
code: string
+ map: string | undefined
}
| false
> {
@@ -227,6 +241,7 @@ class Root {
DEBUG && I.start('Setup compiler')
let addBuildDependenciesPromises: Promise[] = []
this.compiler = await compile(content, {
+ from: this.enableSourceMaps ? this.id : undefined,
base: inputBase,
shouldRewriteUrls: true,
onDependency: (path) => {
@@ -328,8 +343,13 @@ class Root {
let code = this.compiler.build([...this.candidates])
DEBUG && I.end('Build CSS')
+ DEBUG && I.start('Build Source Map')
+ let map = this.enableSourceMaps ? toSourceMap(this.compiler.buildSourceMap()).raw : undefined
+ DEBUG && I.end('Build Source Map')
+
return {
code,
+ map,
}
}