or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

application-management.mdapplication-status-lifecycle.mdconfiguration-timeouts.mderror-handling.mdindex.mdnavigation-routing.mdparcels-system.md

application-status-lifecycle.mddocs/

0

# Application Status & Lifecycle

1

2

Status constants and utilities for monitoring application states and lifecycle management.

3

4

## Capabilities

5

6

### Application Status Constants

7

8

Single-spa defines status constants that represent different states in an application's lifecycle.

9

10

```javascript { .api }

11

// Application loading states

12

const NOT_LOADED = "NOT_LOADED";

13

const LOADING_SOURCE_CODE = "LOADING_SOURCE_CODE";

14

const LOAD_ERROR = "LOAD_ERROR";

15

16

// Application lifecycle states

17

const NOT_BOOTSTRAPPED = "NOT_BOOTSTRAPPED";

18

const BOOTSTRAPPING = "BOOTSTRAPPING";

19

const NOT_MOUNTED = "NOT_MOUNTED";

20

const MOUNTING = "MOUNTING";

21

const MOUNTED = "MOUNTED";

22

const UNMOUNTING = "UNMOUNTING";

23

const UNLOADING = "UNLOADING";

24

25

// Error states

26

const SKIP_BECAUSE_BROKEN = "SKIP_BECAUSE_BROKEN";

27

```

28

29

**Usage Examples:**

30

31

```javascript

32

import {

33

getAppStatus,

34

MOUNTED,

35

NOT_LOADED,

36

SKIP_BECAUSE_BROKEN

37

} from "single-spa";

38

39

function checkApplicationHealth() {

40

const apps = ["navbar", "products", "dashboard"];

41

42

apps.forEach(appName => {

43

const status = getAppStatus(appName);

44

switch (status) {

45

case MOUNTED:

46

console.log(`${appName} is running normally`);

47

break;

48

case NOT_LOADED:

49

console.log(`${appName} hasn't been loaded yet`);

50

break;

51

case SKIP_BECAUSE_BROKEN:

52

console.error(`${appName} is broken and being skipped`);

53

break;

54

default:

55

console.log(`${appName} status: ${status}`);

56

}

57

});

58

}

59

```

60

61

### Get Application Status

62

63

Gets the current lifecycle status of a specific application.

64

65

```javascript { .api }

66

/**

67

* Get the current status of an application

68

* @param appName - Name of the application

69

* @returns Current status string or null if application not found

70

*/

71

function getAppStatus(appName: string): string | null;

72

```

73

74

**Usage Examples:**

75

76

```javascript

77

import { getAppStatus, MOUNTED, MOUNTING } from "single-spa";

78

79

// Check if application is ready

80

function isAppReady(appName) {

81

const status = getAppStatus(appName);

82

return status === MOUNTED;

83

}

84

85

// Wait for application to be mounted

86

async function waitForAppToMount(appName, timeout = 5000) {

87

const startTime = Date.now();

88

89

while (Date.now() - startTime < timeout) {

90

const status = getAppStatus(appName);

91

if (status === MOUNTED) {

92

return true;

93

}

94

if (status === MOUNTING) {

95

await new Promise(resolve => setTimeout(resolve, 100));

96

continue;

97

}

98

throw new Error(`App ${appName} failed to mount (status: ${status})`);

99

}

100

101

throw new Error(`Timeout waiting for ${appName} to mount`);

102

}

103

```

104

105

### Get Mounted Applications

106

107

Returns an array of currently mounted application names.

108

109

```javascript { .api }

110

/**

111

* Get names of currently mounted applications

112

* @returns Array of mounted application names

113

*/

114

function getMountedApps(): string[];

115

```

116

117

**Usage Examples:**

118

119

```javascript

120

import { getMountedApps } from "single-spa";

121

122

// Monitor currently active applications

123

function logActiveApplications() {

124

const mounted = getMountedApps();

125

console.log(`Currently active: ${mounted.join(", ")}`);

126

}

127

128

// Check if specific app is mounted

129

function isAppMounted(appName) {

130

return getMountedApps().includes(appName);

131

}

132

133

// Performance monitoring

134

function trackApplicationUsage() {

135

const mountedApps = getMountedApps();

136

analytics.track("applications_active", {

137

count: mountedApps.length,

138

apps: mountedApps

139

});

140

}

141

```

142

143

## Lifecycle Hooks and Monitoring

144

145

### Application Lifecycle Events

146

147

Monitor application lifecycle changes using custom events:

148

149

```javascript

150

// Listen for application status changes

151

window.addEventListener("single-spa:app-change", (event) => {

152

const {

153

newAppStatuses,

154

appsByNewStatus,

155

totalAppChanges

156

} = event.detail;

157

158

console.log("Application status changes:", newAppStatuses);

159

console.log("Apps by status:", appsByNewStatus);

160

});

161

162

// Listen for routing events that trigger app changes

163

window.addEventListener("single-spa:routing-event", (event) => {

164

console.log("Navigation event:", event.detail);

165

});

166

```

167

168

### Status Monitoring Utilities

169

170

```javascript

171

import {

172

getAppStatus,

173

getMountedApps,

174

getAppNames,

175

MOUNTED,

176

SKIP_BECAUSE_BROKEN

177

} from "single-spa";

178

179

// Create a status dashboard

180

function createStatusDashboard() {

181

const allApps = getAppNames();

182

const mountedApps = getMountedApps();

183

184

const statusReport = allApps.map(appName => ({

185

name: appName,

186

status: getAppStatus(appName),

187

isMounted: mountedApps.includes(appName)

188

}));

189

190

return statusReport;

191

}

192

193

// Health check function

194

function performHealthCheck() {

195

const allApps = getAppNames();

196

const brokenApps = allApps.filter(appName =>

197

getAppStatus(appName) === SKIP_BECAUSE_BROKEN

198

);

199

200

if (brokenApps.length > 0) {

201

console.error("Broken applications detected:", brokenApps);

202

// Trigger alerts or recovery procedures

203

}

204

205

return {

206

healthy: allApps.length - brokenApps.length,

207

broken: brokenApps.length,

208

total: allApps.length

209

};

210

}

211

```

212

213

### Lifecycle State Machine

214

215

Understanding the application lifecycle flow:

216

217

```

218

NOT_LOADED

219

↓ (when activeWhen returns true)

220

LOADING_SOURCE_CODE

221

↓ (app loaded successfully)

222

NOT_BOOTSTRAPPED

223

↓ (bootstrap called)

224

BOOTSTRAPPING

225

↓ (bootstrap complete)

226

NOT_MOUNTED

227

↓ (mount called)

228

MOUNTING

229

↓ (mount complete)

230

MOUNTED

231

↓ (update called - optional, internal state not exported)

232

UPDATING (internal)

233

↓ (update complete)

234

MOUNTED

235

↓ (when activeWhen returns false)

236

UNMOUNTING

237

↓ (unmount complete)

238

NOT_MOUNTED

239

↓ (unload called - optional)

240

UNLOADING

241

↓ (unload complete)

242

NOT_LOADED

243

244

// Error states can occur at any point:

245

LOAD_ERROR (if loading fails)

246

SKIP_BECAUSE_BROKEN (if any lifecycle fails)

247

```

248

249

### Advanced Status Patterns

250

251

```javascript

252

import { getAppStatus, addErrorHandler } from "single-spa";

253

254

// Retry mechanism for failed applications

255

class ApplicationManager {

256

constructor() {

257

this.retryAttempts = new Map();

258

this.maxRetries = 3;

259

}

260

261

async retryFailedApp(appName) {

262

const attempts = this.retryAttempts.get(appName) || 0;

263

264

if (attempts >= this.maxRetries) {

265

console.error(`Max retries exceeded for ${appName}`);

266

return false;

267

}

268

269

this.retryAttempts.set(appName, attempts + 1);

270

271

try {

272

// Trigger app reload/remount logic

273

await triggerAppChange();

274

275

// Check if app recovered

276

const status = getAppStatus(appName);

277

if (status === MOUNTED) {

278

this.retryAttempts.delete(appName);

279

return true;

280

}

281

} catch (error) {

282

console.error(`Retry failed for ${appName}:`, error);

283

}

284

285

return false;

286

}

287

}

288

289

// Circuit breaker pattern

290

class ApplicationCircuitBreaker {

291

constructor(appName, threshold = 5) {

292

this.appName = appName;

293

this.threshold = threshold;

294

this.failures = 0;

295

this.isOpen = false;

296

this.lastFailure = null;

297

}

298

299

recordSuccess() {

300

this.failures = 0;

301

this.isOpen = false;

302

}

303

304

recordFailure() {

305

this.failures++;

306

this.lastFailure = Date.now();

307

308

if (this.failures >= this.threshold) {

309

this.isOpen = true;

310

console.warn(`Circuit breaker opened for ${this.appName}`);

311

}

312

}

313

314

canProceed() {

315

if (!this.isOpen) return true;

316

317

// Check if enough time has passed to try again

318

const timeSinceLastFailure = Date.now() - this.lastFailure;

319

return timeSinceLastFailure > 60000; // 1 minute cooldown

320

}

321

}

322

```

323

324

## Types

325

326

```javascript { .api }

327

interface SingleSpaCustomEventDetail {

328

newAppStatuses: SingleSpaNewAppStatus;

329

appsByNewStatus: SingleSpaAppsByNewStatus;

330

totalAppChanges: number;

331

originalEvent?: Event;

332

oldUrl: string;

333

newUrl: string;

334

navigationIsCanceled: boolean;

335

cancelNavigation?: () => void;

336

}

337

338

interface SingleSpaNewAppStatus {

339

[appName: string]: "MOUNTED" | "NOT_MOUNTED" | "NOT_LOADED" | "SKIP_BECAUSE_BROKEN";

340

}

341

342

interface SingleSpaAppsByNewStatus {

343

MOUNTED: string[];

344

NOT_MOUNTED: string[];

345

NOT_LOADED: string[];

346

SKIP_BECAUSE_BROKEN: string[];

347

}

348

```