Это выглядит фантастически ИМХО.
Легко ли это расширить для сторонних материалов, таких как Material-UI ?
Было бы здорово иметь какое-то руководство о том, как это сделать. :)
Это выглядит фантастически ИМХО.
Спасибо! Рада, что понравилось :smile:
Легко ли это расширить для сторонних материалов, таких как Material-UI?
Конечно, но подход немного отличается, потому что мы не используем размеченные союзы. Я пытаюсь написать что-нибудь, когда позволяет время, но идея в том, что у вас есть два варианта:
prop
дополнительными функциями.prop
, характерный для вашей библиотеки (возможно, Mui
), который имеет все свойства, необходимые для Mui. Вы даже можете использовать псевдоним prop
с Mui
и расширить Mui
специфичными для Mui (перегруженными) свойствами и функциями.Расширение так же просто, как:
type prop with
static member hello (value: string) = Interop.mkAttr "hello" value
Является ли это «окончательной формой» библиотеки и способом ее расширения, все еще рассматривается, поскольку я сначала хочу попробовать ее, создав сторонние библиотеки и посмотреть, как это работает.
Спасибо! Я уже активно тестирую кое-что для MUI, только часть API, чтобы посмотреть, как это работает. Вероятно, поделюсь где-нибудь в выходные/конец, было бы здорово, если бы вы могли взглянуть на него, просто чтобы увидеть, нахожусь ли я на правильном пути и следую ли духу Фелиза. Вроде пока успех!
Однако я не расширил существующий тип prop
. Я определил отдельный тип prop
в другом пространстве имен ( Feliz.MaterialUI
). Работает на вид отлично; вы, конечно, получите доступ ко всем членам из всех соответствующих типов, если вы откроете как Feliz
, так и Feliz.MaterialUI
.
У меня есть тип Mui
, который соответствует Html
и содержит фактические компоненты.
(В настоящее время я поместил реквизиты для конкретных компонентов в отдельные подмодули prop
, как указано в № 13.)
Возможное улучшение в Feliz состоит в том, чтобы иметь reactElement
и createElement
, которые принимают не string
, а ReactElementType
(я думаю). чтобы мы могли вызвать createElement (importDefault "@material-ui/core/Button")
. В настоящее время я сам создал этих двух помощников.
Кстати, все члены должны быть inline
? Каковы плюсы/минусы? Я заметил, что выше вы не использовали inline
, но в Feliz все равно inline
.
Спасибо! Я уже активно тестирую кое-что для MUI, только часть API, чтобы посмотреть, как это работает. Вероятно, поделюсь где-нибудь в выходные/конец, было бы здорово, если бы вы могли взглянуть на него, просто чтобы увидеть, нахожусь ли я на правильном пути и следую ли духу Фелиза. Вроде пока успех!
Это потрясающе! Я определенно с удовольствием посмотрю, если вы
Однако я не расширил существующий тип реквизита. Я определил отдельный тип реквизита в другом пространстве имен (Feliz.MaterialUI). Работает на вид отлично; вы, конечно, получите доступ ко всем членам всех соответствующих типов, если вы откроете и Feliz, и Feliz.MaterialUI.
У меня есть тип Mui, который соответствует Html и содержит фактические компоненты.
Вот что я бы сделал для Муи
(В настоящее время я поместил реквизиты для конкретных компонентов в отдельные подмодули prop, как указано в № 13.)
Это имеет смысл для Mui из-за того, сколько у вас есть вариантов.
Возможное улучшение в Feliz состоит в том, чтобы иметь reactElement и createElement, которые принимают не строку, а ReactElementType (я думаю). так что мы можем вызвать createElement (importDefault "@material-ui/core/Button"). В настоящее время я сам создал этих двух помощников.
Я просматриваю членов, которые я использую в модуле Interop
, я только что показал все, что использовал в библиотеке, будет пересмотрено для стабильной версии
Кстати, все члены должны быть встроенными? Каковы плюсы/минусы? Я заметил, что вы не использовали inline выше, но в Feliz все встроено.
Я должен был встроить расширенный элемент выше!
Эмпирическое правило таково: если значение свойства примитивно, как строка/целое/логическое значение/перечисление, тогда встраивайте свойство, но если ваше свойство вычисляет значение на основе ввода, то лучше не встраивать, потому что каждый раз, когда пользователь вызывает встроенную функцию, все тело функции встроено в этом месте вызова, поэтому, если пользователь использует одну и ту же функцию 10 раз в приложении, тело функции компилируется встроенно 10 раз вместо того, чтобы определяться один раз и ссылаться на него 10 раз.
Эмпирическое правило таково: если значение свойства примитивно, как строка/целое/логическое значение/перечисление, тогда встраивайте свойство, но если ваше свойство вычисляет значение на основе ввода, то лучше не встраивать, потому что каждый раз, когда пользователь вызывает встроенную функцию, все тело функции встроено в этом месте вызова, поэтому, если пользователь использует одну и ту же функцию 10 раз в приложении, тело функции компилируется встроенно 10 раз вместо того, чтобы определяться один раз и ссылаться на него 10 раз.
Приятно знать! Но (в контексте Fable) почему тогда вообще встроенный? В чем преимущество «простых» тел функций/методов?
[<Inject>] ITypeResolver<'t>
как необязательный аргумент статического класса (эту возможность используют только узкоспециализированные библиотеки, см. Fable.SimpleJson/Thoth.Json)Я думаю, что babel выполняет встряхивание деревьев и удаляет неиспользуемые функции, когда вы создаете производственный пакет. Встраивание победило бы это.
@ Luiz-Monad Значит, вы говорите, что в идеале в Feliz ничего не должно быть встроено? Что встраивание по причинам размера пакета контрпродуктивно?
@Luiz-Monad То, что ты говоришь, было бы потрясающе! По крайней мере, если бы компиляция работала именно так. Вот пример, который вы можете попробовать с 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
Где prop
содержит:
f()
содержит тело функции -> не встроено и не используетсяk()
содержит тело функции -> встроено, но не используетсяg()
содержит функцию -> не встроенная и используетсяВы могли бы подумать, что и f()
, и g()
не будут компилироваться, но это не так, f()
(не встроенный и не используемый) все равно компилируется, но k()
(встроенный, не используемый) не попадает в скомпилированный пакет
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);
Это действительно работает, но вам нужно настроить webpack
для этого, потому что то, что делает встряхивание дерева, не является самой басней, поэтому оно не будет работать в REPL.
До
/// 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
После
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
})
Кроме того, в вашем тесте есть одна оговорка, входной файл является особенным, поскольку функции из него не удаляются. (Я предполагаю, что что-то связано с инициализацией статических классов, что-то должно вызывать конструктор статического инициализатора, чтобы выполнять побочные эффекты для модулей)
Посмотрите этот репозиторий, который я сделал для этого тестирования https://github.com/Luiz-Monad/test-tree-shaking .
Большое спасибо за пример репозитория! Я обязательно буду исследовать это дальше, чтобы увидеть, действительно ли встраивание делает что-то полезное в контексте Feliz.
Я обязательно буду исследовать это дальше, чтобы увидеть, действительно ли встраивание делает что-то полезное в контексте Feliz.
Круто, с нетерпением жду, что ты найдешь :)
Это потрясающе! Я определенно с удовольствием посмотрю, если вы
Пожалуйста, ознакомьтесь с веткой feliz
на странице cmeeren/fable-elmish-electron-material-ui-demo .
Большая часть кода генерируется автоматически на основе документации (HTML) API. Есть проект генератора (уродливый и хакерский, но выполняет свою работу) и проект для фактических привязок. В проекте рендерера только App.fs
были преобразованы для использования новых привязок в стиле Feliz.
Пожалуйста, взгляните на него, когда вам захочется, и дайте мне знать, что вы думаете, и если у вас есть какие-либо вопросы.
@cmeeren Выглядит очень красиво и намного лучше, чем текущий API ИМХО, но его все еще немного трудно читать, но это больше характер самой библиотеки, в ней есть много очень специфических частей, с которыми вам нужно ознакомиться. Я думаю, что есть части, которые можно было бы улучшить, возьмем этот пример:
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)
]
]
]
]
]
Моя личная идеальная версия этого фрагмента состоит в том, чтобы превратить его в следующее:
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)
]
]
]
]
]
Таким образом, легко найти элементы Mui, потому что вы можете просто «расставить точки» по Mui, и как только вы найдете свой элемент ( appBar
), вы можете «расставить точки» по имени модуля ( AppBar
) определить свойства и т.п.
Может быть, оставить
AppBar
в нижнем регистре
Я думаю, вы поняли идею, но, если быть более точным, общий синтаксис этого API выглядит следующим образом, где {Element}
— элемент реакции:
Mui.{element} [
{Element}.{propName}.{propValue}
{Element}.children [
Mui.{otherElem} [
{OtherElem}.{propName}.{propValue}
// etc.
]
]
]
Что Вы думаете об этом? Этот API также вдохновил библиотеку на идеи сказочных простых элементов , если вы хотите увидеть конкретную реализацию.
Я думаю, что это идеально, и как раз то, о чем я хотел узнать ваше мнение. Первоначально я решил иметь все под prop
, так как основная библиотека работала так, но, конечно, у вас действительно нет каких-либо реквизитов для конкретных компонентов, тогда как в MUI есть более-менее только реквизиты для конкретных компонентов.
Я думаю, что использование имен модулей в нижнем регистре может выглядеть лучше (и сэкономить дополнительное нажатие клавиши), но я открыт для контраргументов.
Хорошо, что я автоматически сгенерировал этот материал, что упрощает его изменение.
Я обновлю и дам вам знать.
Однако есть одна вещь, по которой я хотел бы узнать мнение. Это ClassName
материал. Хук makeStyles
возвращает объект с теми же реквизитами, что и тот, в который он был передан, но где каждый (JSS) элемент был заменен строкой, которая является именем класса для использования (и может быть передана, например, в prop.className
).
Теперь нет возможности напечатать это на F#, поэтому мне приходится работать с тем, что у меня есть. Обычно все реквизиты объекта стиля IStyleAttribute list
. Это означает, что я могу добавить перегрузку для prop.className
, которая принимает IStyleAttribute list
, что, конечно, является ложью, поскольку во время выполнения это строка. Если вы на самом деле передали IStyleAttribute list
, это потерпит неудачу. В дополнение к prop.className
, это также относится ко всем classes.<element>.<classesName>
(используемым в <element>.classes [ ... ]
). Они также принимают имя класса (строка).
Что я сделал, как вы можете видеть, так это «требовать», чтобы все свойства IStyleAttribute list
объекта стиля были обернуты в asClassName
, что в основном просто распаковывает до IClassName
(прокси для string
, если хотите). Затем я добавил перегрузку к prop.className
, принимающую IClassName
, и заставил все реквизиты classes
принимать IClassName
. Мне нравится, что он более строго типизирован, но мне не нравится, что он требует дополнительного ввода ( asClassName
для каждого правила CSS верхнего уровня). Компилятор будет жаловаться, если вы его пропустите, но не скажет, что делать, и это все равно лишний шум.
Есть ли у вас какие-либо сведения об этом?
Еще я заметил вот это:
f#
listItem.divider ((page = Home))
Здесь требуются двойные круглые скобки, поскольку в противном случае F# интерпретирует это как попытку вызова listItem.divider
с (несуществующим) параметром page
, для которого задано значение Home
(вместо value
Параметр page = Home
). Вы видите способ избежать этого?
Привет @cmeeren , во-первых, мне чертовски нравится этот синтаксис:
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)
]
]
]
]
]
Это выглядит так чисто и так просто! Хотя на вашем месте я бы, вероятно, продублировал некоторые общие функции prop
в специфичные для компонента реквизиты, такие как appBar.className
вместо (или параллельно) prop.className
, чтобы все они выглядят симметрично, но, что более важно, дать перегрузку IClassName
для компонента, специфичного для Mui, вместо общего prop.className
, который принимает строку, потому что makeStyles
также является специфичным для Mui. конструкция, и имеет смысл, что она будет применяться только к компонентам Mui.
Я думаю, что вы справились с makeStyles
наилучшим из возможных способов, по крайней мере, сейчас я не могу придумать лучшего способа (хотя я не большой поклонник asClassName
, может быть, Styles.createClass
вместо
Что касается listItem.divider ((page = Home))
, это сложно, вы можете добавить фиктивную функцию let when (x: bool) = x
, но это просто шум. Я думаю, что лучше всего зарегистрировать это как ошибку компилятора, потому что я не могу придумать причину, по которой компилятор F # не может разрешить правильную перегрузку функции, я сам не пробовал, но я рассмотрю это, когда позволит время
Наконец, на этой неделе я не так быстро отвечаю, как обычно, потому что я сейчас в отпуске, поэтому я не смогу прочитать/проверить все и т. д.
Хотя на вашем месте я бы, вероятно, продублировал некоторые общие функции
prop
в специфичные для компонента реквизиты, такие какappBar.className
вместо (или параллельно)prop.className
, чтобы все они выглядят симметрично, но, что более важно, дать перегрузкуIClassName
для компонента, специфичного для Mui, вместо общегоprop.className
, который принимает строку, потому чтоmakeStyles
также является специфичным для Mui. конструкция, и имеет смысл, что она будет применяться только к компонентам Mui.
Проверьте это прямо сейчас :) Я сделал радикальные улучшения и расширения в последние дни, просто нажал их (не сделано, в настоящее время я просматриваю все компоненты MUI, чтобы проверить и улучшить сгенерированные реквизиты).
Я думаю, что вы справились с
makeStyles
наилучшим из возможных способов, по крайней мере, сейчас я не могу придумать лучшего способа (хотя я не большой поклонникasClassName
, может быть,Styles.createClass
вместо
Я бы хотел, чтобы оно было как можно короче, так как оно будет часто использоваться, но я открыт для других имен. Хотя у меня есть половина разума, чтобы просто перегрузить IStyleAttribute list
. Потенциально это удалит довольно много шума, и я сомневаюсь, что это будет очень опасно, даже если технически его можно использовать неправильно.
Что касается
listItem.divider ((page = Home))
, это сложно, вы можете добавить фиктивную функциюlet when (x: bool) = x
, но это просто шум. Я думаю, что лучше всего зарегистрировать это как ошибку компилятора, потому что я не могу придумать причину, по которой компилятор F # не может разрешить правильную перегрузку функции, я сам не пробовал, но я рассмотрю это, когда позволит время
Спасибо, я зарегистрировал проблему сейчас: https://github.com/dotnet/fsharp/issues/7423
Наконец, на этой неделе я не так быстро отвечаю, как обычно, потому что я сейчас в отпуске, поэтому я не смогу прочитать/проверить все и т. д.
Попался, без проблем. Я буду продолжать публиковать вопросы, если столкнусь с чем-то, а вы просто отвечаете в свое время.
Проверьте это прямо сейчас :) Я сделал радикальные улучшения и расширения в последние дни, просто нажал их (не сделано, в настоящее время я просматриваю все компоненты MUI, чтобы проверить и улучшить сгенерированные реквизиты).
Выглядит очень хорошо, даже со сгенерированными документами 😍 может быть, пришло время поместить его в собственное репо?
Я бы хотел, чтобы оно было как можно короче, так как оно будет часто использоваться, но я открыт для других имен. Хотя у меня есть половина мысли просто иметь перегрузку списка IStyleAttribute. Потенциально это удалит довольно много шума, и я сомневаюсь, что это будет очень опасно, даже если технически его можно использовать неправильно.
Это тоже сработает, библиотеки Fable постоянно обманывают систему типов ;)
Спасибо, я зарегистрировал проблему сейчас: dotnet/fsharp#7423
Потрясающий! большое спасибо
Выглядит очень хорошо, даже со сгенерированными документами 😍 может быть, пришло время поместить его в собственное репо?
Я думал об этом, но есть еще несколько важных ошибок (например, # 27). Я бы предпочел разобраться с удобством, чтобы все было в одном месте, поэтому я думаю, что оставлю это там, пока оно не будет готово. для предварительного выпуска на nuget (надеюсь, не будет слишком долго).
@ Zaid-Ajaj Я почти закончил с Feliz.MaterialUI. Скоро опубликую в отдельном репо. Было бы здорово, если бы вы просмотрели его, в первую очередь, чтобы проверить некоторые дизайнерские решения и обеспечить согласованность с Feliz, а также проверить некоторые моменты реализации (например, использую ли я то, что вы будете делать внутренними, или есть вещи, которые я не пользуюсь от Feliz, но должна пользоваться).
Когда я создаю новый репозиторий, могу ли я создать задачи, объясняющие, что я хочу проверить, и отметить вас?
Я загрузил черновик Feliz.MaterialUI в cmeeren/Feliz.MaterialUI . Я создал несколько вопросов с вещами, которые я хотел бы просмотреть.
Я был бы очень признателен, если бы вы нашли время, чтобы взглянуть на них!
Нет необходимости тратить много времени на каждый вопрос; Мне действительно просто нужно второе мнение по причинам, упомянутым в моем предыдущем комментарии. Я рад углубиться в сорняки, если хотите, но даже просто «выглядит хорошо» было бы здорово.
Нет никакой спешки, конечно. :)
Потрясающая работа @cmeeren! На первый взгляд, переплеты выглядят очень аккуратно, в ближайшие дни я рассмотрю каждый выпуск, обещаю :smile:
Привет! Есть ли шанс продолжить изучение проблем? Опять не торопитесь, просто дружеское напоминание, так как я не слышал от вас пару недель 😃
На самом деле я рассмотрел проблемы, но, как я уже говорил ранее, хороший API или нет, зависит от вариантов использования, поэтому я попросил вас опубликовать альфа-версию, чтобы я мог ее опробовать, но у меня не было время сделать это еще (на этой неделе я думал об этом :smile:)
Привет @cmeeren , я думаю, мы можем считать, что это решено, верно? Я закрою тему, пожалуйста, снова откройте для дальнейшего обсуждения, если это необходимо.
Самый полезный комментарий
Привет @cmeeren , я думаю, мы можем считать, что это решено, верно? Я закрою тему, пожалуйста, снова откройте для дальнейшего обсуждения, если это необходимо.