Uprość swój stos za pomocą niestandardowego generatora stron statycznych

Opublikowany: 2022-03-10
Szybkie podsumowanie ↬ W nowoczesnym programowaniu jest tak wiele świetnych narzędzi do tworzenia stron internetowych, ale często jest to więcej niż to, co jest potrzebne do danego projektu. W tym artykule dowiemy się, jak zrobić skromną stronę HTML i umożliwić edycję jej zawartości w systemie CMS bez frameworków i JavaScriptu po stronie klienta.

Wraz z nadejściem ruchu Jamstack, strony obsługiwane statycznie ponownie stały się modne. Większość programistów obsługujących statyczny kod HTML nie tworzy natywnego kodu HTML. Aby mieć solidne doświadczenie programistyczne, często korzystamy z narzędzi zwanych Static Site Generators (SSG).

Narzędzia te mają wiele funkcji, które sprawiają, że tworzenie statycznych witryn na dużą skalę jest przyjemne. Niezależnie od tego, czy zapewniają proste podpięcia do zewnętrznych interfejsów API, takich jak źródła danych Gatsby, czy też zapewniają dogłębną konfigurację, taką jak ogromna kolekcja silników szablonów 11ty, w generowaniu witryn statycznych każdy znajdzie coś dla siebie.

Ponieważ narzędzia te są przeznaczone do różnych zastosowań, muszą mieć wiele funkcji. Te cechy czynią je potężnymi. Sprawiają też, że są one dość złożone i nieprzejrzyste dla nowych programistów. W tym artykule sprowadzimy SSG do jego podstawowych elementów i stworzymy własne.

Co to jest statyczny generator witryn?

W swej istocie generator witryn statycznych to program, który wykonuje szereg przekształceń na grupie plików w celu przekształcenia ich w statyczne zasoby, takie jak HTML. Jakie rodzaje plików może zaakceptować, jak je przekształca i jakie typy plików są dostępne, odróżniają grupy SSG.

Jekyll, wczesny i wciąż popularny SSG, używa Rubiego do przetwarzania szablonów Liquid i plików treści Markdown na HTML.

Gatsby używa React i JSX do przekształcania komponentów i treści w HTML. Następnie idzie o krok dalej i tworzy jednostronicową aplikację, którą można obsługiwać statycznie.

11ty renderuje kod HTML z silników szablonów, takich jak Liquid, Handlebars, Nunjucks lub literały szablonów JavaScript.

Każda z tych platform posiada dodatkowe funkcje ułatwiające nam życie. Dostarczają motywów, budują potoki, architekturę wtyczek i nie tylko. Z każdą dodatkową funkcją wiąże się większa złożoność, więcej magii i więcej zależności. Z pewnością są to ważne funkcje, ale nie każdy projekt ich potrzebuje.

Pomiędzy tymi trzema różnymi grupami SSG widzimy inny wspólny motyw: dane + szablony = ostateczna witryna. Wydaje się, że jest to podstawowa funkcjonalność witryn statycznych generatorów. To jest funkcja, na której oprzemy nasze SSG.

W swej istocie generator witryn statycznych to program, który wykonuje szereg przekształceń na grupie plików w celu przekształcenia ich w statyczne zasoby, takie jak HTML.

Stos technologiczny naszego nowego generatora stron statycznych: Kierownice, Sanity.io i Netlify

Aby zbudować nasze SSG, potrzebujemy silnika szablonów, źródła danych i hosta, który może uruchomić nasze SSG i zbudować naszą witrynę. Wiele generatorów używa Markdown jako źródła danych, ale co by było, gdybyśmy poszli o krok dalej i natywnie połączyli nasze SSG z CMS?

  • Źródło danych: Sanity.io
  • Pobieranie i tworzenie szablonów danych: węzeł i uchwyty
  • Host i wdrożenie: Netlify.

Warunki wstępne

  • Zainstalowano NodeJS
  • Konto Sanity.io
  • Znajomość Gita
  • Podstawowa znajomość wiersza poleceń
  • Podstawowa wiedza na temat wdrażania do usług takich jak Netlify.

Uwaga : Aby śledzić, możesz znaleźć kod w tym repozytorium na GitHub.

Więcej po skoku! Kontynuuj czytanie poniżej ↓

Konfigurowanie naszej struktury dokumentów w HTML

Aby rozpocząć naszą strukturę dokumentu, napiszemy zwykły HTML. Nie musisz jeszcze komplikować spraw.

W naszej strukturze projektu musimy stworzyć miejsce, w którym będą żyły nasze pliki źródłowe. W takim przypadku utworzymy katalog src i umieścimy w nim nasz index.html .

W index.html określimy treść, którą chcemy. To będzie stosunkowo prosta strona.

 <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Title of the page!</title> </head> <body> <h1>The personal homepage of Bryan Robinson</h1> <p>Some pagraph and rich text content next</p> <h2>Bryan is on the internet</h2> <ul> <li><a href="linkURL">List of links</a></li> </ul> </body> </html>

Niech to będzie proste. Zaczniemy od h1 na naszej stronie. Podążymy za tym kilkoma akapitami informacji biograficznych i zakotwiczymy stronę z listą linków, aby zobaczyć więcej.

Konwertuj nasz kod HTML na szablon, który akceptuje dane

Gdy mamy już podstawową strukturę, musimy skonfigurować proces, aby połączyć to z pewną ilością danych. W tym celu użyjemy mechanizmu szablonów Handlebars.

W swej istocie Handlebars pobiera ciąg znaków podobny do HTML, wstawia dane za pomocą reguł zdefiniowanych w dokumencie, a następnie wyświetla skompilowany ciąg HTML.

Aby użyć Handlebars, musimy zainicjować package.json i zainstalować pakiet.

Uruchom npm init -y , aby utworzyć strukturę pliku package.json z pewną domyślną zawartością. Gdy już to mamy, możemy zainstalować kierownice.

 npm install handlebars

Nasz skrypt kompilacji będzie skryptem węzła. Jest to skrypt, którego użyjemy lokalnie do zbudowania, ale także tego, którego nasz dostawca wdrożeniowy i host użyją do zbudowania naszego kodu HTML dla działającej witryny.

Aby uruchomić nasz skrypt, utworzymy plik index.js i wymagamy dwóch pakietów na górze. Pierwszy to Handlebars, a drugi to domyślny moduł w Node do uzyskiwania dostępu do bieżącego systemu plików.

 const fs = require('fs'); const Handlebars = require('handlebars');

Użyjemy modułu fs , aby uzyskać dostęp do naszego pliku źródłowego, a także do zapisu do pliku dystrybucyjnego. Aby rozpocząć naszą kompilację, utworzymy main funkcję dla naszego pliku, która będzie uruchamiana po wywołaniu, oraz funkcję buildHTML , która łączy nasze dane i znaczniki.

 function buildHTML(filename, data) { const source = fs.readFileSync(filename,'utf8').toString(); const template = Handlebars.compile(source); const output = template(data); return output } async function main(src, dist) { const html = buildHTML(src, { "variableData": "This is variable data"}); fs.writeFile(destination, html, function (err) { if (err) return console.log(err); console.log('index.html created'); }); } main('./src/index.html', './dist/index.html');

Funkcja main() akceptuje dwa argumenty: ścieżkę do naszego szablonu HTML i ścieżkę, którą chcemy, aby nasz zbudowany plik był aktywny. W naszej głównej funkcji uruchamiamy buildHTML na ścieżce źródłowej szablonu z pewną ilością danych.

Funkcja budowania konwertuje dokument źródłowy na ciąg i przekazuje ten ciąg do Handlebars. Kierownica kompiluje szablon przy użyciu tego ciągu. Następnie przekazujemy nasze dane do skompilowanego szablonu, a Handlebars renderuje nowy ciąg HTML, zastępując wszelkie zmienne lub logikę szablonu danymi wyjściowymi.

Zwracamy ten ciąg do naszej funkcji main i używamy metody writeFile dostarczonej przez moduł systemu plików Node, aby zapisać nowy plik w naszej określonej lokalizacji, jeśli katalog istnieje.

Aby zapobiec błędom, dodaj katalog dist do swojego projektu z plikiem .gitkeep . Nie chcemy zatwierdzać naszych zbudowanych plików (nasz proces budowania to zrobi), ale będziemy chcieli upewnić się, że mamy ten katalog dla naszego skryptu.

Zanim utworzymy CMS do zarządzania tą stroną, upewnijmy się, że działa. Aby to przetestować, zmodyfikujemy nasz dokument HTML, aby używał danych, które właśnie do niego przekazaliśmy. Użyjemy składni zmiennej Handlebars, aby uwzględnić zawartość variableData .

 <h1>{{ variableData }}</h1>

Teraz, gdy nasz kod HTML ma zmienną, jesteśmy gotowi do uruchomienia naszego skryptu węzła.

 node index.js

Po zakończeniu skryptu powinniśmy mieć plik pod adresem /dist/index.html . Jeśli przeczytamy otwórz to w przeglądarce, zobaczymy wyrenderowany nasz znacznik, ale także nasz ciąg „To są zmienne dane”.

Podłączanie do CMS

Mamy sposób na zestawienie danych z szablonem, teraz potrzebujemy źródła dla naszych danych. Ta metoda będzie działać z dowolnym źródłem danych, które ma interfejs API. W tym demo użyjemy Sanity.io.

Sanity to źródło danych oparte na interfejsie API, które traktuje zawartość jako dane strukturalne. Mają system zarządzania treścią typu open source, dzięki czemu zarządzanie danymi i dodawanie danych jest wygodniejsze zarówno dla redaktorów, jak i programistów. CMS jest często określany jako „bezgłowy” system CMS. Zamiast tradycyjnego systemu zarządzania, w którym dane są ściśle powiązane z prezentacją, bezgłowy CMS tworzy warstwę danych, która może być wykorzystana przez dowolny frontend lub usługę (i prawdopodobnie wiele jednocześnie).

Sanity jest usługą płatną, ale mają plan „Standardowy”, który jest bezpłatny i ma wszystkie funkcje, których potrzebujemy dla takiej witryny.

Konfigurowanie Sanity

Najszybszym sposobem na rozpoczęcie pracy z nowym projektem Sanity jest użycie Sanity CLI. Zaczniemy od zainstalowania tego globalnie.

 npm install -g @sanity/cli

CLI daje nam dostęp do grupy pomocników do zarządzania, wdrażania i tworzenia. Aby zacząć, uruchomimy sanity init . Przeprowadzi nas to przez kwestionariusz, który pomoże załadować nasze Studio (co Sanity nazywa ich open-source CMS).

 Select a Project to Use: Create new project HTML CMS Use the default dataset configuration? Y // this creates a "Production" dataset Project output path: studio // or whatever directory you'd like this to live in Select project template Clean project with no predefined schemas

Ten krok spowoduje utworzenie nowego projektu i zestawu danych na Twoim koncie Sanity, utworzenie lokalnej wersji Studio oraz powiązanie danych i systemu CMS. Domyślnie katalog studio zostanie utworzony w katalogu głównym naszego projektu. W projektach na większą skalę możesz chcieć skonfigurować to jako osobne repozytorium. W przypadku tego projektu dobrze jest trzymać to razem.

Aby uruchomić nasze Studio lokalnie, zmienimy katalog na katalog studio i uruchomimy sanity start . Spowoduje to uruchomienie Studio na localhost:3333 . Po zalogowaniu zostanie wyświetlony ekran z informacją, że masz „Pusty schemat”. Po tym nadszedł czas, aby dodać nasz schemat, czyli sposób, w jaki nasze dane będą ustrukturyzowane i edytowane.

Tworzenie schematu zdrowia psychicznego

Sposób tworzenia dokumentów i pól w Sanity Studio polega na tworzeniu schematów w pliku schemas/schema.js .

Dla naszej witryny utworzymy typ schematu o nazwie „Informacje o szczegółach”. Nasz schemat będzie wypływał z naszego kodu HTML. Ogólnie rzecz biorąc, większość naszej strony internetowej moglibyśmy uczynić jednym polem z tekstem sformatowanym, ale najlepiej jest ustrukturyzować zawartość w sposób oddzielony. Zapewnia to większą elastyczność w sposobie wykorzystania tych danych w przyszłości.

Na naszej stronie internetowej potrzebujemy zestawu danych, który obejmuje:

  • Tytuł
  • Pełne imię i nazwisko
  • Biografia (z sformatowaną edycją tekstu)
  • Lista stron internetowych z nazwą i adresem URL.

Aby zdefiniować to w naszym schemacie, tworzymy obiekt dla naszego dokumentu i definiujemy jego pola. Lista naszych treści z adnotacjami wraz z type pola :

  • Tytuł — string
  • Imię i nazwisko — ciąg
  • Biografia — tablica „klocków”
  • Lista serwisów — tablica obiektów z polami name i URL string.
 types: schemaTypes.concat([ /* Your types here! */ { title: "About Details", name: "about", type: "document", fields: [ { name: 'title', type: 'string' }, { name: 'fullName', title: 'Full Name', type: 'string' }, { name: 'bio', title: 'Biography', name: 'content', type: 'array', of: [ { type: 'block' } ] }, { name: 'externalLinks', title: 'Social media and external links', type: 'array', of: [ { type: 'object', fields: [ { name: 'text', title: 'Link text', type: 'string' }, { name: 'href', title: 'Link url', type: 'string' } ] } ] } ] } ])

Dodaj to do swoich typów schematów, zapisz, a Twoje Studio ponownie skompiluje i zaprezentuje Ci Twoje pierwsze dokumenty. Stąd dodamy naszą treść do CMS, tworząc nowy dokument i wypełniając informacje.

Strukturyzacja treści w sposób wielokrotnego użytku

W tym momencie możesz się zastanawiać, dlaczego mamy „pełne imię” i „tytuł”. Dzieje się tak, ponieważ chcemy, aby nasze treści miały potencjał wielozadaniowy. Dołączając pole nazwy zamiast umieszczania nazwy tylko w tytule, zwiększamy wykorzystanie tych danych. Następnie możemy wykorzystać informacje zawarte w tym systemie CMS do zasilania strony CV lub pliku PDF. Pole biografii może być programowo używane w innych systemach lub witrynach internetowych. Dzięki temu możemy mieć jedno źródło prawdy dla większości tych treści, zamiast być podyktowanym bezpośrednim przypadkiem użycia tej konkretnej witryny.

Wciąganie naszych danych do naszego projektu

Teraz, gdy udostępniliśmy nasze dane za pośrednictwem interfejsu API, wciągnijmy je do naszego projektu.

Zainstaluj i skonfiguruj klienta Sanity JavaScript

Po pierwsze, potrzebujemy dostępu do danych w Node. Do nawiązania tego połączenia możemy użyć klienta Sanity JavaScript.

 npm install @sanity/client

Spowoduje to pobranie i zainstalowanie pakietu JavaScript SDK. Stąd musimy go skonfigurować, aby pobierał dane z projektu, który skonfigurowaliśmy wcześniej. Aby to zrobić, skonfigurujemy skrypt narzędziowy w /utils/SanityClient.js . Dostarczamy SDK z naszym identyfikatorem projektu i nazwą zestawu danych i jesteśmy gotowi do użycia ich w naszym głównym skrypcie.

 const sanityClient = require('@sanity/client'); const client = sanityClient({ projectId: '4fs6x5jg', dataset: 'production', useCdn: true }) module.exports = client;

Pobieranie naszych danych za pomocą GROQ

W naszym index.js utworzymy nową funkcję do pobierania naszych danych. Aby to zrobić, użyjemy natywnego języka zapytań Sanity, GROQ o otwartym kodzie źródłowym.

Zbudujemy zapytanie w zmiennej, a następnie użyjemy skonfigurowanego klienta do pobrania danych na podstawie zapytania. W tym przypadku budujemy obiekt z właściwością about . W tym obiekcie chcemy zwrócić dane dla naszego konkretnego dokumentu. W tym celu wykonujemy zapytanie na podstawie _id dokumentu, który jest generowany automatycznie podczas tworzenia naszego dokumentu.

Aby znaleźć identyfikator _id dokumentu, przechodzimy do dokumentu w Studio i albo kopiujemy go z adresu URL, albo przechodzimy do trybu „Sprawdź”, aby wyświetlić wszystkie dane w dokumencie. Aby wejść do Inspect, kliknij menu „kabob” w prawym górnym rogu lub użyj skrótu Ctrl + Alt + I . Ten widok wyświetli listę wszystkich danych w tym dokumencie, w tym nasz _id . Sanity zwróci tablicę obiektów dokumentu, więc dla uproszczenia zwrócimy 0th -ty wpis.

Następnie przekazujemy zapytanie do metody fetch naszego klienta Sanity, która zwróci obiekt JSON wszystkich danych w naszym dokumencie. W tym demo zwrócenie wszystkich danych nie jest wielkim problemem. W przypadku większych implementacji GROQ pozwala na opcjonalną „projekcję”, aby zwrócić tylko te pola, które chcesz.

 const client = require('./utils/SanityClient') // at the top of the file // ... async function getSanityData() { const query = `{ "about": *[_id == 'YOUR-ID-HERE'][0] }` let data = await client.fetch(query); }

Konwertowanie pola tekstu sformatowanego do formatu HTML

Zanim będziemy mogli zwrócić dane, musimy dokonać transformacji w naszym polu tekstu sformatowanego. Podczas gdy wiele systemów CMS korzysta z edytorów tekstu sformatowanego, które bezpośrednio zwracają kod HTML, Sanity używa specyfikacji typu open source o nazwie Portable Text. Przenośny tekst zwraca tablicę obiektów (pomyśl o tekście sformatowanym jako liście akapitów i innych blokach multimedialnych) ze wszystkimi danymi dotyczącymi stylu i właściwości tekstu sformatowanego, takich jak łącza, przypisy i inne adnotacje. Pozwala to na przenoszenie tekstu i używanie go w systemach, które nie obsługują języka HTML, takich jak asystenci głosowi i aplikacje natywne.

W naszym przypadku użycia oznacza to, że musimy przekształcić obiekt w HTML. Istnieją moduły NPM, których można użyć do konwersji przenośnego tekstu do różnych zastosowań. W naszym przypadku użyjemy pakietu o nazwie block-content-to-html.

 npm install @sanity/block-content-to-html

Ten pakiet wyrenderuje wszystkie domyślne znaczniki z edytora tekstu sformatowanego. Każdy typ stylu można zastąpić, aby był zgodny z dowolnymi znacznikami potrzebnymi w przypadku użycia. W takim przypadku pakiet wykona za nas pracę.

 const blocksToHtml = require('@sanity/block-content-to-html'); // Added to the top async function getSanityData() { const query = `{ "about": *[_type == 'about'][0] }` let data = await client.fetch(query); data.about.content = blocksToHtml({ blocks: data.about.content }) return await data }

Korzystanie z treści z Sanity.io w kierownicy

Teraz, gdy dane są w kształcie, w którym możemy ich użyć, przekażemy to do naszej funkcji buildHTML jako argument danych.

 async function main(src, dist) { const data = await getSanityData(); const html = buildHTML(src, data) fs.writeFile(dist, html, function (err) { if (err) return console.log(err); console.log('index.html created'); }); }

Teraz możemy zmienić nasz kod HTML, aby używał nowych danych. Użyjemy więcej wywołań zmiennych w naszym szablonie, aby pobrać większość naszych danych.

Aby wyrenderować naszą zmienną content sformatowanego tekstu, musimy dodać dodatkową warstwę nawiasów klamrowych do naszej zmiennej. To powie Handlebars, aby renderowały kod HTML zamiast wyświetlać kod HTML jako ciąg.

W przypadku naszej tablicy externalLinks musimy użyć wbudowanej funkcji pętli Handlebars, aby wyświetlić wszystkie linki, które dodaliśmy do naszego Studio.

 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>{{ about.title }}</title> </head> <body> <h1>The personal homepage of {{ about.fullName }}</h1> {{{ about.content }}} <h2>Bryan is on the internet</h2> <ul> {{#each about.externalLinks }} <li><a href="{{ this.href }}">{{ this.text }}</a></li> {{/each}} </ul> </body> </html>

Konfiguracja wdrożenia

Nagrajmy to na żywo. Aby to zadziałało, potrzebujemy dwóch komponentów. Po pierwsze, potrzebujemy statycznego hosta, który zbuduje dla nas nasze pliki. Następnie musimy uruchomić nową kompilację naszej witryny, gdy zawartość zostanie zmieniona w naszym CMS.

Wdrażanie do Netlify

Do hostingu użyjemy Netlify. Netlify to statyczny host witryny. Obsługuje statyczne zasoby, ale posiada dodatkowe funkcje, które sprawią, że nasza strona będzie działać płynnie. Mają wbudowaną infrastrukturę wdrożeniową, która może uruchamiać nasz skrypt węzła, elementy webhook do wyzwalania kompilacji oraz globalnie dystrybuowaną sieć CDN, aby zapewnić szybką obsługę naszej strony HTML.

Netlify może oglądać nasze repozytorium na GitHub i tworzyć build na podstawie polecenia, które możemy dodać w ich dashboardzie.

Najpierw musimy przekazać ten kod do GitHub. Następnie w panelu Netlify's Dashboard musimy połączyć nowe repozytorium z nową witryną w Netlify.

Kiedy już to zrobimy, musimy powiedzieć Netlify, jak zbudować nasz projekt. W panelu przejdziemy do opcji Ustawienia > Buduj i wdrażaj > Ustawienia kompilacji. W tym obszarze musimy zmienić nasze „polecenie kompilacji” na „węzeł index.js” i nasz „katalog publikacji” na „./dist”.

Kiedy Netlify zbuduje naszą witrynę, uruchomi nasze polecenie, a następnie sprawdzi folder, który wyświetlamy pod kątem zawartości i opublikuje zawartość wewnątrz.

Konfigurowanie webhooka

Musimy również powiedzieć Netliify, aby opublikowała nową wersję, gdy ktoś zaktualizuje zawartość. Aby to zrobić, skonfigurujemy webhooka, aby powiadomić Netlify, że potrzebujemy odbudować witrynę. Webhook to adres URL, do którego można programowo uzyskać dostęp przez inną usługę (taką jak Sanity), aby utworzyć akcję w usłudze pochodzenia (w tym przypadku Netlify).

Możemy skonfigurować konkretny „Hok kompilacji” w naszym panelu Netlify w Ustawienia > Buduj i wdrażaj > Build hooks. Dodaj hak, nadaj mu nazwę i zapisz. Zapewni to adres URL, którego można użyć do zdalnego wyzwalania kompilacji w Netlify.

Następnie musimy poinformować firmę Sanity, aby przesłała żądanie pod ten adres URL, gdy publikujesz zmiany.

W tym celu możemy użyć Sanity CLI. W naszym katalogu /studio możemy uruchomić program sanity hook create , aby się połączyć. Polecenie poprosi o nazwę, zestaw danych i adres URL. Nazwa może być dowolna, zbiór danych powinien być production dla naszego produktu, a URL powinien być adresem URL podanym przez Netlify.

Teraz za każdym razem, gdy publikujemy treści w Studio, nasza strona internetowa zostanie automatycznie zaktualizowana. Nie są potrzebne żadne ramy.

  • Kod można znaleźć w tym repozytorium GitHub →

Następne kroki

To bardzo mały przykład tego, co możesz zrobić, tworząc własne oprzyrządowanie. Podczas gdy bardziej w pełni funkcjonalne grupy SSG mogą być tym, czego potrzebujesz w przypadku większości projektów, utworzenie własnego mini-SSG może pomóc Ci lepiej zrozumieć, co dzieje się w wybranym przez Ciebie generatorze.

  • Ta witryna publikuje tylko jedną stronę, ale przy odrobinie dodatkowej w naszym skrypcie budowania, moglibyśmy opublikować więcej stron. Może nawet opublikować post na blogu.
  • W repozytorium trochę brakuje „Doświadczenia programisty”. Moglibyśmy uruchomić nasz skrypt Node na dowolnym zapisie pliku, implementując pakiet taki jak Nodemon lub dodać „hot reloading” za pomocą czegoś takiego jak BrowserSync.
  • Dane znajdujące się w Sanity mogą zasilać wiele witryn i usług. Możesz utworzyć witrynę CV, która korzysta z tego i publikuje plik PDF zamiast strony internetowej.
  • Możesz dodać CSS i sprawić, by wyglądała jak prawdziwa strona.