Genişletmek
Plugin kullanmak
Bir plugin'in neler yapabildiği, bir plugin'in nasıl kaydedilip yapılandırıldığı ve yayımlanmış üç plugin.
Plugin, sizin oluşturup uygulamanıza verdiğiniz sıradan bir Go değeridir. Uygulamanın yaptıklarını izleyebilir ve ürettiklerinin bir kısmını değiştirebilir; ama router'a, önbelleğe ya da şablon kümesine uzanamaz: dar bir yetenek kümesi alır, fazlasını değil.
Bir plugin yükleyicisi ya da yayımlanacak bir kayıt defteri yoktur. Plugin, import ettiğiniz bir Go modülüdür ve diğer her bağımlılık gibi binary'nize derlenir.
Bir plugin neler yapabilir
Bir plugin'in yaptığı her şey, katılmayı seçtiği bir hook'tan ya da başlangıçta kendisine verilen bir yetenekten geçer. Bunlarla bir plugin şunları yapabilir:
- render edileni yeniden yazmak — bir sayfanın HTML'ini, bir sitemap'in ya da bir JSON document'ının gövdesini — sunulmadan ve önbelleğe alınmadan önce. Bir küçültücü (minifier) bu şekilde çalışır.
- render edilmeden önce head'e hoist ederek sayfaya katkıda bulunmak: bir yapılandırılmış veri bloğu, bir meta etiketi, bir preload ipucu.
- ardından her şablonun çağırabileceği şablon fonksiyonları eklemek.
- mount edilmiş her dosya sistemini dönüştürmek; böylece bir mount'un sunduğu dosyalar, örneğin, zaten küçültülmüş olur.
- kendine ait sayfalar, document'lar ve mount'lar kaydetmek. Bir görsel iyileştirici, bağlantısını verdiği yeniden boyutlandırılmış görselleri kendi mount'undan sunar.
- bir önbellek yazımını ayarlamak — ömrünü ya da etiketlerini değiştirmek veya onu atlamak — ve geçersiz kılmalardan haberdar olmak.
- başarısızlıkları gözlemlemek, gerçekleştikleri pipeline aşamasıyla birlikte.
- programınızın çalıştırdığı komutlar eklemek — iskeleti kurulmuş bir projede
go run . <command>; bkz. collage CLI.
Bunların her birinin plugin tarafından nasıl göründüğü Plugin yazmak sayfasındadır.
Bir plugin'i kaydetmek
Plugin ayrı bir modüldür. Onu ekleyin, oluşturun ve Config.Plugins'e koyun:
go get github.com/Elagoht/collage-minimizer
import minimizer "github.com/Elagoht/collage-minimizer"
app, err := collage.New(&collage.Config{
Template: collage.TemplateConfig{Root: "templates"},
Plugins: []collage.Plugin{minimizer.New()},
})
İkinci bir yol daha vardır: New'den sonra çağrılan app.RegisterPlugin:
if err := app.RegisterPlugin(jsonld.New()); err != nil {
log.Fatal(err)
}
Config.Plugins'i tercih edin. Bazı plugin'lerin uygulama kurulurken harekete
geçmesi gerekir — bir şablon fonksiyonu eklemek ya da mount edilmiş dosya
sistemlerini sarmalamak için — ve bu New'de olur. Böyle bir plugin isteğe bağlı
bir Configure aşaması uygular; RegisterPlugin de onu kabul edip asıl önemli
kısmı sessizce atlamak yerine adıyla birlikte collage.ErrConfigurerRegisteredLate
ile reddeder. Config.Plugins her plugin için çalışır; başvurulacak yol odur.
RegisterPlugin şu durumlarda da reddeder:
| Hata | Ne zaman |
|---|---|
ErrAppStarted |
Uygulama zaten başlamıştır — Handler, ListenAndServe, Start, DispatchCommands ya da bir render çalışmıştır. Başarısız olan her başlatma da buna dahildir — bir plugin'in Init'inde başarısız olan v0.11.0'dan itibaren, başka herhangi bir nedenle başarısız olan v0.12.0'dan itibaren. |
ErrNilPlugin |
Plugin nil'dir. |
ErrEmptyPluginName |
Name()'i boştur. |
ErrDuplicatePlugin |
Başka bir plugin'in adı zaten aynıdır. |
Config.Plugins içindeki bir plugin de aynı şekilde denetlenir ve hatayı New
döndürür.
Sıra önemlidir
Plugin'ler kaydedildikleri sırayla çalışır: önce slice sırasıyla Config.Plugins,
ardından çağrı sırasıyla RegisterPlugin çağrıları. Çıktıyı değiştiren hook'larda
her plugin, kendinden öncekinin ürettiğini görür. Sayfaya ekleme yapan bir plugin
genellikle sayfayı sıkıştıran birinden önce gelmelidir; böylece eklenen de
sıkıştırılır.
Plugin'leri yapılandırmak
Ayar alan bir plugin, bunları plugin'in adıyla anahtarlanmış bir
map[string]json.RawMessage olan Config.PluginConfig'ten okur. Adlar modül
yolları gibi okunur — elagoht/minimizer — böylece anahtar ve plugin tek bir
tanımlayıcıdır.
Yaygın durum, programınızın yanında duran bir JSON dosyasıdır. collage new ile
iskeleti kurulan bir projede boş bir plugins-config.json vardır ve proje onu zaten
yükler:
{
"elagoht/minimizer": { "js": true },
"elagoht/jsonld": { "siteName": "The Wire", "siteURL": "https://thewire.example" }
}
pluginConfig, err := collage.LoadPluginConfig("plugins-config.json")
if err != nil {
log.Fatal(err)
}
app, err := collage.New(&collage.Config{
Template: collage.TemplateConfig{Root: "templates"},
Plugins: []collage.Plugin{minimizer.New(), jsonld.New()},
PluginConfig: pluginConfig,
})
Dosya yoksa LoadPluginConfig bir nil map döndürür ve hata döndürmez: hiçbir şey
yapılandırmayan bir yayına alma, bunu söylemek için boş bir dosyaya ihtiyaç
duymamalıdır. Var olan ama okunamayan ya da bir JSON nesnesi olmayan bir dosya ise
hatadır.
Bunların hiçbiri JSON dosyalarına bağlı değildir. LoadPluginConfig, framework'ün
kendisinin hiç çağırmadığı bir kolaylıktır; PluginConfig'i YAML'dan, ortamdan ya
da Go sabitlerinden doldurabilirsiniz:
PluginConfig: map[string]json.RawMessage{
"elagoht/minimizer": json.RawMessage(`{"js": true}`),
},
Onu hangi yolla doldurursanız doldurun üç kural geçerlidir:
- Bölüm yoksa varsayılanlar geçerlidir. Girdisi olmayan bir plugin, tam olarak constructor'ının kurduğu gibi çalışır.
- Bir bölüm, varsayılanların üzerine decode edilir.
{"js": true}bir ayarı açar, geri kalanını olduğu gibi bırakır. Belirli bir plugin'in nasıl birleştirdiği kendi README'sinde yazar. - Kayıtlı hiçbir plugin'i adlandırmayan bir anahtar, uygulamanın başlamasını
collage.ErrUnknownPluginConfigile durdurur. Aksi hâlde"elagoht/minimzer"gibi bir yazım hatası, plugin'i varsayılanlarında bırakır, sizi de yapılandırıldığından emin. DenetimNew'de değil, uygulama başladığında çalışır, çünküRegisterPluginNew'den sonra da plugin ekleyebilir.
Var olan ama decode edilemeyen bir bölüm — plugin'in boolean beklediği yerde bir string — da bir hatadır; plugin onu okuduğunda ortaya çıkar.
Yayımlanmış plugin'ler
Framework'le birlikte üç plugin yayımlanmıştır. Her biri kendi modülüdür ve tam başvuru kaynağı olan kendi README'si vardır; aşağıdakiler birini kurmaya yeter.
elagoht/minimizer
github.com/Elagoht/collage-minimizer, render edilmiş sayfalardan, JSON uç noktaları gibi document'lardan ve mount'larınızın sunduğu dosyalardan boşlukları ve yorumları ayıklar.
import minimizer "github.com/Elagoht/collage-minimizer"
Plugins: []collage.Plugin{minimizer.New()},
{
"elagoht/minimizer": { "html": true, "json": true, "css": true, "js": false }
}
Config.Plugins'e konmalıdır: mount edilmiş dosya sistemlerini sarmalar ve bu, uygulama kurulurken olur.New()HTML, JSON ve CSS'i etkinleştirir. JavaScript varsayılan olarak kapalıdır;{"js": true}ile açın.minimizer.NewWith(minimizer.Config{...})her anahtarı kendiniz ayarlamanızı sağlar ve bu varsayılanları devre dışı bırakır.- Bir ayrıştırıcı (parser) değil, bir tarayıcıdır (scanner) ve yalnızca anlam
taşıyamayacak olanı kaldırır:
<pre>,<textarea>,<script>ve<style>olduğu gibi korunur, CSS string'lerine dokunulmaz, JavaScript her satır sonunu korur ve geçersiz JSON olduğu gibi döndürülür. - Mount edilmiş dosyalar yanıt değil, dosya sistemi sarmalanarak küçültülür; böylece
bir mount'a yapılan
Rangeistekleri doğru baytları döndürmeye devam eder.
elagoht/jsonld
github.com/Elagoht/collage-jsonld, document'ın head'ine schema.org yapılandırılmış verisi yazar.
import "github.com/Elagoht/collage-jsonld"
Plugins: []collage.Plugin{jsonld.New()},
{
"elagoht/jsonld": {
"siteName": "The Wire",
"siteURL": "https://thewire.example",
"searchURL": "https://thewire.example/search?q={query}"
}
}
Kaydedildiğinde her sayfaya site geneli bir WebSite düğümü yazar — siteName
ayarlanmışsa — ve başka hiçbir şey yazmaz, çünkü plugin bir sayfanın ne hakkında
olduğunu bilemez. Bunu sayfa, makaleyi getiren data handler'dan söyler:
type articleView struct {
Article Article
}
func loadArticle(ctx context.Context, rc *collage.RenderContext) (articleView, []string, error) {
article, err := client.Article(ctx, rc.Param("slug"))
if err != nil {
return articleView{}, nil, err
}
jsonld.Emit(rc, jsonld.Article{
Headline: article.Title,
DatePublished: article.PublishedAt,
AuthorName: article.Author,
})
return articleView{Article: article}, []string{"article:" + article.Slug}, nil
}
Configureaşaması yoktur; bu yüzdenRegisterPluginde onu kabul eder.Emitekleme yapar ve plugin kayıtlı olsun ya da olmasın çalışır. Düğümler schema.org tipine göre anahtarlanır; böylece iç içe bir fragment'inArticle'ı, daha dışarıda bildirilmiş olanın yerini alır ve farklı tiplerdeki düğümlerin hepsi görünür.- Tipli düğümler
Article,BlogPosting,Blog,Person,WebSiteveBreadcrumbList'i kapsar; geri kalan her şey için kaçış kapısıjsonld.Raw'dır ve geçersiz JSON'u reddeder. - Marshal edilemeyen bir düğüm, sayfayı başarısız kılmak yerine atlanır.
Layout'unuzda {{hoist "head"}} olması gerekir — bkz.
aşağısı.
elagoht/opti-image
github.com/Elagoht/collage-opti-image,
piksel cinsinden bir width ve height bildiren her <img>'yi, kendi mount'undan
kendisinin sunduğu yeniden boyutlandırılmış bir kopyaya yönlendirecek şekilde yeniden
yazar.
import optiimage "github.com/Elagoht/collage-opti-image"
Plugins: []collage.Plugin{optiimage.New()},
{
"elagoht/opti-image": {
"allowedOrigins": [{ "scheme": "https", "host": "images.example.com" }],
"webp": "auto"
}
}
Config.Plugins'e konmalıdır.- Boş bir
allowedOriginsonu devre dışı bırakır. Listelemediğiniz bir host'tan asla veri çekmez ve şema (scheme) origin'in bir parçasıdır. - Yalnızca hem
widthhem deheightdeğeri piksel sayısı olan görseller yeniden yazılır; bildirilmiş bu boyut, var olan tek dürüst hedef boyuttur. - Render sırasında hiçbir şey çekilmez. Sayfa
/_image/8f2a91c0b4e7d3a6.webpgibi içerikle adreslenen bir ada bağlantı verir; görsel, bir tarayıcı onu ilk kez istediğinde çekilir ve yeniden boyutlandırılır. - Statik dışa aktarma görselleri çıktısına yazar, çünkü bunlar bir mount'tan sunulur ve her mount, sayfalar render edildikten sonra kopyalanır.
webp;false(varsayılan),trueya da yalnızca görselin aksi hâlde kayıpsız olacağı yerlerde WebP kullanan"auto"olabilir. Üretilen görseller varsayılan olarak bellekte ve.cache/opti-imageiçinde tutulur (cacheDir);p.Purge()vep.PurgeSource(url)bunları temizler.
optiimage.NewWith(optiimage.Config{...}), Go'da bir başlangıç yapılandırması
ayarlar; JSON bölümü ardından bunun üzerine anahtar anahtar decode edilir.
Head'e yazan plugin'ler
Document head'ine katkıda bulunan bir plugin — yapılandırılmış veri, meta
etiketleri, preload ipuçları — bunu, fragment'lerin başlıkları ve stil dosyaları için
kullandığı mekanizmanın aynısıyla, hoist ederek yapar. Hoist edilen içerik, layout'un
{{hoist "head"}}'i çağırdığı yere düşer, başka hiçbir yere değil:
<head>
<meta charset="utf-8">
{{hoist "head"}}
</head>
Bu işaretçi olmadan hiçbir şey görünmez. Plugin kaydolur, çalışır, bloğunu
bildirir ve bloğun gidecek bir yeri olmaz. Bu bilinçlidir: HTML'de </head>'i arayıp
kendini araya ekleyen bir plugin, bir layout sorusunu layout'unuz adına karara
bağlamış olurdu. collage new'den gelen bir layout'ta işaretçi zaten vardır; elle
yazdığınız bir layout'ta olmayabilir. Genel olarak hoist etmek için bkz.
Head ve SEO.
Plugin'ler nerede çalışır
Plugin'ler, bir sunucunun render ettiği sayfalardan fazlasını görür:
- Önbellekteki sayfalar bir kez işlenir. Bir plugin'in HTML'de yaptığı değişiklikler sayfa önbelleğe alınmadan önce yapılır; böylece bir önbellek isabeti (hit), plugin'i yeniden çalıştırmadan işlenmiş baytları sunar. Her istekte çalışması gereken bir plugin — ziyaretçiye özgü bir değer eklemek için — önbelleğe alınan bir sayfayla birleştirilemez.
- Hata sayfaları aynı render hook'larından geçer; böylece 404'ünüz de diğer her sayfa gibi küçültülür ve zenginleştirilir.
- Bir action'ın yanıt olarak verdiği sayfa — bir formun doğrulama sonrası yeniden
render'ı — da
OnAfterRender'ı çalıştırır (v0.10.0'dan itibaren); böylece birGET'in aldığı sayfa gibi küçültülür. Bkz. Formlar ve action'lar. - Document'lar — sitemap'ler, feed'ler, JSON — kendi hook'larından geçer; böylece bir küçültücü onları da kapsar. Bkz. Document'lar.
- Statik dışa aktarma, sunulan bir render'la aynı render hook'larını çalıştırır ve her plugin önce başlatılıp yapılandırılır; böylece dışa aktarılan site, sunucunun sunduğu sitedir. Bkz. Statik dışa aktarma.
Daha ileri
Plugin yazmak; plugin sözleşmesini, her hook'u ve neyi değiştirebileceğini ve testleriyle birlikte eksiksiz bir plugin'i anlatır.