Fable: [Diskussion] Transitive Abhängigkeiten

Erstellt am 27. Apr. 2017  ·  43Kommentare  ·  Quelle: fable-compiler/Fable

Fortsetzung der Diskussion von gitter über transitive Abhängigkeiten, die https://github.com/fable-elmish/react/issues/1 :

Fable-Abhängigkeiten müssen peer , um zu verhindern, dass npm sie bei Versionskonflikten in Unterverzeichnisse dupliziert. Sie können nicht dev da sie auch auf dem Rechner des Endbenutzers Ihrer Bibliothek installiert werden müssen.
Über Nicht-Fabel peerDependencies . Fable installiert einfach alles und prüft, ob sich im Stammordner des Pakets eine .fsproj Datei befindet. In diesem Fall wird eine Projektreferenz hinzugefügt, die anderen werden ignoriert.
Ich versuche nur, den Prozess zu definieren, wir könnten auch die Konvention haben, dass allen Fable-Bibliotheken zum Beispiel fable vorangestellt wird.
Soweit ich weiß, werden devDependencies nur auf dem Entwicklercomputer und nicht im Bibliotheksverbraucher installiert. Ich denke, wir könnten sie als Konvention für Fable-Bibliotheken verwenden, aber ich sehe nicht den Vorteil, die npm-Semantik zu erzwingen. Sie können auch devDependencies haben, die keine Fable-Bibliotheken sind.

Ich gehe davon aus, dass die Situation wie folgt ist:

  • Fable-Bibliotheken, die als Quellen verteilt werden, waren wie alles, was der Transpilation unterliegt, traditionell eine dev Abhängigkeit.
  • Die Anleitung für Fable-Bibliotheken lautete bis zu diesem Punkt: "Listen Sie Fabel-Abhängigkeiten weder als peer noch als normal auf, sondern lassen Sie den Benutzer es herausfinden und installieren".
  • Jetzt, da wir dotnet fable add wir die Abhängigkeiten der hinzugefügten Bibliothek untersuchen und möglicherweise die Installation ihrer (transitiven) Abhängigkeiten auslösen.

Frage: sollen wir?
Frage: Wenn ja, was ist der entsprechende Abschnitt dev oder peer ?
Frage: Was ist das Prädikat zum Auslösen einer transitiven Abhängigkeitsinstallation?
Frage: Was ist das gewünschte Verhalten, wenn mit yarn statt dotnet fable add installiert wird?

discussion

Hilfreichster Kommentar

Obwohl ich Nix persönlich liebe und jeden Tag benutze (mit F#- und Fable-Entwicklung auf NixOS), ist meine persönliche Erfahrung, dass Nix eine steile Lernkurve hat, die sich für neue Benutzer und das Projekt als nachteilig erweisen könnte. Dies wird vor allem diejenigen überfordern, die neugierig sind und einfach nur schnell etwas ausprobieren möchten, denn sie müssen nicht nur die Sprache (F#) und Werkzeuge lernen, sondern auch die Nix-Ausdruckssprache, wie man Paketsets zusammenstellt und wie man Entwicklungsumgebungen einrichtet. Ohne zu sagen, dass meine Erfahrungen repräsentativ für andere sind, aber es hat eine ganze Weile gedauert, bis ich all das groke und produktiv wurde. Daher ist aus meiner Sicht eine tiefe Integration mit Paket vorzuziehen. Meine 2¢.

Alle 43 Kommentare

Meine groben Richtlinien dafür wären:

  • Etwas, das einfach manuell zu tun ist, sollte die Automatisierung eine Bequemlichkeit und keine Voraussetzung sein.
  • Erfordern Sie eine minimale Konvention, um die Möglichkeit falscher Konfigurationen zu reduzieren (wir könnten auch einen dotnet fable validate Befehl hinzufügen, um zu überprüfen, ob die Bibliotheken der Konvention folgen, aber auch dies sollte einfach sein).

Wir könnten auch noch in Betracht ziehen, Nuget zu verwenden, um Fable-Bibliotheken zu verteilen.

Vorteile der Verwendung von npm:

  • Erleichtert das Einbinden von JS-Dateien und Abhängigkeiten in Fable-Bibliotheken
  • Erleichtert das Pushen eines Pakets mit dem gleichen Inhalt wie ein Projekt-Repository
  • Entspricht der üblichen Struktur von Webpack-Projekten, bei denen alles im selben Verzeichnis enthalten ist (obwohl dies mit resolve in der Webpack-Konfiguration gelöst werden kann)
  • Es gibt Pakete, die unbedingt von npm verteilt werden müssen: fable-loader und andere Tools wie Babel oder Webpack

Vorteile der Nutzung von Nuget:

  • Vielleicht eine bessere Unterscheidung zwischen JS- und F#-Abhängigkeiten?
  • Kann Paket verwenden, um Fable-Abhängigkeiten zu verwalten

Andere, zum Beispiel Github (Elm macht das, glaube ich):

  • Kann Paket verwenden, um Fable-Abhängigkeiten zu verwalten
  • Mehr oder weniger dieselben Vorteile wie bei npm, aber GH ist kein Paketmanager, daher können wir Probleme haben, wenn GH ausfällt und / oder wir Millionen von Benutzern bekommen XD

Um die aktuelle Situation mit Fable-Bibliotheken in Fable 1.0 Beta zusammenzufassen:

  • Als @et1975 werden Fable 1.0- devDependencies , aber sie kompilieren vor der Verteilung des Pakets, und wir haben uns entschieden, dies nicht mit Fable 1.0-Bibliotheken zu tun (damit der Endbenutzer die Kompilierungseinstellungen für den gesamten Code frei festlegen kann). .
  • Ich habe vorher nicht empfohlen, peerDependencies da npm nicht richtig damit umgegangen ist. Es scheint in npm 4 (und wahrscheinlich auch in Garn) behoben worden zu sein, so dass wir sie jetzt verwenden können sollten.
  • Im Beitrag zur Ankündigung der Beta-Version von Fable 1.0 wird weiterhin empfohlen, alle Abhängigkeiten wie 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 . In einer neueren Version habe ich eine Überprüfung für peerDependencies hinzugefügt. Wenn also fable-elmish-react alle anderen als Abhängigkeiten auflistet, muss der Benutzer nur dotnet fable add fable-elmish-react@next schreiben.

Ich habe peerDependencies damit ich npm fragen kann, bevor ich den ersten Download mache, aber wir könnten auch die .fsproj direkt überprüfen (obwohl es in diesem Fall schwieriger ist, die Version der Abhängigkeiten anzugeben). Außerdem würde ich der Einfachheit halber nur alle Abhängigkeiten im endgültigen Paket auflisten, aber später könnten wir den gesamten Abhängigkeitsbaum überprüfen (also muss fable-elmish-react nur fable-elmish anstelle von fable-elmish und fable-powerpack auflisten.

Persönlich würde ich lieber bei npm bleiben.

Ich bin mir nicht sicher, ob es eine gute Sache ist, eine "Unterscheidung zwischen JS- und F#-Abhängigkeiten" zu treffen.

Ich liebe es, so zu denken:

  • Wenn ich auf der Serverseite bin, verwende ich das Nuget, um die Libs (suave, Newtonsoft usw.)
  • Wenn ich auf der Clientseite bin, verwende ich npm, um die Libs (react, fable-elmish usw.)

Wir haben jedoch immer noch eine minimale Verwendung von Nuget auf der Clientseite, wenn wir dotnet restore ^^ ausführen (kann nicht perfekt sein)

In meinem Kopf sind Peer-Deps Dinge, die Sie benötigen, aber Sie möchten, dass der Benutzer nach Belieben hoch- oder herunterstufen kann. Es ist ein dep, wenn Sie es benötigen und die Version steuern möchten, die zusammen mit Ihrer Bibliothek installiert wird. Es sollte dem Entwickler überlassen bleiben, was er in einem bestimmten Szenario verwendet. Elmish könnte also eine Fabel als Dep haben, aber Powerpack als Peer-Dep. Der Hauptunterschied für mich ist, dass es bei dep vor mir verborgen ist, bei peer dep behalte ich die Kontrolle. Wenn PowerPack aktualisiert wird, kann ich es als Peer-Dep aktualisieren, als Dep muss ich warten, bis Sie es aktualisieren oder meine eigene Version davon installieren.

Für mich sollten wir nur eine Anleitung geben, wann beides zu verwenden ist und welche Auswirkungen dies hat.

Übrigens, das erste, was ich nach git clone oder dotnet fable new mache, ist meine package.json zu ändern:

"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"
  },

Es nervt mich immens, dass Fable mir Start und Build gestohlen hat. IMO, es sollte stattdessen so aussehen, aber ich kann nicht, ohne es zu brechen.

"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"
  },

Der Vorteil des Hinzufügens von Postinstall ist, dass ich jetzt jedes Mal, wenn ich etwas mit Garn installiere, automatisch die dotnet-Wiederherstellung ausgeführt bekomme. Der Nachteil ist, dass es jedes Mal ausgeführt wird, wenn ich etwas mit Garn installiere, auch wenn es nichts zu tun gibt.

Ich würde es vorziehen, wenn der FS-Code überhaupt nicht in npm wäre, sondern in Nuget, da weder Visual Studio noch die neue Rider-IDE-EAP in Knotenmodulen nach .fs-Code suchen, selbst wenn er in .fsproj angegeben ist. Außerdem möchte ich das gleiche F# schreiben, egal wo ich bin, was bedeutet, dass ich nicht den JS-Konventionen von lowerCamelCase folge. JavaScript ist für mich die IL für Fable, aber Fable ist immer noch F#. Das heißt, wir sollten für alles F#-Konventionen verwenden. Ich möchte keine Dotnet-Core-Konsolen-App schreiben und UpperCamelCase verwenden und muss mich dann daran erinnern, dass es in Fable LowerCamelCase ist. Nur meine Meinung.

Ich persönlich denke nicht, dass eine Quelle in node_modules sein sollte, die für Code gedacht ist, der einsatzbereit ist, weshalb die meisten IDEs sie standardmäßig ignorieren und ausblenden.

@mizzle-mo Ich benutze das package.json :

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

Jetzt kann ich nur yarn build und yarn watch und brauche dotnet überhaupt nicht mehr.

Okay, das wird ein langer Post...

Zunächst einige Fakten:

  • peerDependencies wird in Bibliotheken verwendet, es erzwingt eine einzelne Version eines Pakets, und der Endverbraucher muss alle peerDependencies angeben:

    {
    "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"
    }
    }
    

    Beachten Sie, dass die Anwendung fable-elmish und some-library als Abhängigkeiten auflisten musste, da es sich um transitive Peer-Abhängigkeiten in some-library und some-other-library

    Dies bedeutet, dass die Anwendung alle Abhängigkeiten (sowohl direkte als auch transitive) in ihrer gesamten App kennen muss. Zum Glück warnen npm und Garn, wenn Sie eine Peer-Abhängigkeit vergessen.

  • Da F# nominell typisiert ist, müssen wir eine einzelne Version pro Paket erzwingen. Das Zulassen mehrerer Versionen desselben Pakets führt zu Problemen, da die Typen zwischen den verschiedenen Versionen nicht kompatibel sind.

  • Das Erzwingen einer einzelnen Version verursacht jedoch eine massive Abhängigkeitshölle, da dies bedeutet, dass für das Upgrade eines Pakets auch alle anderen abhängigen Pakete aktualisiert werden müssen. Semver hilft, aber es ist nicht perfekt, und es hilft nicht, Änderungen zu durchbrechen.


Es gibt jedoch eine Lösung für das obige Problem: Paketsätze. Ein Paketsatz besteht im Grunde nur aus Metadaten, die alle verfügbaren Pakete + eine Version für jedes Paket + die Abhängigkeiten jedes Pakets auflisten.

Diese Lösung wird von Haskell (mit Stack ) und PureScript (mit psc-package ) verwendet.

Hier ist der Standard-PureScript-Paketsatz . Es mag einschüchternd wirken, ist aber eigentlich ganz einfach. Dies ist die Grundstruktur:

{
  "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"
  }
}

Jeder Schlüssel ist der Name des Pakets (zB foo , bar , qux ), und jedes Paket hat eine Liste von Abhängigkeiten, eine Git-URL, unter der das Paket gefunden werden kann , und die Version.

Beachten Sie, dass die Version für die Abhängigkeiten nicht aufgeführt ist. Das liegt daran, dass jede Abhängigkeit die in der JSON-Datei angegebene Version verwendet.

Als Beispiel wurde bar als Version v2.1.0 , daher verwenden alle Pakete, die von bar abhängen, [email protected] Dies stellt sicher, dass es nur eine einzelne Version jedes Pakets.

Der Vorteil davon ist, dass alle Pakete + ihre Abhängigkeiten an einer Stelle aufgelistet sind. Nehmen wir also an, dass qux eine neue Hauptversion veröffentlicht. Mit npm muss jedes Paket, das von qux abhängt, einzeln auf die neue Version von qux aktualisiert werden.

Bei Paketsätzen müssen Sie die Versionsnummer jedoch nur an einer Stelle ändern, sodass es viel einfacher ist. Dies bedeutet auch, dass der Paketsatz immer konsistent ist , sodass Sie sich keine Sorgen über die Hölle der Abhängigkeiten machen müssen.

Es ist auch wichtig zu beachten, dass das Paketset selbst auch eine Version hat. Haskell- und PureScript-Paketsätze sind unveränderlich und reproduzierbar: Die einzige Möglichkeit, etwas im Paketsatz zu ändern, besteht darin, eine neue Version des Paketsatzes zu veröffentlichen.

Und sie verwenden auch kein Semver: Alle Versionen sind exakt. Dies hat den gleichen Vorteil wie eine Sperrdatei: Sie garantiert, dass die Pakete korrekt funktionieren. Sie müssen sich nie Sorgen machen, dass ein Paket eine neue Version veröffentlicht und dann andere Pakete beschädigt.

Aber auch wenn kein semver verwendet wird, ist es nicht schwer, die Pakete aktuell zu halten, da die Versionen alle an einer Stelle spezifiziert sind: dem Paketset. Sie stoßen also einfach die Version im Paketsatz an und Sie sind fertig.

Es gibt noch einige andere Vorteile: Das Paketset dient als eine kuratierte Liste von Paketen, so dass es möglich ist, Pakete auszuschließen, deren Qualität nicht ausreicht (wenn Sie möchten). Und es erleichtert den Benutzern auch das Auffinden von Paketen, da alle verfügbaren Pakete im Paketsatz aufgelistet sind.

Sie können auch Dinge wie die automatische kontinuierliche Integration über den gesamten Paketsatz ausführen (um Komponententests auszuführen und Regressionen abzufangen).

Oder Sie können eine Webseite anzeigen, die alle Pakete + Dokumentation für jedes Paket auflistet (sowohl Haskell als auch PureScript tun dies).

Und Sie können (optional) Prüfsummen hinzufügen, die sicherstellen, dass die Pakete nicht beschädigt oder manipuliert wurden. Dies erhöht die Sicherheit und Reproduzierbarkeit.

Es ist ein wirklich fantastisches System, das viele Probleme vollständig löst: Es stellt sicher, dass es nur eine einzige Version jedes Pakets gibt, es garantiert keine Abhängigkeits-Hölle, es garantiert reproduzierbare Builds, es ist durchsuchbar, es ist konsistent und es ist einfach zu verwalten.

Der Kompromiss mit Paketsätzen besteht natürlich darin, dass Sie im Wesentlichen einen Fable-spezifischen Paketmanager erstellen. Der Paketmanager von PureScript ist wirklich einfach, daher muss die Idee eines "benutzerdefinierten Paketmanagers" nicht beängstigend sein. Aber es ist ein Kompromiss, der berücksichtigt werden muss.

Wenn Sie möchten, kann ich Ihnen weitere Details zu Paketsets erklären.


Es gibt noch einige andere tolle Sachen wie Nix , von denen ich glaube, dass sie Paketsets ähnlich sind, aber ich habe keine Erfahrung damit.

Um es klarzustellen, obwohl ich Paketsets wirklich mag und ich denke, dass sie absolut der richtige Weg sind, Pakete zu handhaben, bin ich damit einverstanden, stattdessen npm oder paket zu verwenden. Es wird nicht so gut sein wie Paketsets, aber es wird eine bessere Integration mit bestehenden Paketen / Systemen / Tools haben.

Wenn wir uns für npm entscheiden, möchten wir wahrscheinlich peerDependencies in Bibliotheken und devDependencies in Anwendungen verwenden. Dies macht es für Anwendungen ärgerlicher (weil sie alle transitiven Abhängigkeiten angeben müssen), garantiert aber eine einzige Version pro Paket.

Als Haxe-Benutzer habe ich das hier eingefügt. Es kann Ideen geben: Haxelib

Vielen Dank für die nützlichen Kommentare!

@mizzle-mo Was die Sichtbarkeit der Abhängigkeiten betrifft, ist dies schwierig. Es stimmt, dass sie in Fable 1.0 kein Code "ready to go" sind, aber im Moment betrachten wir sie als normale Abhängigkeiten, die die meisten Pakete irgendwie verbergen. Ich glaube nicht, dass sich das ändern würde, selbst wenn wir sie nach Nuget verlegen. Wir könnten auch erwägen, Fable-Abhängigkeitsprojekte Seite an Seite mit dem Benutzerprojekt zu installieren, aber dies würde wahrscheinlich weitere Fragen aufwerfen (z. B. sollten die Abhängigkeitsprojekte zum Benutzerrepo hinzugefügt werden usw.).

@Pauan Die Idee von

Das einzige, was mich abschreckt, ist die Idee, einen benutzerdefinierten Paketmanager dafür zu haben. Nicht nur wegen des zusätzlichen Wartungsaufwands für Fable, sondern auch, weil sich die Benutzer mit 3 Paketmanagern herumschlagen müssten, da wir derzeit nicht umhin können, sowohl npm/yarn als auch Nuget/Paket zu verwenden.

@whitetigle Haxelib wäre auch ein benutzerdefinierter Paketmanager für Haxe, oder? Wo werden die Pakete gehostet? Funktioniert es auch mit Paketsets?

Das einzige, was mich abschreckt, ist die Idee, einen benutzerdefinierten Paketmanager dafür zu haben. Nicht nur wegen des zusätzlichen Wartungsaufwands für Fable, sondern auch, weil sich die Benutzer mit 3 Paketmanagern herumschlagen müssten, da wir derzeit nicht umhin können, sowohl npm/yarn als auch Nuget/Paket zu verwenden.

100% einverstanden.

Haxelib wäre auch ein benutzerdefinierter Paketmanager für Haxe, oder? Wo werden die Pakete gehostet? Funktioniert es auch mit Paketsets?

Haxelib ist tatsächlich ein benutzerdefinierter Paketmanager. Pakete werden als ZIP-Dateien auf einem zentralen Server gehostet

Wenn wir dann Pakete installieren, löst jedes seine eigenen Abhängigkeiten wie folgt:

{
    "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" }
}

Bezüglich @Pauan Bemerkung:

Dadurch wird sichergestellt, dass es von jedem Paket nur eine einzige Version gibt.

Sofern nicht anders angegeben, installiert haxelib die neueste Version des Pakets, aber wir haben möglicherweise Dutzende verschiedene Versionen, insbesondere wenn wir diese alte veraltete Funktion noch benötigen ... Sie verwenden einen benutzerdefinierten Server.

Aber wenn ich es gut verstehe, scheint es nicht so zu sein, dass etwas stimmig ist, wie ein Paket, das großartig aussieht!

@alfonsogarciacaro Hier ist , wie es in PURESCRIPT funktioniert: es ist ein Paket Satz Betreuer, der das schafft Paketsatz Repo .

Wenn ein Bibliotheksautor eine neue Version seiner Bibliothek erstellt, sendet er eine Pull-Anfrage zum Aktualisieren der Bibliotheksversion im packages.json . Dieser Pull-Request muss vom Paketset-Betreuer akzeptiert (oder abgelehnt) werden.

Es gibt einige Diskussionen über die Vereinfachung dieses Prozesses, einschließlich der Möglichkeit, einen Bot zu haben, der automatisch Pull-Requests akzeptiert.

Auch nachdem der Pull-Request akzeptiert wurde, betrifft dies niemanden, da alle noch die alte Paketset-Version verwenden.

In regelmäßigen Abständen veröffentlicht der Paketsatz-Betreuer eine neue Paketsatz-Version, und Anwendungsautoren können dann auf die neue Paketsatz-Version wechseln.

Natürlich können Anwendungen weiterhin die alte Version des Paketsatzes verwenden. Tatsächlich können Anwendungen jede Version des Paketsatzes verwenden, sogar sehr alte Versionen, und es ist immer noch garantiert, dass er konsistent ist, da Paketsätze unveränderlich sind.

Im Wesentlichen ist jede Paketsatzversion eine unveränderliche Momentaufnahme des packages.json zu einem bestimmten Zeitpunkt. Die Bibliotheksautoren können packages.json ändern, aber die Paketset-Betreuer entscheiden, wann sie den Snapshot erstellen und die neue Version des Paketsets veröffentlichen.

Einen Snapshot zu erstellen bedeutet nur

Es ist möglich, mehrere Betreuer für einen Paketsatz zu haben, und es ist möglich, mehrere Paketsätze zu haben, aber diese Situationen werden selten benötigt.

Wenn ein Bibliotheksautor eine neue Hauptversion veröffentlicht, müssen alle Bibliotheken, die von dieser Bibliothek abhängig sind, aktualisiert werden. Den Bibliotheksautoren wird etwas Zeit (normalerweise einige Wochen oder so) gegeben, um auf die neue Hauptversion zu aktualisieren. Wenn sie nicht rechtzeitig aktualisieren, wird ihr Paket aus dem Paketsatz entfernt.

Nachdem alle abhängigen Bibliotheken entweder aktualisiert oder gelöscht wurden, wird eine neue Hauptversion des Paketsatzes veröffentlicht.

Als Beispiel:

  1. Bibliothek foo Upgrades von 1.0.0 auf 2.0.0

  2. Die Bibliothek bar hat die Version 1.0.0 und ist abhängig von [email protected]

  3. Die Bibliothek qux hat die Version 1.0.0 und ist abhängig von [email protected]

  4. Die Bibliothek corge hat die Version 1.0.0 und ist abhängig von [email protected]

  5. Die Autoren von bar , qux und corge werden benachrichtigt, dass sie auf [email protected] aktualisieren müssen

  6. Die bar Bibliothek wird geändert, um [email protected] , und wird von 1.0.0 auf 1.0.1 aktualisiert, da bar keine grundlegenden Änderungen vornehmen musste

  7. Die qux Bibliothek wird in [email protected] geändert und von 1.0.0 auf 2.0.0 aktualisiert, da qux einige grundlegende Änderungen vornehmen musste

  8. Die corge Bibliothek wurde nicht rechtzeitig aktualisiert, daher wurde sie aus dem Paketsatz entfernt

  9. Kontinuierliche Integrationstests werden ausgeführt, und wenn sie bestehen, wird eine neue Hauptversion des Paketsatzes veröffentlicht

Dies garantiert, dass jede Version des Paketsatzes konsistent ist.

Das Obige ist so ziemlich das Worst-Case-Szenario, der Prozess ist bei nicht größeren Versionen viel einfacher:

  1. Bibliothek foo Upgrades von Version 1.0.0 auf 1.0.1

  2. Kontinuierliche Integrationstests werden ausgeführt, und wenn sie bestehen, wird eine neue Nebenversion des Paketsatzes veröffentlicht


Die obige Diskussion bezieht sich auf das Paketset-Repository und die Bibliotheksautoren, aber es lohnt sich auch, über die Erfahrung eines Anwendungsentwicklers zu sprechen.

Als Anwendungsentwickler erstellen Sie eine psc-package.json Datei , die wie folgt aussieht:

{
    "name": "my-project",
    "set": "psc-0.10.2",
    "source": "https://github.com/purescript/package-sets.git",
    "depends": [
        "foo",
        "bar"
    ]
}
  • "source" ist die Paketsatz-Repository-URL

  • Das "set" ist die Version des Paketsatzes, den Ihre Anwendung verwendet (dies ist nur ein Git-Tag im Paketsatz-Repository ).

  • "depends" ist die Liste der Bibliotheken im Paketsatz, die Ihre Anwendung verwendet

Sie können psc-package install foo , um die foo Bibliothek aus dem Paketsatz zu installieren. Es fügt automatisch foo zum Array depends .

Das Upgrade auf eine neue Version des Paketsatzes ist so einfach wie das Ändern der Eigenschaft "set" und anschließendes Ausführen von psc-package update

Wie Sie sehen, ist es für Anwendungsentwickler super einfach, vor allem, weil sie eine garantierte Konsistenz erhalten.

Paketsets belasten Bibliotheksautoren und Paketsetbetreuer ein wenig mehr, aber im Gegenzug macht es die Dinge für Anwendungsautoren so viel besser .


Drei Paketmanager zu haben ist definitiv schlecht, aber wenn dotnet Integration für benutzerdefinierte Paketmanager erhält, können wir Garn + Paket + Fable-Paketsätze integrieren. Es würde immer noch drei Paketmanager verwenden, aber es wäre unter einem einzigen dotnet System versteckt.

Nix ähnelt Paketsätzen, es basiert auch auf unveränderlichen konsistenten Snapshots und unterstützt bereits npm. Ich bin mir jedoch nicht sicher, ob es Unterstützung für Paket bietet.

@Pauan Können wir jetzt nicht 3 Paketmanager mit Garn machen? Wir können im Postinstall-Schritt eine Dotnet-Wiederherstellung durchführen, was auch den 3. Paketmanager starten könnte. Ich mag die Idee von Paketsätzen.

Ich bin verwirrt, was ein Set ausmacht und wie das Löschen einer Bibliothek aus einer sie nützlich bleibt? Vielleicht würde mir ein Beispiel aus dem Fabel-Ökosystem helfen, dies zu verstehen.
cc @forki , der seltsamerweise in der Diskussion fehlt.

@et1975 Nach meinem Verständnis würde dies eine Verpackung ähnlich einem Mono- verteilt wird. liege . Darin ist er gut. :)

@mizzle-mo Ja, wir können postinstall . Es ist ein bisschen klobig, aber es funktioniert. Es ist nur so, dass ein dritter Paketmanager zusätzliche Dinge bedeutet, die gewartet werden müssen, zusätzliche Dinge zu lernen, zusätzliche Teile, die kaputt gehen können.

Andererseits kann ein Paketset-System auf einfache und robuste Weise konstruiert werden, sodass ein Bruch ziemlich selten sein sollte.

Sie haben Recht, dass das Konzept von Paketsätzen einem Monorepo ähnelt, außer dass es nicht erfordert, dass sich alle Pakete in einem einzigen Git-Repository befinden, sodass es auf viele Entwickler / Repos / Pakete skaliert werden kann. Die Paketsets von Haskell enthalten über 2.300 Pakete, was mit einem Monorepo offensichtlich nicht machbar ist.


@et1975 Es gibt viele Möglichkeiten, Git- Repository gibt, das eine packages.json Datei enthält:

{
  "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"
  }
}

Diese packages.json Datei ist der Paketsatz. Es listet alle Pakete auf, die im Set enthalten sind, und für jedes Paket listet es seine URL, Version und Abhängigkeiten auf. Mit anderen Worten, die Metadaten zu Versionen und Abhängigkeiten sind an einem Ort enthalten. Die Version kann entweder ein Git-Tag oder ein Git-Commit-Hash sein.

Im Allgemeinen enthält ein Paketsatz so viele Pakete wie möglich. Sie können sich vorstellen, dass der Paketsatz einen ähnlichen Zweck erfüllt wie die npm-Registry: Es ist eine Sammlung von Metadaten zu allen verfügbaren Paketen. Im Fall von Fable würde es alle verfügbaren Fable-Bibliotheken enthalten (einschließlich, aber nicht beschränkt auf Elmish, Powerpack, Unit-Test, Aether usw.).

Ein Paketsatz ist nur ein Git-Repo mit einer packages.json Datei, also ist es natürlich einfach, ihn zu forken und mehrere Paketsätze zu haben: Sie können zB einen Paketsatz für alle Fable 0.75-Pakete und einen anderen Paketsatz für Fable haben 1.0 Pakete.

Und es ist auch möglich, einen Paketsatz + benutzerdefinierte Pakete zu verwenden. Sie können beispielsweise sagen: "Ich möchte die Pakete aus dem Paketset von Fable 1.0 verwenden und zusätzlich möchte ich ein Paket foo von GitHub / npm / paket / was auch immer verwenden"

Die packages.json Datei wird ständig aktualisiert, wobei Pakete hinzugefügt, geändert, entfernt usw. werden. Aber in regelmäßigen Abständen wird eine neue Version (dh ein Snapshot) des Paketsatzes erstellt. Im Fall von PureScript ist ein Snapshot nur ein Git-Tag, das auf einen bestimmten Commit im Paketset

Da diese Snapshots unveränderlich sind, haben Sie also beim Wechsel zu einem älteren Snapshot Zugriff auf alles, was zu diesem Zeitpunkt verfügbar war. Wenn beispielsweise ein Paket im 2.0.0 Snapshot entfernt wird, können Sie zum 1.0.0 Snapshot zurückkehren, der das Paket noch enthält.

Oder wenn Sie zu einem älteren Snapshot wechseln, werden die Versionen der Pakete heruntergestuft. Oder wenn Sie zu einem neueren Snapshot wechseln, werden die Versionen der Pakete aktualisiert. Im Grunde kann man es sich ähnlich wie die Datei yarn.lock vorstellen: Sie garantiert exakte Versionen zum Zeitpunkt der Erstellung des Snapshots.

Abgesehen von yarn.lock wird ein Paketsatz von vielen Leuten geteilt, er ist nicht spezifisch für ein einzelnes Projekt. Bei Garn muss jedes neue Projekt selbstständig die richtige Kombination von nicht widersprüchlichen Versionen finden. Aber mit Paketsets muss diese Arbeit nur einmal erledigt werden, und dann kann jedes Projekt davon profitieren.

Auch im Gegensatz zu yarn.lock installiert ein Paketsatz nur die Pakete, die Sie benötigen, es installiert nicht jedes Paket im Satz!

Warum es sinnvoll ist, ein Paket zu löschen, der große Vorteil von Paketsätzen besteht darin, dass sie aktuelle, kuratierte, gewartete und funktionierende Pakete enthalten. Mit anderen Worten, wenn Sie einen Paketsatz verwenden, sollte alles Just Work(tm) sein.

Sie müssen sich keine Sorgen machen, dass ein Paket veraltet ist (zB das Paket funktioniert mit Fable 0.75, wurde aber nicht auf Fable 1.0 aktualisiert). Sie müssen sich keine Sorgen machen, dass ein Paket ein anderes Paket beschädigt. Sie müssen sich nicht um mehrere Versionen desselben Pakets kümmern. Sie müssen sich nicht um widersprüchliche Versionen kümmern. Sie müssen sich nicht mit der Hölle der Abhängigkeit auseinandersetzen.

Pakete nur gelöscht werden , wenn sie brechen, so dass selbst wenn ein Paket nicht gepflegt ist, wird es nicht so lange gefallen lassen , wie es immer wieder zu arbeiten.

Auch wenn ein Paket verworfen wird, bedeutet dies nicht, dass es gesperrt ist, sondern nur, dass es in diesem bestimmten Snapshot nicht verfügbar ist. Dies geschieht, um sicherzustellen, dass der Paketsatz immer konsistent ist und keine Brüche aufweist. Nachdem der Bruch behoben wurde, kann das Paket in einem zukünftigen Snapshot wieder hinzugefügt werden. Es ist keine große Sache.

Es ist auch möglich, die Veröffentlichung eines neuen Snapshots zu verschieben, bis das beschädigte Paket behoben ist, anstatt das Paket zu verwerfen.

Bei Stack werden die meisten Brüche von den Paketautoren innerhalb der Frist behoben, sodass Pakete selten fallen gelassen werden. Sie haben auch ein System, in dem sich jemand freiwillig als Betreuer für ein Paket melden kann, auch wenn er nicht der Autor dieses Pakets ist. Auf diese Weise können sie Brüche beheben, auch wenn das Paket nicht vom Autor gewartet wird.

Allerdings ist das Entfernen defekter Pakete eine soziale Sache, keine technische Sache, so dass der Paketset-Betreuer entscheiden kann, ob er defekte Pakete im Paketset behalten möchte, wenn er möchte.

Aus technischer Sicht ist ein Paketsatz nur eine Ansammlung von Metadaten zu Paketen, Versionen und Abhängigkeiten. Alle anderen Vorteile (Konsistenz, Bruchsicherheit usw.) müssen vom Verwalter des Paketsatzes durchgesetzt werden, daher liegt es letztendlich am Verwalter des Paketsatzes, wie er seinen Paketsatz verwaltet.

Und da es mehrere Paketsätze geben kann, können verschiedene Paketsätze unterschiedliche Betreuer haben, die jeweils ihre eigenen persönlichen Entscheidungen darüber treffen, wie sie ihren Paketsatz verwalten. Das ist in Ordnung, in diesem Fall wählt der Anwendungsentwickler einfach aus, welcher Paketsatz seinen Zielen am besten entspricht.

Aber ich kann mir vorstellen, dass es ein einziges offizielles Fable-Paket geben würde, das die Standardeinstellung wäre, also würden die meisten Benutzer einfach dieses verwenden. In diesem Fall müssten wir als Community entscheiden, wie wir diesen Paketsatz verwalten (z. B. ob defekte Pakete entfernt werden sollen oder nicht, wie viel Zeit wir geben usw.)

Paketsätze sind ein nettes Konzept und lösen viele praktische Probleme mit der Kompatibilität von Transitiven. Aber AFAIK löst das Problem der Auflösung in Ihrem Projekt nicht. Wenn Transitive in mehreren Sätzen verwendet werden oder Sie ungewöhnliche Deps verwenden, wird es wieder kompliziert. Wir sollten nicht sagen "es funktioniert alles".
Ich denke, das eigentliche Problem besteht im Moment darin, dass wir zwei Paketmanager und zwei Projektdateien haben. Wie @7sharp9 auf Slack sagte, ist es für Neulinge sehr schwer zu verstehen, was wohin gehört. Dies ist schwierig für Leute, die von der js-Welt kommen, und für Leute, die von .NET kommen. Es ist auch nicht klar, welches System der Treiber ist. Verwenden wir Node-Tools für Restore, Build, ... oder Dotnet oder gefälschte Skripte? Alles zusammen? Natürlich gibt es zwei Möglichkeiten, es zu sehen, je nachdem, aus welchem ​​​​Ökosystem Sie kommen. Ich meine, in dem netten Fabelding verwenden wir FAKE und ich denke, es funktioniert großartig. Aber offensichtlich bin ich voreingenommen und kenne Fake ziemlich gut.
In den fable dotnet Templates verwenden wir dotnetcli als Treiber. Es ist in Ordnung, aber ich vermisse so viele Dinge.
In vielen Fabelbeispielen muss man Garn nennen. Okay gut.

Es ist wirklich ein Durcheinander und ich persönlich denke, dass Abhängigkeitssätze uns überhaupt nicht helfen werden. Es ist nicht das Problem, das wir jetzt lösen müssen.

@forki Ich denke, die allgemeine Idee ist, dass Sie nicht mehrere Sätze verwenden: Jede Anwendung verwendet einen einzelnen Paketsatz, sodass keine Auflösungsprobleme auftreten.

Ich stimme zu, dass es in bestimmten Situationen immer noch kaputt gehen kann, z. B. bei der Verwendung von npm / paket-Abhängigkeiten. Ich frage mich, ob das gelöst werden kann, indem man eine yarn.lock Datei in das Paket-Set-Repository eincheckt, auf diese Weise sind auch die npm-Abhängigkeiten konsistent.

Zumindest löst es das Problem der Konsistenz mit Fable-Abhängigkeiten, ist also immer noch besser als der Status Quo.

Ich stimme zu, dass es eine große Qual ist, viele Paketmanager verwalten zu müssen. Unabhängig davon, welchen Paketmanager wir wählen, benötigen wir eine einzige einfache Möglichkeit für die Benutzer, ihn zu verwenden.

Das kann bedeuten, mehrere Paketmanager unter der Haube zu verwenden und eine einfache API für Benutzer bereitzustellen, oder es könnte bedeuten, dass ein einzelner Paketmanager verwendet wird.

Wir brauchen ein einziges Werkzeugsystem, kein Mischmasch vieler verschiedener Werkzeuge.


Ich frage mich auch, ob es möglich wäre, Nix zu verwenden. Es ist viel komplizierter als PureScript-Paketsätze, hat aber auch viele sehr nützliche Funktionen: Sie haben bereits viele komplizierte Probleme wie Caching, binäre Builds, kontinuierliche Integration, Prüfsummen usw. gelöst.

Nix hat bereits ein Paket für F# 4.1 , Tausende von npm-Paketen und Hunderte von NuGet-Paketen (einschließlich FAKE)

Genau wie Paketsätze bietet Nix konsistente Snapshots, auch wenn npm- oder NuGet-Pakete verwendet werden. So profitieren wir von den Vorteilen eines einzigen Paketmanagers, wir nutzen die Vorteile bestehender Paket-Ökosysteme (z. B. npm, NuGet usw.) und erhalten konsistente Snapshots.

Nix bietet Pakete für Bibliotheken, aber auch Pakete für Tools, Compiler, Beispiele, Dokumentation, Anwendungen usw. So können wir für alles in Fable ein einziges konsistentes System haben. Das einzige, was mich wirklich beunruhigt, ist, dass ich nicht sicher bin, wie gut die Windows-Unterstützung für Nix ist...

Sie können nicht nur einen öffentlichen Satz verwenden. Dies würde nichts über private Deps wissen.
Sie können also wieder Ihre eigenen Sets verwalten. Was ist wie eine Auflösung
du selbst.

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

@forki https://github.com/forki Ich denke, die allgemeine Idee ist, dass du
Verwenden Sie nicht mehrere Sets: Jede Anwendung verwendet ein einzelnes Paketset, also
es gibt keine auflösungsprobleme.

Ich stimme zu, dass es in bestimmten Situationen immer noch kaputt gehen kann, z. B. bei der Verwendung
npm / paket-Abhängigkeiten. Ich frage mich, ob das durch Einchecken a gelöst werden kann
Garn.lock-Datei in das Paket-Set-Repository, auf diese Weise werden npm-Abhängigkeiten
auch konsequent sein.

Zumindest löst es das Problem der Konsistenz mit Fable
Abhängigkeiten, ist also immer noch besser als der Status Quo.

Ich stimme zu, dass es eine große Qual ist, viele Paketmanager verwalten zu müssen.
Unabhängig davon, welchen Paketmanager wir wählen, brauchen wir einen einzigen einfachen Weg
damit Benutzer es verwenden können.

Das könnte bedeuten, mehrere Paketmanager unter der Haube zu verwenden und
Bereitstellung einer einfachen API für Benutzer oder die Verwendung eines einzelnen Pakets
Manager.

Wir brauchen ein einziges Werkzeugsystem, kein Mischmasch vieler verschiedener Werkzeuge.

Ich frage mich auch, ob es möglich wäre, Nix zu verwenden. Es ist viel mehr
komplizierter als PureScript-Paketsätze, aber es hat auch viele sehr nützliche
Features: Sie haben bereits viele komplizierte Probleme wie Caching gelöst,
binäre Builds, kontinuierliche Integration, Prüfsummen usw.

Nix hat bereits ein Paket für F# 4.1
https://github.com/NixOS/nixpkgs/blob/master/pkgs/development/compilers/fsharp41/default.nix ,
Tausende von npm-Paketen
https://github.com/NixOS/nixpkgs/blob/master/pkgs/development/node-packages/node-packages-v6.nix ,
und Hunderte von NuGet-Paketen (einschließlich FAKE)
https://github.com/NixOS/nixpkgs/blob/master/pkgs/top-level/dotnet-packages.nix

Genau wie Paketsets bietet Nix konsistente Snapshots, auch bei Verwendung
npm- oder NuGet-Pakete. So profitieren wir von den Vorteilen eines einzigen Paketmanagers,
wir profitieren von den Vorteilen bestehender Paket-Ökosysteme (z. B. npm, NuGet,
usw.), und wir erhalten konsistente Schnappschüsse.


Sie erhalten dies, weil Sie erwähnt wurden.
Antworten Sie direkt auf diese E-Mail und zeigen Sie sie auf GitHub an
https://github.com/fable-compiler/Fable/issues/856#issuecomment-298961437 ,
oder den Thread stumm schalten
https://github.com/notifications/unsubscribe-auth/AADgNGj_UpcDGh2YGCqMaxyD-0X8UOfwks5r2KlAgaJpZM4NKObO
.

Bezüglich nix. Die Verwendung eines anderen Standards würde kein einziges Problem lösen.
Vor allem, wenn Sie viele private Pakete haben.

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

Sie können nicht nur einen öffentlichen Satz verwenden. Dies würde nichts über private Deps wissen.
Sie können also wieder Ihre eigenen Sets verwalten. Was ist wie eine Auflösung
du selbst.

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

@forki https://github.com/forki Ich denke, die allgemeine Idee ist, dass du
nicht mehrere Sätze verwenden: jede Anwendung verwendet einen einzelnen Paketsatz.
es gibt also keine auflösungsprobleme.

Ich stimme zu, dass es in bestimmten Situationen immer noch kaputt gehen kann, z. B. bei der Verwendung
npm / paket-Abhängigkeiten. Ich frage mich, ob das durch Einchecken a gelöst werden kann
Garn.lock-Datei in das Paket-Set-Repository, auf diese Weise werden npm-Abhängigkeiten
auch konsequent sein.

Zumindest löst es das Problem der Konsistenz mit Fable
Abhängigkeiten, ist also immer noch besser als der Status Quo.

Ich stimme zu, dass es eine große Qual ist, viele Paketmanager verwalten zu müssen.
Unabhängig davon, welchen Paketmanager wir wählen, brauchen wir einen einzigen einfachen Weg
damit Benutzer es verwenden können.

Das könnte bedeuten, mehrere Paketmanager unter der Haube zu verwenden und
Bereitstellung einer einfachen API für Benutzer oder die Verwendung eines einzelnen Pakets
Manager.

Wir brauchen ein einziges Werkzeugsystem, kein Mischmasch vieler verschiedener Werkzeuge.

Ich frage mich auch, ob es möglich wäre, Nix zu verwenden. Es ist viel mehr
komplizierter als PureScript-Paketsätze, aber es hat auch viele sehr nützliche
Features: Sie haben bereits viele komplizierte Probleme wie Caching gelöst,
binäre Builds, kontinuierliche Integration, Prüfsummen usw.

Nix hat bereits ein Paket für F# 4.1
https://github.com/NixOS/nixpkgs/blob/master/pkgs/development/compilers/fsharp41/default.nix ,
Tausende von npm-Paketen
https://github.com/NixOS/nixpkgs/blob/master/pkgs/development/node-packages/node-packages-v6.nix ,
und Hunderte von NuGet-Paketen (einschließlich FAKE)
https://github.com/NixOS/nixpkgs/blob/master/pkgs/top-level/dotnet-packages.nix

Genau wie Paketsets bietet Nix konsistente Snapshots, auch wenn
mit npm- oder NuGet-Paketen. So profitieren wir von den Vorteilen eines einzigen Pakets
Manager profitieren wir von den Vorteilen bestehender Paket-Ökosysteme (z
npm, NuGet usw.), und wir erhalten konsistente Snapshots.


Sie erhalten dies, weil Sie erwähnt wurden.
Antworten Sie direkt auf diese E-Mail und zeigen Sie sie auf GitHub an
https://github.com/fable-compiler/Fable/issues/856#issuecomment-298961437 ,
oder den Thread stumm schalten
https://github.com/notifications/unsubscribe-auth/AADgNGj_UpcDGh2YGCqMaxyD-0X8UOfwks5r2KlAgaJpZM4NKObO
.

@forki Wenn sich alle Fable-Bibliotheken im

Aber ja, bei privaten Paketen müssen Sie die Auflösung selbst vornehmen.

Wenn Sie über viele private Pakete verfügen, können Sie Ihren eigenen privaten Paketsatz erstellen. Es ist einfach, ein Paketset zu forken, da es sich nur um ein Git-Repository handelt.


Ich verstehe nicht, warum Nix das Problem nicht löst. Nix unterstützt private Pakete. In Nix verwenden private Pakete genau das gleiche System wie öffentliche Pakete, sodass Sie die gleichen Vorteile erhalten.

Wir haben immer private Abhängigkeiten in unseren Produkten. Dies würde nichts für uns beheben. Es würde nur den Schmerz erhöhen, da jetzt Pakete nix konform sein müssen.

@forki Inwiefern unterscheidet sich das davon, dass private Abhängigkeiten

Für welchen Paketmanager wir uns auch entscheiden, Pakete müssen diesem Paketmanager entsprechen.

Ich nehme an, Sie sagen, dass "wir private Abhängigkeiten für npm haben, und wir möchten sie nicht auf Nix ändern, da das zusätzliche Arbeit ist"?

Ich wurde einmal gebeten, bei nix zu helfen. Es war ein Albtraum. Ich will nicht
zwingen meine Kollegen dazu. Dann würde ich wohl meinen eigenen Weg gehen.

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

@forki https://github.com/forki Wie unterscheidet sich das von
Erfordern, dass private Abhängigkeiten npm- oder NuGet-konform sind,
oder paketkonform? Für welchen Paketmanager wir uns auch entscheiden, Pakete
müssen sich an diesen Paketmanager anpassen.

Ich vermute, Sie sagen, dass "wir private Abhängigkeiten für npm haben, und wir
möchte sie nicht auf Nix umstellen, da das zusätzliche Arbeit ist"?


Sie erhalten dies, weil Sie erwähnt wurden.
Antworten Sie direkt auf diese E-Mail und zeigen Sie sie auf GitHub an
https://github.com/fable-compiler/Fable/issues/856#issuecomment-298968019 ,
oder den Thread stumm schalten
https://github.com/notifications/unsubscribe-auth/AADgNLwxzUSLZM3SLK2A_qeu_3BigtTRks5r2K8GgaJpZM4NKObO
.

@forki Ich habe Nix nicht benutzt, also bin ich wirklich neugierig: Wann hast du Nix ausprobiert? Haben Sie versucht, Nix unter Windows zu verwenden? Auf welche Probleme sind Sie gestoßen?

Es war, als wir versuchten, Fake hinzuzufügen. Die meisten Probleme waren monobasiert und meistens
um den Build-Prozess wiederholbar zu machen. IIRC haben wir da zuerst aufgegeben
Versuchen.

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

@forki https://github.com/forki Ich habe Nix nicht benutzt, also bin ich wirklich
neugierig: wann hast du Nix ausprobiert? Haben Sie versucht, Nix unter Windows zu verwenden? Was
auf welche probleme sind Sie gestoßen?


Sie erhalten dies, weil Sie erwähnt wurden.
Antworten Sie direkt auf diese E-Mail und zeigen Sie sie auf GitHub an
https://github.com/fable-compiler/Fable/issues/856#issuecomment-298969907 ,
oder den Thread stumm schalten
https://github.com/notifications/unsubscribe-auth/AADgNEffp6-ZASShsev6WRfWxTmzeFjqks5r2LChgaJpZM4NKObO
.

Hier werden mehrere Dinge besprochen. Ich denke, das ist gut, denn es gibt uns die Möglichkeit, die Tools und das Ökosystem zu diskutieren, bevor die stabile 1.0-Version veröffentlicht wird. Das ist der Zweck der Beta und das haben wir mit Fable 0.7 getan.

Ich habe viel darüber nachgedacht. Ich versuche jetzt, einige der aktuellen Probleme und mögliche Lösungen aufzuschlüsseln, es kann einfacher sein, sie einzeln anzugehen, anstatt zu versuchen, alles auf einmal zu beheben:

Reibung zwischen .NET und JS

Auch die Neuheit des dotnet SDK wirkt sich darauf aus. Die Leute müssen über zwei Ökosysteme Bescheid wissen, Abhängigkeiten von zwei Registern synchronisieren, .NET- und JS-Tools gleichzeitig aufrufen usw. Mögliche Lösungen:

  • Gehen Sie voll JS : Dank @ncave- Arbeit sind wir im Grunde da. Frühere Tests haben auch gezeigt, dass dadurch auch die Anfangszeit halbiert werden kann (Uhrenzusammenstellungen können einige Millisekunden länger dauern).
  • Behalten Sie Fable als .NET-Tool bei, aber booten Sie mit Node wie zuvor : Wir brauchen also keine Fable-Nuget-Pakete ( dotnet restore wäre zumindest für das FSharp.NET.Sdk immer noch erforderlich). Das Hauptproblem, das ich dabei gefunden habe, ist, dass es schwierig ist, den Lebenszyklus der Kompilierung von einem Webpack-Loader aus zu überprüfen, sodass es schwierig ist zu wissen, wann der .NET-Prozess gestoppt werden muss.

Verteilen von F#-Bibliotheken als Quellen und Verwenden von Projektreferenzen

F#-Tools sind nicht für die Verteilung von Bibliotheken als Quellen ausgelegt und offensichtlich wurde npm nicht für die Verteilung von F#-Bibliotheken entwickelt, sodass auch hier Reibungen (die eigentlich diesen Thread motiviert haben) erwartet werden. Mögliche Lösungen:

  • Verwenden Sie Paket und lassen Sie es zaubern : Dies erfordert das Hinzufügen neuer Funktionen zu Paket, um Abhängigkeiten mithilfe von Projektreferenzen zu verknüpfen.
  • Verwenden Sie npm und lassen Sie Fable zaubern : Wir würden immer noch npm verwenden, aber Fable-Abhängigkeiten würden in die .fsproj Datei mit einem neuen Element wie <FableReference Include="fable-elmish-react" /> und Fable müsste sich um die Ausgabe der korrekten kümmern Befehle (ausgelöst durch fable restore oder ähnliches). So etwas wurde bei der Implementierung der dotnet SDK-Integration untersucht. Andere JS-Abhängigkeiten würden in die package.json aufgenommen (oder nicht).
  • Verteilen Sie gleichzeitig die .dll und die Quellen : Dies wird für Paket und die IDEs viel einfacher sein (derzeit dauert der F#-Sprachdienst lange, um Abhängigkeiten in einem fable-elmish-react-Projekt aufzulösen). Fable würde beim Kompilieren nach den Quellen suchen. Es kann etwas schwierig sein, den Nuget-Ordner in einigen Computern zu finden, aber es sollte möglich sein.
  • Garn standardmäßig verwenden : Dies scheint von der Community bevorzugt zu werden, es ermöglicht uns zum Beispiel, den Flat-Modus zu verwenden, damit wir uns keine Sorgen um Peer-Abhängigkeiten machen müssen.

Verwaltung von Abhängigkeitsversionen

Ein Paketsatz könnte von Vorteil sein, um dem Ökosystem von Fable Stabilität und Transparenz zu verleihen, aber wir sollten auf die Wartung und den kognitiven Overhead achten, die dies mit sich bringen würde. Außerdem glaube ich, dass dies wahrscheinlich weniger problematisch sein wird, wenn wir die oben genannten Probleme lösen können (z. B. mit nur einem Paketmanager).

Bitte kommentieren Sie, wenn Sie mit einigen dieser Lösungen einverstanden sind (die Dinge so zu lassen, wie sie sind, ist auch eine Alternative) oder wenn Sie einen anderen Vorschlag haben.

@alfonsogarciacaro Ich bin mir nicht sicher, wie zuverlässig der --flat Modus von Yarn ist, da er meiner Meinung nach ursprünglich aus Gründen der Bower-Kompatibilität erstellt wurde, aber Yarn hat die Bower-Unterstützung vollständig entfernt. Daher vermute ich, dass sie --flat in Zukunft entfernen oder verwerfen könnten. Aber zumindest im Moment funktioniert es.

Wenn Sie ein Paket erstellen und --flat angeben, erzwingt dies außerdem, dass alle Ihre Abhängigkeiten flach sind. Aber das wollen wir nicht. Wir möchten, dass unsere Fable- Abhängigkeiten flach sind, aber unsere JavaScript- Abhängigkeiten nicht flach. Das lässt das Garn nicht zu, entweder ist alles flach oder nichts ist flach. Wir müssten also immer noch peerDependencies

@alfonsogarciacaro @Pauan Ich mag die Idee, Paket mit Modifikationen zu verwenden. Ich denke, wenn wir die Möglichkeit hinzufügen könnten, Projektreferenzen zu verknüpfen, und vielleicht später die Möglichkeit, öffentliche APIs zu unterscheiden, um Semver zu erzwingen, wäre das rockig und das Tooling hätte eine einfachere Zeit, wenn ich mich nicht irre.

Entschuldigung, wenn dies völlig irrelevant ist (ich habe Fable Jet leider noch nicht verwendet, werde es aber hoffentlich bald tun). Aber könnte dies ein guter Punkt sein, um darüber nachzudenken, wie man Fable-Pakete verteilt? Was ich überall über das Verteilen von Quell- und fsproj-Dateien lese, sieht eher wie ein Hack aus den frühen Tagen aus? Können wir nicht stattdessen DLL- und Javascript-Code (oder etwas Ähnliches) verpacken?

Das ist eigentlich eine gute Frage @alfonsogarciacaro. Warum verpacken wir die Quelle?

@mizzle-mo Dies wurde bereits besprochen und hat keinen Einfluss auf die obigen Auswahlmöglichkeiten. Unter anderem: weil es dem Verbraucher eine freie Wahl der Ausgabe ermöglicht: js version/modules system/etc ist eine Matrix, und in der Vergangenheit musste der Autor der Bibliothek alles produzieren; und wenn Ihre Wunschkombination nicht dabei ist - viel Glück. Persönlich mag ich die Verteilung von Quellen sehr, lassen Sie uns diese Konversation nicht erneut eröffnen.

Ja, eines der Hauptprobleme beim Packen der JS-Quellen besteht darin, dass wenn der Compiler eine neue Funktion hinzufügt (z. B. detailliertere Reflexionsinformationen für die Typen), die Paketautoren gezwungen sind, ihre Pakete erneut zu veröffentlichen, nur um das generierte JS mit dem neue Funktion. Und es trägt zur Hölle der Versionsverwaltung bei, da Sie nicht nur die Fable-Lib-Version in das Konto aufnehmen müssen, sondern auch die Fable-Compiler-Version, die zum Generieren des Codes verwendet wurde. Also ja, ich denke, wir sollten diese Wahl verwerfen.

DLL + F#-Quellen, die mit Nuget/Paket verteilt werden, sind jedoch immer noch eine Option. Es kann jedoch einige Schwierigkeiten geben: Wenn die Bibliothek JS-Abhängigkeiten hat, wie markieren Sie diese? Wenn Fable alle Quelldateien sammeln muss, wie kann es den Abhängigkeitsgraphen auflösen ... aber wir könnten trotzdem in diese Richtung gehen.

@alfonsogarciacaro Ich weiß, dass @forki Nix nicht mag, aber das ist eine der wirklich coolen Funktionen von Nix: Wenn sich der Fable-Compiler ändert, werden alle Fable-Pakete automatisch neu kompiliert, um den neuen Fable-Compiler zu verwenden. Selbst bei der DLL-Kompilierung müssen Bibliotheksautoren also nicht bei jeder Änderung manuell neu veröffentlichen.

Es ist auch möglich, Nix-Pakete auf verschiedene Weise zu konfigurieren. Zum Beispiel kann der Konsument einer Fable-Bibliothek den Modultyp, Polyfill, Fable-Version, Fable-Core-Version usw. auswählen. Sie bleiben nicht bei der Wahl des Bibliotheksautors hängen.

Nix hat einen globalen Cache, und Nix-Pakete sind rein und unveränderlich, sodass Pakete mit benutzerdefinierter Konfiguration zwischengespeichert werden können. Im Moment müssen Fable-Bibliotheken immer wieder neu kompiliert werden. Bei Nix müssten sie nur einmal kompiliert und dann zwischengespeichert werden.

Das bedeutet, dass Sie unglaubliche Flexibilität, mehr Komfort für Entwickler und schnellere Build-Zeiten erhalten. Sie haben wirklich darüber nachgedacht, wie diese schwierigen Verpackungsprobleme gelöst werden können.


Ich weiß, dass ich wirklich auf Paketsätze dränge, aber es gibt noch eine andere Option: Paketsätze für Fable mit zusätzlichen npm-Metadaten:

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

Es ist das gleiche wie zuvor, aber es hat ein zusätzliches Feld npm-dependencies . Dies ermöglicht es uns, Fable-Abhängigkeiten und npm-Abhängigkeiten in derselben Konfigurationsdatei anzugeben.

Die Installation eines Pakets ist so einfach wie fable install foo . Wenn Fable ein Paket installiert, verwendet es den Paketsatzalgorithmus für Fable-Abhängigkeiten und ruft dann automatisch yarn für die npm-dependencies

Dies bedeutet, dass Benutzer nur ein System, eine Konfigurationsdatei und einen Satz von Tools erlernen müssen.

Obwohl ich Nix persönlich liebe und jeden Tag benutze (mit F#- und Fable-Entwicklung auf NixOS), ist meine persönliche Erfahrung, dass Nix eine steile Lernkurve hat, die sich für neue Benutzer und das Projekt als nachteilig erweisen könnte. Dies wird vor allem diejenigen überfordern, die neugierig sind und einfach nur schnell etwas ausprobieren möchten, denn sie müssen nicht nur die Sprache (F#) und Werkzeuge lernen, sondern auch die Nix-Ausdruckssprache, wie man Paketsets zusammenstellt und wie man Entwicklungsumgebungen einrichtet. Ohne zu sagen, dass meine Erfahrungen repräsentativ für andere sind, aber es hat eine ganze Weile gedauert, bis ich all das groke und produktiv wurde. Daher ist aus meiner Sicht eine tiefe Integration mit Paket vorzuziehen. Meine 2¢.

@mizzle-mo Dies wurde bereits besprochen und hat keinen Einfluss auf die obigen Auswahlmöglichkeiten. Unter anderem: weil es dem Verbraucher eine freie Wahl der Ausgabe ermöglicht: js version/modules system/etc ist eine Matrix, und in der Vergangenheit musste der Autor der Bibliothek alles produzieren; und wenn Ihre Wunschkombination nicht dabei ist - viel Glück. Persönlich mag ich die Verteilung von Quellen sehr, lassen Sie uns diese Konversation nicht erneut eröffnen.

Schön, dass es diese Diskussion schon früher gegeben hat. Könntest du es bitte verlinken?

Ja, eines der Hauptprobleme beim Packen der JS-Quellen besteht darin, dass wenn der Compiler eine neue Funktion hinzufügt (z. B. detailliertere Reflexionsinformationen für die Typen), die Paketautoren gezwungen sind, ihre Pakete erneut zu veröffentlichen, nur um das generierte JS mit dem neue Funktion. Und es trägt zur Hölle der Versionsverwaltung bei, da Sie nicht nur die Fable-Lib-Version in das Konto aufnehmen müssen, sondern auch die Fable-Compiler-Version, die zum Generieren des Codes verwendet wurde. Also ja, ich denke, wir sollten diese Wahl verwerfen.

Ja, das bedeutet, dass wir nach bahnbrechenden Änderungen Ausschau halten und diese abschwächen müssen. Aber jeder Compiler auf der Welt muss das tun. Wovor ich wirklich Angst habe, ist, dass dieses Zeug jetzt funktioniert, da wir nur einige kleine Projekte und keine große Anzahl von Fable-Paketen haben (also explizit eine große Anzahl von Fable-Paketen mit einer großen Anzahl transitiver Abhängigkeiten verwenden)?
Während ich denke, dass msbuild mehrere hundert (direkte + indirekte) Abhängigkeiten problemlos verarbeiten kann. Ich glaube nicht, dass die Codebasis des F#-Compilers dies tun wird. Ich möchte wirklich nicht jedes Mal jede Abhängigkeit neu kompilieren :/.
Aber wenn Sie sagen, dass dieses Szenario bereits funktioniert, bin ich still. Bitte verlinke auch alte Diskussionen, die ich wirklich gerne durchlesen würde, um auf die gleiche Seite wie du zu kommen :)

@matthid Es gibt ein Problem mit der Diskussion vor der Veröffentlichung von 0.7, ich erinnere mich nicht, welches, aber trotzdem wurde beschlossen, sich für .dll + vorkompilierte JS-Dateien zu entscheiden. Ich denke, die Diskussionen über die Probleme, die später auftraten (mehr oder weniger oben skizziert) und die Entwicklung von Fable 1.0 motivierten, fanden in Gitter statt, daher können wir sie nicht verlinken :/

Es ist schwierig, weil das oben erwähnte Problem nicht nur Breaking Changes betrifft, sondern auch additive Änderungen, Bugfixes usw. im Compiler. Mit Fable 0.7 war es sehr schwierig, alle Pakete (und es waren nicht viele) mit der Compiler-Entwicklung auf dem neuesten Stand zu halten. Als Autor des beliebtesten Fable-Pakets hat @et1975 diesbezüglich etwas zu sagen ;)

Der einzige Vorteil der Verteilung vorkompilierter JS-Dateien besteht darin, dass Sie die Abhängigkeiten nicht selbst kompilieren müssen. Das sind wir in .NET gewohnt (nicht in anderen Communities) und es stimmt, dass die erste Kompilierung für ein einfaches fable-elmish-react-Projekt mit Fable 1.0 aufgrund der Abhängigkeiten einige Zeit dauert, aber Entwickler verwenden normalerweise den Watch-Modus Mit Fable müssen diese zusätzlichen Sekunden also nur einmal warten.

In einigen Fällen möchten Sie Ihre Bibliothek auch als JS verteilen, dies geschieht mit dem Gamma-Skript und das möchten wir mit dem JS-kompilierten FCS + Fable tun, aber in diesen Fällen ist die API aufgrund der Art und Weise, wie die Bündelung funktioniert, anders ab, wenn Sie JS-Dateien 1:1 auf F# gemappt haben. Daher kann es etwas verwirrend sein, Bibliotheken mit JS zu haben, die nur für die Verwendung von F# vorbereitet sind, und andere mit JS, die für andere JS-Bibliotheken vorbereitet sind.

@alfonsogarciacaro Ich suchen , lag an Problemen mit Dateipfaden in den JS-Dateien? Vielleicht wurde das von Webpack gelöst, ich weiß es nicht.

Auch der Watch-Modus ist fantastisch und ich wünschte, jede Sprache würde ihn unterstützen, aber er ist kein Ersatz für die Vorkompilierung. Wenn die Erstkompilierung 5 Minuten dauert, müssen Sie bei jedem Neustart des Watch-Modus 5 Minuten warten.

Es gibt viele Gründe, warum Sie den Überwachungsmodus möglicherweise neu starten müssen: Neustart Ihres Computers, Probleme mit dem Cache, Hinzufügen neuer Abhängigkeiten, Ändern von webpack.config.js usw.

Ich verwende ständig den Watch-Modus bei verschiedenen JavaScript-Projekten, und selbst 30 Sekunden zu warten fühlt sich zu viel an, da ich den Watch-Modus oft neu starten muss (aus den oben genannten Gründen).

Ich denke, es wäre cool, wenn Fable Fable-Bibliotheken irgendwie zwischenspeichern könnte, sodass sie nur einmal kompiliert werden müssen. Die Kompilierung würde immer noch auf der Benutzerseite erfolgen, nicht auf der Bibliotheksseite, daher sollte es keine Probleme verursachen.

@Pauan Ich glaube auch, dass die Verwendung der Quelle anstelle der .dll Fable hilft, vollen Zugriff auf den AST von F # zu haben, wo er bei der Verwendung von DLL eingeschränkt war. (auch mit der fablemap- Datei)

@MangelMaxime Ah, ja, ich denke, es gab auch einige Probleme mit inline Funktionen, Generika usw.

Ich denke, es wäre cool, wenn Fable Fable-Bibliotheken irgendwie zwischenspeichern könnte, sodass sie nur einmal kompiliert werden müssen.

@Pauan Das ist eine tolle Idee! Und auch eine gute PR-Gelegenheit :)

Ich werde bald PR #884 zusammenführen. Damit werden Fable-Bibliotheken in Form von DLL + F#-Quellen über Nuget verteilt und von Paket verwaltet. Hoffentlich löst dies die meisten der oben beschriebenen Probleme 😸

Wenn Sie einen Kommentar haben, können Sie ihn bitte in die PR schreiben? Danke!

War diese Seite hilfreich?
0 / 5 - 0 Bewertungen

Verwandte Themen

rommsen picture rommsen  ·  3Kommentare

MangelMaxime picture MangelMaxime  ·  3Kommentare

alfonsogarciacaro picture alfonsogarciacaro  ·  3Kommentare

jwosty picture jwosty  ·  3Kommentare

nozzlegear picture nozzlegear  ·  3Kommentare