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

module-analysis.mddocs/

0

# Module Dependency Analysis

1

2

Recursive module dependency analysis with support for TypeScript, ESM, and CommonJS import patterns. Provides comprehensive dependency tracking for hot module reloading and build optimization.

3

4

## Capabilities

5

6

### Get Module Dependencies Function

7

8

Recursively analyzes module dependencies and returns all file paths.

9

10

```typescript { .api }

11

/**

12

* Recursively traces all dependencies of a module

13

* Returns an unordered set of absolute file paths

14

* @param absoluteFilePath - Absolute path to the entry module file

15

* @returns Promise resolving to array of absolute dependency file paths

16

*/

17

function getModuleDependencies(absoluteFilePath: string): Promise<string[]>;

18

```

19

20

**Usage Examples:**

21

22

```typescript

23

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

24

import path from "path";

25

26

// Analyze a TypeScript module

27

const entryFile = path.resolve(process.cwd(), "src/index.ts");

28

const dependencies = await getModuleDependencies(entryFile);

29

30

console.log("Dependencies:", dependencies);

31

// Output: [

32

// "/path/to/project/src/index.ts",

33

// "/path/to/project/src/utils/helpers.ts",

34

// "/path/to/project/src/components/Button.tsx",

35

// "/path/to/project/src/types/index.ts"

36

// ]

37

38

// Analyze a JavaScript module

39

const jsFile = path.resolve(process.cwd(), "config/webpack.config.js");

40

const jsDependencies = await getModuleDependencies(jsFile);

41

42

console.log("JS Dependencies:", jsDependencies);

43

```

44

45

### Hot Module Reloading Integration

46

47

Use dependency analysis for hot module reloading setup:

48

49

```typescript

50

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

51

import { watch } from "chokidar";

52

53

async function setupHMR(entryFile: string) {

54

// Get all dependencies

55

const dependencies = await getModuleDependencies(entryFile);

56

57

// Watch all dependency files

58

const watcher = watch(dependencies, {

59

ignoreInitial: true

60

});

61

62

watcher.on('change', async (changedFile) => {

63

console.log(`File changed: ${changedFile}`);

64

65

// Re-analyze dependencies in case new ones were added

66

const newDependencies = await getModuleDependencies(entryFile);

67

68

// Update watcher with new dependencies

69

const newFiles = newDependencies.filter(file => !dependencies.includes(file));

70

if (newFiles.length > 0) {

71

watcher.add(newFiles);

72

dependencies.push(...newFiles);

73

}

74

75

// Trigger rebuild

76

await rebuild();

77

});

78

79

return watcher;

80

}

81

82

// Usage

83

const watcher = await setupHMR("./src/index.ts");

84

```

85

86

### Build Tool Integration

87

88

Integration with build tools for dependency tracking:

89

90

```typescript

91

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

92

93

// Webpack plugin example

94

class DependencyTrackingPlugin {

95

apply(compiler: any) {

96

compiler.hooks.compilation.tap('DependencyTrackingPlugin', (compilation: any) => {

97

compilation.hooks.buildModule.tapAsync('DependencyTrackingPlugin',

98

async (module: any, callback: Function) => {

99

if (module.resource) {

100

try {

101

const dependencies = await getModuleDependencies(module.resource);

102

103

// Add dependencies to webpack's dependency graph

104

dependencies.forEach(dep => {

105

if (dep !== module.resource) {

106

module.addDependency(createDependency(dep));

107

}

108

});

109

} catch (error) {

110

console.warn(`Failed to analyze dependencies for ${module.resource}:`, error);

111

}

112

}

113

callback();

114

}

115

);

116

});

117

}

118

}

119

```

120

121

### Bundle Analysis

122

123

Use for bundle analysis and optimization:

124

125

```typescript

126

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

127

import fs from "fs/promises";

128

129

async function analyzeBundleSize(entryPoints: string[]) {

130

const bundleAnalysis = new Map<string, {

131

size: number;

132

dependencies: string[];

133

}>();

134

135

for (const entry of entryPoints) {

136

const dependencies = await getModuleDependencies(entry);

137

138

let totalSize = 0;

139

for (const dep of dependencies) {

140

try {

141

const stats = await fs.stat(dep);

142

totalSize += stats.size;

143

} catch (error) {

144

console.warn(`Could not stat file: ${dep}`);

145

}

146

}

147

148

bundleAnalysis.set(entry, {

149

size: totalSize,

150

dependencies

151

});

152

}

153

154

return bundleAnalysis;

155

}

156

157

// Usage

158

const analysis = await analyzeBundleSize([

159

"./src/app.ts",

160

"./src/worker.ts"

161

]);

162

163

analysis.forEach((info, entry) => {

164

console.log(`${entry}: ${info.size} bytes, ${info.dependencies.length} files`);

165

});

166

```

167

168

## Supported Import Patterns

169

170

The dependency analysis recognizes various import and require patterns:

171

172

### ESM Imports

173

174

```typescript

175

// Named imports

176

import { foo, bar } from './utils';

177

import { default as utils } from './utils';

178

179

// Default imports

180

import utils from './utils';

181

import * as utils from './utils';

182

183

// Side-effect imports

184

import './polyfills';

185

186

// Dynamic imports (string literals only)

187

const module = await import('./dynamic');

188

```

189

190

### CommonJS Requires

191

192

```javascript

193

// Basic require

194

const utils = require('./utils');

195

const { foo, bar } = require('./utils');

196

197

// Conditional requires (string literals)

198

if (condition) {

199

const optional = require('./optional');

200

}

201

```

202

203

### Export Statements

204

205

```typescript

206

// Re-exports

207

export { foo } from './foo';

208

export * from './bar';

209

export { default } from './baz';

210

211

// Named exports with re-export

212

export { foo as publicFoo } from './internal';

213

```

214

215

## Resolution Strategy

216

217

The module resolution follows Node.js conventions with TypeScript support:

218

219

### Extension Priority

220

221

For **JavaScript files** (`.js`, `.cjs`, `.mjs`):

222

1. No extension

223

2. `.js`

224

3. `.cjs`

225

4. `.mjs`

226

5. `.ts`

227

6. `.cts`

228

7. `.mts`

229

8. `.jsx`

230

9. `.tsx`

231

232

For **TypeScript files** (`.ts`, `.cts`, `.mts`, `.tsx`):

233

1. No extension

234

2. `.ts`

235

3. `.cts`

236

4. `.mts`

237

5. `.tsx`

238

6. `.js`

239

7. `.cjs`

240

8. `.mjs`

241

9. `.jsx`

242

243

### Directory Resolution

244

245

```typescript

246

// For import './components'

247

// Tries in order:

248

// 1. ./components.ts (or appropriate extension)

249

// 2. ./components/index.ts

250

// 3. ./components/index.js

251

// etc.

252

```

253

254

## Performance Considerations

255

256

### Circular Dependency Handling

257

258

```typescript

259

// The function handles circular dependencies gracefully

260

// Example: A.ts imports B.ts, B.ts imports A.ts

261

262

const dependencies = await getModuleDependencies("A.ts");

263

// Returns: ["A.ts", "B.ts"] (both files, no infinite loop)

264

```

265

266

### Caching Strategy

267

268

```typescript

269

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

270

271

// For performance, implement your own caching layer

272

const dependencyCache = new Map<string, string[]>();

273

274

async function getCachedDependencies(filePath: string): Promise<string[]> {

275

if (dependencyCache.has(filePath)) {

276

return dependencyCache.get(filePath)!;

277

}

278

279

const dependencies = await getModuleDependencies(filePath);

280

dependencyCache.set(filePath, dependencies);

281

282

return dependencies;

283

}

284

285

// Invalidate cache when files change

286

function invalidateCache(filePath: string) {

287

dependencyCache.delete(filePath);

288

}

289

```

290

291

### Parallel Analysis

292

293

```typescript

294

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

295

296

// Analyze multiple entry points in parallel

297

async function analyzeMultipleEntries(entryPoints: string[]) {

298

const results = await Promise.all(

299

entryPoints.map(async (entry) => ({

300

entry,

301

dependencies: await getModuleDependencies(entry)

302

}))

303

);

304

305

return results;

306

}

307

308

const analysis = await analyzeMultipleEntries([

309

"./src/client.ts",

310

"./src/server.ts",

311

"./src/worker.ts"

312

]);

313

```

314

315

## Error Handling

316

317

The function handles various error conditions gracefully:

318

319

```typescript

320

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

321

322

try {

323

const dependencies = await getModuleDependencies("./nonexistent.ts");

324

} catch (error) {

325

console.error("Analysis failed:", error.message);

326

// File may not exist or may have unresolvable dependencies

327

}

328

329

// Missing dependencies are silently skipped

330

const dependencies = await getModuleDependencies("./file-with-missing-deps.ts");

331

// Returns dependencies that could be resolved, skips missing ones

332

```

333

334

## Limitations

335

336

- Only analyzes **relative imports** (starting with `./` or `../`)

337

- Does not resolve **node_modules** dependencies

338

- **Dynamic imports** with variables are not analyzed

339

- **Conditional requires** with dynamic paths are skipped

340

- **Webpack-style** imports (`require.context`) are not supported