Cela semble fantastique à mon humble avis.
Est-ce simple à étendre pour des éléments tiers, tels que Material-UI ?
Ce serait formidable d'avoir une sorte de guide sur la façon de le faire. :)
Cela semble fantastique à mon humble avis.
Merci! Contente que ça te plaise :sourire:
Est-ce simple à étendre pour des éléments tiers, tels que Material-UI ?
Bien sûr, mais l'approche est un peu différente parce que nous n'utilisons pas de syndicats discriminés. J'essaie d'écrire quelque chose quand le temps le permet, mais l'idée est que vous avez essentiellement deux options :
prop
avec plus de fonctionsprop
similaire, spécifique à votre bibliothèque (peut-être Mui
) qui possède toutes les propriétés requises par le Mui. Vous pouvez même alias prop
avec Mui
et étendre Mui
avec des propriétés et des fonctions spécifiques à Mui (surchargées).L'extension est aussi simple que :
type prop with
static member hello (value: string) = Interop.mkAttr "hello" value
Que ce soit la "forme finale" de la bibliothèque et la manière de l'étendre, est toujours à l'étude car je veux d'abord l'essayer en construisant des bibliothèques tierces et voir comment ça se passe
Merci! Je suis déjà en train de tester quelque chose pour MUI, juste pour une fraction de l'API, pour voir comment cela fonctionne. Je partagerai probablement au cours du week-end/fin, ce serait formidable si vous pouviez y jeter un coup d'œil juste pour voir si je suis sur la bonne voie et si je suis l'esprit de Feliz. Ça a l'air d'être un succès jusqu'à présent !
Cependant, je n'ai pas étendu le type prop
existant. J'ai défini un type prop
séparé dans un autre espace de noms ( Feliz.MaterialUI
). Fonctionne apparemment très bien ; vous avez bien sûr accès à tous les membres de tous les types correspondants si vous ouvrez à la fois Feliz
et Feliz.MaterialUI
.
J'ai un type Mui
qui correspond à Html
et contient les composants réels.
(Actuellement, j'ai placé des accessoires spécifiques aux composants dans des sous-modules séparés de prop
, comme mentionné au #13.)
Un point d'amélioration possible à Feliz est d'avoir un reactElement
et createElement
qui n'acceptent pas string
, mais ReactElementType
(je pense). afin que nous puissions appeler createElement (importDefault "@material-ui/core/Button")
. J'ai créé ces deux assistants moi-même actuellement.
Au fait, tous les membres devraient-ils être inline
? Quels sont les avantages/inconvénients ? J'ai remarqué que vous n'avez pas utilisé inline
ci-dessus, mais tout à Feliz est inline
.
Merci! Je suis déjà en train de tester quelque chose pour MUI, juste pour une fraction de l'API, pour voir comment cela fonctionne. Je partagerai probablement au cours du week-end/fin, ce serait formidable si vous pouviez y jeter un coup d'œil juste pour voir si je suis sur la bonne voie et si je suis l'esprit de Feliz. Ça a l'air d'être un succès jusqu'à présent !
C'est génial! Je serais certainement heureux de jeter un coup d'œil si vous
Cependant, je n'ai pas étendu le type d'accessoire existant. J'ai défini un type d'accessoire séparé dans un autre espace de noms (Feliz.MaterialUI). Fonctionne apparemment très bien ; vous avez bien sûr accès à tous les membres de tous les types correspondants si vous ouvrez à la fois Feliz et Feliz.MaterialUI.
J'ai un type Mui qui correspond à Html et contient les composants réels.
C'est ce que je ferais pour Mui
(Actuellement, j'ai placé des accessoires spécifiques aux composants dans des sous-modules séparés de l'accessoire, comme mentionné au n ° 13.)
Cela a du sens pour Mui en raison du nombre d'options que vous avez
Un point d'amélioration possible dans Feliz est d'avoir un reactElement et un createElement qui n'acceptent pas de chaîne, mais ReactElementType (je pense). afin que nous puissions appeler createElement (importDefault "@material-ui/core/Button"). J'ai créé ces deux assistants moi-même actuellement.
Je passe en revue les membres que j'utilise dans le module Interop
, je viens d'exposer tout ce que j'utilisais dans la bibliothèque, sera reconsidéré pour la version stable
Au fait, tous les membres devraient-ils être en ligne ? Quels sont les avantages/inconvénients ? Je remarque que vous n'avez pas utilisé inline ci-dessus, mais tout dans Feliz est en ligne.
J'aurais dû insérer le membre étendu ci-dessus !
La règle d'or est la suivante : si la valeur de la propriété est primitive comme une chaîne/int/bool/enum, inlinez la propriété, mais si votre propriété calcule une valeur basée sur l'entrée, il est préférable de ne pas l'inline car chaque fois que l'utilisateur appelle la fonction en ligne, tout le corps de la fonction est en ligne à cet endroit d'invocation, donc si un utilisateur utilise la même fonction 10 fois dans l'application, le corps de la fonction est compilé en ligne 10 fois au lieu d'être défini une fois et référencé 10 fois
La règle d'or est la suivante : si la valeur de la propriété est primitive comme une chaîne/int/bool/enum, inlinez la propriété, mais si votre propriété calcule une valeur basée sur l'entrée, il est préférable de ne pas l'inline car chaque fois que l'utilisateur appelle la fonction en ligne, tout le corps de la fonction est en ligne à cet endroit d'invocation, donc si un utilisateur utilise la même fonction 10 fois dans l'application, le corps de la fonction est compilé en ligne 10 fois au lieu d'être défini une fois et référencé 10 fois
Bon à savoir! Mais (dans le contexte de Fable) pourquoi inline en premier lieu, alors ? Quel est l'avantage pour les corps de fonction/méthode "simples" ?
[<Inject>] ITypeResolver<'t>
comme argument facultatif d'une classe statique (seules les bibliothèques hautement spécialisées utilisent cette fonctionnalité, voir Fable.SimpleJson/Thoth.Json)Je pense que babel secoue les arbres et supprime les fonctions inutilisées lorsque vous créez le bundle de production. L'inlining irait à l'encontre de cela.
@Luiz-Monad Êtes-vous en train de dire que, idéalement, rien à Feliz ne devrait être aligné? Que l'inlining pour des raisons de taille de bundle est contre-productif ?
@Luiz-Monad Ce que vous dites serait génial ! Du moins si la compilation fonctionnait de cette façon. Voici un exemple que vous pouvez essayer avec le REPL :
module App
type prop =
// does useless stuff
static member f() =
[ 1 .. 100 ]
|> List.map (fun x -> x * 20)
|> List.collect (fun n -> [n; n])
|> List.fold (+) 0
// does useless stuff
static member inline k() =
[ 1 .. 100 ]
|> List.map (fun x -> x * 20)
|> List.collect (fun n -> [n; n])
|> List.fold (+) 0
static member g() = 1
let value = prop.g()
printfn "%d" value
Où prop
contient :
f()
contient un corps de fonction -> non aligné et également non utilisék()
contient un corps de fonction -> inline mais non utiliség()
contient une fonction -> pas en ligne et utiliséeOn pourrait penser que f()
et g()
ne seront pas compilés, mais ce n'est pas le cas, f()
(non intégré et non utilisé) est compilé de toute façon, mais k()
(inlined, not used) n'entre pas dans le bundle compilé
import { fold, collect, map, ofSeq, ofArray } from "fable-library/List.js";
import { type } from "fable-library/Reflection.js";
import { rangeNumber } from "fable-library/Seq.js";
import { toConsole, printf } from "fable-library/String.js";
import { declare } from "fable-library/Types.js";
export const prop = declare(function App_prop() {});
export function prop$reflection() {
return type("App.prop");
}
export function prop$$$f() {
return fold(function folder(x$$1, y) {
return x$$1 + y;
}, 0, collect(function mapping$$1(n) {
return ofArray([n, n]);
}, map(function mapping(x) {
return x * 20;
}, ofSeq(rangeNumber(1, 1, 100)))));
}
export function prop$$$g() {
return 1;
}
export const value = prop$$$g();
toConsole(printf("%d"))(value);
Cela fonctionne en effet, mais vous devez configurer webpack
pour ce faire, car ce qui fait trembler l'arbre n'est pas une fable en soi, donc cela ne fonctionnera pas dans le REPL.
Avant de
/// Library.fs
module Library
type prop =
// does useless stuff
static member f() =
[ 1 .. 100 ]
|> List.map (fun x -> x * 20)
|> List.collect (fun n -> [n; n])
|> List.fold (+) 0
// does useless stuff
static member inline k() =
[ 1 .. 100 ]
|> List.map (fun x -> x * 20)
|> List.collect (fun n -> [n; n])
|> List.fold (+) 0
type AppMain =
static member g() = 1
//// App.fs
module App
let value = Library.AppMain.g ()
printfn "%d" value
Après
declare(function Library_prop() {
// see its empty, this weren't removed too because of `keep_classnames: true, keep_fnames: true ` in the terser plugin
});
declare(function Library_AppMain() {
});
!function toConsole(arg) {
return arg.cont(function (x) {
console.log(x)
})
}(printf('%d')) (1),
__webpack_require__.d(__webpack_exports__, 'value', function () {
return 1
})
De plus, il y a une mise en garde à votre test, le fichier d'entrée est un peu spécial en ce sens que les fonctions qu'il contient ne sont pas supprimées. (Je suppose qu'il y a quelque chose à voir avec l'initialisation des classes statiques, quelque chose doit appeler le constructeur d'initialisation statique pour faire des effets secondaires sur les modules)
Voir ce référentiel que j'ai créé pour ce test https://github.com/Luiz-Monad/test-tree-shaking
Merci beaucoup pour l'exemple de dépôt ! Je vais certainement étudier cela plus avant pour voir si l'inlining fait réellement quelque chose d'utile dans le contexte de Feliz
Je vais certainement étudier cela plus avant pour voir si l'inlining fait réellement quelque chose d'utile dans le contexte de Feliz
Cool, hâte d'entendre ce que tu trouveras :)
C'est génial! Je serais certainement heureux de jeter un coup d'œil si vous
Veuillez consulter la branche feliz
sur cmeeren/fable-elmish-electron-material-ui-demo .
La plupart du code est généré automatiquement sur la base de la documentation de l'API (HTML). Il y a un projet de générateur (moche et hacky, mais fait le travail) et un projet pour les liaisons réelles. Dans le projet de rendu, seul App.fs
a été converti pour utiliser les nouvelles liaisons de style Feliz.
Jetez-y un coup d'œil quand vous en avez envie, et dites-moi ce que vous en pensez et si vous avez des questions.
@cmeeren A l'air très agréable et bien meilleur que l'API actuelle IMHO mais est-ce encore un peu difficile à lire mais c'est plus la nature de la bibliothèque elle-même, elle a beaucoup de parties très spécifiques avec lesquelles vous devez vous familiariser. Je pense qu'il y a des parties qui pourraient être améliorées, prenons cet exemple :
Mui.appBar [
prop.className c.appBar
prop.appBar.position.fixed'
prop.children [
Mui.toolbar [
prop.children [
Mui.typography [
prop.typography.variant.h6
prop.typography.color.inherit'
prop.text (pageTitle model.Page)
]
]
]
]
]
Ma version personnelle parfaite de cet extrait serait de le transformer en ce qui suit :
Mui.appBar [
AppBar.className c.appBar
AppBar.position.fixed'
AppBar.children [
Mui.toolbar [
Toolbar.children [
Mui.typography [
Typography.variant.h6
Typography.color.inherit'
Typygraphy.text (pageTitle model.Page)
]
]
]
]
]
De cette façon, il est facile de trouver des éléments Mui car vous pouvez simplement "pointer" Mui et une fois que vous avez trouvé votre élément ( appBar
), vous pouvez "pointer" le nom du module ( AppBar
) pour définir les propriétés et telles
Peut-être garder
AppBar
en minuscules aussi
Je pense que vous avez compris l'idée mais pour être plus exact, la syntaxe générale de cette API est la suivante où {Element}
est un élément react :
Mui.{element} [
{Element}.{propName}.{propValue}
{Element}.children [
Mui.{otherElem} [
{OtherElem}.{propName}.{propValue}
// etc.
]
]
]
Que penses-tu de cela? Cette API a également inspiré à la bibliothèque les idées de fabuleux-simples-éléments si vous voulez voir une implémentation concrète
Je pense que c'est parfait, et juste le genre de chose sur laquelle je voulais avoir votre avis. J'ai initialement choisi d'avoir tout sous prop
car c'est ainsi que fonctionnait la bibliothèque principale, mais bien sûr, vous n'avez pas vraiment d'accessoires spécifiques aux composants, alors que MUI a plus plus moins seulement des accessoires spécifiques aux composants.
Je pense que s'en tenir aux noms de module en minuscules peut sembler préférable (et économiser une frappe supplémentaire), mais je suis ouvert aux contre-arguments.
C'est bien que j'aie généré automatiquement ce truc, ce qui le rend simple à changer.
Je mettrai à jour et je vous tiendrai au courant.
Il y a une chose en particulier sur laquelle j'aimerais avoir des avis. C'est le truc ClassName
. Le crochet makeStyles
renvoie un objet avec les mêmes accessoires que celui dans lequel il est passé, mais où chaque élément (JSS) a été remplacé par une chaîne, qui est le nom de la classe à utiliser (et peut être passé à par exemple prop.className
).
Maintenant, il n'y a aucun moyen de taper cela en F #, donc je dois travailler avec ce que j'ai. Normalement, tous les props de l'objet style sont IStyleAttribute list
. Cela signifie que je peux ajouter une surcharge pour prop.className
qui accepte IStyleAttribute list
, ce qui est bien sûr un mensonge car au moment de l'exécution, c'est une chaîne. Si vous réussissiez réellement IStyleAttribute list
, cela échouerait. En plus de prop.className
, cela vaut également pour tous les classes.<element>.<classesName>
(utilisés dans <element>.classes [ ... ]
). Ils acceptent également un nom de classe (chaîne).
Ce que j'ai fait, comme vous pouvez le voir, est "d'exiger" que toutes les propriétés IStyleAttribute list
de l'objet de style soient enveloppées dans asClassName
, qui se déballe simplement en IClassName
(un proxy pour string
, si vous le souhaitez). Et puis j'ai ajouté une surcharge à prop.className
acceptant IClassName
, et fait en sorte que tous les accessoires classes
acceptent IClassName
. J'aime le fait qu'il soit plus fortement typé, mais je n'aime pas le fait qu'il nécessite une saisie supplémentaire ( asClassName
pour chaque règle CSS de niveau supérieur). Le compilateur se plaindra si vous le manquez, mais il ne vous dira pas quoi faire, et c'est toujours du bruit supplémentaire.
Avez-vous des commentaires à ce sujet?
Aussi, j'ai remarqué ceci :
f#
listItem.divider ((page = Home))
Ici, les doubles parenthèses sont nécessaires, car sinon F# l'interprète comme essayant d'appeler listItem.divider
avec le paramètre (inexistant) page
défini sur Home
(au lieu de value
paramètre page = Home
). Voyez-vous un moyen d'éviter cela?
Bonjour @cmeeren , tout d'abord, j'adore cette syntaxe :
Mui.appBar [
prop.className c.appBar
appBar.position.fixed'
appBar.children [
Mui.toolbar [
toolbar.children [
Mui.typography [
typography.variant.h6
typography.color.inherit'
prop.text (pageTitle model.Page)
]
]
]
]
]
Ça a l'air si propre et si simple! Bien que si j'étais vous, j'aurais probablement dupliqué certaines des fonctions génériques prop
dans des accessoires spécifiques aux composants tels que appBar.className
au lieu de (ou à côté) prop.className
afin que ils ont tous l'air symétriques mais surtout pour donner la surcharge IClassName
au composant spécifique à Mui au lieu du générique prop.className
qui prend une chaîne car makeStyles
est également un Mui-spécifique construct et il est logique qu'il ne s'applique qu'aux composants Mui.
Je pense que vous avez abordé les makeStyles
la meilleure façon possible, du moins pour le moment, je ne peux pas penser à une meilleure façon (bien que je ne sois pas un grand fan de asClassName
, peut-être Styles.createClass
la place ? c'est à vous de décider).
Quant à listItem.divider ((page = Home))
, c'est délicat, vous pouvez ajouter une fonction factice let when (x: bool) = x
mais ce n'est que du bruit. Je pense qu'il est préférable de le classer en tant que bogue du compilateur car je ne peux pas penser à la raison pour laquelle le compilateur F # ne peut pas résoudre la surcharge appropriée de la fonction, je n'ai pas essayé moi-même mais je l'examinerai quand le temps le permettra
Enfin, je ne suis pas aussi réactif que d'habitude cette semaine car je suis en vacances maintenant, donc je ne pourrai peut-être pas tout lire/vérifier, etc.
Bien que si j'étais vous, j'aurais probablement dupliqué certaines des fonctions génériques
prop
dans des accessoires spécifiques aux composants tels queappBar.className
au lieu de (ou à côté)prop.className
afin que ils ont tous l'air symétriques mais surtout pour donner la surchargeIClassName
au composant spécifique à Mui au lieu du génériqueprop.className
qui prend une chaîne carmakeStyles
est également un Mui-spécifique construct et il est logique qu'il ne s'applique qu'aux composants Mui.
Découvrez-le maintenant :) J'ai apporté des améliorations et des extensions drastiques ces derniers jours, je les ai juste poussées (pas fait, je suis actuellement en train de parcourir tous les composants MUI pour vérifier et améliorer les accessoires générés).
Je pense que vous avez abordé les
makeStyles
la meilleure façon possible, du moins pour le moment, je ne peux pas penser à une meilleure façon (Bien que je ne sois pas un grand fan deasClassName
, peut-êtreStyles.createClass
la place ? c'est à vous de décider).
J'aimerais le garder aussi court que possible car il sera beaucoup utilisé, mais je suis ouvert à d'autres noms. Bien que j'aie à moitié envie d'avoir juste une surcharge IStyleAttribute list
. Cela supprimera potentiellement pas mal de bruit, et je doute que ce soit très dangereux même s'il peut techniquement être utilisé de manière incorrecte.
Quant à
listItem.divider ((page = Home))
, c'est délicat, vous pouvez ajouter une fonction facticelet when (x: bool) = x
mais ce n'est que du bruit. Je pense qu'il est préférable de le classer en tant que bogue du compilateur car je ne peux pas penser à la raison pour laquelle le compilateur F # ne peut pas résoudre la surcharge appropriée de la fonction, je n'ai pas essayé moi-même mais je l'examinerai quand le temps le permettra
Merci, j'ai déposé un problème maintenant : https://github.com/dotnet/fsharp/issues/7423
Enfin, je ne suis pas aussi réactif que d'habitude cette semaine car je suis en vacances maintenant, donc je ne pourrai peut-être pas tout lire/vérifier, etc.
Compris, pas de problème. Je continuerai à publier des problèmes si je rencontre des problèmes, et vous répondez simplement à votre rythme.
Découvrez-le maintenant :) J'ai apporté des améliorations et des extensions drastiques ces derniers jours, je les ai juste poussées (pas fait, je suis actuellement en train de parcourir tous les composants MUI pour vérifier et améliorer les accessoires générés).
Ça a l'air vraiment bien, avec les documents générés aussi 😍 peut-être qu'il est temps de mettre son propre dépôt ?
J'aimerais le garder aussi court que possible car il sera beaucoup utilisé, mais je suis ouvert à d'autres noms. Bien que j'aie à moitié envie d'avoir juste une surcharge de liste IStyleAttribute. Cela supprimera potentiellement pas mal de bruit, et je doute que ce soit très dangereux même s'il peut techniquement être utilisé de manière incorrecte.
Cela fonctionnerait aussi, les bibliothèques Fable trompent le système de type tout le temps ;)
Merci, j'ai déposé un problème maintenant : dotnet/fsharp#7423
Impressionnant! Merci beaucoup
Ça a l'air vraiment bien, avec les documents générés aussi 😍 peut-être qu'il est temps de mettre son propre dépôt ?
J'y ai pensé, mais il y a encore quelques bugs importants (par exemple # 27) que je préférerais comprendre avec la commodité d'avoir tout au même endroit, donc je pense que je vais le garder là jusqu'à ce qu'il soit prêt pour une avant-première sur nuget (espérons-le ne sera pas trop longue).
@Zaid-Ajaj J'ai presque fini avec Feliz.MaterialUI. Publiera bientôt dans un dépôt séparé. Ce serait formidable que vous le révisiez, d'abord et avant tout pour vérifier certaines décisions de conception et assurer la cohérence avec Feliz, mais aussi pour vérifier certains éléments d'implémentation (par exemple, est-ce que j'utilise des choses que vous ferez en interne, ou y a-t-il des choses que je Je n'utilise pas Feliz mais je devrais utiliser).
Lorsque je crée le nouveau dépôt, est-ce que je peux créer des problèmes expliquant ce que j'aimerais revoir et vous taguer ?
J'ai maintenant téléchargé un brouillon de Feliz.MaterialUI sur cmeeren/Feliz.MaterialUI . J'ai créé plusieurs problèmes avec des choses que j'aimerais revoir.
Je vous serais très reconnaissant si vous pouviez trouver le temps d'y jeter un œil !
Il n'est pas nécessaire de passer beaucoup de temps sur chaque problème ; Je veux vraiment juste un deuxième avis pour les raisons mentionnées dans mon commentaire précédent. Je suis heureux d'aller dans les mauvaises herbes si vous voulez, mais même juste "ça a l'air bien" serait génial.
Il n'y a pas d'urgence, bien sûr. :)
Super travail @cmeeren ! A première vue, les reliures ont l'air très propres, je vais jeter un oeil à chaque numéro dans les prochains jours, promis :sourire:
Hé! Une chance de continuer à examiner les problèmes ? Encore une fois pas pressé, juste un rappel amical puisque je n'ai pas eu de vos nouvelles depuis quelques semaines 😃
En fait, j'ai examiné les problèmes, mais comme je l'ai déjà dit, qu'une API soit bonne ou non provient de cas d'utilisation, c'est pourquoi je vous ai demandé de publier une version alpha afin que je puisse l'essayer, mais je n'ai pas eu le il est encore temps de le faire (c'était dans ma tête cette semaine :sourire:)
Bonjour @cmeeren , je suppose que nous pouvons considérer cela comme résolu, n'est-ce pas ? Je vais fermer le sujet, veuillez le rouvrir pour une discussion plus approfondie si nécessaire
Commentaire le plus utile
Bonjour @cmeeren , je suppose que nous pouvons considérer cela comme résolu, n'est-ce pas ? Je vais fermer le sujet, veuillez le rouvrir pour une discussion plus approfondie si nécessaire