or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

cache-management.mdcompilation.mdindex.mdinstrumentation.mdmodule-analysis.mdoptimization.mdpath-utils.mdsource-maps.mdurl-processing.md

url-processing.mddocs/

0

# URL Processing

1

2

CSS URL rewriting functionality for asset path management and relative URL transformation in build processes. Handles `url()` functions and `image-set()` properties with comprehensive path resolution and rewriting.

3

4

## Capabilities

5

6

### Rewrite URLs Function

7

8

Rewrites URLs in CSS for proper relative path handling during build processes.

9

10

```typescript { .api }

11

/**

12

* Rewrites URLs in CSS for proper relative path handling

13

* Handles url() and image-set() CSS functions with path transformation

14

* @param options - Configuration for URL rewriting

15

* @returns Promise resolving to CSS with rewritten URLs

16

*/

17

function rewriteUrls(options: {

18

/** CSS string containing URLs to rewrite */

19

css: string;

20

/** Base directory of the CSS file being processed */

21

base: string;

22

/** Root directory for the project (target for relative paths) */

23

root: string;

24

}): Promise<string>;

25

```

26

27

**Usage Examples:**

28

29

```typescript

30

import { rewriteUrls } from "@tailwindcss/node";

31

32

// Basic URL rewriting

33

const css = `

34

.hero {

35

background-image: url('./images/hero.jpg');

36

}

37

38

.icon {

39

background: url('../assets/icon.svg');

40

}

41

`;

42

43

const rewritten = await rewriteUrls({

44

css,

45

base: '/project/src/styles', // Directory containing the CSS file

46

root: '/project' // Project root directory

47

});

48

49

console.log(rewritten);

50

// Output:

51

// .hero {

52

// background-image: url('./src/styles/images/hero.jpg');

53

// }

54

//

55

// .icon {

56

// background: url('./src/assets/icon.svg');

57

// }

58

```

59

60

### Image Set Rewriting

61

62

Handles CSS `image-set()` properties with multiple image candidates:

63

64

```typescript

65

import { rewriteUrls } from "@tailwindcss/node";

66

67

const css = `

68

.responsive-bg {

69

background-image: image-set(

70

url('./images/hero-1x.jpg') 1x,

71

url('./images/hero-2x.jpg') 2x,

72

url('./images/hero-3x.jpg') 3x

73

);

74

}

75

`;

76

77

const rewritten = await rewriteUrls({

78

css,

79

base: '/project/src/components',

80

root: '/project'

81

});

82

83

console.log(rewritten);

84

// All URLs in the image-set are rewritten relative to the project root

85

```

86

87

### Build Tool Integration

88

89

Common usage in build tools and asset processing:

90

91

```typescript

92

import { rewriteUrls } from "@tailwindcss/node";

93

import { compile } from "@tailwindcss/node";

94

import path from "path";

95

96

// Webpack loader example

97

module.exports = function(source: string) {

98

const callback = this.async();

99

const resourcePath = this.resourcePath;

100

101

const baseDir = path.dirname(resourcePath);

102

const rootDir = this.rootContext;

103

104

rewriteUrls({

105

css: source,

106

base: baseDir,

107

root: rootDir

108

}).then(rewrittenCss => {

109

callback(null, rewrittenCss);

110

}).catch(callback);

111

};

112

113

// Vite plugin example

114

export function urlRewritePlugin() {

115

return {

116

name: 'url-rewrite',

117

transform(code: string, id: string) {

118

if (id.endsWith('.css')) {

119

return rewriteUrls({

120

css: code,

121

base: path.dirname(id),

122

root: process.cwd()

123

});

124

}

125

}

126

};

127

}

128

```

129

130

### Compilation Integration

131

132

Use with Tailwind CSS compilation for comprehensive asset handling:

133

134

```typescript

135

import { compile, rewriteUrls } from "@tailwindcss/node";

136

137

async function compileWithUrlRewriting(css: string, options: {

138

base: string;

139

shouldRewriteUrls?: boolean;

140

}) {

141

// First compile with Tailwind

142

const compiler = await compile(css, {

143

...options,

144

onDependency: (path) => console.log("Dependency:", path),

145

shouldRewriteUrls: true // This enables automatic URL rewriting

146

});

147

148

const compiled = compiler.build();

149

150

// Additional URL rewriting if needed

151

if (options.shouldRewriteUrls) {

152

return rewriteUrls({

153

css: compiled,

154

base: options.base,

155

root: process.cwd()

156

});

157

}

158

159

return compiled;

160

}

161

162

const result = await compileWithUrlRewriting(`

163

@tailwind base;

164

165

.custom {

166

background: url('./assets/bg.jpg');

167

}

168

`, {

169

base: '/project/src/styles',

170

shouldRewriteUrls: true

171

});

172

```

173

174

## URL Processing Behavior

175

176

### Supported URL Types

177

178

The URL rewriter processes these CSS functions:

179

180

```css

181

/* Standard url() functions */

182

.class1 { background: url('./image.jpg'); }

183

.class2 { background: url("../assets/icon.svg"); }

184

.class3 { background: url(./fonts/font.woff2); }

185

186

/* Image-set functions */

187

.responsive {

188

background-image: image-set(

189

url('./img-1x.jpg') 1x,

190

url('./img-2x.jpg') 2x

191

);

192

}

193

194

/* Complex image-set with mixed formats */

195

.modern {

196

background-image: image-set(

197

url('./image.avif') type('image/avif'),

198

url('./image.webp') type('image/webp'),

199

url('./image.jpg') type('image/jpeg')

200

);

201

}

202

```

203

204

### Skipped URLs

205

206

These URL types are not processed:

207

208

```css

209

/* External URLs */

210

.external { background: url('https://example.com/image.jpg'); }

211

.protocol { background: url('//cdn.example.com/icon.svg'); }

212

213

/* Data URLs */

214

.data { background: url('data:image/svg+xml;base64,PHN2Zz48L3N2Zz4='); }

215

216

/* Absolute paths */

217

.absolute { background: url('/static/image.jpg'); }

218

219

/* CSS functions */

220

.gradient { background: linear-gradient(to right, red, blue); }

221

.element { background: element(#myElement); }

222

223

/* Dynamic URLs */

224

.dynamic { background: url(var(--image-url)); }

225

.function { background: url(DYNAMIC_URL('./path')); }

226

```

227

228

### Path Resolution Logic

229

230

The rewriting process transforms paths as follows:

231

232

```typescript

233

// Given:

234

// base: '/project/src/styles'

235

// root: '/project'

236

// CSS: url('./images/hero.jpg')

237

238

// Step 1: Resolve relative to base

239

// '/project/src/styles' + './images/hero.jpg' = '/project/src/styles/images/hero.jpg'

240

241

// Step 2: Make relative to root

242

// path.relative('/project', '/project/src/styles/images/hero.jpg') = 'src/styles/images/hero.jpg'

243

244

// Step 3: Ensure relative path prefix

245

// 'src/styles/images/hero.jpg' -> './src/styles/images/hero.jpg'

246

```

247

248

### Quote Handling

249

250

The rewriter preserves and manages quotes appropriately:

251

252

```css

253

/* Input CSS */

254

.single { background: url('image.jpg'); }

255

.double { background: url("image.jpg"); }

256

.none { background: url(image.jpg); }

257

258

/* Output CSS (quotes preserved/added as needed) */

259

.single { background: url('./path/to/image.jpg'); }

260

.double { background: url("./path/to/image.jpg"); }

261

.none { background: url(./path/to/image.jpg); }

262

263

/* Special characters require quotes */

264

.spaces { background: url("./path with spaces/image.jpg"); }

265

.quotes { background: url("./path/image's.jpg"); }

266

```

267

268

## Advanced Usage

269

270

### Custom Asset Processing

271

272

```typescript

273

import { rewriteUrls } from "@tailwindcss/node";

274

275

// Process CSS with custom asset handling

276

async function processWithAssets(css: string, assetMap: Map<string, string>) {

277

// First rewrite URLs to normalized paths

278

const rewritten = await rewriteUrls({

279

css,

280

base: './src/styles',

281

root: './dist'

282

});

283

284

// Then replace with hashed asset paths

285

let processed = rewritten;

286

assetMap.forEach((hashedPath, originalPath) => {

287

processed = processed.replace(

288

new RegExp(`url\\(['"]?${originalPath}['"]?\\)`, 'g'),

289

`url('${hashedPath}')`

290

);

291

});

292

293

return processed;

294

}

295

296

// Usage with asset hashing

297

const assetMap = new Map([

298

['./assets/hero.jpg', './assets/hero.abc123.jpg'],

299

['./fonts/font.woff2', './fonts/font.def456.woff2']

300

]);

301

302

const processed = await processWithAssets(css, assetMap);

303

```

304

305

### Development vs Production

306

307

```typescript

308

import { rewriteUrls } from "@tailwindcss/node";

309

310

async function processUrls(css: string, isDevelopment: boolean) {

311

if (isDevelopment) {

312

// Development: rewrite for dev server

313

return rewriteUrls({

314

css,

315

base: './src/styles',

316

root: './src'

317

});

318

} else {

319

// Production: rewrite for build output

320

return rewriteUrls({

321

css,

322

base: './src/styles',

323

root: './dist'

324

});

325

}

326

}

327

```

328

329

### Performance Optimization

330

331

```typescript

332

import { rewriteUrls } from "@tailwindcss/node";

333

334

// Skip processing if no URLs detected

335

async function optimizedRewrite(css: string, options: Parameters<typeof rewriteUrls>[0]) {

336

// Quick check to avoid unnecessary processing

337

if (!css.includes('url(') && !css.includes('image-set(')) {

338

return css;

339

}

340

341

return rewriteUrls(options);

342

}

343

344

// Cache processed results

345

const processedCache = new Map<string, string>();

346

347

async function cachedRewrite(css: string, options: Parameters<typeof rewriteUrls>[0]) {

348

const cacheKey = `${css}:${options.base}:${options.root}`;

349

350

if (processedCache.has(cacheKey)) {

351

return processedCache.get(cacheKey)!;

352

}

353

354

const result = await rewriteUrls(options);

355

processedCache.set(cacheKey, result);

356

357

return result;

358

}

359

```

360

361

## Error Handling

362

363

The URL rewriter handles errors gracefully:

364

365

```typescript

366

import { rewriteUrls } from "@tailwindcss/node";

367

368

// Malformed CSS is handled gracefully

369

const malformedCss = `

370

.broken { background: url('unclosed-quote.jpg; }

371

.valid { background: url('./valid.jpg'); }

372

`;

373

374

const result = await rewriteUrls({

375

css: malformedCss,

376

base: './src',

377

root: './dist'

378

});

379

380

// Valid URLs are processed, malformed ones are left unchanged

381

console.log(result);

382

```

383

384

## Browser Compatibility

385

386

The rewritten CSS maintains compatibility with all modern browsers and build tools that consume CSS with `url()` and `image-set()` functions. The output follows standard CSS specifications and works with:

387

388

- All modern browsers (Chrome, Firefox, Safari, Edge)

389

- CSS preprocessors (Sass, Less, Stylus)

390

- PostCSS and other CSS processing tools

391

- Bundlers (Webpack, Vite, Rollup, esbuild)