Fable: [Discussion] Dépendances transitives

Créé le 27 avr. 2017  ·  43Commentaires  ·  Source: fable-compiler/Fable

Poursuivant la conversation de gitter sur le support des dépendances transitives @alfonsogarciacaro ajoute, commencé dans https://github.com/fable-elmish/react/issues/1 :

Les dépendances de fable doivent être de peer pour empêcher npm de les dupliquer dans des sous-répertoires s'il y a des conflits de version. Ils ne peuvent pas être dev car ils doivent également être installés sur la machine de l'utilisateur final de votre bibliothèque.
À propos de peerDependencies non-Fable . Fable va simplement tout installer et vérifier s'il y a un fichier .fsproj dans le dossier racine du paquet. Dans ce cas, il ajoutera une référence de projet, les autres seront ignorés.
J'essaie juste de définir le processus, nous pourrions également avoir la convention que toutes les bibliothèques Fable sont préfixées par fable - par exemple.
Autant que je sache, les devDependencies ne sont installés que sur l'ordinateur développeur et non sur le consommateur de la bibliothèque. Je suppose que nous pourrions les utiliser comme convention pour les bibliothèques de fables mais je ne vois pas l'intérêt de forcer la sémantique npm, vous pouvez également avoir des devDependencies qui ne sont pas des bibliothèques Fable.

Je suppose que la situation est la suivante :

  • Les bibliothèques de fable distribuées en tant que sources, comme tout ce qui est sujet à transpilation, ont traditionnellement été une dépendance de dev .
  • les conseils pour les bibliothèques de fables jusqu'à présent ont été "ne pas répertorier les dépendances de fable en tant que peer ou normales, laissez l'utilisateur le découvrir et l'installer".
  • maintenant que nous avons dotnet fable add nous pouvons examiner les dépendances de la bibliothèque en cours d'ajout et potentiellement déclencher l'installation de ses dépendances (transitives).

Question : devrions-nous ?
Question : si oui, quelle est la section appropriée dev ou peer ?
Question : quel est le prédicat pour déclencher une installation de dépendance transitive ?
Question : quel est le comportement souhaité si installé avec yarn au lieu de dotnet fable add ?

discussion

Commentaire le plus utile

Bien que j'aime personnellement Nix et utilise tous les jours (faire F # et le développement Fable sur Nixos) mon expérience personnelle est que Nix a une forte courbe d' apprentissage qui pourrait se révéler désavantageux pour les nouveaux utilisateurs et le projet. Ce sera particulièrement écrasant pour ce genre de personnes qui sont curieuses et qui veulent juste essayer les choses rapidement, car non seulement elles devront apprendre le langage (F#) et les outils, mais aussi le langage d'expression Nix, comment composer des ensembles de packages et comment configurer des environnements de développement. Sans dire que mes expériences sont représentatives pour les autres, mais il m'a fallu un certain temps pour comprendre tout cela et devenir productif. Ainsi, une intégration profonde avec Paket est - à mon avis - préférable. Mon 2¢.

Tous les 43 commentaires

Mes lignes directrices approximatives pour cela seraient:

  • Quelque chose de facile à faire manuellement, l'automatisation doit être une commodité et non une exigence.
  • Nécessite une convention minimale, pour réduire les possibilités de mauvaises configurations (on pourrait aussi ajouter une commande dotnet fable validate pour vérifier que les bibliothèques respectent la convention, mais encore une fois cela devrait être simple).

Nous pourrions également envisager d'utiliser Nuget pour distribuer les bibliothèques Fable.

Avantages de l'utilisation de npm :

  • Facilite l'inclusion de fichiers JS et de dépendances dans les bibliothèques Fable
  • Facilite le push d'un package avec le même contenu qu'un référentiel de projet
  • Conforme à la structure habituelle des projets Webpack où tout est contenu dans le même répertoire (bien que cela puisse être résolu en utilisant resolve dans la configuration Webpack)
  • Il y a des packages qui doivent être distribués par npm forcément : fable-loader et d'autres outils comme Babel ou Webpack

Avantages de l'utilisation de Nuget :

  • Peut-être une meilleure distinction entre les dépendances JS et F# ?
  • Peut utiliser Paket pour gérer les dépendances de Fable

Autre, par exemple Github (Elm fait comme ça, je crois) :

  • Peut utiliser Paket pour gérer les dépendances de Fable
  • Plus ou moins les mêmes avantages qu'avec npm, mais GH n'est pas un gestionnaire de paquets donc on peut avoir des problèmes quand GH est en panne et/ou on a des millions d'utilisateurs XD

Aussi, juste pour résumer la situation actuelle avec les bibliothèques Fable dans Fable 1.0 beta :

  • Comme @et1975 , les devDependencies pour cela mais ils précompilent avant de distribuer le package, et nous avons décidé de ne pas le faire avec les bibliothèques Fable 1.0 (afin que l'utilisateur final puisse définir librement les paramètres de compilation pour tout le code) .
  • Je n'avais pas recommandé d'utiliser peerDependencies auparavant car npm ne les traitait pas correctement. Il semble avoir été corrigé dans npm 4 (et probablement dans le fil aussi), nous devrions donc pouvoir les utiliser maintenant.
  • Dans la publication de l'annonce bêta de Fable 1.0, il est toujours recommandé de répertorier toutes les dépendances telles que dotnet fable add fable-powerpack<strong i="12">@next</strong> fable-react<strong i="13">@next</strong> fable-elmish<strong i="14">@next</strong> fable-elmish-react@next . Dans une version récente, j'ai ajouté une vérification pour peerDependencies donc si fable-elmish-react répertorie toutes les autres comme dépendances, l'utilisateur a juste besoin d'écrire dotnet fable add fable-elmish-react@next .

J'ai utilisé peerDependencies donc je peux demander à npm avant de faire le premier téléchargement, mais nous pourrions aussi vérifier le .fsproj directement (bien que dans ce cas il soit plus difficile de spécifier la version des dépendances). De plus, pour plus de simplicité, je répertorierais simplement toutes les dépendances dans le package final, mais nous pourrions plus tard vérifier l'ensemble de l'arbre de dépendances (donc fable-elmish-react n'a besoin de répertorier que fable-elmish au lieu de fable-elmish et fable-powerpack.

Personnellement, je préférerais m'en tenir à npm.

Je ne suis pas sûr que ce soit une bonne chose de faire une "distinction entre les dépendances JS et F#".

J'aime penser comme ça :

  • Si je suis côté serveur, j'utilise le nuget pour obtenir les libs (suave, Newtonsoft, etc.)
  • Si je suis côté client, j'utilise npm pour gérer les libs (react, fable-elmish, etc.)

Cependant, nous avons toujours une utilisation minimale de nuget côté client lorsque nous faisons dotnet restore ^^ (ne peut pas être parfait)

Dans ma tête, les services homologues sont des choses dont vous avez besoin, mais vous voulez que l'utilisateur puisse mettre à niveau ou rétrograder à volonté. C'est un dep si vous en avez besoin et que vous souhaitez contrôler la version qui est installée avec votre bibliothèque. Il devrait appartenir au développeur d'utiliser dans un scénario donné. Donc elmish pourrait avoir fable en tant que dep, mais powerpack en tant que pair dep. La principale différence pour moi, c'est qu'avec dep, cela m'est caché, avec des pairs dep, je garde le contrôle. Si PowerPack met à jour, en tant que service homologue, je peux le mettre à niveau, en tant que service, je dois attendre que vous le mettiez à niveau ou que vous installiez ma propre version.

Pour moi, nous devrions simplement fournir des conseils sur le moment d'utiliser les deux et les implications de cela.

BTW, la première chose que je fais après git clone ou dotnet fable new est de changer mon package.json en ceci :

"scripts": {
    "build": "webpack",
    "start": "webpack-dev-server",
    "test": "echo \"Error: no test specified\" && exit 1",
    "postinstall": "dotnet restore",
    "fable": "dotnet fable npm-run",
    "bld": "yarn fable -- build",
    "dev": "yarn fable -- dev"
  },

Cela m'ennuie énormément que Fable m'ait volé le début et la construction. OMI, ça devrait plutôt ressembler à ça mais je ne peux pas sans le casser.

"scripts": {
    "webpack": "webpack",
    "webpack-dev-server": "webpack-dev-server",
    "test": "echo \"Error: no test specified\" && exit 1",
    "postinstall": "dotnet restore",
    "fable": "dotnet fable npm-run",
    "build": "yarn fable -- build",
    "start": "yarn fable -- start"
  },

L'avantage d'ajouter la post-installation, c'est que maintenant la restauration dotnet est exécutée automatiquement chaque fois que j'installe quelque chose avec fil, l'inconvénient est qu'elle s'exécute chaque fois que j'installe quelque chose avec fil, même s'il n'y a rien à faire.

Je préférerais que le code FS ne soit pas du tout dans npm et dans Nuget, car ni Visual Studio ni le nouveau Rider IDE EAP ne rechercheront dans les modules de nœud le code .fs même s'il est spécifié dans le .fsproj. De plus, je veux écrire le même F# où que je sois, c'est-à-dire ne pas suivre les conventions JS de lowerCamelCase. JavaScript pour moi, est l'IL pour Fable, mais Fable est toujours F#. Cela signifie que nous devrions utiliser les conventions F# pour tout. Je ne veux pas écrire une application de console dotnet core et utiliser UpperCamelCase, puis je dois me rappeler qu'il s'agit de lowerCamelCase dans Fable. Juste mon avis.

Personnellement, je ne pense pas qu'une source devrait être dans node_modules, qui est destiné au code prêt à être utilisé, c'est pourquoi la plupart des IDE l'ignorent et le masquent par défaut.

@mizzle-mo j'utilise ce package.json :

"scripts": {
  "postinstall": "dotnet restore Main.fsproj",
  "build": "dotnet fable webpack",
  "watch": "dotnet fable webpack-dev-server"
}

Maintenant, je peux juste utiliser yarn build et yarn watch et je n'ai pas du tout besoin d'utiliser dotnet .

Bon, ça va être un long post...

Tout d'abord, quelques faits :

  • peerDependencies est utilisé dans les bibliothèques, il force une seule version d'un package, et le consommateur final doit spécifier tous les peerDependencies :

    {
    "name": "some-library",
    "peerDependencies": {
      "fable-elmish": "^1.0.0"
    }
    }
    
    {
    "name": "some-other-library",
    "peerDependencies": {
      "some-library": "^1.0.0"
    }
    }
    
    {
    "name": "my-application",
    "devDependencies": {
      "some-other-library": "^1.0.0",
      "some-library": "^1.0.0",
      "fable-elmish": "^1.0.0"
    }
    }
    

    Notez que l'application a dû lister fable-elmish et some-library comme dépendances, car ce sont des dépendances transitives de pairs dans some-library et some-other-library

    Cela signifie que l'application doit être consciente de toutes les dépendances (directes et transitives) dans l'ensemble de son application. Heureusement, npm et fil vous avertiront si vous oubliez une dépendance aux pairs.

  • Parce que F# est nominalement typé, nous devons forcer une seule version par package. Permettre à plusieurs versions du même paquet causera la douleur, car les types seront incompatibles entre les différentes versions.

  • Cependant, forcer une seule version provoque un enfer de dépendance massif, car cela signifie que la mise à niveau d'un package nécessite également la mise à niveau de tous les autres packages dépendants. Semver aide, mais ce n'est pas parfait, et cela n'aide pas à interrompre les changements.


Il existe cependant une solution au problème ci-dessus : les ensembles de packages. Un ensemble de packages n'est essentiellement que quelques métadonnées qui répertorient tous les packages disponibles + une version pour chaque package + les dépendances de chaque package.

Cette solution est utilisée par Haskell (avec Stack ) et PureScript (avec psc-package )

Voici l' ensemble de packages PureScript standard . Cela peut sembler intimidant, mais c'est en fait très simple. Voici la structure de base :

{
  "foo": {
    "dependencies": [
      "bar",
      "qux"
    ],
    "repo": "https://github.com/foo/foo.git",
    "version": "v3.0.0"
  },
  "bar": {
    "dependencies": [
      "qux"
    ],
    "repo": "https://github.com/bar/bar.git",
    "version": "v2.1.0"
  },
  "qux": {
    "dependencies": [],
    "repo": "https://github.com/qux/qux.git",
    "version": "v5.0.0"
  }
}

Chaque clé est le nom du package (par exemple foo , bar , qux ), et chaque package a une liste de dépendances, une URL Git où le package peut être trouvé , et la version.

Notez qu'il ne répertorie pas la version des dépendances. En effet, chaque dépendance utilisera la version spécifiée dans le fichier JSON.

Par exemple, bar a été répertorié comme version v2.1.0 , donc tous les packages qui dépendent de bar utiliseront [email protected] Cela garantit qu'il n'y a que une seule version de chaque package.

L'avantage de ceci est que tous les packages + leurs dépendances sont répertoriés au même endroit. Disons donc que qux sort une nouvelle version majeure. Avec npm, chaque package qui dépend de qux devra être mis à niveau individuellement vers la nouvelle version de qux .

Mais avec les ensembles de packages, vous n'avez besoin de modifier le numéro de version qu'à un seul endroit, c'est donc beaucoup plus facile. Cela signifie également que l'ensemble de packages est toujours cohérent , vous n'avez donc pas à vous soucier de l'enfer des dépendances.

Il est également important de noter que l'ensemble de packages lui-même a également une version. Les ensembles de packages Haskell et PureScript sont immuables et reproductibles : la seule façon de modifier quoi que ce soit dans l'ensemble de packages est de publier une nouvelle version de l'ensemble de packages.

Et ils n'utilisent pas non plus semver : toutes les versions sont exactes. Cela a le même avantage qu'un fichier de verrouillage : cela garantit que les packages fonctionneront correctement. Vous n'avez jamais à vous soucier de la publication d'une nouvelle version par un package, puis de la rupture d'autres packages.

Mais même s'ils n'utilisent pas semver, il n'est pas difficile de maintenir les packages à jour, car les versions sont toutes spécifiées au même endroit : l'ensemble de packages. Donc, vous venez de modifier la version dans l'ensemble de packages et vous avez terminé.

Il y a aussi d'autres avantages : l'ensemble de packages sert de liste organisée de packages, il est donc possible d'exclure les packages qui ne sont pas de qualité suffisante (si vous le souhaitez). Et cela permet également aux utilisateurs de trouver plus

Vous pouvez également faire des choses comme exécuter une intégration continue automatique sur l'ensemble du package (pour exécuter des tests unitaires et attraper des régressions).

Ou vous pouvez afficher une page Web qui répertorie tous les packages + la documentation pour chaque package ( Haskell et PureScript le font).

Et vous pouvez ajouter des sommes de contrôle (facultatifs) qui garantissent que les packages n'ont pas été corrompus ou falsifiés. Cela augmente la sécurité et la reproductibilité.

C'est un système vraiment fantastique qui résout complètement de nombreux problèmes : il garantit qu'il n'y a qu'une seule version de chaque package, il garantit aucune dépendance infernale, il garantit des builds reproductibles, il est consultable, il est cohérent et il est facile à gérer.

Bien sûr, le compromis avec les ensembles de packages est que vous créez essentiellement un gestionnaire de packages spécifique à Fable. Le gestionnaire de packages de PureScript est vraiment simple, donc l'idée de "gestionnaire de packages personnalisé" n'a pas besoin d'être effrayante. Mais c'est un compromis qui doit être considéré.

Je peux expliquer plus de détails sur les ensembles de packages, si vous le souhaitez.


Il y a d'autres trucs géniaux comme Nix , qui, je crois, sont similaires aux ensembles de packages, mais je n'ai aucune expérience avec cela.

Aussi, juste pour être clair, même si j'aime vraiment les ensembles de packages, et je pense qu'ils sont absolument la bonne façon de gérer les packages, je suis d'accord pour utiliser npm ou paket à la place. Ce ne sera pas aussi bon que les ensembles de packages, mais il aura une meilleure intégration avec les packages / systèmes / outils existants.

Si nous décidons d'utiliser npm, nous souhaitons probablement utiliser peerDependencies dans les bibliothèques et devDependencies dans les applications. Cela rend les choses plus ennuyeuses pour les applications (car elles doivent spécifier toutes les dépendances transitives), mais cela garantit une seule version par package.

Étant un utilisateur de Haxe, je l'ai mis ici. Ça peut donner des idées : Haxelib

Merci beaucoup pour les commentaires utiles!

@mizzle-mo À propos de la visibilité des dépendances, c'est délicat. Il est vrai que dans Fable 1.0, ils ne sont pas du code "prêt à l'emploi", mais pour le moment, nous les considérons comme des dépendances normales que la plupart des packages cachent d'une manière ou d'une autre. Je ne pense pas que cela changerait même si nous les déplaçons vers Nuget. Nous pourrions également envisager d'installer des projets de dépendance Fable côte à côte avec le projet utilisateur, mais cela soulèverait probablement un autre ensemble de questions (comme si les projets de dépendance devaient être ajoutés au référentiel utilisateur, etc.).

@Pauan L'idée des ensembles de packages semble très intéressante et, comme vous le dites, elle peut aider à stabiliser l'écosystème Fable, à s'assurer que les packages fonctionnent bien les uns avec les autres et offrent une meilleure visibilité. Je suppose que cela a un coût en termes de flexibilité, par exemple, si un auteur de package souhaite publier une nouvelle version majeure avec quelques modifications importantes, il doit s'assurer que les packages dépendants fonctionnent toujours avant de remplacer la version de l'ensemble de packages. Ai-je raison?

La seule chose qui me rebute est l'idée d'avoir un gestionnaire de packages personnalisé pour cela. Non seulement à cause de la surcharge de maintenance supplémentaire pour Fable, mais aussi parce que les utilisateurs auraient à traiter avec 3 gestionnaires de paquets car nous ne pouvons pas éviter d'utiliser à la fois npm/yarn et Nuget/Paket pour le moment.

@whitetigle Haxelib serait également un gestionnaire de packages personnalisé pour Haxe, non ? Où sont hébergés les packages ? Est-ce que ça marche aussi avec les ensembles de paquets ?

La seule chose qui me rebute est l'idée d'avoir un gestionnaire de packages personnalisé pour cela. Non seulement à cause de la surcharge de maintenance supplémentaire pour Fable, mais aussi parce que les utilisateurs auraient à traiter avec 3 gestionnaires de paquets car nous ne pouvons pas éviter d'utiliser à la fois npm/yarn et Nuget/Paket pour le moment.

100% d'accord.

Haxelib serait également un gestionnaire de packages personnalisé pour Haxe, n'est-ce pas ? Où sont hébergés les packages ? Est-ce que ça marche aussi avec les ensembles de paquets ?

En effet, haxelib est un gestionnaire de packages personnalisé. Les packages sont hébergés sous forme de fichiers zip sur un serveur central

Ensuite, lorsque nous installons des packages, chacun résout ses propres dépendances comme ceci :

{
    "name": "flixel",
    "url" : "http://haxeflixel.com",
    "license": "MIT",
    "tags": ["game", "openfl", "flash", "html5", "neko", "cpp", "android", "ios", "cross"],
    "description": "HaxeFlixel is a 2D game engine based on OpenFL that delivers cross-platform games.",
    "version": "4.2.1",
    "releasenote": "Fixed rendering with Haxe 3.4.0 and OpenFL Next.",
    "contributors": ["haxeflixel"],
    "dependencies": { "lime": "2.9.1", "openfl": "3.6.1" }
}

Concernant la remarque de @Pauan :

Cela garantit qu'il n'y a qu'une seule version de chaque package.

Sauf indication contraire, haxelib installe la dernière version du package, mais nous pouvons avoir des dizaines de versions différentes, en particulier lorsque nous avons encore besoin de cette ancienne fonctionnalité obsolète... Ils utilisent un serveur personnalisé.

Mais si j'ai bien compris, il ne semble pas quelque chose de cohérent comme un ensemble de packages qui semble génial !

@alfonsogarciacaro Voici comment cela fonctionne dans PureScript : il existe un responsable de l'ensemble de packages, qui gère le dépôt de l'ensemble de packages .

Lorsqu'un auteur de bibliothèque crée une nouvelle version de sa bibliothèque, il envoie une demande d'extraction pour mettre à niveau la version de la bibliothèque dans le packages.json . Cette pull request doit être acceptée (ou rejetée) par le mainteneur de l'ensemble de packages.

Il y a des discussions sur la manière de rendre ce processus plus facile, y compris la possibilité d'avoir un bot qui acceptera automatiquement les demandes de tirage.

Même après l'acceptation de la pull request, cela n'affecte personne, car tout le monde utilise toujours l'ancienne version de l'ensemble de packages.

À intervalles réguliers, le responsable de l'ensemble de packages publiera une nouvelle version de l'ensemble de packages, puis les auteurs d'applications pourront basculer vers la nouvelle version de l'ensemble de packages.

Bien entendu, les applications peuvent continuer à utiliser l'ancienne version de l'ensemble de packages. En fait, les applications peuvent utiliser n'importe quelle version de l'ensemble de packages, même de très anciennes versions, et sa cohérence est toujours garantie, car les ensembles de packages sont immuables.

Essentiellement, chaque version d'ensemble de packages est un instantané immuable du packages.json à un moment donné. Les auteurs de la bibliothèque peuvent modifier le packages.json , mais les responsables de l'ensemble de packages choisissent quand créer l'instantané et publier la nouvelle version de l'ensemble de packages.

Faire un instantané signifie simplement utiliser git tag pour marquer un commit dans le repo de l'ensemble de packages . C'est tout ce qui est nécessaire pour publier une nouvelle version de l'ensemble de packages. C'est très simple pour les mainteneurs du paquet.

Il est possible d'avoir plusieurs mainteneurs pour un ensemble de packages, et il est possible d'avoir plusieurs ensembles de packages, mais ces situations sont rarement nécessaires.

Si un auteur de bibliothèque publie une nouvelle version majeure, toutes les bibliothèques qui dépendent de cette bibliothèque devront être mises à jour. Les auteurs de la bibliothèque disposent d'un certain temps (généralement quelques semaines environ) pour passer à la nouvelle version majeure. S'ils ne sont pas mis à niveau à temps, leur package sera supprimé de l'ensemble de packages.

Une fois toutes les bibliothèques dépendantes mises à niveau ou supprimées, une nouvelle version majeure de l'ensemble de packages est publiée.

Par exemple:

  1. Mises à niveau de la bibliothèque foo de 1.0.0 à 2.0.0

  2. La bibliothèque bar est à la version 1.0.0 et elle a une dépendance sur [email protected]

  3. La bibliothèque qux est à la version 1.0.0 et elle a une dépendance sur [email protected]

  4. La bibliothèque corge est à la version 1.0.0 et elle a une dépendance sur [email protected]

  5. Les auteurs de bar , qux et corge sont informés qu'ils doivent passer à [email protected]

  6. La bibliothèque bar change pour utiliser [email protected] , et passe de 1.0.0 à 1.0.1 car bar n'a pas eu besoin d'apporter de modifications importantes

  7. La bibliothèque qux change pour utiliser [email protected] , et passe de 1.0.0 à 2.0.0 car qux devait apporter des modifications importantes

  8. La bibliothèque corge n'a pas été mise à niveau à temps, elle est donc supprimée de l'ensemble de packages

  9. Des tests d'intégration continue sont exécutés et s'ils réussissent, une nouvelle version majeure de l'ensemble de packages est publiée

Cela garantit que chaque version de l'ensemble de packages est cohérente.

Ce qui précède est à peu près le pire des cas, le processus est beaucoup plus facile pour les modifications de version non majeures :

  1. Bibliothèque foo mises à jour de la version 1.0.0 à 1.0.1

  2. Des tests d'intégration continue sont exécutés et s'ils réussissent, une nouvelle version mineure de l'ensemble de packages est publiée


La discussion ci-dessus concerne le dépôt de l'ensemble de packages et les auteurs de la bibliothèque, mais cela vaut également la peine de parler de l'expérience d'un développeur d'applications.

En tant que développeur d'applications, vous créez un fichier psc-package.json , qui ressemble à ceci :

{
    "name": "my-project",
    "set": "psc-0.10.2",
    "source": "https://github.com/purescript/package-sets.git",
    "depends": [
        "foo",
        "bar"
    ]
}
  • Le "source" est l'URL du référentiel de l'ensemble de packages

  • Le "set" est la version de l'ensemble de packages utilisé par votre application (il s'agit simplement d'une balise git dans le référentiel de l'ensemble de packages )

  • Le "depends" est la liste des bibliothèques de l'ensemble de packages que votre application utilise

Vous pouvez utiliser psc-package install foo pour installer la bibliothèque foo partir de l'ensemble de packages. Il ajoutera automatiquement foo au tableau depends .

La mise à niveau vers une nouvelle version de l'ensemble de packages est aussi simple que de modifier la propriété "set" puis d'exécuter psc-package update

Comme vous pouvez le voir, c'est super facile pour les développeurs d'applications, notamment parce qu'ils bénéficient d'une cohérence garantie.

Ainsi, les ensembles de packages imposent un peu plus de fardeau aux auteurs de bibliothèques et aux mainteneurs d'ensembles de packages, mais en échange, cela rend les choses tellement meilleures pour les auteurs d'applications.


Avoir trois gestionnaires de packages est certainement mauvais, mais si dotnet obtient l'intégration pour les gestionnaires de packages personnalisés, nous pouvons intégrer les ensembles de packages fil + Paket + Fable. Il utiliserait toujours trois gestionnaires de paquets, mais il serait caché sous un seul système dotnet .

Nix est similaire aux ensembles de packages, il est également basé sur des instantanés cohérents immuables et il prend déjà en charge npm. Je ne sais pas s'il prend en charge Paket cependant.

@Pauan Ne pouvons-nous pas faire 3 gestionnaires de paquets avec du fil maintenant? Nous pouvons restaurer par dotnet à l'étape de post-installation, ce qui pourrait également lancer le 3ème gestionnaire de packages, j'aime l'idée des ensembles de packages.

Je suis confus, qu'est-ce qui constitue un ensemble et comment le fait de supprimer une bibliothèque d'un autre le maintient-il utile ? Peut-être qu'un exemple de l'écosystème de la fable m'aiderait à comprendre cela.
cc @forki qui est curieusement absent de la discussion.

@et1975 Je crois comprendre que cela permettrait un emballage similaire à un dépôt mono. Où Elmish, Fable, Powerpack, seraient emballés avec un numéro de version. Ainsi, lorsque je dois mettre à jour mes deps, je reçois les 3 dans une version connue pour fonctionner ensemble (avec test). Ainsi, les consommateurs mettraient à jour une dépendance au lieu de 3. Ensuite, nous pourrions faire la même chose pour Electron, où cela dépend du package centralisé, mais est lui-même également distribué sous forme de package avec les 4. @Pauan me corrigera si je me trompe. Il est bon à ça. :)

@mizzle-mo Oui, nous pouvons utiliser postinstall . C'est un peu maladroit, mais ça marche. C'est juste qu'un troisième gestionnaire de paquets signifie des choses supplémentaires à maintenir, des choses supplémentaires à apprendre, des parties supplémentaires qui peuvent casser.

Là encore, un système d'ensembles d'emballages peut être conçu de manière simple et robuste, de sorte que la casse devrait être assez rare.

Vous avez raison de dire que le concept d'ensembles de packages est similaire à un monorepo, sauf qu'il n'exige pas que tous les packages se trouvent dans un seul référentiel Git, il s'adapte donc à de nombreux développeurs / référentiels / packages. Les ensembles de packages d'Haskell contiennent plus de 2 300 packages, ce qui est évidemment infaisable avec un monorepo.


@et1975 Il existe de nombreuses façons d'implémenter des ensembles de packages, mais la façon dont PureScript le fait est qu'il existe un dépôt git qui contient un fichier packages.json :

{
  "aether": {
    "dependencies": [],
    "repo": "https://github.com/Prolucid/fable-aether.git",
    "version": "927a4083e78f41b62669ac4030747478cd2f5b50"
  },
  "elmish": {
    "dependencies": [
      "powerpack"
    ],
    "repo": "https://github.com/fable-elmish/elmish.git",
    "version": "v0.8.0"
  },
  "powerpack": {
    "dependencies": [],
    "repo": "https://github.com/fable-compiler/fable-powerpack.git",
    "version": "19b64ecf670e015ec23fb11d6f9069f4c3c23e75"
  },
  "unit-test": {
    "dependencies": [
      "powerpack"
    ],
    "repo": "https://github.com/fable-compiler/fable-unit-test.git",
    "version": "f63db8efa7b07be56982b966c0df9866838d232d"
  }
}

Ce fichier packages.json est l'ensemble de packages. Il répertorie tous les packages qui sont dans l'ensemble, et pour chaque package, il répertorie son URL, sa version et ses dépendances. En d'autres termes, les métadonnées sur les versions et les dépendances sont contenues dans un seul endroit. La version peut être soit une balise git, soit un hachage de commit git.

De manière générale, un ensemble de packages contiendra autant de packages que possible. Vous pouvez considérer l'ensemble de packages comme ayant un objectif similaire à celui du registre npm : il s'agit d'une collection de métadonnées sur tous les packages disponibles. Dans le cas de Fable, il contiendrait toutes les bibliothèques Fable disponibles (y compris, mais sans s'y limiter, elmish, powerpack, unit-test, aether, etc.).

Un ensemble de packages n'est qu'un dépôt git avec un fichier packages.json , il est donc bien sûr facile de le créer et d'avoir plusieurs ensembles de packages : par exemple, vous pouvez avoir un package défini pour tous les packages Fable 0.75 et un autre package défini pour Fable 1.0 paquets.

Et il est également possible d'utiliser un ensemble de packages + packages personnalisés. Par exemple, vous pouvez dire "Je veux utiliser les packages de l'ensemble de packages Fable 1.0, et en plus de cela, je veux utiliser un package foo de GitHub / npm / paket / peu importe"

Le fichier packages.json sera mis à jour tout le temps, avec des packages ajoutés, modifiés, supprimés, etc. Mais à intervalles réguliers, une nouvelle version (c'est-à-dire un instantané) de l'ensemble de packages est créée. Dans le cas de PureScript, un instantané n'est qu'une balise git qui pointe vers un commit particulier dans le package set repo .

Étant donné que ces instantanés sont immuables, cela signifie que si vous passez à un instantané plus ancien, vous aurez accès à tout ce qui était disponible à ce moment-là. Par exemple, si un package est supprimé dans l'instantané 2.0.0 , vous pouvez revenir à l'instantané 1.0.0 qui contient toujours le package.

Ou si vous passez à un instantané plus ancien, les versions des packages seront rétrogradées. Ou si vous passez à un instantané plus récent, les versions des packages seront mises à niveau. Fondamentalement, vous pouvez le considérer comme similaire au fichier yarn.lock : il garantit des versions exactes au moment où l'instantané a été créé.

Sauf que contrairement à yarn.lock , un ensemble de packages est partagé par plusieurs personnes, il n'est pas spécifique à un seul projet. Avec le fil, chaque nouveau projet doit trouver indépendamment la bonne combinaison de versions non conflictuelles. Mais avec les ensembles de packages, ce travail ne doit être effectué qu'une seule fois, et chaque projet peut ensuite en bénéficier.

De plus, contrairement à yarn.lock , un ensemble de packages installe uniquement les packages dont vous avez besoin, il n'installe pas tous les packages de l'ensemble !

Quant à savoir pourquoi il est utile de supprimer un package, le gros avantage des ensembles de packages est qu'ils contiennent des packages de travail à jour, organisés, maintenus. En d'autres termes, lors de l'utilisation d'un ensemble de packages, tout devrait simplement fonctionner (tm).

Vous n'avez pas à vous soucier de l'obsolescence d'un package (par exemple, le package fonctionne avec Fable 0.75 mais n'a pas été mis à niveau vers Fable 1.0). Vous n'avez pas à vous soucier qu'un paquet casse un autre paquet. Vous n'avez pas à vous soucier de plusieurs versions du même package. Vous n'avez pas à vous soucier des versions contradictoires. Vous n'avez pas besoin de faire face à l'enfer de la dépendance.

Les packages ne sont supprimés que lorsqu'ils se cassent , donc même si un package n'est pas maintenu, il ne sera pas supprimé tant qu'il continuera de fonctionner.

De plus, même si un paquet est supprimé, cela ne signifie pas qu'il est interdit, cela signifie simplement qu'il n'est pas disponible dans cet instantané particulier. Ceci est fait pour s'assurer que l'ensemble de packages est toujours cohérent et ne présente aucune casse. Une fois la casse réparée, le package peut être rajouté dans un futur instantané. Ce n'est pas grave.

Il est également possible de retarder la publication d'un nouvel instantané jusqu'à ce que le package cassé soit réparé, plutôt que de supprimer le package.

Avec Stack , la plupart des casses sont corrigées par les auteurs du package dans les délais, il est donc rare que les packages soient abandonnés. Ils ont aussi un système où quelqu'un peut se porter volontaire pour être le mainteneur d'un paquet, même s'il n'est pas l'auteur de ce paquet. De cette façon, ils peuvent réparer les casses même si le paquet n'est pas maintenu par l'auteur.

Cela dit, la suppression des paquets cassés est une chose sociale, pas une chose technique, donc le mainteneur de l'ensemble de paquets peut choisir de garder les paquets cassés dans l'ensemble de paquets s'il le souhaite.

D'un point de vue technique, un ensemble de packages n'est qu'un ensemble de métadonnées sur les packages, les versions et les dépendances. Tous les autres avantages (cohérence, non-casse, etc.) doivent être appliqués par le responsable de l'ensemble de packages, c'est donc finalement au responsable de l'ensemble de packages de décider comment il choisit de gérer son ensemble de packages.

Et comme il peut y avoir plusieurs ensembles de packages, différents ensembles de packages peuvent avoir différents responsables, chacun avec ses propres décisions personnelles sur la façon de gérer son ensemble de packages. C'est bien, dans ce cas, le développeur de l'application choisit simplement quel ensemble de packages correspond le plus à ses objectifs.

Mais j'imagine qu'il y aurait un seul ensemble de packages Fable officiel, qui serait la valeur par défaut, donc la plupart des utilisateurs l'utiliseraient simplement. Dans ce cas, nous aurions besoin de décider en tant que communauté comment gérer cet ensemble de packages (par exemple, si les packages cassés doivent être supprimés ou non, combien de temps nous accordons, etc.)

Les ensembles de paquets sont un bon concept et résolvent de nombreux problèmes pratiques avec la compatibilité des transitifs. Mais autant que je sache, cela ne résout pas le problème de la résolution de votre projet. Si les transitifs sont utilisés dans plusieurs ensembles ou si vous utilisez des deps peu communs, les choses se compliquent à nouveau. Il ne faut pas dire "tout marche".
Je pense que le vrai problème en ce moment est que nous avons deux gestionnaires de packages et deux fichiers de projet. Comme @ 7sharp9 l'a dit sur slack, il est très difficile pour les nouveaux arrivants de comprendre qui va où. C'est difficile pour les personnes venant du monde js et pour les personnes venant de .NET. On ne sait pas non plus quel système est le pilote. Utilisons-nous des outils de nœud pour la restauration, la construction, .. ou dotnet ou de faux scripts ? Tout ensemble ? Naturellement, il y a deux façons de le voir selon l'écosystème d'où vous venez. Je veux dire dans la fable suave que nous utilisons FAKE et je pense que cela fonctionne très bien. Mais évidemment, je suis partial et je connais assez bien le faux.
Dans les modèles de fable dotnet, nous utilisons dotnetcli comme pilote. C'est bon mais il me manque tellement de choses.
Dans de nombreux échantillons de fables, vous devez appeler fil. OK bien.

C'est vraiment un gâchis et je pense personnellement que les ensembles de dépendances ne nous aideront pas du tout. Ce n'est pas le problème que nous devons résoudre maintenant.

@forki Je pense que l'idée générale est que vous n'utilisez pas plusieurs ensembles : chaque application utilise un seul ensemble de packages, il n'y a donc pas de problèmes de résolution.

Je conviens qu'il peut toujours se briser dans certaines situations, comme lors de l'utilisation de dépendances npm / paket. Je me demande si cela peut être résolu en archivant un fichier yarn.lock dans le référentiel de l'ensemble de packages, de cette façon les dépendances npm seront également cohérentes.

À tout le moins, cela résout le problème de cohérence avec les dépendances de Fable, donc c'est toujours mieux que le statu quo.

Je suis d'accord qu'avoir à gérer de nombreux gestionnaires de paquets est une énorme douleur. Quel que soit le gestionnaire de packages que nous choisissons, nous avons besoin d'un seul moyen simple pour les utilisateurs de l'utiliser.

Cela peut signifier utiliser plusieurs gestionnaires de packages sous le capot et fournir une API simple aux utilisateurs, ou cela peut signifier utiliser un seul gestionnaire de packages.

Nous avons besoin d'un système d'outils unique, pas d'un méli-mélo de nombreux outils différents.


Je me demande aussi s'il serait possible d'utiliser Nix. C'est beaucoup plus compliqué que les ensembles de packages PureScript, mais il possède également de nombreuses fonctionnalités très utiles : ils ont déjà résolu de nombreux problèmes complexes comme la mise en cache, les builds binaires, l'intégration continue, les sommes de contrôle, etc.

Nix a déjà un package pour F# 4.1 , des milliers de packages npm et des centaines de packages NuGet (y compris FAKE)

Tout comme les ensembles de packages, Nix fournit des instantanés cohérents, même lors de l'utilisation de packages npm ou NuGet. Ainsi, nous obtenons les avantages d'un seul gestionnaire de packages, nous obtenons les avantages de l'utilisation des écosystèmes de packages existants (par exemple, npm, NuGet, etc.) et nous obtenons des instantanés cohérents.

Nix a des packages pour les bibliothèques, mais il a également des packages pour les outils, les compilateurs, les exemples, la documentation, les applications, etc. Nous pouvons donc avoir un seul système cohérent pour tout dans Fable. La seule chose qui m'inquiète vraiment, c'est que je ne suis pas sûr de la qualité de la prise en charge de Windows pour Nix...

Vous ne pouvez pas utiliser un seul ensemble public. Cela ne connaîtrait pas les deps privés.
Vous êtes donc de retour à la gestion de vos propres ensembles. C'est comme résoudre
toi-même.

Am 03.05.2017 18:20 schrieb "Pauan" [email protected] :

@forki https://github.com/forki Je pense que l'idée générale est que vous
n'utilisez pas plusieurs ensembles : chaque application utilise un seul ensemble de packages, donc
il n'y a pas de problèmes de résolution.

Je suis d'accord qu'il peut encore se casser dans certaines situations, comme lors de l'utilisation
dépendances npm/paket. Je me demande si cela peut être résolu en vérifiant dans un
fil.lock dans le référentiel de l'ensemble de packages, de cette façon les dépendances npm seront
aussi être cohérent.

À tout le moins, cela résout le problème de cohérence avec Fable
dépendances, donc c'est toujours mieux que le statu quo.

Je suis d'accord qu'avoir à gérer de nombreux gestionnaires de paquets est une énorme douleur.
Quel que soit le gestionnaire de packages que nous choisissons, nous avons besoin d'un seul moyen simple
pour que les utilisateurs l'utilisent.

Cela peut signifier utiliser plusieurs gestionnaires de paquets sous le capot et
fournir une API simple pour les utilisateurs, ou cela peut signifier utiliser un seul package
directeur.

Nous avons besoin d'un système d'outils unique, pas d'un méli-mélo de nombreux outils différents.

Je me demande aussi s'il serait possible d'utiliser Nix. C'est beaucoup plus
compliqué que les ensembles de paquets PureScript, mais il a aussi beaucoup de très utiles
fonctionnalités : ils ont déjà résolu de nombreux problèmes complexes comme la mise en cache,
builds binaires, intégration continue, sommes de contrôle, etc.

Nix a déjà un package pour F# 4.1
https://github.com/NixOS/nixpkgs/blob/master/pkgs/development/compilers/fsharp41/default.nix ,
des milliers de paquets npm
https://github.com/NixOS/nixpkgs/blob/master/pkgs/development/node-packages/node-packages-v6.nix ,
et des centaines de packages NuGet (y compris FAKE)
https://github.com/NixOS/nixpkgs/blob/master/pkgs/top-level/dotnet-packages.nix

Tout comme les ensembles de packages, Nix fournit des instantanés cohérents, même lors de l'utilisation
npm ou les packages NuGet. Nous bénéficions ainsi des avantages d'un seul gestionnaire de packages,
nous obtenons les avantages de l'utilisation des écosystèmes de packages existants (par exemple, npm, NuGet,
etc.), et nous obtenons des instantanés cohérents.

-
Vous recevez ceci parce que vous avez été mentionné.
Répondez directement à cet e-mail, consultez-le sur GitHub
https://github.com/fable-compiler/Fable/issues/856#issuecomment-298961437 ,
ou couper le fil
https://github.com/notifications/unsubscribe-auth/AADgNGj_UpcDGh2YGCqMaxyD-0X8UOfwks5r2KlAgaJpZM4NKObO
.

Concernant nix. L'utilisation d'une autre norme ne résoudrait pas un seul problème.
Surtout si vous avez beaucoup de forfaits privés.

Am 03.05.2017 18:36 schrieb "Steffen Forkmann" [email protected] :

Vous ne pouvez pas utiliser un seul ensemble public. Cela ne connaîtrait pas les deps privés.
Vous êtes donc de retour à la gestion de vos propres ensembles. C'est comme résoudre
toi-même.

Am 03.05.2017 18:20 schrieb "Pauan" [email protected] :

@forki https://github.com/forki Je pense que l'idée générale est que vous
n'utilisez pas plusieurs ensembles : chaque application utilise un seul ensemble de packages,
il n'y a donc pas de problèmes de résolution.

Je suis d'accord qu'il peut encore se casser dans certaines situations, comme lors de l'utilisation
dépendances npm/paket. Je me demande si cela peut être résolu en vérifiant dans un
fil.lock dans le référentiel de l'ensemble de packages, de cette façon les dépendances npm seront
aussi être cohérent.

À tout le moins, cela résout le problème de cohérence avec Fable
dépendances, donc c'est toujours mieux que le statu quo.

Je suis d'accord qu'avoir à gérer de nombreux gestionnaires de paquets est une énorme douleur.
Quel que soit le gestionnaire de packages que nous choisissons, nous avons besoin d'un seul moyen simple
pour que les utilisateurs l'utilisent.

Cela peut signifier utiliser plusieurs gestionnaires de paquets sous le capot et
fournir une API simple pour les utilisateurs, ou cela peut signifier utiliser un seul package
directeur.

Nous avons besoin d'un système d'outils unique, pas d'un méli-mélo de nombreux outils différents.

Je me demande aussi s'il serait possible d'utiliser Nix. C'est beaucoup plus
compliqué que les ensembles de paquets PureScript, mais il a aussi beaucoup de très utiles
fonctionnalités : ils ont déjà résolu de nombreux problèmes complexes comme la mise en cache,
builds binaires, intégration continue, sommes de contrôle, etc.

Nix a déjà un package pour F# 4.1
https://github.com/NixOS/nixpkgs/blob/master/pkgs/development/compilers/fsharp41/default.nix ,
des milliers de paquets npm
https://github.com/NixOS/nixpkgs/blob/master/pkgs/development/node-packages/node-packages-v6.nix ,
et des centaines de packages NuGet (y compris FAKE)
https://github.com/NixOS/nixpkgs/blob/master/pkgs/top-level/dotnet-packages.nix

Tout comme les ensembles de packages, Nix fournit des instantanés cohérents, même lorsque
en utilisant les packages npm ou NuGet. Ainsi, nous bénéficions des avantages d'un seul package
gestionnaire, nous obtenons les avantages de l'utilisation des écosystèmes de packages existants (par exemple
npm, NuGet, etc.), et nous obtenons des instantanés cohérents.

-
Vous recevez ceci parce que vous avez été mentionné.
Répondez directement à cet e-mail, consultez-le sur GitHub
https://github.com/fable-compiler/Fable/issues/856#issuecomment-298961437 ,
ou couper le fil
https://github.com/notifications/unsubscribe-auth/AADgNGj_UpcDGh2YGCqMaxyD-0X8UOfwks5r2KlAgaJpZM4NKObO
.

@forki Si toutes les bibliothèques Fable se trouvent dans l'ensemble de packages, la plupart des projets n'auront besoin d'aucune dépendance privée. Et pour les projets qui nécessitent des dépendances privées, ils ne devraient pas en avoir trop.

Mais oui, les packages privés vous obligent à faire la résolution vous-même.

Si vous avez de nombreux packages privés, vous pouvez créer votre propre ensemble de packages privés. Il est facile de créer un ensemble de packages, car il ne s'agit que d'un dépôt Git.


Je ne vois pas pourquoi Nix ne résout pas le problème. Nix prend en charge les packages privés. Dans Nix, les packages privés utilisent exactement le même système que les packages publics, vous obtenez donc les mêmes avantages.

Nous avons toujours des dépendances privées dans nos produits. Cela ne réglerait rien pour nous. Cela ne ferait qu'augmenter la douleur puisque maintenant les packages doivent se conformer à nix.

@forki En quoi est-ce différent d'exiger que les dépendances privées se conforment à npm, ou se conforment à NuGet, ou se conforment à Paket?

Quel que soit le gestionnaire de packages que nous décidons d'utiliser, les packages devront se conformer à ce gestionnaire de packages.

Je suppose que vous dites que "nous avons des dépendances privées pour npm, et nous ne voulons pas les changer en Nix, car c'est du travail supplémentaire" ?

On m'a demandé d'aider avec nix une fois. C'était un cauchemar. je ne veux pas
forcer mes collègues là-dessus. Je suppose qu'alors je suivrais mon propre chemin.

Am 03.05.2017 18:44 schrieb "Pauan" [email protected] :

@forki https://github.com/forki En quoi est-ce différent de
exiger que les dépendances privées se conforment à npm ou à NuGet,
ou se conformer à Paket ? Quel que soit le gestionnaire de packages que nous décidons d'utiliser, les packages
devra se conformer à ce gestionnaire de paquets.

Je suppose que vous dites que "nous avons des dépendances privées pour npm, et nous
Je ne veux pas les changer en Nix, car c'est du travail supplémentaire » ?

-
Vous recevez ceci parce que vous avez été mentionné.
Répondez directement à cet e-mail, consultez-le sur GitHub
https://github.com/fable-compiler/Fable/issues/856#issuecomment-298968019 ,
ou couper le fil
https://github.com/notifications/unsubscribe-auth/AADgNLwxzUSLZM3SLK2A_qeu_3BigtTRks5r2K8GgaJpZM4NKObO
.

@forki Je n'ai pas utilisé Nix, donc je suis vraiment curieux : quand avez-vous essayé Nix ? Avez-vous essayé d'utiliser Nix sous Windows ? Quels problèmes avez-vous rencontrés ?

C'était quand nous avons essayé d'ajouter du faux. La plupart des problèmes étaient basés sur mono et principalement
à propos de rendre le processus de construction reproductible. IIRC nous avons abandonné à ce premier
essayer.

Am 03.05.2017 18:51 schrieb "Pauan" [email protected] :

@forki https://github.com/forki Je n'ai pas utilisé Nix, donc je suis vraiment
curieux : quand avez-vous essayé Nix ? Avez-vous essayé d'utiliser Nix sous Windows ? Quoi
des problèmes avez-vous rencontré?

-
Vous recevez ceci parce que vous avez été mentionné.
Répondez directement à cet e-mail, consultez-le sur GitHub
https://github.com/fable-compiler/Fable/issues/856#issuecomment-298969907 ,
ou couper le fil
https://github.com/notifications/unsubscribe-auth/AADgNEffp6-ZASShsev6WRfWxTmzeFjqks5r2LChgaJpZM4NKObO
.

Il y a plusieurs choses qui sont discutées ici. Je pense que c'est bien car cela nous donne l'occasion de discuter des outils et de l'écosystème avant la sortie de la version stable 1.0. C'est le but de la bêta et c'est ce que nous avons fait avec Fable 0.7.

J'ai beaucoup réfléchi à ça. Je vais maintenant essayer de décomposer certains des problèmes actuels et des solutions possibles, il peut être plus facile de les traiter individuellement au lieu d'essayer de tout résoudre en même temps :

Friction entre .NET et JS

La nouveauté du SDK dotnet affecte également cela. Les gens doivent connaître deux écosystèmes, synchroniser les dépendances à partir de deux registres, appeler les outils .NET et JS en même temps, etc. Solutions possibles :

  • Go full JS : grâce au travail de @ncave on y est en gros. Des tests antérieurs ont également montré que cela peut également réduire de moitié le temps initial (les compilations de montres peuvent prendre quelques millisecondes de plus).
  • Gardez Fable comme outil .NET mais amorcez avec Node comme avant : Nous n'avons donc pas besoin des packages Fable Nuget ( dotnet restore seraient toujours nécessaires au moins pour le FSharp.NET.Sdk). Le principal problème que j'ai trouvé pour cela est qu'il est difficile de vérifier le cycle de vie de la compilation à partir d'un chargeur Webpack, il est donc compliqué de savoir quand arrêter le processus .NET.

Distribuer des bibliothèques F# en tant que sources et utiliser des références de projet

L'outil F# n'est pas conçu pour distribuer des bibliothèques en tant que sources et npm n'a évidemment pas été conçu pour distribuer des bibliothèques F#, donc des frictions (qui ont en fait motivé ce fil) sont également attendues ici. Solutions possibles:

  • Utilisez Paket et laissez-le faire sa magie : Cela nécessitera d'ajouter de nouvelles fonctionnalités à Paket pour lier les dépendances à l'aide de références de projet.
  • Utilisez npm et faites que Fable fasse de la magie : Nous utiliserions toujours npm, mais les dépendances de Fable iraient dans le fichier .fsproj avec un nouvel élément comme <FableReference Include="fable-elmish-react" /> et Fable devrait s'occuper d'émettre le bon commandes (déclenchées par fable restore ou similaire). Quelque chose comme cela était à l'étude lors de la mise en œuvre de l'intégration du SDK dotnet. Les autres dépendances JS iraient dans le package.json (ou non).
  • Distribuer en même temps les .dll et les sources : Ce sera beaucoup plus facile pour Paket et les IDE (actuellement le service en langage F# prend beaucoup de temps pour résoudre les dépendances dans un projet fable-elmish-react). Fable rechercherait les sources lors de la compilation. Il peut être un peu difficile de trouver le dossier Nuget sur certaines machines, mais cela devrait être possible.
  • Utiliser le fil par défaut : Cela semble être favorisé par la communauté, cela nous permettra d'utiliser le mode plat par exemple afin de ne pas avoir à nous soucier des dépendances des pairs.

Gestion des versions des dépendances

Un ensemble de packages pourrait être bénéfique pour donner stabilité et visibilité à l'écosystème de Fable, mais nous devons faire attention à la maintenance et à la surcharge cognitive que cela entraînerait. De plus, je pense que si nous pouvons résoudre les problèmes ci-dessus (par exemple, en utilisant un seul gestionnaire de packages), ce sera probablement moins problématique.

Veuillez commenter si vous êtes d'accord avec certaines de ces solutions (laisser les choses telles qu'elles sont est également une alternative) ou si vous avez d'autres suggestions.

@alfonsogarciacaro Je ne sais pas à quel point le mode --flat Yarn est fiable, car je pense qu'il a été créé à l'origine pour des raisons de compatibilité avec Bower, mais Yarn a complètement supprimé la prise en charge de Bower. Je soupçonne donc qu'ils pourraient supprimer ou déprécier --flat à l'avenir. Mais pour l'instant au moins, ça marche.

De plus, lorsque vous créez un package et que vous spécifiez --flat , cela force toutes vos dépendances à être plates. Mais nous ne voulons pas de cela. Nous voulons que nos dépendances Fable soient plates, mais que nos dépendances JavaScript ne le soient pas. Le fil ne permet pas cela, soit tout est plat, soit rien n'est plat. Nous aurions donc toujours besoin d'utiliser peerDependencies

@alfonsogarciacaro @Pauan J'aime l'idée d'utiliser Paket avec des modifications. Je pense que si nous pouvions ajouter la possibilité de lier des références de projet, et peut-être ajouter plus tard la possibilité de différencier les API publiques pour appliquer semver, ce serait basculer et l'outillage aurait plus de facilité si je ne me trompe pas.

Désolé si c'est complètement hors de propos (je n'ai malheureusement pas utilisé fable tout à fait jet, mais je l'espère bientôt). Mais cela pourrait-il être un bon point pour réfléchir à la façon de distribuer des paquets de fable ? Ce que je lis partout avec la distribution des fichiers source et fsproj ressemble plus à un hack des premiers jours ? Ne pouvons-nous pas empaqueter le code dll et javascript (ou quelque chose de similaire) à la place ?

C'est en fait une bonne question @alfonsogarciacaro. Pourquoi emballons-nous la source ?

@mizzle-mo Cela a déjà été discuté et cela n'a aucune incidence sur les choix ci-dessus. Entre autres : parce qu'il laisse au consommateur le libre choix de la sortie : js version/modules system/etc est une matrice, et dans le passé l'auteur de la bibliothèque devait tout produire ; et si la combinaison souhaitée n'est pas là, bonne chance. Personnellement j'aime beaucoup la distribution des sources, ne rouvrons pas cette conversation.

Oui, l'un des principaux problèmes de l'empaquetage des sources JS est que si le compilateur ajoute une nouvelle fonctionnalité (par exemple, des informations de réflexion plus détaillées pour les types), cela oblige les auteurs de packages à republier leurs packages juste pour regrouper le JS généré avec le nouvelle fonctionnalité. Et cela ajoute à l'enfer de la gestion des versions, car vous n'avez pas seulement besoin de prendre la version de la bibliothèque Fable dans le compte, mais la version du compilateur Fable qui a été utilisée pour générer le code. Alors oui, je pense que nous devrions rejeter ce choix.

Cependant, les sources .dll + F# distribuées avec Nuget/Paket sont toujours une option. Il peut cependant y avoir quelques difficultés : si la lib a des dépendances JS, comment les marquer ; si Fable doit collecter tous les fichiers sources, comment il peut résoudre le graphe de dépendance... mais nous pourrions quand même prendre cette direction.

@alfonsogarciacaro Je sais que @forki n'aime pas Nix, mais c'est l'une des fonctionnalités vraiment intéressantes de Nix : si le compilateur Fable change, tous les packages Fable seront automatiquement recompilés pour utiliser le nouveau compilateur Fable. Ainsi, même avec la compilation DLL, les auteurs de bibliothèques n'ont pas besoin de republier manuellement à chaque modification.

Il est également possible de configurer les packages Nix de différentes manières. Par exemple, le consommateur d'une bibliothèque Fable peut choisir le type de module, le polyfill, la version Fable, la version fable-core, etc. Vous n'êtes pas coincé avec le choix fait par l'auteur de la bibliothèque.

Nix a un cache global et les packages Nix sont purs et immuables, de sorte que les packages avec une configuration personnalisée peuvent être mis en cache. À l'heure actuelle, les bibliothèques Fable doivent être recompilées encore et encore. Avec Nix, ils n'auraient besoin d'être compilés qu'une seule fois, puis mis en cache.

Cela signifie que vous bénéficiez d'une flexibilité incroyable, d'une plus grande commodité pour les développeurs et de temps de construction plus rapides. Ils ont vraiment réfléchi à la façon de résoudre ces problèmes d'emballage difficiles.


Je sais que je demande vraiment des ensembles de packages, mais il existe une autre option : des ensembles de packages pour Fable, avec des métadonnées npm supplémentaires :

{
  "foo": {
    "dependencies": [
      "bar",
      "qux"
    ],
    "npm-dependencies": {
      "webpack": "^1.0.0"
    },
    "repo": "https://github.com/foo/foo.git",
    "version": "v3.0.0"
  }
}

C'est le même que précédemment, mais il a un champ npm-dependencies supplémentaire. Cela nous permet de spécifier les dépendances Fable et les dépendances npm dans le même fichier de configuration.

L'installation d'un package est aussi simple que fable install foo . Lorsque Fable installe un package, il utilisera l'algorithme d'ensemble de packages pour les dépendances de Fable, puis il appellera automatiquement yarn pour le npm-dependencies

Cela signifie que les utilisateurs n'ont besoin d'apprendre qu'un seul système, un seul fichier de configuration, un seul ensemble d'outils.

Bien que j'aime personnellement Nix et utilise tous les jours (faire F # et le développement Fable sur Nixos) mon expérience personnelle est que Nix a une forte courbe d' apprentissage qui pourrait se révéler désavantageux pour les nouveaux utilisateurs et le projet. Ce sera particulièrement écrasant pour ce genre de personnes qui sont curieuses et qui veulent juste essayer les choses rapidement, car non seulement elles devront apprendre le langage (F#) et les outils, mais aussi le langage d'expression Nix, comment composer des ensembles de packages et comment configurer des environnements de développement. Sans dire que mes expériences sont représentatives pour les autres, mais il m'a fallu un certain temps pour comprendre tout cela et devenir productif. Ainsi, une intégration profonde avec Paket est - à mon avis - préférable. Mon 2¢.

@mizzle-mo Cela a déjà été discuté et cela n'a aucune incidence sur les choix ci-dessus. Entre autres : parce qu'il laisse au consommateur le libre choix de la sortie : js version/modules system/etc est une matrice, et dans le passé l'auteur de la bibliothèque devait tout produire ; et si la combinaison souhaitée n'est pas là, bonne chance. Personnellement j'aime beaucoup la distribution des sources, ne rouvrons pas cette conversation.

C'est bien que cette discussion ait déjà émergé auparavant. Pourriez-vous s'il vous plaît le lier?

Oui, l'un des principaux problèmes de l'empaquetage des sources JS est que si le compilateur ajoute une nouvelle fonctionnalité (par exemple, des informations de réflexion plus détaillées pour les types), cela oblige les auteurs de packages à republier leurs packages juste pour regrouper le JS généré avec le nouvelle fonctionnalité. Et cela ajoute à l'enfer de la gestion des versions, car vous n'avez pas seulement besoin de prendre la version de la bibliothèque Fable dans le compte, mais la version du compilateur Fable qui a été utilisée pour générer le code. Alors oui, je pense que nous devrions rejeter ce choix.

Oui, cela signifie que nous devrons rechercher les changements de rupture et les atténuer. Mais chaque compilateur dans le monde doit le faire. Ce dont j'ai vraiment peur, c'est que ce truc fonctionne maintenant que nous n'avons que quelques petits projets et pas un grand nombre de packages de fable (donc en utilisant explicitement un grand nombre de packages de fable avec un grand nombre de dépendances transitives) ?
Bien que je pense que msbuild peut gérer plusieurs centaines de dépendances (directes + indirectes). Je ne pense pas que la base de code du compilateur F# le fera. Je ne veux vraiment pas recompiler chaque dépendance à chaque fois :/.
Mais si vous dites que ce scénario fonctionne déjà, je me tais. Veuillez également lier d'anciennes discussions que j'aimerais vraiment les lire pour être sur la même page que vous :)

@matthid Il y a un problème avec la discussion avant la publication de la 0.7, je ne me souviens plus lequel mais de toute façon, il a été décidé d'opter pour des fichiers .dll + JS précompilés. Je pense que les discussions sur les problèmes qui sont survenus plus tard (plus ou moins décrits ci-dessus) et qui ont motivé le développement de Fable 1.0 se sont déroulées dans Gitter, nous ne pouvons donc pas les lier :/

C'est délicat car le problème que j'ai mentionné ci-dessus affecte non seulement les modifications de rupture, mais également les modifications additives, les corrections de bogues, etc. dans le compilateur. Il était très difficile avec Fable 0.7 de garder tous les packages (et il n'y en avait pas beaucoup) à jour avec le développement du compilateur. En tant qu'auteur du package Fable le plus populaire, @et1975 a quelque chose à dire à cet égard ;)

Le seul avantage de la distribution de fichiers JS précompilés est que vous n'avez pas à compiler les dépendances vous-même. C'est quelque chose auquel nous sommes habitués dans .NET (pas dans d'autres communautés) et il est vrai que la première compilation prend un certain temps pour un simple projet fable-elmish-react avec Fable 1.0 à cause des dépendances, mais les développeurs utilisent normalement le mode veille avec Fable, ces secondes supplémentaires à attendre n'arrivent qu'une seule fois.

De plus, dans certains cas, vous souhaitez distribuer votre bibliothèque en tant que JS, cela se produit avec le script gamma et c'est ce que nous voulons faire avec le JS compilé FCS + Fable, mais dans ces cas, en raison de la façon dont fonctionne le regroupement, l'API est différente à partir du moment où vous avez des fichiers JS mappés 1:1 à F#. Il peut donc être un peu déroutant d'avoir des bibliothèques avec JS uniquement préparées pour être utilisées à partir de F# et d'autres avec JS préparées pour d'autres bibliothèques JS.

@alfonsogarciacaro Je ne me souviens pas très bien de tous les détails, mais je pense que la décision d'opter pour les sources était due à des problèmes avec les chemins de fichiers dans les fichiers JS ? Peut-être que cela a été résolu par Webpack, je ne sais pas.

De plus, le mode montre est fantastique et je souhaite que toutes les langues le prennent en charge, mais cela ne remplace pas la précompilation. Si la compilation initiale prend 5 minutes, vous devez attendre 5 minutes à chaque redémarrage du mode montre.

Il existe de nombreuses raisons pour lesquelles vous devrez peut-être redémarrer le mode surveillance : redémarrage de votre ordinateur, problèmes de cache, ajout de nouvelles dépendances, modification de webpack.config.js , etc.

J'utilise le mode veille tout le temps sur divers projets JavaScript, et même attendre 30 secondes me semble trop, car j'ai souvent besoin de redémarrer le mode veille (pour les raisons énumérées ci-dessus).

Je pense que ce serait cool si Fable pouvait mettre en cache les bibliothèques Fable, donc elles n'ont besoin d'être compilées qu'une seule fois. La compilation se produirait toujours du côté de l'utilisateur, pas du côté de la bibliothèque, donc cela ne devrait pas poser de problèmes.

@Pauan Je pense également que l'utilisation de la source au lieu du .dll aide Fable à avoir un accès complet à l'AST de F # où il était limité lors de l'utilisation de DLL. (même avec le fichier fablemap )

@MangelMaxime Ah, oui, je pense qu'il y avait aussi des problèmes avec les fonctions inline , les génériques, etc.

Je pense que ce serait cool si Fable pouvait mettre en cache les bibliothèques Fable, donc elles n'ont besoin d'être compilées qu'une seule fois.

@Pauan C'est une super idée ! Et aussi une bonne opportunité de relations publiques :)

Je fusionnerai bientôt PR #884. Avec cela, les bibliothèques Fable seront distribuées sous forme de sources dll + F# via Nuget et gérées par Paket. Espérons que cela résoudra la plupart des problèmes décrits ci-dessus 😸

Si vous avez des commentaires, pourriez-vous les écrire dans le PR ? THX!

Cette page vous a été utile?
0 / 5 - 0 notes

Questions connexes

forki picture forki  ·  3Commentaires

et1975 picture et1975  ·  3Commentaires

MangelMaxime picture MangelMaxime  ·  3Commentaires

forki picture forki  ·  3Commentaires

stkb picture stkb  ·  3Commentaires