Hugo Statik Site Üreticisindeki Bağlam ve Değişkenler
Yayınlanan: 2022-03-10Bu makalede, Hugo statik site oluşturucuda bağlamın nasıl çalıştığına yakından bakacağız. Verilerin içerikten şablonlara nasıl aktığını, belirli yapıların hangi verilerin mevcut olduğunu nasıl değiştirdiğini ve bu verileri kısmilere ve temel şablonlara nasıl aktarabileceğimizi inceleyeceğiz.
Bu makale Hugo'ya bir giriş değildir . Hugo ile biraz deneyiminiz varsa, muhtemelen bundan en iyi şekilde yararlanacaksınız, çünkü her kavramı sıfırdan ele almayacağız, bunun yerine bağlam ve değişkenlerin ana konusuna odaklanacağız. Bununla birlikte, baştan sona Hugo belgelerine başvurursanız, daha önce deneyiminiz olmasa bile takip edebilirsiniz!
Örnek bir sayfa oluşturarak çeşitli kavramları inceleyeceğiz. Örnek site için gereken her dosya ayrıntılı olarak ele alınmayacaktır, ancak projenin tamamı GitHub'da mevcuttur. Parçaların nasıl bir araya geldiğini anlamak istiyorsanız, bu iyi bir başlangıç noktasıdır. Ayrıca, bir Hugo sitesinin nasıl kurulacağını veya geliştirme sunucusunun nasıl çalıştırılacağını ele almayacağımızı lütfen unutmayın - örneği çalıştırmaya yönelik talimatlar havuzdadır.
Statik Site Oluşturucu Nedir?
Statik site oluşturucu kavramı sizin için yeniyse, işte size hızlı bir giriş! Statik site oluşturucular belki de en iyi şekilde dinamik sitelerle karşılaştırılarak tanımlanır. CMS gibi dinamik bir site genellikle her ziyaret için sıfırdan bir sayfa oluşturur, belki de bir veritabanından veri alır ve bunu yapmak için çeşitli şablonları birleştirir. Pratikte, önbelleğe almanın kullanılması, sayfanın çok sık yenilenmediği anlamına gelir, ancak bu karşılaştırmanın amacı için, bunu bu şekilde düşünebiliriz. Dinamik bir site, dinamik içeriğe çok uygundur: sık sık değişen içerik, girdiye bağlı olarak birçok farklı konfigürasyonda sunulan içerik ve site ziyaretçisi tarafından değiştirilebilen içerik.
Buna karşılık, birçok site nadiren değişir ve ziyaretçilerden çok az girdi kabul eder. Bir uygulama için bir “yardım” bölümü, bir makale listesi veya bir e-Kitap bu tür sitelere örnek olabilir. Bu durumda, içerik değiştiğinde son sayfaları bir araya getirmek, daha sonra içerik tekrar değişene kadar aynı sayfaları her ziyaretçiye sunmak daha mantıklıdır.
Dinamik siteler daha fazla esnekliğe sahiptir, ancak üzerinde çalıştıkları sunucuya daha fazla talep getirir. Özellikle veritabanları söz konusuysa, coğrafi olarak dağıtılmaları da zor olabilir. Statik site oluşturucular, statik dosyalar sunabilen herhangi bir sunucuda barındırılabilir ve dağıtılması kolaydır.
Günümüzde bu yaklaşımları karıştıran yaygın bir çözüm JAMstack'tir. "JAM", JavaScript, API'ler ve işaretleme anlamına gelir ve bir JAMstack uygulamasının yapı taşlarını tanımlar: statik bir site oluşturucu, istemciye teslim edilmek üzere statik dosyalar oluşturur, ancak yığının, istemcide çalışan JavaScript biçiminde dinamik bir bileşeni vardır — bu istemci bileşeni daha sonra kullanıcıya dinamik işlevsellik sağlamak için API'leri kullanabilir.
Hugo
Hugo popüler bir statik site oluşturucudur. Go'da yazılmıştır ve Go'nun derlenmiş bir programlama dili olması, Hugos'un bazı yararları ve sakıncaları hakkında ipuçları vermektedir. Birincisi, Hugo çok hızlıdır , yani çok hızlı bir şekilde statik siteler oluşturur. Elbette bunun Hugo kullanılarak oluşturulan sitelerin son kullanıcı için ne kadar hızlı veya yavaş olduğuyla bir ilgisi yok ama geliştirici için Hugo'nun büyük siteleri bile göz açıp kapayıncaya kadar derlemesi oldukça değerli.
Ancak Hugo derlenmiş bir dilde yazıldığı için genişletmek zor . Diğer bazı site oluşturucular, derleme işlemine Ruby, Python veya JavaScript gibi dillerde kendi kodunuzu eklemenize izin verir. Hugo'yu genişletmek için kodunuzu Hugo'nun kendisine eklemeniz ve yeniden derlemeniz gerekir - aksi takdirde Hugo'nun kutudan çıktığı gibi gelen şablon işlevlerine takılıp kalırsınız.
Zengin çeşitli işlevler sağlarken, sayfalarınızın oluşturulması karmaşık bir mantık içeriyorsa bu gerçek sınırlayıcı olabilir. Bulduğumuz gibi, orijinal olarak dinamik bir platformda çalışan bir siteye sahip olduğunuzda, özel kodunuzu verme yeteneğinizi kabul ettiğiniz durumlar birikme eğilimindedir.
Ekibimiz, ana ürünümüz Tower Git istemcisi ile ilgili çeşitli web sitelerini yönetiyor ve yakın zamanda bunlardan bazılarını statik bir site oluşturucuya taşımayı düşündük. Sitelerimizden biri olan “Öğrenme” sitesi, bir pilot proje için özellikle uygun görünüyordu. Bu site, Git'teki videolar, e-Kitaplar ve SSS'lerin yanı sıra diğer teknik konuları da içeren çeşitli ücretsiz öğrenme materyalleri içerir.
İçeriği büyük ölçüde statik bir yapıya sahiptir ve ne tür etkileşimli özellikler varsa (bülten kayıtları gibi) zaten JavaScript tarafından desteklenmektedir. 2020'nin sonunda, bu siteyi önceki CMS'mizden Hugo'ya dönüştürdük ve bugün statik bir site olarak çalışıyor. Doğal olarak bu süreçte Hugo hakkında çok şey öğrendik. Bu makale, öğrendiklerimizden bazılarını paylaşmanın bir yolu.
Örneğimiz
Bu makale, sayfalarımızı Hugo'ya dönüştürme çalışmalarımızdan doğduğundan, örnek olarak (çok!) basitleştirilmiş varsayımsal bir açılış sayfasını bir araya getirmek doğal görünüyor. Ana odak noktamız, yeniden kullanılabilir bir "liste" şablonu olacaktır.
Kısacası, Hugo, alt sayfaları içeren herhangi bir sayfa için bir liste şablonu kullanacaktır. Hugos şablon hiyerarşisinde bundan daha fazlası vardır, ancak olası her şablonu uygulamanız gerekmez. Tek bir liste şablonu uzun bir yol kat eder. Daha fazla özel şablonun bulunmadığı bir liste şablonu gerektiren herhangi bir durumda kullanılacaktır.
Potansiyel kullanım örnekleri arasında bir ana sayfa, bir blog dizini veya bir SSS listesi bulunur. Yeniden kullanılabilir liste şablonumuz , projemizde layouts/_default/list.html
içinde yer alacaktır. Yine, örneğimizi derlemek için gereken dosyaların geri kalanı GitHub'da mevcuttur, burada parçaların nasıl bir araya geldiğine daha iyi bir göz atabilirsiniz. GitHub deposu ayrıca bir single.html
şablonuyla birlikte gelir - adından da anlaşılacağı gibi, bu şablon alt sayfaları olmayan, ancak kendi başlarına tek içerik parçası olarak hareket eden sayfalar için kullanılır.
Şimdi sahneyi kurduk ve ne yapacağımızı açıkladık, başlayalım!
Bağlam Veya “Nokta”
Her şey nokta ile başlar. Bir Hugo şablonunda, nesne .
— "nokta" — mevcut bağlama atıfta bulunur. Ne anlama geliyor? Hugo'da oluşturulan her şablonun bir dizi veriye , yani bağlamına erişimi vardır. Bu, başlangıçta, içeriği ve bazı meta veriler dahil olmak üzere, şu anda oluşturulmakta olan sayfayı temsil eden bir nesneye ayarlanır. Bağlam ayrıca yapılandırma seçenekleri ve mevcut ortamla ilgili bilgiler gibi site genelindeki değişkenleri de içerir. .Title
ve .Hugo.Version
aracılığıyla kullanılan Hugo sürümünü kullanarak geçerli sayfanın başlığı gibi bir alana erişirsiniz - başka bir deyişle, .
yapı.
Daha da önemlisi, bu bağlam değişebilir, yukarıdaki '.Title' gibi bir referans başka bir şeye işaret eder veya hatta onu geçersiz kılar. Bu, örneğin, range
kullanarak bir tür koleksiyon üzerinde döngü yaptığınızda veya şablonları kısmi ve temel şablonlara böldüğünüzde olur . Buna daha sonra ayrıntılı olarak bakacağız!
Hugo, Go “şablonları” paketini kullanır, bu nedenle bu makalede Hugo şablonlarına atıfta bulunduğumuzda, gerçekten Go şablonlarından bahsediyoruz. Hugo, standart Go şablonlarında bulunmayan çok sayıda şablon işlevi ekler.
Bence bağlam ve onu yeniden bağlama olasılığı Hugos'un en iyi özelliklerinden biridir. Bana göre, belirli bir noktada şablonumun ana odak noktası olan nesneyi her zaman "noktanın" temsil etmesi çok mantıklı geliyor, ben ilerledikçe gerektiği gibi yeniden birleştiriyor. Tabii ki, kendinizi karışık bir karmaşanın içine sokmanız da mümkün, ancak şimdiye kadar bundan memnun kaldım, o kadar ki, baktığım diğer herhangi bir statik site oluşturucuda onu çabucak kaçırmaya başladım.
Bununla, örneğimizin mütevazı başlangıç noktasına bakmaya hazırız - aşağıdaki şablon, projemizdeki layouts/_default/list.html
içinde bulunur:
<html> <head> <title>{{ .Title }} | {{ .Site.Title }}</title> <link rel="stylesheet" href="/css/style.css"> </head> <body> <nav> <a class="logo" href="{{ "/" | relURL }}"> <img src="/img/tower-logo.svg"> <img src="/img/tower-claim.svg"> </a> <ul> <li><a href="/">Home</a></li> </ul> </nav> <section class="content"> <div class="container"> <h1>{{ .Title }}</h1> {{ .Content }} </div> </section> </body> </html>
Şablonun çoğu, bir stil sayfası bağlantısı, gezinme için bir menü ve stil için kullanılan bazı ekstra öğeler ve sınıflar içeren çıplak bir HTML yapısından oluşur. İlginç olan şey, Hugo'ya adım atmasını ve sihrini yapmasını işaret eden, kaşlı ayraçlar arasında ne varsa, bir ifadeyi değerlendirmenin ve potansiyel olarak bağlamı da manipüle etmenin sonucuyla değiştiren kaşlı ayraçlar arasındadır.
Tahmin edebileceğiniz gibi, başlık etiketindeki {{ .Title }}
, geçerli sayfanın başlığına atıfta bulunurken, {{ .Site.Title }}
, Hugo yapılandırmasında ayarlanan tüm sitenin başlığına atıfta bulunur. . {{ .Title }}
gibi bir etiket, Hugo'ya bu etiketi mevcut bağlamda Title
alanının içeriğiyle değiştirmesini söyler.
Böylece bir şablonda sayfaya ait bazı verilere ulaştık. Bu veriler nereden geliyor? Aşağıdaki bölümün konusu budur.
İçerik ve Ön Konu
Bağlamda bulunan bazı değişkenler Hugo tarafından otomatik olarak sağlanır. Diğerleri, esas olarak içerik dosyalarında tarafımızca tanımlanır. Yapılandırma dosyaları, ortam değişkenleri, veri dosyaları ve hatta API'ler gibi başka veri kaynakları da vardır. Bu yazıda veri kaynağı olarak içerik dosyalarına odaklanacağız.
Genel olarak, tek bir içerik dosyası tek bir sayfayı temsil eder. Tipik bir içerik dosyası, o sayfanın ana içeriğini ve aynı zamanda sayfanın başlığı veya oluşturulduğu tarih gibi meta verileri içerir. Hugo, hem ana içerik hem de meta veriler için çeşitli biçimleri destekler. Bu makalede, belki de en yaygın kombinasyonu ele alacağız: içerik, YAML ön maddesi olarak meta verileri içeren bir dosyada Markdown olarak sağlanır.
Pratikte bu, içerik dosyasının her iki ucunda üç tire içeren bir çizgiyle sınırlanan bir bölümle başladığı anlamına gelir. Bu bölüm ön konuyu oluşturur ve burada meta veriler bir key: value
sözdizimi (Yakında göreceğimiz gibi, YAML daha ayrıntılı veri yapılarını da destekler). Ön konuyu, Markdown işaretleme dili kullanılarak belirtilen gerçek içerik takip eder.
Bir örneğe bakarak işleri daha somut hale getirelim. İşte bir ön konu alanı ve bir paragraf içerik içeren çok basit bir içerik dosyası:
--- title: Home --- Home page of the Tower Git client. Over 100,000 developers and designers use Tower to be more productive!
(Bu dosya content/_index.md
bulunur ve _index.md
alt sayfaları olan bir sayfanın içerik dosyasını belirtir. Yine GitHub deposu hangi dosyanın nereye gitmesi gerektiğini netleştirir.)
Bazı stiller ve çevresel dosyalar (tümü GitHub'da bulunur) ile birlikte daha önceki şablon kullanılarak işlenir, sonuç şöyle görünür:
İçerik dosyamızın ön maddesindeki alan adlarının önceden belirlenmiş olup olmadığını veya istediğimiz herhangi bir alanı ekleyip ekleyemeyeceğimizi merak edebilirsiniz. Cevap "her ikisi" dir. Önceden tanımlanmış alanların bir listesi var, ancak bulabileceğimiz başka alanları da ekleyebiliriz. Ancak bu alanlara şablonda biraz farklı şekilde erişilir. title
gibi önceden tanımlanmış bir alana basitçe .Title
olarak erişilirken, author
gibi özel bir alana .Params.author
kullanılarak erişilir.
(Fonksiyonlar, fonksiyon parametreleri ve sayfa değişkenleri gibi şeylerle birlikte önceden tanımlanmış alanlara hızlı bir başvuru için kendi Hugo hile sayfamıza bakın!)
Şablonunuzdaki içerik dosyasından ana içeriğe erişmek için kullanılan .Content
değişkeni özeldir. Hugo, Markdown içeriğinizde bazı ekstra etiketler kullanmanıza izin veren bir "kısa kod" özelliğine sahiptir. Ayrıca kendinizinkini de tanımlayabilirsiniz. Ne yazık ki, bu kısa kodlar yalnızca .Content
değişkeni aracılığıyla çalışacaktır - başka herhangi bir veri parçasını bir Markdown filtresi aracılığıyla çalıştırabilirsiniz, ancak bu, içerikteki kısa kodları işlemez.
Burada tanımsız değişkenler hakkında bir not: .Date
gibi önceden tanımlanmış bir alana erişmek, ayarlamamış olsanız bile her zaman çalışır - bu durumda boş bir değer döndürülür. .Params.thisHasNotBeenSet
gibi tanımsız bir özel alana erişmek de işe yarar ve boş bir değer döndürür. Ancak, .thisDoesNotExist
gibi önceden tanımlanmamış bir üst düzey alana erişmek sitenin derlenmesini engeller.
.Site.title
ile daha önce .Hugo.version
ve .Params.author
tarafından belirtildiği gibi, zincirleme çağrılar başka bir veri yapısında yuvalanmış bir alana erişmek için kullanılabilir. Bu tür yapıları ön maddemizde tanımlayabiliriz. İçerik dosyamızdaki sayfada bir başlık için bazı özellikler belirten bir harita veya sözlük tanımladığımız bir örneğe bakalım. İşte güncellenmiş content/_index.md
:
--- title: Home banner: headline: Try Tower For Free! subline: Download our trial to try Tower for 30 days --- Home page of the Tower Git client. Over 100,000 developers and designers use Tower to be more productive!
Şimdi, yukarıda açıklanan şekilde .Params
kullanarak banner verilerine atıfta bulunarak şablonumuza bir banner ekleyelim:
<html> ... <body> ... <aside> <h2>{{ .Params.banner.headline }}</h2> <p>{{ .Params.banner.subline}}</p> </aside> </body> </html>
Sitemizin şimdi nasıl göründüğü:
Peki! Şu anda, varsayılan bağlamın alanlarına herhangi bir sorun olmadan erişiyoruz. Ancak, daha önce belirtildiği gibi, bu bağlam sabit değildir, değişebilir.
Bunun nasıl olabileceğine bir göz atalım.
Akış kontrolü
Akış denetimi ifadeleri, bir şablonlama dilinin önemli bir parçasıdır ve değişkenlerin değerine, veriler arasında döngüye ve daha fazlasına bağlı olarak farklı şeyler yapmanıza olanak tanır. Hugo şablonları, koşullu mantık için if/else
ve döngü range
dahil olmak üzere beklenen yapı kümesini sağlar. Burada, genel olarak Hugo'daki akış kontrolünü ele almayacağız (bununla ilgili daha fazla bilgi için belgelere bakın), ancak bu ifadelerin bağlamı nasıl etkilediğine odaklanacağız. Bu durumda, en ilginç ifadeler with
ve range
.
with
başlayalım. Bu ifade, bazı ifadelerin "boş olmayan" bir değere sahip olup olmadığını kontrol eder ve varsa , bu ifadenin değerine atıfta bulunmak için bağlamı yeniden bağlar . end
etiketi, with
ifadesinin etkisinin durduğu noktayı belirtir ve bağlam daha önce neyse ona geri döner. Hugo belgeleri boş olmayan bir değeri false, 0 ve herhangi bir sıfır uzunluklu dizi, dilim, harita veya dize olarak tanımlar.
Şu anda liste şablonumuz pek fazla listeleme yapmıyor. Bir liste şablonunun aslında bazı alt sayfalarını bir şekilde öne çıkarması mantıklı olabilir. Bu bize akış kontrol ifadelerimizin örnekleri için mükemmel bir fırsat verir.
Belki de sayfamızın üst kısmında öne çıkan bazı içerikleri görüntülemek istiyoruz. Bu herhangi bir içerik parçası olabilir - örneğin bir blog yazısı, bir yardım makalesi veya bir tarif. Şu anda, Tower örnek sitemizin özelliklerini, kullanım durumlarını, bir yardım sayfasını, bir blog sayfasını ve bir "öğrenme platformu" sayfasını vurgulayan bazı sayfalara sahip olduğunu varsayalım. Bunların hepsi content/
dizinde bulunur. Ana sayfamız content/_index.md
için içerik dosyasına bir alan ekleyerek hangi içeriğin öne çıkacağını yapılandırıyoruz. Sayfa, içerik dizininin kök olduğu varsayılarak, yolu ile anılır:
--- title: Home banner: headline: Try Tower For Free! subline: Download our trial to try Tower for 30 days without limitations featured: /features.md ... --- ...
Ardından, bu içerik parçasını görüntülemek için liste şablonumuzun değiştirilmesi gerekiyor. Hugo'nun .GetPage
adlı bir şablon işlevi vardır ve bu, şu anda oluşturmakta olduğumuzdan farklı sayfa nesnelerine başvurmamıza olanak tanır. Bağlamın nasıl olduğunu hatırlayın, .
, başlangıçta oluşturulan sayfayı temsil eden bir nesneye mi bağlıydı? .GetPage
ve with
kullanarak, öne çıkan içeriğimizi görüntülerken o sayfanın alanlarına atıfta bulunarak bağlamı geçici olarak başka bir sayfaya yeniden bağlayabiliriz:
<nav> ... </nav> <section class="featured"> <div class="container"> {{ with .GetPage .Params.featured }} <article> <h2>{{ .Title }}</h2> {{ .Summary }} <p><a href="{{ .Permalink }}">Read more →</a></p> </article> {{ end }} </div> </section>
Burada, with
ve end
etiketleri arasındaki {{ .Title }}
, {{ .Summary }}
ve {{ .Permalink }}
, ana sayfaya değil , öne çıkan sayfadaki alanlara atıfta bulunur.
Öne çıkan bir içeriğe sahip olmanın yanı sıra, birkaç içeriği daha aşağıda listeleyelim. Öne çıkan içerik gibi, listelenen içerik parçaları da ana sayfamızın içerik dosyası olan content/_index.md
içinde tanımlanacaktır. Ön konumuza bunun gibi bir içerik yolları listesi ekleyeceğiz (bu durumda bölüm başlığını da belirtiyoruz):
--- ... listing_headline: Featured Pages listing: - /help.md - /use-cases.md - /blog/_index.md - /learn.md ---
Blog sayfasının kendi dizinine ve bir _index.md
dosyasına sahip olmasının nedeni, blogun kendi alt sayfalarına sahip olmasıdır - blog gönderileri.
Bu listeyi şablonumuzda görüntülemek için range
kullanacağız. Şaşırtıcı olmayan bir şekilde, bu ifade bir liste üzerinde döngü yapacak, ancak aynı zamanda bağlamı sırayla listenin her bir öğesine yeniden bağlayacaktır. Bu, içerik listemiz için çok uygundur.
Hugo'nun bakış açısından "listeleme"nin yalnızca bazı dizeleri içerdiğine dikkat edin. "Aralık" döngüsünün her yinelemesi için bağlam, bu dizelerden birine bağlanacaktır . Asıl sayfa nesnesine erişmek için, yol dizesini (şimdi değeri .
) .GetPage
bir argüman olarak sağlıyoruz. Ardından, bağlamı yol dizesi yerine listelenen sayfa nesnesine yeniden bağlamak için with
ifadesini tekrar kullanacağız. Şimdi, listelenen her sayfanın içeriğini sırayla görüntülemek kolaydır:
<aside> ... </aside> <section class="listing"> <div class="container"> <h1>{{ .Params.listing_headline }}</h1> <div> {{ range .Params.listing }} {{ with $.GetPage . }} <article> <h2>{{ .Title }}</h2> {{ .Summary }} <p><a href="{{ .Permalink }}">Read more →</a></p> </article> {{ end }} {{ end }} </div> </div> </section>
İşte bu noktada sitenin nasıl göründüğü:
Ama bir dakika, yukarıdaki şablonda garip bir şey var — .GetPage
yerine $.GetPage
. .GetPage
neden çalışmadığını tahmin edebilir misiniz?
.GetPage
gösterimi, GetPage
işlevinin geçerli bağlamın bir yöntemi olduğunu gösterir. Aslında, varsayılan bağlamda böyle bir yöntem vardır, ancak biz biraz önce ilerledik ve bağlamı değiştirdik ! .GetPage
, bağlam, bu yönteme sahip olmayan bir dizeye bağlanır. Bu sorunu çözme yöntemimiz bir sonraki bölümün konusudur.
Küresel Bağlam
Yukarıda görüldüğü gibi, bağlamın değiştiği durumlar vardır, ancak yine de orijinal bağlama erişmek isteriz. Burada bunun nedeni, orijinal bağlamda var olan bir yöntemi çağırmak istememizdir - başka bir yaygın durum, oluşturulan ana sayfanın bazı özelliklerine erişmek istediğimiz zamandır. Sorun değil, bunu yapmanın kolay bir yolu var.
Bir Hugo şablonunda, global bağlam olarak bilinen $
, bağlamın orijinal değerini - şablon işleme başladığında bağlamı ifade eder. Önceki bölümde, bağlamı bir dizgeye geri döndürmüş olmamıza rağmen .GetPage
yöntemini çağırmak için kullanıldı. Şimdi, onu, işlenmekte olan sayfanın bir alanına erişmek için de kullanacağız.
Bu yazının başında liste şablonumuzun tekrar kullanılabilir olduğundan bahsetmiştim. Şimdiye kadar bunu yalnızca ana sayfa için kullandık ve content/_index.md
bulunan bir içerik dosyası oluşturduk. Örnek depoda, bu şablon kullanılarak oluşturulacak başka bir içerik dosyası vardır: content/blog/_index.md
. Bu, blog için bir dizin sayfasıdır ve tıpkı ana sayfada olduğu gibi, öne çıkan bir içerik parçasını gösterir ve bu durumda birkaç blog gönderisini daha listeler.
Şimdi, ana sayfada listelenen içeriği biraz farklı göstermek istediğimizi varsayalım - ayrı bir şablonu garanti etmek için yeterli değil, ancak şablonun kendisinde koşullu bir ifadeyle yapabileceğimiz bir şey. Örnek olarak, ana sayfayı oluşturduğumuzu tespit edersek, listelenen içeriği tek sütunlu bir liste yerine iki sütunlu bir ızgarada görüntüleyeceğiz.
Hugo, tam olarak ihtiyacımız olan işlevselliği sağlayan bir sayfa yöntemi olan .IsHome
ile birlikte gelir. Ana sayfada olduğumuzu öğrendiğimizde, içeriğin tek tek parçalarına bir sınıf ekleyerek sunumdaki asıl değişikliği halledeceğiz ve gerisini CSS dosyamıza bırakacağız.
Elbette, sınıfı gövde öğesine veya bunun yerine içeren bazı öğelere ekleyebiliriz, ancak bu, küresel bağlamın o kadar iyi bir gösterimini sağlamaz. Listelenen içerik parçası için HTML'yi yazarken, .
listelenen sayfaya atıfta bulunur , ancak oluşturulan ana sayfada IsHome
gerekir. Küresel bağlam kurtarmaya geliyor:
<section class="listing"> <div class="container"> <h1>{{ .Params.listing_headline }}</h1> <div> {{ range .Params.listing }} {{ with $.GetPage . }} <article{{ if $.IsHome }} class="home"{{ end }}> <h2>{{ .Title }}</h2> {{ .Summary }} <p><a href="{{ .Permalink }}">Read more →</a></p> </article> {{ end }} {{ end }} </div> </div> </section>
Blog dizini, farklı içerikle de olsa ana sayfamızın yaptığı gibi görünüyor:
…ama ana sayfamız artık öne çıkan içeriğini bir ızgarada gösteriyor:
Kısmi Şablonlar
Gerçek bir web sitesi kurarken, şablonlarınızı parçalara bölmek hızlı bir şekilde faydalı olur. Belki bir şablonun belirli bir bölümünü yeniden kullanmak istersiniz veya belki de sadece büyük, hantal bir şablonu tutarlı parçalara bölmek istersiniz. Bu amaçla, Hugo'nun kısmi şablonları gidilecek yoldur.
Bağlam açısından bakıldığında, burada önemli olan şey, kısmi bir şablon eklediğimizde, onu kullanıma sunmak istediğimiz bağlamı açıkça iletmiş olmamızdır. Yaygın bir uygulama, bağlamı kısmi dahil edildiğinde olduğu gibi iletmektir, şöyle: {{ partial "my/partial.html" . }}
{{ partial "my/partial.html" . }}
. Buradaki nokta, işlenmekte olan sayfaya atıfta bulunuyorsa, kısmi bölüme geçirilecek olan budur; bağlam başka bir şeye geri döndüyse, aktarılan budur.
Elbette, normal şablonlarda olduğu gibi kısmi şablonlarda bağlamı yeniden bağlayabilirsiniz. Bu durumda, küresel bağlam, $
, oluşturulan ana sayfaya değil, kısmi sayfaya iletilen orijinal içeriğe atıfta bulunur (geçilen şey bu değilse).
Kısmi bir şablonun belirli bir veri parçasına erişimi olmasını istiyorsak, sadece bunu kısmiye iletirsek problemlerle karşılaşabiliriz. Bağlamı yeniden bağladıktan sonra sayfa yöntemlerine erişmeyle ilgili sorunumuzu daha önce hatırlıyor musunuz? Aynı şey kısmiler için de geçerlidir, ancak bu durumda küresel bağlam bize yardımcı olamaz - örneğin bir dizeyi kısmi bir şablona ilettiysek, kısmi içindeki genel bağlam bu dizeye atıfta bulunur ve biz kazandık ' sayfa bağlamında tanımlanan yöntemleri çağırabilir.
Bu sorunun çözümü, kısmi veriyi dahil ederken birden fazla veri parçasının iletilmesinde yatmaktadır. Ancak, kısmi çağrıya yalnızca bir argüman sunmamıza izin verilir. Bununla birlikte, bu argümanı bir bileşik veri türü, genellikle bir harita (diğer programlama dillerinde sözlük veya karma olarak bilinir) yapabiliriz.
Bu haritada, örneğin, herhangi bir özel verinin iletilmesi için diğer anahtarlarla birlikte geçerli sayfa nesnesine ayarlanmış bir Page
anahtarına sahip olabiliriz. Sayfa nesnesi daha sonra kısmi olarak .Page
olarak kullanılabilir ve diğer haritanın değerlerine benzer şekilde erişilir. Çift sayıda argüman alan, dönüşümlü olarak anahtar, değeri, anahtarı, değeri vb. olarak yorumlanan dict
şablon işlevi kullanılarak bir harita oluşturulur.
Örnek şablonumuzda, öne çıkan ve listelenen içeriğimizin kodunu kısmi parçalara taşıyalım. Öne çıkan içerik için öne çıkan sayfa nesnesini iletmek yeterlidir. Ancak listelenen içeriğin, oluşturulan belirli listelenen içeriğe ek olarak .IsHome
yöntemine erişmesi gerekir. Daha önce de belirtildiği gibi, .IsHome
listelenen sayfa için sayfa nesnesinde de mevcut olsa da, bu bize doğru cevabı vermeyecektir - oluşturulan ana sayfanın ana sayfa olup olmadığını bilmek istiyoruz.
Bunun yerine, .IsHome
çağrısının sonucuna bir boole setini iletebiliriz, ancak belki de kısminin gelecekte diğer sayfa yöntemlerine erişmesi gerekecek - hadi ana sayfa nesnesinin yanı sıra listelenen sayfa nesnesini iletelim. Örneğimizde, ana sayfa $
ve listelenen sayfa içinde bulunur .
. Böylece, listed
kısmiye iletilen haritada, Page
anahtarı $
değerini alırken, “Listelenen” anahtarı değeri alır .
. Bu güncellenmiş ana şablondur:
<body> <nav> <a class="logo" href="{{ "/" | relURL }}"> <img src="/img/tower-logo.svg"> <img src="/img/tower-claim.svg"> </a> <ul> <li><a href="/">Home</a></li> <li><a href="/blog/">Blog</a></li> </ul> </nav> <section class="featured"> <div class="container"> {{ with .GetPage .Params.featured }} {{ partial "partials/featured.html" . }} {{ end }} </div> </section> <section class="content"> <div class="container"> <h1>{{ .Title }}</h1> {{ .Content }} </div> </section> <aside> <h2>{{ .Params.banner.headline }}</h2> <p>{{ .Params.banner.subline}}</p> </aside> <section class="listing"> <div class="container"> <h1>{{ .Params.listing_headline }}</h1> <div> {{ range .Params.listing }} {{ with $.GetPage . }} {{ partial "partials/listed.html" (dict "Page" $ "Listed" .) }} {{ end }} {{ end }} </div> </div> </section> </body>
"Öne çıkan" kısmımızın içeriği, liste şablonunun bir parçası olduğu zamana kıyasla değişmez:
<article> <h2>{{ .Title }}</h2> {{ .Summary }} <p><a href="{{ .Permalink }}">Read more →</a></p> </article>
Ancak, listelenen içerik için kısmi özelliğimiz, orijinal sayfa nesnesinin artık .Page
, listelenen içerik parçasının .Listed
içinde bulunduğu gerçeğini yansıtır:
<article{{ if .Page.IsHome }} class="home"{{ end }}> <h2>{{ .Listed.Title }}</h2> {{ .Listed.Summary }} <p><a href="{{ .Listed.Permalink }}">Read more →</a></p> </article>
Hugo ayrıca, alt şablonlar eklemek yerine ortak bir temel şablonu genişletmenize izin veren temel şablon işlevselliği sağlar. Bu durumda bağlam benzer şekilde çalışır: bir temel şablonu genişletirken, o şablonda orijinal bağlamı oluşturacak verileri sağlarsınız.
Özel Değişkenler
Bir Hugo şablonunda kendi özel değişkenlerinizi atamak ve yeniden atamak da mümkündür. Bunlar, ilan edildikleri şablonda mevcut olacaklar, ancak biz onları açıkça iletmedikçe, herhangi bir kısmi veya temel şablona girmeyecekler. Bir if
deyimi tarafından belirtilene benzer bir "blok" içinde bildirilen bir özel değişken, yalnızca o bloğun içinde kullanılabilir olacaktır - eğer ona bloğun dışında başvurmak istiyorsak, onu bloğun dışında bildirmemiz ve ardından bunu bloğun içinde değiştirmemiz gerekir. gerektiği gibi engelleyin.
Özel değişkenlerin adlarının önüne dolar işareti ( $
) eklenir. Bir değişkeni bildirmek ve aynı anda ona bir değer vermek için :=
operatörünü kullanın. Değişkene sonraki atamalar =
operatörünü kullanır (iki nokta üst üste olmadan). Bir değişken bildirilmeden önce atanamaz ve bir değer verilmeden bildirilemez.
Özel değişkenler için bir kullanım örneği, uygun şekilde adlandırılmış bir değişkene bazı ara sonuçlar atayarak uzun işlev çağrılarını basitleştirmektir. Örneğin, öne çıkan sayfa nesnesini $featured
adlı bir değişkene atayabilir ve ardından bu değişkeni with
ifadesine sağlayabiliriz. Ayrıca, bir değişkende "listelenen" kısmiye tedarik edilecek verileri koyabilir ve bunu kısmi çağrıya verebiliriz.
Bu değişikliklerle şablonumuz şöyle görünür:
<section class="featured"> <div class="container"> {{ $featured := .GetPage .Params.featured }} {{ with $featured }} {{ partial "partials/featured.html" . }} {{ end }} </div> </section> <section class="content"> ... </section> <aside> ... </aside> <section class="listing"> <div class="container"> <h1>{{ .Params.listing_headline }}</h1> <div> {{ range .Params.listing }} {{ with $.GetPage . }} {{ $context := (dict "Page" $ "Listed" .) }} {{ partial "partials/listed.html" $context }} {{ end }} {{ end }} </div> </div> </section>
Hugo ile olan deneyimime dayanarak, bir şablonda biraz daha ilgili mantığı uygulamaya çalıştığınız anda özel değişkenleri özgürce kullanmanızı tavsiye ederim. Kodunuzu kısa ve öz tutmaya çalışmak doğal olsa da, bu, her şeyi olabileceğinden daha az anlaşılır hale getirerek sizin ve diğerlerinin kafasını karıştırabilir.
Bunun yerine, her adım için tanımlayıcı olarak adlandırılmış değişkenler kullanın ve birinin yapacağı yerde iki satır (veya üç veya dört, vb.) kullanma konusunda endişelenmeyin.
.Kaşımak
Son olarak .Scratch
mekanizmasına değinelim. Hugo'nun önceki sürümlerinde, özelleştirilebilen değişkenler yalnızca bir kez atanabiliyordu; bir özel değişkeni yeniden tanımlamak mümkün değildi. Günümüzde, özel değişkenler yeniden tanımlanabiliyor, bu da .Scratch
daha az önemli hale getiriyor, ancak hala kullanımları var.
Kısacası, .Scratch
, özel değişkenler gibi kendi değişkenlerinizi ayarlamanıza ve değiştirmenize izin veren bir çizik alanıdır. Özel değişkenlerden farklı olarak, .Scratch
sayfa bağlamına aittir, bu nedenle, örneğin, bu bağlamı kısmi bir duruma geçirmek, otomatik olarak sıfırdan değişkenleri de beraberinde getirecektir.
Set
ve Get
yöntemlerini çağırarak .Scratch
üzerinde değişkenleri ayarlayabilir ve alabilirsiniz. Bileşik veri türlerini ayarlamak ve güncellemek için bunlardan daha fazla yöntem var, ancak buradaki ihtiyaçlarımız için bu ikisi yeterli olacaktır. Set
iki parametre alır: anahtar ve ayarlamak istediğiniz verinin değeri. Get
sadece bir tane alır: almak istediğiniz verinin anahtarı.
Daha önce, birden çok veri parçasını bir kısmi veriye geçirmek için bir harita veri yapısı oluşturmak için dict
kullandık. Bu, listelenen bir sayfanın kısmi bölümünün hem orijinal sayfa içeriğine hem de belirli listelenen sayfa nesnesine erişebilmesi için yapıldı. .Scratch
kullanmak, bunu yapmak için mutlaka daha iyi veya daha kötü bir yol değildir - hangisinin tercih edildiği duruma bağlı olabilir.
Verileri kısmiye geçirmek için dict
yerine .Scratch
kullanarak liste şablonumuzun nasıl görüneceğini görelim. "Listelenen" sıfırdan değişkeni olarak ayarlamak için (yine global bağlamı kullanarak) $.Scratch.Get
.
— bu durumda, listelenen sayfa nesnesi. Ardından, yalnızca sayfa nesnesini $
'ı kısmi öğeye iletiriz. Scratch değişkenleri otomatik olarak takip edecek.
<section class="listing"> <div class="container"> <h1>{{ .Params.listing_headline }}</h1> <div> {{ range .Params.listing }} {{ with $.GetPage . }} {{ $.Scratch.Set "listed" . }} {{ partial "partials/listed.html" $ }} {{ end }} {{ end }} </div> </div> </section>
Bu, listed.html
kısmi dosyasında da bazı değişiklikler gerektirecektir - orijinal sayfa bağlamı, listelenen sayfa .Scratch
nesnesinden alınırken artık "nokta" olarak kullanılabilir. Listelenen sayfaya erişimi basitleştirmek için özel bir değişken kullanacağız:
<article{{ if .IsHome }} class="home"{{ end }}> {{ $listed := .Scratch.Get "listed" }} <h2>{{ $listed.Title }}</h2> {{ $listed.Summary }} <p><a href="{{ $listed.Permalink }}">Read more →</a></p> </article>
İşleri bu şekilde yapmanın bir argümanı tutarlılıktır. .Scratch
kullanarak, mevcut sayfa nesnesini her zaman herhangi bir kısmi nesneye geçirmeyi alışkanlık haline getirebilirsiniz ve herhangi bir ekstra veriyi sıfırdan değişkenler olarak ekleyebilirsiniz. Ardından, kısmi bölümlerinizi her yazdığınızda veya düzenlediğinizde, bunu bilirsiniz .
bir sayfa nesnesidir. Elbette, aktarılan bir haritayı kullanarak da kendiniz için bir kural oluşturabilirsiniz: örneğin, sayfa nesnesini her zaman .Page
olarak göndermek.
Çözüm
Bağlam ve veri söz konusu olduğunda, statik bir site oluşturucu hem faydalar hem de sınırlamalar getirir. Bir yandan, her sayfa ziyareti için çalıştırıldığında çok verimsiz olan bir işlem, sayfa derlenirken yalnızca bir kez çalıştırıldığında mükemmel şekilde iyi olabilir. Öte yandan, ağırlıklı olarak statik bir sitede bile ağ isteğinin bir kısmına erişmenin ne sıklıkla yararlı olacağı sizi şaşırtabilir.
Örneğin, statik bir sitede sorgu dizesi parametrelerini işlemek için JavaScript'e veya Netlify'ın yönlendirmeleri gibi bazı özel çözümlere başvurmanız gerekir. Buradaki nokta, dinamikten statik bir alana atlamak teoride basit olsa da, zihniyette bir değişiklik gerektiriyor. Başlangıçta eski alışkanlıklarınıza geri dönmek kolaydır, ancak pratik yapmak sizi mükemmelleştirir.
Bununla, Hugo statik site oluşturucusunda veri yönetimine bakışımızı tamamlıyoruz. Even though we focused only on a narrow sector of its functionality, there are certainly things we didn't cover that could have been included. Nevertheless, I hope this article gave you some added insight into how data flows from content files, to templates, to subtemplates and how it can be modified along the way.
Note : If you already have some Hugo experience, we have a nice resource for you, quite appropriately residing on our aforementioned, Hugo-driven “Learn” site! When you just need to check the order of the arguments to the replaceRE
function, how to retrieve the next page in a section, or what the “expiration date” front matter field is called, a cheat sheet comes in handy. We've put together just such a reference, so download a Hugo cheat sheet, in a package also featuring a host of other cheat sheets on everything from Git to the Visual Studio Code editor.
Daha fazla okuma
If you're looking for more information on Hugo, here are some nice resources:
- The official Hugo documentation is always a good place to start!
- A great series of in-depth posts on Hugo on Regis Philibert's blog.