Outils·6 min de lecture·Par Solingo

Ethers.js vs Web3.js — Quelle Bibliothèque Choisir ?

Ethers.js et Web3.js sont les deux bibliothèques JavaScript les plus populaires pour Ethereum. Comparez leurs fonctionnalités, design d'API, taille de bundle et performances pour choisir la bonne pour votre projet.

# Ethers.js vs Web3.js — Quelle Bibliothèque Choisir ?

Lors de la construction de dApps Ethereum, vous avez besoin d'une bibliothèque JavaScript pour interagir avec la blockchain. Les deux choix dominants sont Ethers.js et Web3.js. Les deux permettent les connexions de portefeuilles, les interactions avec les contrats et la gestion des transactions — mais ils diffèrent significativement en philosophie de design, taille de bundle et expérience développeur. Ce guide compare les deux bibliothèques pour vous aider à choisir la bonne pour votre projet.

Tableau de comparaison rapide

| Fonctionnalité | Ethers.js | Web3.js |

|---------|-----------|---------|

| Taille du bundle | 116 KB (minifié) | 600+ KB (minifié) |

| Design de l'API | Moderne, propre, TypeScript-first | Legacy, lourd en callbacks |

| TypeScript | Support natif complet | Ajouté via @types/web3 |

| Maintenance | Activement maintenu | Mises à jour plus lentes |

| Documentation | Excellente | Bonne mais dispersée |

| Courbe d'apprentissage | Modérée | Plus raide |

| Gestion du provider | Simple (BrowserProvider) | Complexe (Web3.providers) |

| Support ENS | Intégré | Via package séparé |

| BigNumber | BigInt natif + BigNumber personnalisé | BigNumber personnalisé |

| Communauté | Croissance rapide | Établie |

| Meilleur pour | Nouveaux projets, dApps production | Projets legacy, Web3.js v4 |

Installation

Ethers.js v6

npm install ethers
import { BrowserProvider, Contract } from 'ethers';

Web3.js v4

npm install web3
import { Web3 } from 'web3';

Se connecter à Ethereum

Ethers.js

import { BrowserProvider } from 'ethers';

// Se connecter à MetaMask

const provider = new BrowserProvider(window.ethereum);

const signer = await provider.getSigner();

const address = await signer.getAddress();

console.log('Connected:', address);

Séparation claire :

  • Provider : Accès lecture seule à la blockchain
  • Signer : Accès écriture (transactions, signature)

Web3.js

import { Web3 } from 'web3';

// Se connecter à MetaMask

const web3 = new Web3(window.ethereum);

const accounts = await web3.eth.requestAccounts();

const address = accounts[0];

console.log('Connected:', address);

Séparation moins explicite entre les opérations lecture/écriture.

Lire les données de la blockchain

Ethers.js

// Obtenir le solde

const balance = await provider.getBalance(address);

console.log('Balance:', ethers.formatEther(balance), 'ETH');

// Obtenir le numéro de bloc

const blockNumber = await provider.getBlockNumber();

// Obtenir le prix du gas

const feeData = await provider.getFeeData();

console.log('Gas price:', ethers.formatUnits(feeData.gasPrice, 'gwei'), 'gwei');

// Obtenir une transaction

const tx = await provider.getTransaction(txHash);

Web3.js

// Obtenir le solde

const balance = await web3.eth.getBalance(address);

console.log('Balance:', web3.utils.fromWei(balance, 'ether'), 'ETH');

// Obtenir le numéro de bloc

const blockNumber = await web3.eth.getBlockNumber();

// Obtenir le prix du gas

const gasPrice = await web3.eth.getGasPrice();

console.log('Gas price:', web3.utils.fromWei(gasPrice, 'gwei'), 'gwei');

// Obtenir une transaction

const tx = await web3.eth.getTransaction(txHash);

API très similaire, mais espaces de noms de fonctions utilitaires différents.

Envoyer des transactions

Ethers.js

const signer = await provider.getSigner();

const tx = await signer.sendTransaction({

to: '0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb',

value: ethers.parseEther('0.1')

});

console.log('Transaction hash:', tx.hash);

// Attendre la confirmation

const receipt = await tx.wait();

console.log('Confirmed in block:', receipt.blockNumber);

tx.wait() retourne une promesse qui se résout lorsque la transaction est minée.

Web3.js

const accounts = await web3.eth.getAccounts();

const tx = await web3.eth.sendTransaction({

from: accounts[0],

to: '0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb',

value: web3.utils.toWei('0.1', 'ether')

});

console.log('Transaction hash:', tx.transactionHash);

console.log('Confirmed in block:', tx.blockNumber);

Web3.js retourne le reçu directement (pas d'appel séparé wait()).

Interaction avec les contrats

Ethers.js

import { Contract } from 'ethers';

const abi = [

"function balanceOf(address owner) view returns (uint256)",

"function transfer(address to, uint256 amount) returns (bool)"

];

const contract = new Contract(contractAddress, abi, signer);

// Fonction de lecture (pas de gas)

const balance = await contract.balanceOf(address);

console.log('Balance:', ethers.formatUnits(balance, 18));

// Fonction d'écriture (coûte du gas)

const tx = await contract.transfer('0x...', ethers.parseUnits('10', 18));

await tx.wait();

console.log('Transfer complete');

ABI lisible — vous pouvez définir les interfaces comme des chaînes au lieu de JSON.

Web3.js

const abi = [

{

"name": "balanceOf",

"type": "function",

"inputs": [{"name": "owner", "type": "address"}],

"outputs": [{"name": "", "type": "uint256"}],

"stateMutability": "view"

},

{

"name": "transfer",

"type": "function",

"inputs": [

{"name": "to", "type": "address"},

{"name": "amount", "type": "uint256"}

],

"outputs": [{"name": "", "type": "bool"}]

}

];

const contract = new web3.eth.Contract(abi, contractAddress);

// Fonction de lecture

const balance = await contract.methods.balanceOf(address).call();

console.log('Balance:', web3.utils.fromWei(balance, 'ether'));

// Fonction d'écriture

const accounts = await web3.eth.getAccounts();

await contract.methods.transfer('0x...', web3.utils.toWei('10', 'ether'))

.send({ from: accounts[0] });

ABI JSON requis — plus verbeux, mais compatible avec tous les outils.

Écoute d'événements

Ethers.js

// Écouter les événements Transfer

contract.on('Transfer', (from, to, amount, event) => {

console.log(Transfer from ${from} to ${to}: ${ethers.formatUnits(amount, 18)} tokens);

});

// Requêter les événements passés

const filter = contract.filters.Transfer(null, myAddress);

const events = await contract.queryFilter(filter, startBlock, endBlock);

API d'événements propre avec filtres.

Web3.js

// Écouter les événements Transfer

contract.events.Transfer()

.on('data', (event) => {

console.log(Transfer from ${event.returnValues.from} to ${event.returnValues.to});

});

// Requêter les événements passés

const events = await contract.getPastEvents('Transfer', {

filter: { to: myAddress },

fromBlock: startBlock,

toBlock: endBlock

});

Gestion des événements plus verbeuse.

Gestion des BigNumber

Ethers.js

Ethers.js v6 utilise le BigInt natif JavaScript pour la plupart des opérations, avec une classe BigNumber personnalisée pour les besoins avancés :

const amount = ethers.parseEther('1.5'); // BigInt: 1500000000000000000n

const formatted = ethers.formatEther(amount); // "1.5"

// Opérations mathématiques

const doubled = amount * 2n; // BigInt natif

Web3.js

Web3.js utilise une implémentation BigNumber personnalisée :

const amount = web3.utils.toWei('1.5', 'ether'); // "1500000000000000000"

const formatted = web3.utils.fromWei(amount, 'ether'); // "1.5"

// Les opérations mathématiques nécessitent une conversion BigInt

const doubled = (BigInt(amount) * 2n).toString();

Web3.js retourne des chaînes pour les grands nombres, nécessitant une conversion manuelle pour les maths.

Taille du bundle

Ethers.js : ~116 KB minifié

Web3.js : ~600 KB minifié

Pour les apps de production, la taille du bundle compte :

  • Ethers.js est 5x plus petit, menant à des temps de chargement plus rapides
  • Critique pour les utilisateurs mobiles et les dApps sensibles aux performances

Support TypeScript

Ethers.js

TypeScript natif — écrit en TypeScript depuis le début :

import { BrowserProvider, Contract, Signer } from 'ethers';

const provider: BrowserProvider = new BrowserProvider(window.ethereum);

const signer: Signer = await provider.getSigner();

Inférence de types complète, pas besoin de package @types.

Web3.js

Ajouté via @types/web3 — nécessite des définitions de types séparées :

npm install --save-dev @types/web3
import { Web3 } from 'web3';

const web3: Web3 = new Web3(window.ethereum);

Les types sont moins précis et peuvent être obsolètes.

Support ENS (Ethereum Name Service)

Ethers.js

Support ENS intégré — résout les noms en adresses automatiquement :

const address = await provider.resolveName('vitalik.eth');

// "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"

const name = await provider.lookupAddress(address);

// "vitalik.eth"

// Utiliser ENS directement dans les transactions

const tx = await signer.sendTransaction({

to: 'vitalik.eth',

value: ethers.parseEther('0.1')

});

Web3.js

Nécessite un package séparé (web3-eth-ens) :

npm install web3-eth-ens
const address = await web3.eth.ens.getAddress('vitalik.eth');

Moins intégré, plus de configuration requise.

Guide de migration : Web3.js → Ethers.js

Configuration du provider

Avant (Web3.js) :

const web3 = new Web3(window.ethereum);

Après (Ethers.js) :

const provider = new BrowserProvider(window.ethereum);

const signer = await provider.getSigner();

Obtenir le solde

Avant :

const balance = await web3.eth.getBalance(address);

const eth = web3.utils.fromWei(balance, 'ether');

Après :

const balance = await provider.getBalance(address);

const eth = ethers.formatEther(balance);

Interaction avec les contrats

Avant :

const contract = new web3.eth.Contract(abi, address);

const balance = await contract.methods.balanceOf(owner).call();

Après :

const contract = new Contract(address, abi, provider);

const balance = await contract.balanceOf(owner);

Envoi de transactions

Avant :

await contract.methods.transfer(to, amount).send({ from: account });

Après :

const tx = await contract.transfer(to, amount);

await tx.wait();

Laquelle choisir ?

Choisissez Ethers.js si :

  • Vous démarrez un nouveau projet
  • La taille du bundle compte (mobile, performance)
  • Vous utilisez TypeScript
  • Vous voulez une API moderne et propre
  • Le support ENS est nécessaire
  • Vous préférez une maintenance active et des mises à jour

Choisissez Web3.js si :

  • Vous maintenez du code legacy
  • Votre équipe connaît déjà Web3.js
  • Vous avez besoin de compatibilité avec d'anciens outils
  • Vous préférez l'écosystème établi
  • Vous migrez vers Web3.js v4 (très amélioré)

Conclusion

Ethers.js est le choix moderne pour la plupart des nouveaux projets. Sa taille de bundle plus petite, son API plus propre, son support TypeScript natif et son ENS intégré en font l'outil idéal pour les dApps de production. Web3.js reste viable pour les projets legacy, mais Ethers.js est devenu le standard de facto pour le nouveau développement.

Commencez à développer avec Ethers.js aujourd'hui — intégrez-le dans votre dApp et ressentez la différence. Pratiquez les interactions blockchain avec les défis Web3 pratiques de Solingo pour maîtriser les deux bibliothèques.

Prochaines étapes :

  • Migrez un projet Web3.js existant vers Ethers.js
  • Construisez une dApp en utilisant Ethers.js depuis zéro
  • Comparez les tailles de bundle dans votre build de production
  • Explorez les fonctionnalités avancées comme multicall et les providers personnalisés

Prêt à mettre en pratique ?

Applique ces concepts avec des exercices interactifs sur Solingo.

Commencer gratuitement