From bb78c597704935304b7d7633fdbaab6a25e9052a Mon Sep 17 00:00:00 2001 From: Jordan Pittman Date: Tue, 29 Apr 2025 19:16:49 -0400 Subject: [PATCH] Add source map support to Vite --- integrations/vite/source-maps.test.ts | 96 +++++++++++++++++++++++++ packages/@tailwindcss-vite/src/index.ts | 22 +++++- 2 files changed, 117 insertions(+), 1 deletion(-) create mode 100644 integrations/vite/source-maps.test.ts 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, } }