or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

compilation.mdcomponent-factory.mdcomponent-registration.mdindex.mdmounting-lifecycle.mdplugin-system.mdpure-components.mdutilities.md

plugin-system.mddocs/

0

# Plugin System

1

2

Component enhancement system for adding cross-cutting functionality to all components. Plugins are functions that receive component instances and can modify their behavior, add methods, or enhance functionality.

3

4

## Capabilities

5

6

### Install Plugin

7

8

Installs a plugin that will be applied to all component instances.

9

10

```typescript { .api }

11

/**

12

* Define a riot plugin

13

* @param plugin - Function that receives and enhances component instances

14

* @returns Set containing all installed plugins

15

*/

16

function install(plugin: ComponentEnhancer): InstalledPluginsSet;

17

```

18

19

**Usage Example:**

20

21

```javascript

22

import { install } from "riot";

23

24

// Create a plugin that adds logging to components

25

const loggingPlugin = (component) => {

26

const originalMount = component.mount;

27

const originalUnmount = component.unmount;

28

29

component.mount = function(...args) {

30

console.log(`Mounting component: ${this.name || 'unnamed'}`);

31

return originalMount.apply(this, args);

32

};

33

34

component.unmount = function(...args) {

35

console.log(`Unmounting component: ${this.name || 'unnamed'}`);

36

return originalUnmount.apply(this, args);

37

};

38

39

return component;

40

};

41

42

// Install the plugin

43

install(loggingPlugin);

44

```

45

46

### Uninstall Plugin

47

48

Removes a previously installed plugin from the system.

49

50

```typescript { .api }

51

/**

52

* Uninstall a riot plugin

53

* @param plugin - Plugin function to remove

54

* @returns Set containing remaining installed plugins

55

*/

56

function uninstall(plugin: ComponentEnhancer): InstalledPluginsSet;

57

```

58

59

**Usage Example:**

60

61

```javascript

62

import { uninstall } from "riot";

63

64

// Remove the logging plugin

65

uninstall(loggingPlugin);

66

```

67

68

## Plugin Development

69

70

### Component Enhancer Function

71

72

Plugins are functions that receive a component instance and return the enhanced component:

73

74

```typescript { .api }

75

type ComponentEnhancer = <Props extends DefaultProps, State extends DefaultState>(

76

component: RiotComponent<Props, State>

77

) => RiotComponent<Props, State>;

78

```

79

80

### Plugin Patterns

81

82

**Method Enhancement Plugin:**

83

84

```javascript

85

const methodEnhancementPlugin = (component) => {

86

// Add a new method to all components

87

component.addClass = function(className) {

88

this.root.classList.add(className);

89

return this;

90

};

91

92

component.removeClass = function(className) {

93

this.root.classList.remove(className);

94

return this;

95

};

96

97

return component;

98

};

99

100

install(methodEnhancementPlugin);

101

```

102

103

**State Management Plugin:**

104

105

```javascript

106

const stateHistoryPlugin = (component) => {

107

const stateHistory = [];

108

const originalUpdate = component.update;

109

110

component.update = function(newState, ...args) {

111

// Store previous state

112

stateHistory.push({ ...this.state });

113

114

// Add undo functionality

115

this.undo = () => {

116

if (stateHistory.length > 0) {

117

const previousState = stateHistory.pop();

118

return originalUpdate.call(this, previousState, ...args);

119

}

120

};

121

122

return originalUpdate.call(this, newState, ...args);

123

};

124

125

return component;

126

};

127

128

install(stateHistoryPlugin);

129

```

130

131

**Event Plugin:**

132

133

```javascript

134

const eventEmitterPlugin = (component) => {

135

const listeners = new Map();

136

137

component.on = function(event, callback) {

138

if (!listeners.has(event)) {

139

listeners.set(event, []);

140

}

141

listeners.get(event).push(callback);

142

return this;

143

};

144

145

component.emit = function(event, ...args) {

146

if (listeners.has(event)) {

147

listeners.get(event).forEach(callback => callback(...args));

148

}

149

return this;

150

};

151

152

component.off = function(event, callback) {

153

if (listeners.has(event)) {

154

const eventListeners = listeners.get(event);

155

const index = eventListeners.indexOf(callback);

156

if (index > -1) {

157

eventListeners.splice(index, 1);

158

}

159

}

160

return this;

161

};

162

163

return component;

164

};

165

166

install(eventEmitterPlugin);

167

```

168

169

### Plugin Best Practices

170

171

1. **Always return the component** - Plugins must return the component instance

172

2. **Preserve original methods** - Store references to original methods before overriding

173

3. **Use proper `this` binding** - Use arrow functions or `.call()/.apply()` for method context

174

4. **Handle cleanup** - Add cleanup logic in `onUnmounted` if needed

175

5. **Check for existing functionality** - Test if methods/properties already exist before adding

176

177

**Robust Plugin Example:**

178

179

```javascript

180

const robustPlugin = (component) => {

181

// Only add functionality if it doesn't exist

182

if (!component.customMethod) {

183

component.customMethod = function() {

184

console.log("Custom functionality");

185

return this;

186

};

187

}

188

189

// Enhance existing lifecycle method safely

190

const originalOnUnmounted = component.onUnmounted;

191

component.onUnmounted = function(...args) {

192

// Plugin cleanup logic

193

console.log("Plugin cleanup");

194

195

// Call original if it exists

196

if (originalOnUnmounted) {

197

return originalOnUnmounted.apply(this, args);

198

}

199

};

200

201

return component;

202

};

203

```

204

205

## Error Handling

206

207

Plugins are validated when installed:

208

209

```javascript

210

import { install } from "riot";

211

212

// These will throw errors:

213

install("not a function"); // Error: Plugins must be of type function

214

install(loggingPlugin); // First install succeeds

215

install(loggingPlugin); // Error: This plugin was already installed

216

217

// These will throw errors when uninstalling:

218

uninstall(notInstalledPlugin); // Error: This plugin was never installed

219

```

220

221

## Types

222

223

```typescript { .api }

224

type ComponentEnhancer = <

225

Props extends DefaultProps,

226

State extends DefaultState

227

>(

228

component: RiotComponent<Props, State>

229

) => RiotComponent<Props, State>;

230

231

type InstalledPluginsSet = Set<ComponentEnhancer>;

232

233

type DefaultProps = Record<PropertyKey, any>;

234

type DefaultState = Record<PropertyKey, any>;

235

```