or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

component-resolution.mdindex.mdnuxt-integration.mdplugin-configuration.mdtypescript-integration.mdui-library-resolvers.md

component-resolution.mddocs/

0

# Component Resolution

1

2

Built-in component discovery from directories and extensible resolver system for UI libraries, with support for custom resolution logic and namespace management.

3

4

## Capabilities

5

6

### Component Discovery

7

8

Automatic component discovery from configured directories with flexible naming and namespace support.

9

10

```typescript { .api }

11

/**

12

* Component discovery configuration

13

*/

14

interface ComponentDiscoveryOptions {

15

/** Directories to search for components */

16

dirs?: string | string[];

17

/** File extensions to consider as components */

18

extensions?: string | string[];

19

/** Search subdirectories recursively */

20

deep?: boolean;

21

/** Use directory structure as component namespaces */

22

directoryAsNamespace?: boolean;

23

/** Component name prefix */

24

prefix?: string;

25

}

26

```

27

28

**Usage Examples:**

29

30

```typescript

31

// Basic directory discovery

32

Components({

33

dirs: ["src/components"],

34

extensions: ["vue", "tsx"],

35

deep: true,

36

});

37

38

// With namespacing

39

Components({

40

dirs: ["src/components"],

41

directoryAsNamespace: true,

42

// src/components/form/Input.vue becomes <FormInput>

43

});

44

```

45

46

### Custom Resolvers

47

48

Extensible resolver system for custom component resolution logic, supporting both function-based and object-based resolvers.

49

50

```typescript { .api }

51

/**

52

* Function-based component resolver

53

* @param name - Component name to resolve

54

* @returns Component resolution result

55

*/

56

type ComponentResolverFunction = (name: string) => ComponentResolveResult;

57

58

/**

59

* Object-based component resolver with type specification

60

*/

61

interface ComponentResolverObject {

62

/** Type of items this resolver handles */

63

type: "component" | "directive";

64

/** Resolution function */

65

resolve: ComponentResolverFunction;

66

}

67

68

/**

69

* Union type for all resolver types

70

*/

71

type ComponentResolver = ComponentResolverFunction | ComponentResolverObject;

72

73

/**

74

* Result of component resolution

75

*/

76

type ComponentResolveResult = Awaitable<string | ComponentInfo | null | undefined | void>;

77

78

/**

79

* Component information returned by resolvers

80

*/

81

interface ComponentInfo {

82

/** Import alias name */

83

as?: string;

84

/** Component name */

85

name?: string;

86

/** Import path or module name */

87

from: string;

88

/** Side effect imports (CSS, etc.) */

89

sideEffects?: SideEffectsInfo;

90

}

91

92

type SideEffectsInfo = (ImportInfo | string)[] | ImportInfo | string | undefined;

93

94

interface ImportInfo {

95

as?: string;

96

name?: string;

97

from: string;

98

}

99

```

100

101

**Usage Examples:**

102

103

```typescript

104

// Function-based resolver

105

Components({

106

resolvers: [

107

(name: string) => {

108

if (name.startsWith("My")) {

109

return {

110

name,

111

from: `@/components/${name}.vue`,

112

};

113

}

114

},

115

],

116

});

117

118

// Object-based resolver with type

119

Components({

120

resolvers: [

121

{

122

type: "component",

123

resolve: (name: string) => {

124

if (name.match(/^V[A-Z]/)) {

125

return {

126

name,

127

from: "vuetify/components",

128

sideEffects: "vuetify/styles",

129

};

130

}

131

},

132

},

133

],

134

});

135

```

136

137

### Resolver Chaining

138

139

Multiple resolvers can be configured and will be called in order until one returns a result.

140

141

```typescript { .api }

142

/**

143

* Multiple resolvers are processed in order

144

*/

145

interface ResolverChainOptions {

146

resolvers?: ComponentResolver[];

147

}

148

```

149

150

**Usage Examples:**

151

152

```typescript

153

Components({

154

resolvers: [

155

// First try UI library resolvers

156

ElementPlusResolver(),

157

AntDesignVueResolver(),

158

159

// Then custom business logic

160

(name: string) => {

161

if (name.startsWith("App")) {

162

return { name, from: `@/components/app/${name}.vue` };

163

}

164

},

165

166

// Finally fallback resolver

167

(name: string) => {

168

return { name, from: `@/components/fallback/${name}.vue` };

169

},

170

],

171

});

172

```

173

174

### Advanced Resolution Features

175

176

Advanced features for complex resolution scenarios including conditional resolution and dynamic imports.

177

178

```typescript { .api }

179

/**

180

* Advanced resolver with conditional logic

181

*/

182

interface AdvancedResolverResult {

183

/** Component name override */

184

name?: string;

185

/** Import source */

186

from: string;

187

/** Import alias */

188

as?: string;

189

/** Side effects to import */

190

sideEffects?: SideEffectsInfo;

191

}

192

```

193

194

**Usage Examples:**

195

196

```typescript

197

// Conditional resolution based on environment

198

Components({

199

resolvers: [

200

(name: string) => {

201

// Use different components for different environments

202

if (name === "DataGrid") {

203

const isDev = process.env.NODE_ENV === "development";

204

return {

205

name,

206

from: isDev ? "@/components/dev/DataGrid.vue" : "@/components/prod/DataGrid.vue",

207

};

208

}

209

},

210

],

211

});

212

213

// Dynamic resolution with side effects

214

Components({

215

resolvers: [

216

(name: string) => {

217

if (name.startsWith("Chart")) {

218

return {

219

name,

220

from: "chart-library",

221

sideEffects: [

222

"chart-library/styles/index.css",

223

{ from: "chart-library/themes", name: "defaultTheme" },

224

],

225

};

226

}

227

},

228

],

229

});

230

```

231

232

### Resolution Context

233

234

Access to resolution context for advanced use cases.

235

236

```typescript { .api }

237

/**

238

* Extended resolver function with context

239

*/

240

type ContextualResolverFunction = (

241

name: string,

242

context?: ResolutionContext

243

) => ComponentResolveResult;

244

245

interface ResolutionContext {

246

/** File path where component is being used */

247

filename?: string;

248

/** Additional context information */

249

[key: string]: any;

250

}

251

```

252

253

**Usage Examples:**

254

255

```typescript

256

// Context-aware resolution

257

Components({

258

resolvers: [

259

(name: string, context?: ResolutionContext) => {

260

if (context?.filename?.includes("/admin/")) {

261

// Use admin-specific components

262

return { name, from: `@/components/admin/${name}.vue` };

263

}

264

return { name, from: `@/components/public/${name}.vue` };

265

},

266

],

267

});

268

```

269

270

### Built-in Utilities

271

272

Utility functions commonly used in custom resolvers.

273

274

```typescript { .api }

275

/**

276

* String case conversion utilities

277

*/

278

function camelCase(str: string): string;

279

function kebabCase(str: string): string;

280

function pascalCase(str: string): string;

281

```

282

283

**Usage Examples:**

284

285

```typescript

286

import { camelCase, kebabCase, pascalCase } from "unplugin-vue-components";

287

288

Components({

289

resolvers: [

290

(name: string) => {

291

// Convert PascalCase component name to kebab-case file name

292

const fileName = kebabCase(name);

293

return {

294

name,

295

from: `@/components/${fileName}.vue`,

296

};

297

},

298

],

299

});

300

```

301

302

### Component Name Patterns

303

304

Common patterns for component name resolution and transformation.

305

306

**Usage Examples:**

307

308

```typescript

309

// Prefix-based resolution

310

Components({

311

resolvers: [

312

(name: string) => {

313

// Handle prefixed components: AppButton -> app/Button.vue

314

const match = name.match(/^App(.+)$/);

315

if (match) {

316

return {

317

name,

318

from: `@/components/app/${match[1]}.vue`,

319

};

320

}

321

},

322

],

323

});

324

325

// Namespace-based resolution

326

Components({

327

resolvers: [

328

(name: string) => {

329

// Handle namespaced components: FormInput -> form/Input.vue

330

const parts = name.match(/^([A-Z][a-z]+)([A-Z].+)$/);

331

if (parts) {

332

const [, namespace, component] = parts;

333

return {

334

name,

335

from: `@/components/${namespace.toLowerCase()}/${component}.vue`,

336

};

337

}

338

},

339

],

340

});

341

```

342

343

### Error Handling

344

345

Proper error handling in custom resolvers.

346

347

**Usage Examples:**

348

349

```typescript

350

Components({

351

resolvers: [

352

(name: string) => {

353

try {

354

// Custom resolution logic that might fail

355

if (name.startsWith("External")) {

356

const moduleName = name.replace("External", "").toLowerCase();

357

// Validate module exists

358

require.resolve(`external-components/${moduleName}`);

359

return {

360

name,

361

from: `external-components/${moduleName}`,

362

};

363

}

364

} catch (error) {

365

// Silently fail - let other resolvers handle it

366

return null;

367

}

368

},

369

],

370

});

371

```