Sealpage - status report

Od pewnego czasu siedzę nad rewritem sealpage’a. Czas na status report :slight_smile:

Język

Całośc piszę od podstaw w typescripcie

Podział na moduły

Zdecydowałem się podzielić ten projekt na osobne moduły.

  • tempseal - do obsługi templatek. Moduł node’owy, który bierze nasz array-of-objects i wypluwa wyrenderowaną wersję.

    W przeciwieństwie do naszego poprzedniego podejścia zamiast zwracać po prostu ciąg znaków z HTML-em teraz każdy komponent zwraca dwie rzeczy: result i side_effects.

    result jest stringiem z HTML-em, a side_effects jest listą efektów ubocznych - np. utworzenie pliku, dodanie stylu (s)css, zmiana tytułu strony, dodanie obrazka, itp. Następnie Tempseal iteruje przez listę efektów ubocznych i poddaje ją analizie - które efekty się powtarzają i można je scalić, które css-y się powtarzają, które pliki już istnieją i nie trzeba ich tworzyć, etc, etc. Póki co optymalizacje oparte o te side effects są dosyć trywialne i nie wykraczają poza optymalizacje które robliśmy w dotychczasowej wersji sealpage’a, ale otwiera nam to sposób na super eleganckie optymalizacje.

    Podstawowa wersja tego modułu jest już gotowa, szlifuję ją.

  • tempseal-components - moduł z defaultowymi komponentami sealpage’owymi. Oczywiście będzie możliwość dodawania własnych komponentów - myślę też nad możliwością kustomizowania tych już istniejących.

    Mam już zaimplementowane kilka komponentów

  • tempseal-docs - apka react-owa, która na podstawie zadanej listy komponentów tworzy ich dokumentację i możliwość podglądu a’la Fractal - ale z kilkoma ulepszeniami:

    • automatycznie generuje lorem-ipsumowe wartości propsów do podglądu. Daje także guzik do ich przelosowania, aby były innej długości - w celu testowania elastyczności layoutu;
    • pokazuje jeden komponent w kilku szerokościach ekranu jednocześnie;
    • pokazuje jak zadany komponent zachowuje się w sąsiedztwie innych istniejących komponentów, czy się nie gryzie layoutowo;

    Ten moduł póki co mam tylko w koncepcie

  • sealpage - narzędzie, które używając tempseal tworzy stronę z panelem admina. Trzeba pomyśleć nad tym, jak użytkownik strony będzie tworzył jej strukturę - czy będzie ona opisana w kodzie, czy być może będzie do wyklikania? Być może dobrze będzie zacząć od struktury napisanej w kodzie, a potem przejść do wyklikiwalnej.

Monorepo

Wszystkie te moduły planuję trzymać w jednym repo (!) i opublikować na npm-ie, żeby ułatwić ich instalację.

3lajki

jak się definiuje takie side_effects?

Póki co rozwiązuję to w ten sposób:

import { Component, FileSideEffect } from "tempseal";

export class ThumbnailParagraph extends Component {
  static identifier = "thumbnail-paragraph";
  props = { image_path: {} }; // to jest jeszcze niepełne, siedzę właśnie nad określaniem propsów tak żeby typescript mógł je analizować ale także żeby można je było czytać w kodzie

  async _render({
    image_path,
    img_side,
    headline,
    title,
    description,
    alt_text,
    sticky = false
  }) {
    // need to add styles
    const image = await FileSideEffect.fromPath(image_path);
    const result = /* HTML */ `
      <div
        class="thumbnail-paragraph thumbnail-paragraph--${img_side ||
          "right"}"
      >
        <div class="thumbnail ${sticky ? "thumbnail--sticky" : ""}">
          <img
            alt="${alt_text || ""}"
            src="${image.url_placeholder}"
          />
        </div>
        <div class="header">
          <div class="headline">${headline || ""}</div>
          <h3>${title || ""}</h3>
        </div>
        <div class="paragraph">
          ${description || ""}
        </div>
      </div>
    `;
    return {
      result,
      side_effects: [image]
    };
  }
}

Zdałem sobie sprawę, że moje podejście do skutków ubocznych jest bardzo podobne do tego jakie robi Parcel.

https://parceljs.org/asset_types.html

Aktualnie rozważam możliwość zrobienia z tempSeal pluginu do Parcela - albo jako opcjonalnie, albo być może w ścisłym powiązaniu z Parcelem

Plugin imho wydaję się lepszym podjeściem

Rozważam to coraz bardziej. Myślę, że zastosuję rozwiązanie hybrydowe - będzie samodzielny builder w tempseal, a Parcel będzie wykorzystany do koordynacji procesu budowania (bo ma już wielowątkowość itp)

1lajk

Siedzę drugi dzień nad integracją z Parcelem i widzę już kilka cięższych problemów:

  1. Dokumentacja parcela jest za mało szczegółowa. Dużo muszę zgadywać, często zaglądam po prostu do kodu źródłowego, aby sprawdzić jak różne rzeczy działają. Wersja v2 ma lepszą dokumentację, ale póki co stabilna jest tylko v1.
  2. Parcel służy głównie do transpilacji, a nie do generowanie kodu - nie znalazłem w jego logice miejsca na:
    • reużywalne templatki - w naszym przypadku plik opisujący komponent - jakie argumenty przyjmuje i jak ma się zbudować. Można wskazać Pracelowi jakąś templatkę, ale nie można do niej przekazać innych danych. Dodatkowo Parcel traktuje dwa odwołania się do jakiejś templatki jako duplikat, i załącza ją tylko raz. Dla każdego użycia templatki musielibyśmy tworzyć zduplikowany plik z kodem…
    • nieistniejące jeszcze pliki - Parcel zakłada, że wspomniane przeze mnie wcześniej dependencies już istnieją na dysku jako pliki, trzeba je tylko jakoś przetransformować. Dlatego bez przesadnej gimnastyki, a może nawet wcale, nie można stworzyć komponentu responsiveImage, który tworzy pliki graficzne do outputu na podstawie jednego pliku. Parcel zakłada, że te pomniejszone zdjęcia już są na dysku, i trzeba je tylko zoptymalizować i przekopiować do public.
  3. Wydajność - Parcel działa szybko - ale wczytuje się długo. Na moim komputerze renderowanie pustego HTML-a Parcelem trwa ponad 1s (z czego samo faktyczne przetwarzanie HTML to kilka ms)… Startup time jest naprawdę długi. Oczywiście kolejne przerenderowania są szybsze, ale trzeba trzymać włączony wątek Parcela. Ponownie prześwituje fakt, że Parcel nie jest do końca stworzony do celu, do którego próbuję go tutaj użyć.

Dlatego też planuję porzucić tę ścieżkę poszukiwań i nie naginać się do ograniczeń jakie w tym kontekście nadaje Parcel. Niemniej jednak w konstrukcji sealpage’a/tempseal-a będę się inspirował dobrymi elementami Parcela, jak np. wsparcie dla wielowątkowego renderowania i podział na drzewo dependencji.

Hmm może Rollup?

1lajk

Rollup ma znacznie lepiej napisaną dokumentację :heart_eyes:

Zwróciłem uwagę na metodę emitFile , która wydaje się być odpowiedzią na przynajmniej część z moich zarzutów wobec Parcela - bo pozwala emitować arbitralne pliki, niekoniecznie takie które istnieją na dysku.

Obawiałem się, czy pozwala to na zrównoleglenie generowania tych plików, i wychodzi na to, że tak!

It is possible to defer setting the source via this.setAssetSource(assetReferenceId, source) to a later time to be able to reference a file during the build phase while setting the source separately for each output during the generate phase.

Obczaję Rollup jako alternatywę dla Parcela - dzięki!

1lajk

Najs :slight_smile:

1lajk

Z mojego riserczu wnioskuję, że rollup niestety nie ma wsparcia dla cache’a offline (tzn nie w RAM-ie, tylko na dysku)- co było dane automatycznie w przypadku Parcela. Obawiam się, że w obliczu tej informacji korzystanie z rollupa oznaczałoby potrzebę dopisania do niego opcji zapisywania cache’a na dysk. Podejrzewam, że łatwiej będzie samemu napisać cache’owanie do dysku niż dopisywać to do rollupa…

(checkpoint myślowy)

w dalszych pracach nad sealpage’m muszę:

  • zaimplementować lub znaleźć implementację bundlera który cache’uje wyniki działania w systemie plików i który pozwala na dodawanie nowych targetów z poziomu jednego targeta i każdej z jego dependencji
  • identyfikować moduły i pluginy za pomocą ścieżek do ich plików, a nie za pomocą obiektów - dzięki temu będzie można zrównoleglić budowanie na wiele wątków