> For the complete documentation index, see [llms.txt](https://docs.devolutions.net/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.devolutions.net/powershell-universal/fr/applis/components/custom-components/building-custom-components.md).

# Créer des composants JavaScript personnalisés

Créez des composants JavaScript et React personnalisés pour les applis PowerShell Universal, en couvrant le regroupement Webpack, l'enregistrement des composants, les props et le dépannage.

Universal est extensible et vous pouvez créer des composants et des cadres JavaScript personnalisés. Ce document explique comment créer des composants personnalisés qui s'intègrent à la plateforme d'applis Universal.

{% hint style="warning" %}
Il s'agit d'un sujet avancé qui n'est pas nécessaire si vous souhaitez simplement utiliser les applis Universal.
{% endhint %}

{% hint style="info" %}
Pour un exemple complet et fonctionnel, consultez le projet [ud-mermaid](https://github.com/ironmansoftware/ud-mermaid) sur GitHub. Il s'agit d'un composant personnalisé prêt pour la production qui intègre la bibliothèque de diagrammes Mermaid à PowerShell Universal.
{% endhint %}

## Survol

La création d'un composant React personnalisé pour PowerShell Universal implique plusieurs éléments clés :

1. **Structure du projet** : un projet Node.js avec Webpack pour regrouper les composants React
2. **Composant React (JSX)** : le composant React qui affiche votre interface utilisateur
3. **Module PowerShell (PSM1)** : des fonctions PowerShell qui créent des définitions de composants
4. **Manifeste de module (PSD1)** : métadonnées standards de module PowerShell
5. **Processus de génération** : configuration Webpack pour regrouper les actifs JavaScript
6. **Enregistrement du composant** : enregistrement de votre composant auprès de Universal Dashboard

### Fonctionnement

L'intégration entre PowerShell et React fonctionne comme suit :

1. **Côté PowerShell** : votre fonction PowerShell retourne une table de hachage contenant les propriétés du composant
2. **Enregistrement de l'actif** : le JavaScript regroupé est enregistré auprès du AssetService de PowerShell Universal
3. **Type de composant** : la propriété `type` relie la table de hachage PowerShell au composant React
4. **Passage des props** : les propriétés de la table de hachage deviennent automatiquement des props React
5. **Affichage** : Universal Dashboard charge le paquet JavaScript et affiche le composant React

```
PowerShell Function → Hashtable → Asset Service → React Component → DOM
```

### L'exemple ud-mermaid

Tout au long de ce guide, nous ferons référence au projet [ud-mermaid](https://github.com/ironmansoftware/ud-mermaid) comme exemple concret. Ce composant encapsule la bibliothèque de diagrammes Mermaid.js pour une utilisation dans PowerShell Universal, ce qui démontre :

* L'intégration d'une bibliothèque JavaScript tierce
* L'utilisation des crochets React (useEffect, useRef)
* Le passage d'objets de configuration
* Une structure de projet professionnelle
* L'automatisation de la génération

## Étape par étape

La section suivante vous guidera étape par étape à travers les différents aspects de la création d'un composant d'appli Universal.

### 1. Installer les dépendances

Vous devrez installer les dépendances suivantes avant de créer votre composant.

* [NodeJS](https://nodejs.org/en/) - Requis pour npm et l'exécution des outils de génération

### 2. Créer un nouveau projet

Créez un nouveau répertoire pour votre projet de composant :

```powershell
New-Item -Path .\MyComponent -ItemType Directory
Set-Location .\MyComponent
```

Initialisez un nouveau projet npm :

```powershell
npm init -y
```

Cela crée une structure de projet de base comprenant :

* `package.json` - Les dépendances Node.js et les scripts de génération

### 3. Installer les dépendances JavaScript

Installez les outils de génération et les dépendances React requis :

```powershell
npm install --save-dev @babel/core @babel/preset-env @babel/preset-react babel-loader webpack webpack-cli css-loader style-loader @babel/plugin-proposal-class-properties @babel/plugin-syntax-dynamic-import --legacy-peer-deps
```

Installez le paquet Universal Dashboard :

```powershell
npm install universal-dashboard --legacy-peer-deps
```

Par exemple, le projet [ud-mermaid](https://github.com/ironmansoftware/ud-mermaid) inclut le paquet `mermaid` comme dépendance additionnelle :

```json
"dependencies": {
    "mermaid": "^9.4.3",
    "universal-dashboard": "^1.0.1"
}
```

Installez toute bibliothèque additionnelle dont votre composant a besoin :

```powershell
npm install mermaid --legacy-peer-deps
```

### 4. Créer la structure du projet

Créez les répertoires nécessaires pour votre composant :

```powershell
New-Item -Path .\Components -ItemType Directory
```

### 5. Créer votre composant React

Créez un composant React dans le répertoire `Components/`. Votre composant doit :

1. Importer depuis `universal-dashboard`
2. Utiliser le HOC `withComponentFeatures` (composant d'ordre supérieur)
3. Accepter des props qui correspondent aux paramètres de votre fonction PowerShell

**Exemple provenant de ud-mermaid** (`Components/mermaid.jsx`) :

```jsx
import React, { useEffect, useRef } from 'react';
import { withComponentFeatures } from 'universal-dashboard';
import mermaid from 'mermaid';

const UDMermaid = (props) => {
  const mermaidRef = useRef(null);
  const { id, diagram, config } = props;

  useEffect(() => {
    mermaid.initialize(config || {});
    
    if (mermaidRef.current) {
      mermaidRef.current.removeAttribute('data-processed');
      mermaid.contentLoaded();
    }
  }, [diagram, config]);

  return (
    <div className="mermaid" id={id} ref={mermaidRef}>
      {diagram}
    </div>
  );
};

export default withComponentFeatures(UDMermaid);
```

### 6. Enregistrer votre composant

Créez un fichier `index.js` dans le répertoire `Components/` qui enregistre votre composant auprès de Universal Dashboard :

```javascript
import UDMermaid from './mermaid';
UniversalDashboard.register("ud-mermaid", UDMermaid);
```

La chaîne que vous passez à `register()` devient la propriété `type` que vous utiliserez dans votre fonction PowerShell.

### 7. Créer les fonctions PowerShell

Vous devrez maintenant écrire le code du module PowerShell. Vous devrez mettre à jour le fichier PSM1 pour charger les actifs et définir des fonctions qui créent des définitions de composants.

Le fichier PSM1 doit :

1. Enregistrer le fichier JavaScript regroupé auprès du AssetService
2. Définir des fonctions qui retournent des tables de hachage contenant les propriétés du composant

**Exemple provenant de ud-mermaid** (`UniversalDashboard.Mermaid.psm1`) :

```powershell
# Register JavaScript assets with PowerShell Universal
Get-ChildItem "$PSScriptRoot\*.js" | ForEach-Object {
    $Item = [UniversalDashboard.Services.AssetService]::Instance.RegisterAsset($_.FullName)
    if ($_.Name.StartsWith("index.") -and $_.Name.EndsWith(".bundle.js")) {
        $AssetId = $Item
    }
}

function New-UDMermaid {
    param(
        [Parameter()]
        [string]$Id = (New-Guid).ToString(),
        [Parameter(Mandatory)]
        [string]$Diagram,
        [Parameter()]
        [hashtable]$Config
    )

    @{
        assetId = $AssetId 
        isPlugin = $true 
        type = "ud-mermaid"  # This matches the name used in UniversalDashboard.register()
        id = $Id
        diagram = $Diagram
        config = $Config
    }
}
```

**Propriétés clés de la table de hachage :**

* `assetId` - L'ID retourné par RegisterAsset
* `isPlugin` - Toujours défini à `$true` pour les composants personnalisés
* `type` - Doit correspondre au nom que vous avez utilisé dans `UniversalDashboard.register()`
* `id` - Un identifiant unique pour l'instance du composant
* Les propriétés additionnelles sont passées comme props à votre composant React

### 8. Configurer Webpack

Votre fichier `webpack.config.js` doit regrouper vos composants et externaliser les dépendances React et Universal Dashboard. Voici la configuration essentielle de ud-mermaid :

```javascript
module.exports = (env) => {
  return {
    entry: {
      'index': __dirname + '/components/index.js'
    },
    output: {
      path: BUILD_DIR,
      filename: '[name].[hash].bundle.js',
      library: 'udcomponent',
      libraryTarget: 'var'
    },
    module: {
      rules: [
        { test: /\.(js|jsx)$/, exclude: [/public/], loader: 'babel-loader' },
        { test: /\.css$/, loader: "style-loader!css-loader" }
      ]
    },
    externals: {
      'react': 'react',
      'react-dom': 'reactdom',
      UniversalDashboard: 'UniversalDashboard'
    },
    resolve: {
      extensions: ['.js', '.jsx']
    }
  };
}
```

**Externals importants :**

* `react` et `react-dom` - Fournis par PowerShell Universal
* `UniversalDashboard` - L'objet global Universal Dashboard

### 8.1. Configurer Babel

Créez un fichier `.babelrc` pour configurer la transformation JSX et JavaScript moderne :

```json
{
  "presets": [
    ["@babel/preset-env", {
      "targets": {
        "browsers": [">0.5%", "not dead"]
      }
    }],
    "@babel/preset-react"
  ],
  "plugins": [
    "@babel/plugin-proposal-class-properties",
    "@babel/plugin-syntax-dynamic-import",
    "@babel/plugin-proposal-optional-chaining",
    "@babel/plugin-proposal-nullish-coalescing-operator"
  ]
}
```

Cette configuration :

* Transforme le JSX en JavaScript
* Transpile le JavaScript moderne pour la compatibilité avec les navigateurs
* Active des fonctionnalités utiles du langage JavaScript

### 9. Créer le manifeste du module

Créez un manifeste de module PowerShell standard (`.psd1`) avec les métadonnées de votre composant :

```powershell
@{
    RootModule = 'UniversalDashboard.Mermaid.psm1'
    ModuleVersion = '1.0.0'
    Author = 'Your Name'
    Description = 'Custom component description'
    FunctionsToExport = @('New-UDMermaid')
}
```

### 10. Générer le projet

Vous pouvez maintenant générer votre projet. Il produira un module que vous pourrez charger dans PowerShell Universal.

D'abord, ajoutez des scripts de génération à votre `package.json` :

```json
"scripts": {
    "build": "webpack -p --env production",
    "dev": "webpack-dev-server --config webpack.config.js -p --env development"
}
```

Puis lancez la génération :

```powershell
npm run build
```

**Facultatif : créer un script de génération** (comme le `component.build.ps1` de ud-mermaid) :

```powershell
# component.build.ps1
$OutputPath = "$PSScriptRoot\output"

Remove-Item -Path $OutputPath -Force -ErrorAction SilentlyContinue -Recurse
Remove-Item -Path "$PSScriptRoot\public" -Force -ErrorAction SilentlyContinue -Recurse

npm install --legacy-peer-deps
npm run build

New-Item -Path $OutputPath -ItemType Directory

Copy-Item $PSScriptRoot\public\*.* $OutputPath
Copy-Item $PSScriptRoot\UniversalDashboard.MyComponent.psd1 $OutputPath
Copy-Item $PSScriptRoot\UniversalDashboard.MyComponent.psm1 $OutputPath
```

Puis exécutez-le :

```powershell
.\component.build.ps1
```

Le processus de génération :

1. Regroupe tout le code JavaScript/React à l'aide de Webpack
2. Produit des fichiers regroupés avec des noms de hachage (p. ex., `index.78a6d857.bundle.js`)
3. Copie les fichiers du module (`.psm1`, `.psd1`) dans le répertoire de sortie

### 11. Utiliser dans PowerShell Universal

Dans votre appli, chargez votre module et exécutez la fonction.

```powershell
Import-Module .\output\UniversalDashboard.Mermaid.psd1

New-UDApp -Content {
   New-UDMermaid -Diagram @"
graph TD
    A[Start] --> B[Process]
    B --> C[End]
"@
}
```

## Exemple de structure de projet

Voici la structure typique d'un projet de composant personnalisé (provenant de [ud-mermaid](https://github.com/ironmansoftware/ud-mermaid)) :

```
project/
├── Components/
│   ├── index.js              # Component registration
│   └── mermaid.jsx           # React component
├── output/                   # Build output (git ignored)
│   ├── index.[hash].bundle.js
│   ├── UniversalDashboard.Mermaid.psm1
│   └── UniversalDashboard.Mermaid.psd1
├── package.json              # Node.js dependencies
├── webpack.config.js         # Webpack configuration
├── component.build.ps1       # Optional build script
├── UniversalDashboard.Mermaid.psm1   # PowerShell module
└── UniversalDashboard.Mermaid.psd1   # Module manifest
```

## Props

Les props sont des valeurs qui sont passées soit à partir de la table de hachage PowerShell fournie par l'utilisateur, soit par la fonction d'ordre supérieur `withComponentsFeature` de l'appli Universal.

### Standard

Les propriétés que vous définissez dans votre table de hachage dans PowerShell seront automatiquement envoyées comme props au composant React.

Par exemple, si vous définissez les propriétés `diagram` et `config` dans la table de hachage :

```powershell
function New-UDMermaid {
    param(
        [Parameter()]
        [string]$Id = (New-Guid).ToString(),
        [Parameter(Mandatory)]
        [string]$Diagram,
        [Parameter()]
        [hashtable]$Config
    )

    @{
        type = "ud-mermaid"
        isPlugin = $true
        assetId = $AssetId 
        id = $Id
        diagram = $Diagram
        config = $Config
    }
}
```

Vous aurez alors accès à ces props dans React :

```javascript
import React, { useEffect, useRef } from 'react';
import { withComponentFeatures } from 'universal-dashboard';
import mermaid from 'mermaid';

const UDMermaid = (props) => {
  const { id, diagram, config } = props;

  useEffect(() => {
    mermaid.initialize(config || {});
  }, [diagram, config]);

  return <div className="mermaid" id={id}>{diagram}</div>;
};

export default withComponentFeatures(UDMermaid);
```

**Meilleures pratiques pour les props :**

* Utilisez des noms de props descriptifs qui correspondent aux noms des paramètres PowerShell
* Gérez les props facultatifs avec des valeurs par défaut ou une logique conditionnelle
* Les tables de hachage dans PowerShell deviennent automatiquement des objets JavaScript

### Crochets React et cycle de vie du composant

Lorsque vous créez des composants personnalisés, vous pouvez utiliser tous les crochets React standards. Le composant ud-mermaid démontre l'utilisation de `useEffect` et `useRef` pour gérer le cycle de vie du composant et les références au DOM :

```javascript
import React, { useEffect, useRef } from 'react';

const UDMermaid = (props) => {
  const mermaidRef = useRef(null);
  const { diagram, config } = props;

  // Run when diagram or config changes
  useEffect(() => {
    mermaid.initialize(config || {});
    
    if (mermaidRef.current) {
      mermaidRef.current.removeAttribute('data-processed');
      mermaid.contentLoaded();
    }
  }, [diagram, config]); // Dependency array

  return <div ref={mermaidRef}>{diagram}</div>;
};
```

**Modèles courants :**

* `useEffect` - Pour l'initialisation, le nettoyage et la réaction aux changements de props
* `useRef` - Pour accéder directement aux éléments du DOM
* `useState` - Pour gérer l'état interne du composant
* `useMemo` / `useCallback` - Pour l'optimisation de la performance

### Points de terminaison

Les points de terminaison sont particuliers par la façon dont ils sont enregistrés et par la façon dont ils sont passés comme props à votre composant. Vous devrez appeler `Register` sur le point de terminaison dans PowerShell et passer les variables Id et PSCmdlet.

```powershell
function New-UD95Button {
    param(
        [Parameter()]
        [string]$Id = [Guid]::NewGuid(),
        [Parameter()]
        [string]$Text,
        [Parameter()]
        [Endpoint]$OnClick
    )

    if ($OnClick)
    {
        $OnClick.Register($Id, $PSCmdlet)
    }

    @{
        type = "ud95-button"
        isPlugin = $true 
        assetId = $AssetId

        id = $Id 
        text = $Text 
        onClick = $OnClick
    }
}
```

Les points de terminaison sont créés à partir de ScriptBlocks et sont exécutés lorsque cet événement se produit.

```powershell
New-UD95Button -Text 'Hello' -OnClick {
    Show-UDToast -Message 'Test' 
}
```

Universal reliera automatiquement le point de terminaison à une fonction dans JavaScript. Cela signifie que vous pouvez utiliser les props pour appeler ce point de terminaison.

Remarquez l'appel de fonction `props.onClick`. Cela appellera automatiquement le bloc de script PowerShell sur le serveur.

```javascript
import React from 'react';
import { withComponentFeatures } from 'universal-dashboard';
import { Button } from 'react95';

const UD95Button = props => {

    const p = {
        onClick: () => props.onClick()
    }

    return <Button {...p}>{props.text}</Button>
}

export default withComponentFeatures(UD95Button);
```

### setState

La prop `setState` est utilisée pour définir l'état du composant. Cela garantit que l'état est suivi et que votre composant fonctionnera avec `Get-UDElement`.

Par exemple, avec un champ de texte, vous voudrez appeler `props.setState` et passer la nouvelle valeur de texte pour l'état.

```javascript
const UDTextField = (props) => {
    const onChange = (e) => {
        props.setState({value: e.target.value})
    }

    return <TextField  {...props} onChange={onChange} />
}

export default withComponentFeatures(UDTextField);
```

### children

La prop `children` est une prop React standard. Si votre composant prend en charge des éléments enfants, comme une liste ou une boîte de sélection, vous devriez utiliser la prop standard `props.children` pour vous assurer que les applets de commande `Add-UDElement` , `Remove-UDElement` et `Clear-UDElement` fonctionnent correctement.

## Dépannage et débogage

### Problèmes courants

**Le composant ne s'affiche pas :**

1. Vérifiez que le `type` dans votre fonction PowerShell correspond au nom `UniversalDashboard.register()`
2. Vérifiez que l'actif est correctement enregistré auprès d'AssetService
3. Assurez-vous que `isPlugin` est défini à `$true`
4. Confirmez que le fichier JavaScript regroupé existe dans le répertoire du module

**Les props ne sont pas transmises correctement :**

1. Vérifiez que les noms de propriétés correspondent entre la table de hachage PowerShell et le composant React
2. Vérifiez la console du navigateur pour repérer les erreurs JavaScript
3. Utilisez React DevTools pour inspecter les props du composant

**Échecs de compilation :**

1. Exécutez `npm install --legacy-peer-deps` pour vous assurer que les dépendances sont installées
2. Recherchez les erreurs de syntaxe dans les fichiers JSX
3. Vérifiez que les externals de webpack.config.js sont correctement configurés
4. Assurez-vous que babel est correctement configuré pour la transformation JSX

### Conseils de débogage

**Console du navigateur :** Ouvrez les outils de développement du navigateur (F12) pour voir les erreurs et avertissements JavaScript.

**React DevTools :** Installez l'extension de navigateur React DevTools pour inspecter la hiérarchie et les props du composant.

**Débogage PowerShell :** Utilisez `Write-Host` ou `Write-Debug` dans vos fonctions PowerShell pour tracer l'exécution.

**Serveur de développement Webpack :** Pendant le développement, utilisez webpack-dev-server pour le rechargement à chaud :

```powershell
npm run dev
```

Configurez ensuite PowerShell Universal pour charger depuis l'URL du serveur de développement.

## Exemple : flux de travail complet d'un composant

Voici un exemple complet basé sur le projet [ud-mermaid](https://github.com/ironmansoftware/ud-mermaid) :

**1. Créer le composant React** (`Components/mermaid.jsx`) :

```jsx
import React, { useEffect, useRef } from 'react';
import { withComponentFeatures } from 'universal-dashboard';
import mermaid from 'mermaid';

const UDMermaid = (props) => {
  const mermaidRef = useRef(null);
  const { id, diagram, config } = props;

  useEffect(() => {
    mermaid.initialize(config || {});
    if (mermaidRef.current) {
      mermaidRef.current.removeAttribute('data-processed');
      mermaid.contentLoaded();
    }
  }, [diagram, config]);

  return <div className="mermaid" id={id} ref={mermaidRef}>{diagram}</div>;
};

export default withComponentFeatures(UDMermaid);
```

**2. Enregistrer le composant** (`Components/index.js`) :

```javascript
import UDMermaid from './mermaid';
UniversalDashboard.register("ud-mermaid", UDMermaid);
```

**3. Créer la fonction PowerShell** (`UniversalDashboard.Mermaid.psm1`) :

```powershell
Get-ChildItem "$PSScriptRoot\*.js" | ForEach-Object {
    $Item = [UniversalDashboard.Services.AssetService]::Instance.RegisterAsset($_.FullName)
    if ($_.Name.StartsWith("index.") -and $_.Name.EndsWith(".bundle.js")) {
        $AssetId = $Item
    }
}

function New-UDMermaid {
    param(
        [Parameter()]
        [string]$Id = (New-Guid).ToString(),
        [Parameter(Mandatory)]
        [string]$Diagram,
        [Parameter()]
        [hashtable]$Config
    )

    @{
        assetId = $AssetId 
        isPlugin = $true 
        type = "ud-mermaid"
        id = $Id
        diagram = $Diagram
        config = $Config
    }
}
```

**4. Compiler et tester** :

```powershell
# Build
npm run build

# Test in PowerShell Universal
Import-Module .\output\UniversalDashboard.Mermaid.psd1

New-UDApp -Content {
    New-UDMermaid -Diagram @"
graph TD
    A[Christmas] -->|Get money| B(Go shopping)
    B --> C{Let me think}
    C -->|One| D[Laptop]
    C -->|Two| E[iPhone]
    C -->|Three| F[Car]
"@
}
```

## Ressources supplémentaires

* **Dépôt GitHub ud-mermaid** : <https://github.com/ironmansoftware/ud-mermaid> - Exemple fonctionnel complet
* **Documentation de React** : <https://react.dev>
* **Documentation de Webpack** : <https://webpack.js.org>


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.devolutions.net/powershell-universal/fr/applis/components/custom-components/building-custom-components.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
