or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

tessl/npm-loader-runner

Runs webpack loaders programmatically with full context support and dependency tracking

Workspace
tessl
Visibility
Public
Created
Last updated
Describes
npmpkg:npm/loader-runner@4.3.x

To install, run

npx @tessl/cli install tessl/npm-loader-runner@4.3.0

0

# Loader Runner

1

2

Loader Runner is a JavaScript library that provides a runtime execution engine for webpack loaders. It enables programmatic execution of webpack's transformation pipeline outside of webpack itself, offering a complete API for running sequences of loaders against resources with full context support, dependency tracking, and error handling.

3

4

## Package Information

5

6

- **Package Name**: loader-runner

7

- **Package Type**: npm

8

- **Language**: JavaScript

9

- **Installation**: `npm install loader-runner`

10

11

## Core Imports

12

13

```javascript

14

import { runLoaders, getContext } from "loader-runner";

15

```

16

17

For CommonJS:

18

19

```javascript

20

const { runLoaders, getContext } = require("loader-runner");

21

```

22

23

## Basic Usage

24

25

```javascript

26

import { runLoaders } from "loader-runner";

27

import fs from "fs";

28

29

// Execute a simple loader chain

30

runLoaders({

31

resource: "/path/to/source.js",

32

loaders: [

33

"/path/to/babel-loader.js",

34

"/path/to/eslint-loader.js"

35

],

36

context: { minimize: true },

37

readResource: fs.readFile.bind(fs)

38

}, (err, result) => {

39

if (err) {

40

console.error("Loader execution failed:", err);

41

return;

42

}

43

44

console.log("Transformed code:", result.result.toString());

45

console.log("Dependencies:", result.fileDependencies);

46

});

47

```

48

49

## Architecture

50

51

Loader Runner implements webpack's loader execution model with these key components:

52

53

- **Loader Chain Execution**: Manages the two-phase loader execution (pitching and normal phases)

54

- **Context Management**: Provides comprehensive loader context with dependency tracking

55

- **Module Loading**: Handles both CommonJS and ES module loaders with retry logic

56

- **Error Handling**: Robust error handling with proper stack traces and loader isolation

57

- **Dependency Tracking**: Tracks file, context, and missing dependencies for caching systems

58

59

## Capabilities

60

61

### Loader Execution

62

63

Main function to execute sequences of loaders against resources with comprehensive result metadata.

64

65

```javascript { .api }

66

/**

67

* Execute a sequence of loaders against a resource

68

* @param {LoaderOptions} options - Configuration options for loader execution

69

* @param {function} callback - Completion callback with signature (err, result)

70

*/

71

function runLoaders(options, callback);

72

73

interface LoaderOptions {

74

/** Absolute path to the resource file (optionally including query string) */

75

resource?: string;

76

/** Array of loader paths or loader configuration objects */

77

loaders?: (string | LoaderConfig)[];

78

/** Additional loader context used as base context */

79

context?: object;

80

/** Custom function to process the resource */

81

processResource?: (loaderContext: LoaderContext, resourcePath: string, callback: Function) => void;

82

/** Custom function to read the resource (defaults to fs.readFile) */

83

readResource?: (path: string, callback: Function) => void;

84

}

85

86

interface LoaderConfig {

87

/** Absolute path to the loader */

88

loader: string;

89

/** Loader options object */

90

options?: object;

91

/** Loader identifier for option serialization */

92

ident?: string;

93

/** Fragment identifier */

94

fragment?: string;

95

/** Loader type (module or commonjs) */

96

type?: string;

97

}

98

99

interface LoaderResult {

100

/** The transformation result (array of results from loader chain) */

101

result?: any[];

102

/** The raw resource as Buffer (useful for SourceMaps) */

103

resourceBuffer?: Buffer;

104

/** Whether the result is cacheable */

105

cacheable: boolean;

106

/** Array of file paths the result depends on */

107

fileDependencies: string[];

108

/** Array of directory paths the result depends on */

109

contextDependencies: string[];

110

/** Array of missing file paths the result depends on */

111

missingDependencies: string[];

112

}

113

```

114

115

**Usage Examples:**

116

117

```javascript

118

import { runLoaders } from "loader-runner";

119

import fs from "fs";

120

121

// Simple loader execution

122

runLoaders({

123

resource: "/project/src/index.js",

124

loaders: ["/node_modules/babel-loader/lib/index.js"]

125

}, (err, result) => {

126

if (!err) {

127

console.log("Result:", result.result.toString());

128

}

129

});

130

131

// Complex loader chain with options

132

runLoaders({

133

resource: "/project/src/styles.scss?theme=dark",

134

loaders: [

135

{

136

loader: "/node_modules/sass-loader/dist/cjs.js",

137

options: { sourceMap: true }

138

},

139

{

140

loader: "/node_modules/css-loader/dist/cjs.js",

141

options: { modules: true }

142

}

143

],

144

context: {

145

mode: "production",

146

minimize: true

147

},

148

readResource: fs.readFile.bind(fs)

149

}, (err, result) => {

150

if (!err) {

151

console.log("CSS:", result.result.toString());

152

console.log("Dependencies:", result.fileDependencies);

153

console.log("Cacheable:", result.cacheable);

154

}

155

});

156

157

// Custom resource processing

158

runLoaders({

159

resource: "/project/data.json",

160

loaders: ["/custom/json-transformer.js"],

161

processResource: (loaderContext, resourcePath, callback) => {

162

// Custom resource reading logic

163

fs.readFile(resourcePath, 'utf8', (err, data) => {

164

if (err) return callback(err);

165

166

// Add dependency tracking

167

loaderContext.addDependency(resourcePath);

168

169

// Custom processing

170

const processed = JSON.parse(data);

171

callback(null, JSON.stringify(processed, null, 2));

172

});

173

}

174

}, (err, result) => {

175

// Handle result

176

});

177

```

178

179

### Context Utilities

180

181

Utility function to extract directory context from resource paths.

182

183

```javascript { .api }

184

/**

185

* Extract the directory context from a resource path

186

* @param {string} resource - Resource path with optional query and fragment

187

* @returns {string} Directory path of the resource

188

*/

189

function getContext(resource);

190

```

191

192

**Usage Examples:**

193

194

```javascript

195

import { getContext } from "loader-runner";

196

197

// Extract directory from resource path

198

const context = getContext("/project/src/components/Button.jsx?inline");

199

console.log(context); // "/project/src/components"

200

201

// Handle paths with complex queries

202

const context2 = getContext("/assets/image.png?width=200&height=100#section");

203

console.log(context2); // "/assets"

204

205

// Root directory handling

206

const context3 = getContext("/index.js");

207

console.log(context3); // "/"

208

```

209

210

## Loader Context

211

212

The loader context object provided to loaders during execution contains comprehensive information and utilities:

213

214

### Context Properties

215

216

```javascript { .api }

217

interface LoaderContext {

218

/** Directory of the resource being processed */

219

context: string;

220

/** Full resource path with query and fragment */

221

resource: string;

222

/** Path to the resource file */

223

resourcePath: string;

224

/** Query string portion of the resource */

225

resourceQuery: string;

226

/** Fragment portion of the resource */

227

resourceFragment: string;

228

/** Full loader chain request string */

229

request: string;

230

/** Remaining loaders in the chain */

231

remainingRequest: string;

232

/** Current loader and remaining chain */

233

currentRequest: string;

234

/** Previously executed loaders */

235

previousRequest: string;

236

/** Current loader index in the chain */

237

loaderIndex: number;

238

/** Current loader options/query */

239

query: object | string;

240

/** Shared data object for pitch/normal phases */

241

data: object;

242

/** Array of all loaders in the chain */

243

loaders: LoaderObject[];

244

/** Async callback function (null until async() is called) */

245

async: Function | null;

246

/** Callback function (null until async() is called) */

247

callback: Function | null;

248

}

249

```

250

251

### Context Methods

252

253

```javascript { .api }

254

interface LoaderContextMethods {

255

/**

256

* Make loader execution asynchronous

257

* @returns {function} Async callback function

258

*/

259

async(): Function;

260

261

/**

262

* Async callback function for returning results

263

* @param {Error} err - Error if execution failed

264

* @param {*} result - Transformation result

265

* @param {object} sourceMap - Optional source map

266

* @param {object} meta - Optional metadata

267

*/

268

callback(err?: Error, result?: any, sourceMap?: object, meta?: object): void;

269

270

/**

271

* Mark the result as cacheable or non-cacheable

272

* @param {boolean} flag - Cacheable flag (defaults to true)

273

*/

274

cacheable(flag?: boolean): void;

275

276

/**

277

* Add a file dependency for caching

278

* @param {string} file - File path to add as dependency

279

*/

280

addDependency(file: string): void;

281

282

/**

283

* Alias for addDependency (legacy compatibility)

284

* @param {string} file - File path to add as dependency

285

*/

286

dependency(file: string): void;

287

288

/**

289

* Add a directory dependency for caching

290

* @param {string} context - Directory path to watch

291

*/

292

addContextDependency(context: string): void;

293

294

/**

295

* Add a missing file dependency for caching

296

* @param {string} missing - Missing file path

297

*/

298

addMissingDependency(missing: string): void;

299

300

/**

301

* Get current file dependencies

302

* @returns {string[]} Array of file dependencies

303

*/

304

getDependencies(): string[];

305

306

/**

307

* Get current context dependencies

308

* @returns {string[]} Array of context dependencies

309

*/

310

getContextDependencies(): string[];

311

312

/**

313

* Get current missing dependencies

314

* @returns {string[]} Array of missing dependencies

315

*/

316

getMissingDependencies(): string[];

317

318

/**

319

* Clear all dependencies and reset cacheable flag

320

*/

321

clearDependencies(): void;

322

}

323

```

324

325

## Loader Object Structure

326

327

Internal structure representing individual loaders in the execution chain:

328

329

```javascript { .api }

330

interface LoaderObject {

331

/** Absolute path to the loader file */

332

path: string;

333

/** Query string from the loader request */

334

query: string;

335

/** Fragment from the loader request */

336

fragment: string;

337

/** Parsed options object */

338

options: object;

339

/** Loader identifier for options */

340

ident: string;

341

/** Normal phase loader function */

342

normal: Function;

343

/** Pitch phase loader function */

344

pitch: Function;

345

/** Whether loader expects raw Buffer input */

346

raw: boolean;

347

/** Shared data object for pitch/normal communication */

348

data: object;

349

/** Whether pitch phase has been executed */

350

pitchExecuted: boolean;

351

/** Whether normal phase has been executed */

352

normalExecuted: boolean;

353

/** Full loader request string */

354

request: string;

355

/** Loader type (module or commonjs) */

356

type?: string;

357

}

358

```

359

360

## Error Handling

361

362

Loader Runner provides comprehensive error handling with proper error propagation. Errors can occur during loader loading, resource processing, or loader execution:

363

364

**Common Error Scenarios:**

365

366

```javascript

367

runLoaders({

368

resource: "/path/to/file.js",

369

loaders: ["/invalid/loader.js"]

370

}, (err, result) => {

371

if (err) {

372

console.log("Execution error:", err.message);

373

// Errors may include loader loading failures,

374

// resource processing errors, or loader execution errors

375

}

376

});

377

```

378

379

## Advanced Usage

380

381

### Custom Resource Processing

382

383

```javascript

384

runLoaders({

385

resource: "/project/template.html",

386

loaders: ["/custom/template-loader.js"],

387

processResource: (loaderContext, resourcePath, callback) => {

388

// Custom resource processing with caching control

389

loaderContext.addDependency(resourcePath);

390

391

// Custom read logic (e.g., from memory, network, etc.)

392

customReadFunction(resourcePath, (err, content) => {

393

if (err) return callback(err);

394

callback(null, content);

395

});

396

}

397

}, callback);

398

```

399

400

### Loader Chain Optimization

401

402

```javascript

403

// Conditional loader application

404

const loaders = [];

405

if (process.env.NODE_ENV === 'development') {

406

loaders.push('/dev/source-map-loader.js');

407

}

408

loaders.push('/transpiler/babel-loader.js');

409

410

runLoaders({

411

resource: "/src/app.js",

412

loaders: loaders,

413

context: { mode: process.env.NODE_ENV }

414

}, callback);

415

```

416

417

### Dependency Management

418

419

```javascript

420

runLoaders(options, (err, result) => {

421

if (!err && result) {

422

// Use dependency information for build optimization

423

console.log("Watch these files:", result.fileDependencies);

424

console.log("Watch these directories:", result.contextDependencies);

425

console.log("Cache valid:", result.cacheable);

426

427

// Implement custom caching based on dependencies

428

if (result.cacheable) {

429

cache.set(cacheKey, result.result, result.fileDependencies);

430

}

431

}

432

});

433

```