Feliz: стороннее руководство

Созданный на 11 авг. 2019  ·  25Комментарии  ·  Источник: Zaid-Ajaj/Feliz

Это выглядит фантастически ИМХО.

Легко ли это расширить для сторонних материалов, таких как Material-UI ?

Было бы здорово иметь какое-то руководство о том, как это сделать. :)

Самый полезный комментарий

Привет @cmeeren , я думаю, мы можем считать, что это решено, верно? Я закрою тему, пожалуйста, снова откройте для дальнейшего обсуждения, если это необходимо.

Все 25 Комментарий

Это выглядит фантастически ИМХО.

Спасибо! Рада, что понравилось :smile:

Легко ли это расширить для сторонних материалов, таких как Material-UI?

Конечно, но подход немного отличается, потому что мы не используем размеченные союзы. Я пытаюсь написать что-нибудь, когда позволяет время, но идея в том, что у вас есть два варианта:

  • 1) Расширьте статический тип prop дополнительными функциями.
  • 2) Создайте аналогичный статический тип 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) почему тогда вообще встроенный? В чем преимущество «простых» тел функций/методов?

  • Размер пакета: если эти функции не используются (а их сотни), они все равно компилируются, увеличивая размер пакета AFAIK (влияние, конечно, по-прежнему зависит от общего размера приложения)
  • Аргументы универсального типа: не имеет значения для Feliz, но в контексте 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 , я думаю, мы можем считать, что это решено, верно? Я закрою тему, пожалуйста, снова откройте для дальнейшего обсуждения, если это необходимо.

Была ли эта страница полезной?
0 / 5 - 0 рейтинги

Смежные вопросы

cmeeren picture cmeeren  ·  13Комментарии

cmeeren picture cmeeren  ·  4Комментарии

Dzoukr picture Dzoukr  ·  9Комментарии

mastoj picture mastoj  ·  3Комментарии

l3m picture l3m  ·  7Комментарии