Comment rechercher des bugs sur le front-end: 4 étapes principales


Dans cet article, j'examinerai la question de l'identification et du traitement des erreurs qui se produisent sur le frontend (navigateur ou vue Web).

Sur le frontend, le code JS est exécuté dans le navigateur. JavaScript n'est pas un langage compilé, il y a donc toujours un risque d'erreur de performance lors de l'utilisation directe du programme. Une erreur d'exécution bloque le code situé après le lieu de l'erreur et les utilisateurs du programme courent le risque de rester avec un écran d'application non fonctionnel qui ne peut être rechargé ou fermé. Mais il existe des méthodes pour détecter les erreurs et leur accompagnement sûr, pour éviter de telles situations.

1. Outils JavaScript


Essayer / attraper des blocs


Les fonctions qui peuvent échouer peuvent être encapsulées dans des blocs try / catch. Tout d'abord, le programme essaie d'exécuter le code dans le bloc try. Si, pour une raison quelconque, l'exécution du code est interrompue, le programme va dans le bloc catch, où trois paramètres sont disponibles:

  • nom - nom normalisé de l'erreur;
  • message - message sur les détails de l'erreur;
  • stack - la pile d'appels en cours dans laquelle l'erreur s'est produite.

C'est à dire:

try {

   callFunc();

} catch (e) {

   console.log(e.name) // ReferenceError

   console.log(e.message) // callFunc is not defined

   console.log(e.stack) // ReferenceError: callFunc is not defined at window.onload

}

Pour le développeur, l'essentiel est que le programme puisse continuer son exécution après le bloc catch. Ainsi, l'interaction de l'utilisateur ne sera pas interrompue.

En utilisant le bloc try / catch, vous pouvez également provoquer vos propres erreurs, par exemple, lors de la vérification des données:

const user = {

  name : «Mike»

};

try {

   if (!user.age) throw new SyntaxError(«User age is absent!»);

} catch (e) {

   console.log(e.name) // SyntaxError

   console.log(e.message) // User age is absent!

   console.log(e.stack) // SyntaxError: User age is absent! at window.onload

}

Enfin, vous pouvez étendre cette instruction avec un bloc de plus - enfin, qui est toujours exécuté: à la fois dans le cas où il n'y a pas eu d'erreur dans try, et dans le cas où le contrôle est passé au bloc catch:

try {

   callFunc();

} catch (e) {

   console.log(e)

} finally {

   ...

}

Parfois, ils utilisent l'instruction try / finally (sans catch) afin que vous puissiez continuer à utiliser le code sans gérer des erreurs spécifiques.

Événement Window.onerror


Il est souvent utile de savoir que le script de la page s'est cassé même si le programme s'est cassé et que la session utilisateur s'est terminée sans succès. Habituellement, ces informations sont ensuite utilisées dans les systèmes d'enregistrement des erreurs.

L'objet fenêtre global a un événement onerror ( utilisez-le avec précaution: l'implémentation peut différer selon les navigateurs! ):

window.onerror = function(message, url, line, col, error) {

   console.log(`${message}\n  ${line}:${col}  ${url}`);

};

Si vous placez ce code au début du script ou le chargez dans un script distinct en premier lieu, pour toute erreur ci-dessous, le développeur disposera d'informations détaillées à ce sujet.

Cependant, les informations complètes ne sont disponibles que pour les scripts téléchargés à partir du même domaine. Si le script cassé est chargé à partir d'un autre domaine, window.onerror fonctionnera, mais il n'y aura pas de détails sur l'erreur.

Composants du framework


Certains frameworks JS ( React , Vue) proposent leurs propres solutions de gestion des erreurs. Par exemple, React pourra dessiner une disposition spéciale à l'emplacement du bloc dans lequel l'erreur s'est produite:

class ErrorBoundary extends React.Component {

   constructor(props) {

       super(props);

       this.state = { hasError: false };

   }

   static getDerivedStateFromError(error) {

       //    ,      UI.

       return { hasError: true };

   }

   componentDidCatch(error, errorInfo) {

       //           

       logErrorToMyService(error, errorInfo);

   }

   render() {

       if (this.state.hasError) {

           //    UI  

           return <h1>-   .</h1>;

       }

       return this.props.children;

   }

}

<ErrorBoundary>

   <MyWidget />

</ErrorBoundary>

En fait, le composant React est enveloppé dans un composant spécial qui gère les erreurs. Ceci est similaire à l'encapsulation de fonctions avec une construction try / catch.

2. Outils d'assemblage de projet


Les scripts JS modernes sont généralement transposés. Autrement dit, le développement est effectué en utilisant les dernières normes ES. Et puis le code du développeur utilisant le générateur de projet (tel que Webpack) est converti en code qui sera garanti pour fonctionner dans le nombre de navigateurs sélectionné.

Au stade de la construction, le code est vérifié pour la syntaxe correcte. Un support ouvert ou une désignation incorrecte d'un champ de classe provoquera immédiatement une erreur lors de l'assemblage et le bundle ne sera tout simplement pas assemblé. Le développeur devra corriger immédiatement ces erreurs afin de continuer à travailler.

En outre, le collecteur peut suggérer que certains morceaux de code ne sont pas utilisés lors de l'exécution du programme. Cela incitera peut-être le développeur à réfléchir à une étude plus approfondie du code, ce qui pourrait indirectement affecter l'identification de nouvelles erreurs.

3. Test


Une autre façon d'éviter les erreurs dans le code est de le tester. Il existe des outils en frontend pour une utilisation efficace des tests unitaires. En règle générale, des cadres tels que Jest, Karma, Mocha, Jasmine sont utilisés. Avec les frameworks de test, ils utilisent souvent des extensions telles que Enzyme, React Testing Library, Sinon et autres, qui permettent d'enrichir les tests à l'aide de la simulation, des fonctions d'espionnage et d'autres outils.

Lors de la recherche d'erreurs, les tests sont principalement utiles pour charger une variété de données pouvant entraîner des erreurs d'exécution. Ainsi, le code suivant passera la validation de la syntaxe et fonctionnera comme prévu:

const func = (data) => {

   return JSON.parse(data)

}

func('{«a»:1}')

Cependant, il se cassera si vous lui donnez la mauvaise valeur:

func() // Uncaught SyntaxError: Unexpected token u in JSON at position 0.


Ce code passe également la validation lors de l'assemblage:

const obj = {

   outer : {

       last : 9

   }

}

if (obj.outer.inner.last) {

   console.log(«SUCCESS»)

}

Cependant, il se cassera également pendant l'exécution. Après les tests, le développeur fera probablement des vérifications supplémentaires:

if (obj.outer?.inner?.last) {

   console.log(«SUCCESS»)

}

Souvent, de telles erreurs se produisent lors de la réception de données du serveur (par exemple, avec une demande AJAX) avec leur analyse ultérieure. Le test du code vous permet d'identifier et d'éliminer à l'avance les cas où le code peut se casser pendant l'exécution dans le navigateur du client.

4. Enregistrement


Supposons que nous ayons pris toutes les mesures possibles pour éviter les erreurs lors du développement et du montage du projet. Cependant, les erreurs peuvent toujours infiltrer le code productif. Nous devons en quelque sorte découvrir leur présence et prendre des mesures correctives immédiates. Demander aux utilisateurs d'ouvrir une console de navigateur et de prendre des captures d'écran n'est pas la meilleure option. Par conséquent, il est bon de connecter la journalisation des erreurs au projet.

La signification est simple: pour chaque événement window.onerror ou chaque transition de l'exécution de code vers le bloc catch, une simple requête AJAX est adressée à une adresse de serveur spécialement allouée, dans le corps de laquelle sont placées les informations d'erreur. Ensuite, vous aurez besoin d'un outil qui avertira rapidement le support technique et les développeurs de la présence de nouvelles erreurs et vous permettra de travailler efficacement avec eux. Sentry est le plus populaire de ces outils frontaux.

Le système de journalisation Sentry vous permet de collecter, grouper, présenter les erreurs en temps réel. Il existe des assemblages pour différentes langues, y compris JavaScript. Le projet fournit un accès payant avec des fonctionnalités avancées pour les entreprises, cependant, vous pouvez essayer ses principales fonctionnalités sur un compte de test gratuit.

Sentry peut être connecté à la fois directement dans le fichier HTML et dans des composants exécutés sur l'un des frameworks populaires: React, Vue, Angular, Ember et autres.

Pour connecter les capacités de journalisation directement dans le navigateur de la section, chargez le script:

<script

   src=«https://browser.sentry-cdn.com/5.13.0/bundle.min.js»

   integrity=«sha384-ePH2Cp6F+/PJbfhDWeQuXujAbpil3zowccx6grtsxOals4qYqJzCjeIa7W2UqunJ»

   crossorigin="anonymous"></script>


Ensuite, dans le code JS, nous initialisons:

Sentry.init({

   dsn: 'https://<your account key here>@sentry.io/<your project id here>'

});

Tout. Si et quand une erreur se produit dans le code sous cette ligne, Sentry l'enregistrera. Les journaux seront enregistrés même lorsque l'erreur s'est produite en raison de la faute de scripts d'autres domaines:



Sentry a amplement l'occasion d'analyser un tableau de messages d'erreur et de configurer des notifications. Il est également possible de regrouper les journaux d'erreurs par les versions de votre produit:

Sentry.init({

   dsn: 'https://<your account key here>@sentry.io/<your project id here>',

   release: '2020.03.06.1'

});

À l'aide de Sentry, les statistiques peuvent être utilisées pour transférer le contexte d'une erreur, par exemple, les informations client, l'empreinte digitale, le niveau d'erreur (fatal, erreur, avertissement, info, débogage) et la balise.

Il est possible d'enregistrer les événements utilisateur dans les statistiques. Par exemple, vous pouvez définir le suivi pour modifier la taille de la fenêtre du navigateur ou effectuer une demande AJAX. Sentry a également son propre widget avec une fenêtre de rétroaction, qui peut être montrée à l'utilisateur en cas d'erreur. Cela fournira des informations supplémentaires pour enquêter sur les circonstances de l'erreur.

Pour déployer Sentry avec les frameworks, il suffit d'installer le package et de se connecter:

# Using yarn

yarn add @sentry/browser

# Using npm

npm install @sentry/browser


Nous faisons l'initialisation dans le script principal du projet (pour React et Angular):

import * as Sentry from «@sentry/browser»;

Sentry.init({ dsn: 'https://<your account key here>@sentry.io/<your project id here>' });


Pour Vue et Ember, nous passons une autre ligne de configuration requise:

# Vue

Sentry.init({

   dsn: '<your account key here>@sentry.io/<your project id here>',

   integrations: [new Integrations.Vue({Vue, attachProps: true})],

});

# Ember

Sentry.init({

   dsn: '<your account key here>@sentry.io/<your project id here>',

   integrations: [new Integrations.Ember()]

});

Le package d'intégration est installé séparément:

# Using yarn

yarn add @sentry/integrations

# Using npm

npm install @sentry/integrations

Pour éviter les conflits et la duplication d'informations lors de la connexion de plusieurs scripts dans un même projet, Sentry vous permet de créer un client distinct pour chaque initialisation de journalisation:

import { BrowserClient } from «@sentry/browser»;

const client = new BrowserClient({

   dsn: '<your account key here>@sentry.io/<your project id here>',

});

client.captureException(new Error('example'));

Le site Web du projet contient une documentation détaillée avec des exemples d'utilisation: https://docs.sentry.io .

Cet article a été préparé avec le support de la plateforme cloud Mail.ru Cloud Solutions .

Quoi d'autre à lire sur le sujet:

  1. Composants Reactable React: comment arrêter d'écrire la même chose .
  2. Comment éviter les erreurs lors du développement sur React .
  3. - .

All Articles