# 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