expo-migrate-module

Par expo · skills

Framework (OSS). Migrer un module natif Apple/Swift existant basé sur l'Expo Modules API 1.0 (DSL de définition) vers l'API macro 2.0 (parfois appelée v2), tout en préservant le contrat JavaScript et TypeScript. À utiliser lors de la conversion ou de l'adoption progressive de `@ExpoModule`, `@JS`, `@Event`, `@SharedObject` ou `@Record` dans un module existant. Ne pas utiliser pour créer un nouveau module, pour des mises à jour générales de l'Expo SDK, ni pour des migrations Android/Kotlin.

npx skills add https://github.com/expo/skills --skill expo-migrate-module

Migrer un module Expo

Migrer le côté Swift d'un module Expo existant sans modifier son API JS observable. Traiter la surface JS/TypeScript actuelle et les tests comme le contrat de compatibilité. Laisser Kotlin sur le DSL 1.0 sauf si l'utilisateur élargit explicitement la tâche.

Prérequis

Les macros de l'API Expo Modules 2.0 nécessitent expo 57.0.7 ou plus récent. Avant de modifier, vérifier la version installée de la cible (expo dans package.json/lockfile, ou npm ls expo). Si elle est plus ancienne, s'arrêter et demander à l'utilisateur de mettre à niveau d'abord ; ne pas tenter la migration contre une version non prise en charge. C'est un plancher, pas une garantie : la surface macro et core exacte varie toujours dans 57.x, donc l'étape 2 doit toujours vérifier la source extraite.

Références

  • Lire references/migration-map.md avant de modifier la source. Elle contient les mappages 1.0-to-2.0, les pièges sémantiques, et les règles de mode mixte.
  • Lire references/example.md pour une démonstration complète avant/après d'un module en mode mixte jusqu'à une migration complète. La consulter quand on a besoin de voir comment les règles par membre se composent.
  • Lire references/compatibility.md quand la version ou la branche expo-modules-core extraite n'est pas connue pour supporter chaque macro demandée. Elle explique comment vérifier la surface compile-time et runtime réelle au lieu de deviner à partir d'un numéro de SDK.

Flux de travail

1. Établir le contrat

Inspecter les instructions du repository et l'arborescence avant de modifier. Localiser les classes de module Swift, les records, les objets partagés, les vues natives, les bindings JS/TS, les tests, l'app exemple, le podspec, et expo-modules-core installé ou extrait.

Inventorier chaque élément exporté avant de le réécrire :

  • noms JS du module et des objets partagés
  • noms de fonction, arité, labels, valeurs par défaut, nullabilité, comportement sync/async, erreurs, et sémantique de queue
  • noms de propriété, mutabilité, et comportement de cache constant
  • noms de wire d'événement et formes de payload
  • noms de champ record, valeurs par défaut, requérabilité, et nullabilité
  • constructeurs d'objet partagé et placement instance/static
  • hooks de cycle de vie et vues

Utiliser les déclarations TypeScript et les sites d'appel JS pour résoudre l'ambiguïté. Ne pas silencieusement « améliorer » la requérabilité, renommer un événement, ou changer le comportement sync pendant une migration syntaxique.

2. Vérifier la surface 2.0 disponible

Inspecter les déclarations de macro et les hooks core correspondants dans la dépendance réellement utilisée par la cible. Ne pas supposer que tous les éléments du design 2.0 sont présents parce qu'une macro compile.

Classifier chaque élément 1.0 comme :

  • Migrer : sa macro et le support runtime core requis existent.
  • Garder dans le DSL : le mode mixte le préserve en sécurité, ou 2.0 n'a pas d'équivalent.
  • Bloqué : la migration altèrerait le contrat JS ou nécessite un support runtime indisponible.

Préférer un résultat en mode mixte incrémental au code généré spéculatif. Garder definition() pour tout élément DSL restant ; le supprimer seulement s'il est vide et que le nom de module résolu est préservé par @ExpoModule.

3. Appliquer la migration

Migrer un groupe sémantique à la fois : noms de module, fonctions, propriétés/constantes, événements, objets partagés, puis records. Garder le diff étroit.

Suivre ces invariants :

  • Préserver explicitement chaque nom JS-visible existant quand les règles de nommage Swift ou les défauts de macro diffèrent.
  • Garder le comportement optionnel/défaut original. Un champ record 1.0 optionnel ne doit pas devenir requis simplement parce que 2.0 peut exprimer des champs requis.
  • Ne pas migrer les surcharges de même nom JS à moins que la macro extraite ne les groupe et dispatche.
  • Ne pas migrer les fonctions DSL épinglées à queue tel quel ; restructurer vers Swift Concurrency ou dispatcher vers la queue originale via une continuation, selon les règles async-function dans references/migration-map.md.
  • Ne pas migrer les vues, unions, événements synchrones, ou fonctions statiques d'objet partagé sans support vérifié.
  • Ne pas changer Kotlin, les wrappers JS, ou les fichiers .d.ts publics sauf si l'utilisateur a demandé un changement d'API.

Après chaque groupe, rechercher les anciennes entrées DSL et les sites d'appel qui auraient dû se déplacer. Éviter le formatage large ou le nettoyage non lié.

Quand un équivalent 2.0 manque ou un groupe échoue

Quand l'étape 2 a classifié un élément comme Bloqué, ou qu'un groupe migré échoue à compiler ou casse le contrat, ne pas le forcer. S'arrêter sur ce groupe et :

  1. Demander à l'utilisateur comment procéder pour cet élément, avec deux options :

    • Co-exister : garder l'élément dans le DSL definition() 1.0 à côté du @ExpoModule migré (mode mixte) et continuer avec les autres groupes.
    • Revenir : annuler les modifications du groupe, le laisser intact sur 1.0, et passer au suivant.

    Par défaut, préférer la co-existence quand le mode mixte est vérifié sûr, car il préserve le plus de progrès. Revenir quand le changement partiellement appliqué a laissé le module dans un état ne compilant pas et ne peut pas être sauvegardé de manière incrémentale.

  2. Ouvrir un issue de suivi sur expo/expo notant la fonctionnalité que 2.0 ne couvre pas encore, de sorte que l'écart soit enregistré plutôt que silencieusement contourné. Utiliser gh issue create --repo expo/expo et confirmer avec l'utilisateur avant de poster (selon les conventions du repo, ne pas poster de commentaires visibles sans approbation). Inclure :

    • le membre 1.0 et son contrat JS
    • la macro spécifique ou le hook core manquant (citer l'écart de preuve de references/compatibility.md)
    • la version/branche expo-modules-core extraite

    Référencer l'issue dans le handoff pour que l'entrée DSL restante soit traçable à une limitation connue.

Continuer avec les groupes qui migrent sans problème ; un membre bloqué ne bloque pas le reste.

4. Vérifier le comportement

Exécuter les vérifications les plus étroites en premier, puis la surface d'intégration réelle :

  1. Compiler ou vérifier les types du module Apple contre la cible expo-modules-core.
  2. Exécuter les tests unitaires natifs et les tests JS/TS.
  3. Compiler et lancer l'app exemple quand le repository en fournit une.
  4. Comparer la surface exportée finale avec l'inventaire de l'étape 1.
  5. Rechercher les entrées Name périmées, les entrées migrées Function/Property/Constant/Events, les anciens appels sendEvent, @Field, et les registrations dupliquées.

Les tests d'expansion seuls sont insuffisants : le code macro généré peut sembler correct tout en échouant contre les symboles core mal appairés. Si les dépendances ont changé ou les flags du plugin macro manquent, réinstaller les dépendances JS le cas échéant, exécuter le flux de travail d'installation CocoaPods du repository, et redémarrer Xcode avant de diagnostiquer les défaillances de communication du plugin.

Handoff

Signaler :

  • quels membres ont passé à 2.0
  • quels membres restent intentionnellement dans le DSL 1.0 et pourquoi
  • tous les choix sensibles à la compatibilité, spécialement les noms d'événement, la requérabilité record, les constantes, et les queues
  • les commandes exécutées et toute vérification non complétée

Skills similaires