Aller au contenu
17 mars 2026·8 min de lecture

Migration de Visualforce vers LWC : un guide pratique

Migrez les pages Visualforce vers les Lightning Web Components étape par étape — correspondance des concepts VF vers LWC, patterns d'accès aux données et gestion des cas limites qui font trébucher les migrations.

Retour

Visualforce ne disparaît pas du jour au lendemain, mais les Lightning Web Components sont le présent et le futur du développement UI Salesforce. Migrer de façon incrémentale — un composant à la fois — est l'approche réaliste pour la plupart des orgs.


Quand migrer (et quand ne pas le faire)

Bons candidats à la migration :

  • Pages à fort trafic qui bénéficieraient des performances LWC
  • Pages dont les utilisateurs se plaignent de la lenteur (le view state VF est un coupable courant)
  • Nouvelles fonctionnalités que vous construisez à côté de pages VF existantes

Gardez en Visualforce :

  • Génération de PDF (VF génère nativement des PDF — LWC non)
  • Templates d'email utilisant <messaging:emailTemplate>
  • Grilles d'édition inline complexes nécessitant une refonte importante
  • Pages qui fonctionnent et que personne ne touche — ne migrez pas pour migrer

Correspondance des concepts

| Visualforce | Équivalent LWC | |-------------|----------------| | <apex:page> | Fichiers html + js du composant | | <apex:form> + <apex:commandButton> | <form> + Server Action ou @wire | | <apex:inputField> | <lightning-input-field> | | <apex:outputField> | <lightning-output-field> | | <apex:pageBlock> | <lightning-card> | | <apex:dataTable> | <lightning-datatable> | | <apex:repeat> | Directive for:each | | Contrôleur standard | Wire adapters lightning/uiRecordApi | | Contrôleur personnalisé | Classe Apex appelée avec @wire ou callApex | | $User.Id, $Label | @salesforce/user/Id, @salesforce/label/c.Mon_Label |


Migration d'affichage de champs simple

Visualforce :

<apex:page standardController="Account">
    <apex:pageBlock title="Détails du compte">
        <apex:pageBlockSection>
            <apex:outputField value="{!Account.Name}"/>
            <apex:outputField value="{!Account.Phone}"/>
            <apex:outputField value="{!Account.Industry}"/>
        </apex:pageBlockSection>
    </apex:pageBlock>
</apex:page>

Équivalent LWC :

<!-- detailsCompte.html -->
<template>
    <lightning-card title="Détails du compte">
        <div class="slds-p-around_medium">
            <lightning-record-view-form record-id={recordId} object-api-name="Account">
                <lightning-output-field field-name="Name"></lightning-output-field>
                <lightning-output-field field-name="Phone"></lightning-output-field>
                <lightning-output-field field-name="Industry"></lightning-output-field>
            </lightning-record-view-form>
        </div>
    </lightning-card>
</template>
// detailsCompte.js
import { LightningElement, api } from 'lwc';
 
export default class DetailsCompte extends LightningElement {
    @api recordId;
}

Migration d'un formulaire avec logique personnalisée

LWC avec Server Action :

// formulaireCompte.js
import { LightningElement } from 'lwc';
import { NavigationMixin } from 'lightning/navigation';
import creerCompte from '@salesforce/apex/AccountFormController.creerCompte';
import { ShowToastEvent } from 'lightning/platformShowToastEvent';
 
export default class FormulaireCompte extends NavigationMixin(LightningElement) {
    nom = '';
    telephone = '';
 
    handleNomChange(event) {
        this.nom = event.target.value;
    }
 
    async handleSave() {
        if (!this.nom) {
            this.dispatchEvent(new ShowToastEvent({
                title: 'Erreur de validation',
                message: 'Le nom est obligatoire',
                variant: 'error',
            }));
            return;
        }
 
        try {
            const accountId = await creerCompte({ nom: this.nom, telephone: this.telephone });
            this[NavigationMixin.Navigate]({
                type: 'standard__recordPage',
                attributes: { recordId: accountId, actionName: 'view' },
            });
        } catch (error) {
            this.dispatchEvent(new ShowToastEvent({
                title: 'Erreur',
                message: error.body?.message ?? 'Erreur inconnue',
                variant: 'error',
            }));
        }
    }
}

Remplacer <apex:repeat> et les tableaux dynamiques

Visualforce :

<apex:repeat value="{!contacts}" var="c">
    <div>{!c.Name} — {!c.Email}</div>
</apex:repeat>

LWC :

<template for:each={contacts} for:item="contact">
    <div key={contact.Id}>
        {contact.Name} — {contact.Email}
    </div>
</template>

Pour les tableaux éditables, utilisez <lightning-datatable> :

colonnes = [
    { label: 'Nom', fieldName: 'Name', type: 'text', editable: true },
    { label: 'Email', fieldName: 'Email', type: 'email' },
    { label: 'Téléphone', fieldName: 'Phone', type: 'phone' },
];

Stratégie de migration

  1. Identifier la complexité de la page — simple (< 1 jour), moyenne (1–3 jours), complexe (1+ semaine)
  2. Créer le LWC à côté de la page VF — ne pas supprimer VF avant que le LWC soit validé
  3. Utiliser un feature flag — Custom Setting LWC_Active__c pour basculer entre VF et LWC par utilisateur
  4. Valider avec les utilisateurs d'abord — déployer LWC sur un sous-ensemble d'utilisateurs avant le déploiement complet
  5. Supprimer la page VF — seulement après 2–4 semaines d'utilisation LWC réussie

Pièges courants

  • View state → pas de view state : LWC n'a pas de concept de view state — utilisez @wire pour les données, les propriétés régulières pour l'état local
  • Redirections de page : VF utilise PageReference — LWC utilise NavigationMixin
  • apex:messages : les messages d'erreur VF utilisent ApexPages.addMessage — LWC utilise ShowToastEvent
  • CSS inline dans VF : LWC impose le Lightning Design System — évitez les CSS bruts dans la portée du composant

Ressources

Aïcha Imène DAHOUMANE
À propos de l'auteure
Aïcha Imène DAHOUMANE
Administratrice & Développeuse Salesforce · Consultante

Développeuse Salesforce avec un background en infrastructures IT — je construis des solutions fiables et maintenables avec Apex, Flows, LWC et CI/CD.

PartagerPartager sur LinkedIn