=pod =head1 Statische Webseiten mit Blio =head2 META =head3 Author Thomas Klausner =head3 Email domm AT plix.at =head3 URL http://domm.plix.at =head3 URL_slides http://domm.plix.at/talks/2013_linuxwochen_blio =head3 Date 2013-05-03 =head3 Location FH Technikum Wien =head3 Event Linuxwochen Wien 2013 =head2 Thomas Klausner domm Just another EPU Perl Hacker =for newslide =for img vienna.pm.org.png =for newslide =for img bicycle.pm.png =for newslide =for img validad.com.png =for newslide =for img oe1.orf.at.png =head2 dynamische Webseiten sind so Nuller-Jahre =head3 dynamische Webseite pro Request wird die angeforderte Seite frisch (=dynamisch) gebaut B Der Server schickt einfach HTML-Files, die im Filesystem rumliegen, an den Client =head4 Vorteile customizable aktuell ... =head4 Nachteile kompliziert in Setup und Betrieb Fehleranfällig Ressourcenintensiv ... =head3 statische Webseiten Für viele Zwecke reichen statische Webseiten komplett aus: Blog Projektbeschreibung Lokal / Restaurant =for newslide vor allem, seit JavaScript funktioniert also seit JQuery... statische Webseiten können so relativ einfach aufgefettet werden (später ein bischen mehr dazu) =head4 ABER Niemand mag direkt HTML erstellen schon gar nicht für mehr als 10 Seiten schon gar nicht für mehr als 2 Seiten Layout-Änderungen neuer Bereiche ... =for newslide d.h. wir wollen etwas, das aus einem leicht und angenehm zu verwaltendem Ausgangsformat eine nette und praktische Webseite baut. =head2 Blio Blio ist meine private Blogging "Engine" currently powers: =for newslide =for img domm.plix.at.png =for newslide =for img wochentags.plix.at.png =for newslide =for img hollerbusch.at.png =for newslide =for img timetracker.plix.at.png =for newslide Das Projekt ist schon recht alt Erster Commit ins aktuelle Repo war 2005-02-02 Aber die Konzepte sind noch älter Und auch nicht einzigartig, es gibt sehr viele ähnliche System zB Jekyl -> http://jekyllrb.com/ =for newslide =for img jekyl.png =head2 Konzept Wir nehmen einen Verzeichnisbaum ("src") dieser enthält Text-Dateien und ev Bilder ("nodes") und transformieren diese in einen gleichförmigen Verzeichnisbaum ("out") aus gerenderten HTML-Dateien von Bildern (wenn vorhanden) sollen auch Thumbnails erstellt werden =head2 Setup =head3 Installation Seit gestern ist C auf C Deswegen geht die Installation jetzt auch sehr einfach: =for newslide domm@t430:~/perl/blio.plix.at$ cpanm Blio =for newslide domm@t430:~/perl/blio.plix.at$ **cpanm** Blio C ist der neueste (& beste) C client zeroconf, schnell, super =for newslide domm@t430:~/perl/blio.plix.at$ cpanm Blio Fetching http://www.cpan.org/authors/id/D/DO/DOMM/Blio-2.002.tar.gz ... OK Configuring Blio-2.002 ... OK =for newslide domm@t430:~/perl/blio.plix.at$ cpanm Blio Fetching http://www.cpan.org/authors/id/D/DO/DOMM/Blio-2.002.tar.gz ... OK Configuring Blio-2.002 ... OK ... # je nach System wird hier jetzt einiges installiert =for newslide domm@t430:~/perl/blio.plix.at$ cpanm Blio Fetching http://www.cpan.org/authors/id/D/DO/DOMM/Blio-2.002.tar.gz ... OK Configuring Blio-2.002 ... OK ... # je nach System wird hier jetzt einiges installiert Building and testing Blio-2.002 ... OK Successfully installed Blio-2.002 yay! =for newslide Jetzt können wir unsere neue Website starten: =head3 Verzeichnisstruktur domm@t430:~/perl/blio.plix.at$ tree . ├── blio.ini ├── out └── src ├── blog │   └── 2012_08_09_blio_my_blogging_engine.txt ├── blog.txt ├── documentation │   └── overview.txt ├── documentation.txt └── index.txt =for newslide domm@t430:~/perl/blio.plix.at$ tree . ├── **blio.ini** ├── out └── src ├── blog │   └── 2012_08_09_blio_my_blogging_engine.txt ├── blog.txt ├── documentation │   └── overview.txt ├── documentation.txt └── index.txt =for newslide domm@t430:~/perl/blio.plix.at$ tree . ├── blio.ini ├── out └── **src** ├── blog │   └── 2012_08_09_blio_my_blogging_engine.txt ├── blog.txt ├── documentation │   └── overview.txt ├── documentation.txt └── index.txt =for newslide domm@t430:~/perl/blio.plix.at$ tree . ├── blio.ini ├── **out** └── src ├── blog │   └── 2012_08_09_blio_my_blogging_engine.txt ├── blog.txt ├── documentation │   └── overview.txt ├── documentation.txt └── index.txt =for newslide domm@t430:~/perl/blio.plix.at$ tree . ├── blio.ini ├── out └── src ├── blog │   └── 2012_08_09_blio_my_blogging_engine.txt ├── **blog.txt** ├── documentation │   └── overview.txt ├── **documentation.txt** └── **index.txt** =for newslide domm@t430:~/perl/blio.plix.at$ tree . ├── blio.ini ├── out └── src ├── **blog** │   └── %%2012_08_09_blio_my_blogging_engine.txt%% ├── **blog**.@@txt@@ ├── documentation │   └── overview.txt ├── documentation.txt └── index.txt =head3 Node Syntax domm@t430:~/perl/blio.plix.at$ **head** src/blog/2012_08_09_blio_my_blogging_engine.txt =for newslide title: Blio - my blogging "engine" date: 2012-08-09T20:54:30+0200 language: en tags: release, Blio, blogging engine converter: textile Today I finally pushed *Blio*, my personal blogging "engine" to "github":https://github.com/domm/Blio. I call it an '"engine"'[0] because Blio is basically a slightly enhanced and streamlined (for my use cases, at least) ... =for newslide **H** title: Blio - my blogging "engine" **E** date: 2012-08-09T20:54:30+0200 **A** language: en **D** tags: release, Blio, blogging engine **E** converter: textile **R** Today I finally pushed *Blio*, my personal blogging "engine" to "github":https://github.com/domm/Blio. I call it an '"engine"'[0] because Blio is basically a slightly enhanced and streamlined (for my use cases, at least) ... =for newslide title: Blio - my blogging "engine" date: 2012-08-09T20:54:30+0200 language: en tags: release, Blio, blogging engine converter: textile **C** Today I finally pushed *Blio*, my personal blogging "engine" to **O** "github":https://github.com/domm/Blio. **N** **T** I call it an '"engine"'[0] because Blio is basically a slightly enhanced and **E** streamlined (for my use cases, at least) **N** ... **T** =head4 Header @@title@@**:** %%Blio - my blogging "engine"%% date: 2012-08-09T20:54:30+0200 language: en tags: release, Blio, blogging engine converter: textile Key-Value Paare getrennt mit B<:> =for newslide **title**: Blio - my blogging "engine" date: 2012-08-09T20:54:30+0200 language: en tags: release, Blio, blogging engine converter: textile B ist das einzige required field und enthält den Titel der jeweiligen Seite =for newslide title: Blio - my blogging "engine" **date**: 2012-08-09T20:54:30+0200 language: en tags: release, Blio, blogging engine converter: textile B<date> ist Datum der Veröffentlichung (ISO 8601) Wenn nicht vorhanden, wird die C<mtime> der Datei verwendet Über B<date> können Posts auch in der Zukunft gescheduled werden. =for newslide title: Blio - my blogging "engine" date: 2012-08-09T20:54:30+0200 **language**: en tags: release, Blio, blogging engine converter: textile Ein Hinweis an die User, aber nicht weiter wichtig =for newslide title: Blio - my blogging "engine" date: 2012-08-09T20:54:30+0200 language: en **tags**: release, Blio, blogging engine converter: textile Tags sind immer praktisch =for newslide title: Blio - my blogging "engine" date: 2012-08-09T20:54:30+0200 language: en tags: release, Blio, blogging engine **converter**: textile B<converter> bestimmt das Markup-Format des Contents Wenn kein C<converter> angegeben wird, bleibt der Content unverändert zZ werden alle Formate unterstützt, die das CPAN-Modul C<Markup::Unified> anbietet: Textile Markdown BBCode =head4 Content Der Content ist alles, was nicht der Header ist. D.h. alles nach der ersten Leerzeile (denn diese beendet den Header). Ich mag C<Textile> als einfache Markup-Sprache am liebsten. Aber andere Formate können entweder über C<Markup::Unified> eingebunden werden oder einfach dazuimplementiert werden (patches welcome!) =head4 zB Textile Today I finally pushed *Blio*, my personal blogging "engine" to "github":https://github.com/domm/Blio. I call it an '"engine"'[0] because Blio is basically a slightly enhanced and streamlined (for my use cases, at least) =for newslide Today I finally pushed %%*%%@@Blio@@%%*%%, my personal blogging "engine" to "github":https://github.com/domm/Blio. I call it an '"engine"'[0] because Blio is basically a slightly enhanced and streamlined (for my use cases, at least) ... =for newslide Today I finally pushed *Blio*, my personal blogging "engine" to **"**%%github%%**":**@@https://github.com/domm/Blio@@. I call it an '"engine"'[0] because Blio is basically a slightly enhanced and streamlined (for my use cases, at least) ... =for newslide Today I finally pushed *Blio*, my personal blogging "engine" to "github":https://github.com/domm/Blio. I call it an '"engine"'**[0]** because Blio is basically a slightly enhanced and streamlined (for my use cases, at least) ... =for newslide In jedem Post das Markup-Format (C<converter>) angeben zu müssen, ist aber recht mühsam Deswegen gibts eine Config-Datei, F<blio.ini> =head3 Config-Datei domm@t430:~/perl/blio.plix.at$ tree . ├── **blio.ini** ├── out └── src ├── blog │   └── 2012_08_09_blio_my_blogging_engine.txt ├── blog.txt ├── documentation │   └── overview.txt ├── documentation.txt └── index.txt =for newslide domm@t430:~/perl/blio.plix.at$ less blio.ini **name** = Blio site_url = http://blio.plix.at site_author = Thomas Klausner <domm@plix.at> thumbnail = 300 Der Name der Seite, zB für den C<page-title> =for newslide domm@t430:~/perl/blio.plix.at$ less blio.ini name = Blio **site_url** = http://blio.plix.at **site_author** = Thomas Klausner <domm@plix.at> thumbnail = 300 zB für RSS/Atom-Feeds =for newslide domm@t430:~/perl/blio.plix.at$ less blio.ini name = Blio site_url = http://blio.plix.at site_author = Thomas Klausner <domm@plix.at> **thumbnail** = 300 Breite von Thumbnails =for newslide domm@t430:~/perl/blio.plix.at$ less blio.ini name = Blio site_url = http://blio.plix.at site_author = Thomas Klausner <domm@plix.at> thumbnail = 300 **language** = en **converter** = textile Und hier ist auch ein bessere Platz für C<converter> und C<language> Natürlich können diese Werte für einzelne Posts in diesen überschrieben werden =head2 Build it! C<Blio> kommt mit ein paar default-templates und einem kleinen Script C<blio.pl> Damit kann man eine erste (schirche) Seite bauen: =for newslide domm@t430:~/perl/blio.plix.at$ blio.pl --source_dir src --output_dir out =for newslide domm@t430:~/perl/blio.plix.at$ blio.pl =for newslide domm@t430:~/perl/blio.plix.at$ blio.pl writing documentation.html writing blog/2012_08_09_blio_my_blogging_engine.html writing blog.html writing documentation/overview.html writing index.html =for newslide domm@t430:~/perl/blio.plix.at$ tree . ├── blio.ini ├── **out** │   ├── blog │   │   └── 2012_08_09_blio_my_blogging_engine.html │   ├── blog.html │   ├── documentation │   │   └── overview.html │   ├── documentation.html │   └── index.html └── src ├── blog │   └── 2012_08_09_blio_my_blogging_engine.txt ├── blog.txt ├── documentation │   └── overview.txt ├── documentation.txt └── index.txt =for newslide domm@t430:~/perl/blio.plix.at$ tree . ├── blio.ini ├── out │   ├── @@blog@@ │   │   └── @@2012_08_09_blio_my_blogging_engine@@.**html** │   ├── blog.html │   ├── documentation │   │   └── overview.html │   ├── documentation.html │   └── index.html └── src ├── @@blog@@ │   └── @@2012_08_09_blio_my_blogging_engine@@.**txt** ├── blog.txt ├── documentation │   └── overview.txt ├── documentation.txt └── index.txt =for newslide Yay, wir haben eine Site! Aber pott-hässlich: =for newslide =for img blio_01.png =for newslide Wir könnten jetzt das vorhande HTML mit CSS aufhübschen Oder eigene C<templates> verwenden, was wesentlich mächtiger ist. =head2 Templates C<Blio> verwendet C<Template::Toolkit> als templating engine. C<Template::Toolkit> ist seit Jahren das Standardwerkzeug in Perl sehr stabil, schnell, einfach schaut ein bischen aus wie PHP bzw schaut PHP aus wie C<Template::Toolkit> :-) =for newslide C<Blio> benutzt per default zwei templates: C<wrapper.tt> und C<node.tt> C<node.tt> definiert, wie eine einzlene Node (oder eine Liste von Nodes) ausschaut. C<wrapper.tt> definiert das drumherum, in das die Node eingepackt ist. =for newslide Also laden wir uns schnell mal Bootstrap runter und kopieren die CSS/JS-Dateien nach F<out/js>, F<out/css> und F<out/img> Danach legen wir die templates an. Per default sucht C<Blio> im Verzeichnis F<templates> =for newslide domm@t430:~/perl/blio.plix.at$ tree . ├── blio.ini ├── out ├── src └── **templates** ├── node.tt └── wrapper.tt =for newslide domm@t430:~/perl/blio.plix.at$ less **node.tt** <h2>[% node.title %]</h2> <p>[% node.content %]</p> [% IF node.has_children %] <ul> [% FOREACH child IN node.sorted_children %] <li><a href="[% base %][% child.url %]">[% child.title %]</a></li> [% END %] </ul> [% END %] =for newslide domm@t430:~/perl/blio.plix.at$ less node.tt <h2>[% node.title %]</h2> <p>[% node.content %]</p> =for newslide domm@t430:~/perl/blio.plix.at$ less node.tt <h2>**[%** node.title **%]**</h2> <p>**[%** node.content **%]**</p> =for newslide domm@t430:~/perl/blio.plix.at$ less node.tt <h2>[% **node**.title %]</h2> <p>[% **node**.content %]</p> =for newslide domm@t430:~/perl/blio.plix.at$ less node.tt <h2>[% node.**title** %]</h2> <p>[% node.**content** %]</p> =for newslide [% IF node.has_children %] <ul> [% FOREACH child IN node.sorted_children %] <li><a href="[% base %][% child.url %]">[% child.title %]</a></li> [% END %] </ul> [% END %] =for newslide [% IF node.**has_children** %] <ul> [% FOREACH child IN node.sorted_children %] <li><a href="[% base %][% child.url %]">[% child.title %]</a></li> [% END %] </ul> [% END %] =for newslide [% IF node.has_children %] <ul> [% **FOREACH** @@child@@ IN %%node%%.**sorted_children** %] <li><a href="[% base %][% child.url %]">[% child.title %]</a></li> [% END %] </ul> [% END %] =for newslide [% IF node.has_children %] <ul> [% FOREACH child IN node.sorted_children %] <li><a href="[% base %][% **child.url** %]">[% **child.title** %]</a></li> [% END %] </ul> [% END %] =for newslide [% IF node.has_children %] <ul> [% FOREACH child IN node.sorted_children %] <li><a href="[% **base** %][% child.url %]">[% child.title %]</a></li> [% END %] </ul> [% END %] =for newslide einfach! =for newslide domm@t430:~/perl/blio.plix.at$ less **wrapper.tt** <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <title>[% blio.name %] / [% node.title %]
[% content %]
=for newslide [% **blio**.@@name@@ %] / [% **node**.@@title@@ %] -> Blio / Documentation =for newslide =for newslide
[% content %]
Da F ein sog. WRAPPER ist, wird an dieser Stelle C<[% content %]> der Inhalt des aktuell gerenderten Templates (F) eingesetzt =for newslide Und wie schaut's jetzt aus? =for newslide =for img blio_02.png =for newslide =for img blio_01.png =for newslide =for img blio_02.png =for newslide =for img blio_03.png =for newslide =for img blio_04.png =for newslide =head2 Noch ein paar Features =head3 Tags hab ich eh schon kurz hergezeigt In einer Node: tags: foo, bar, baz Dann müssen die Erstellung einer Tag-Liste noch in der Config-Datei freigegeben werden: tags = 1 =for newslide =for img blio_05.png =head3 Bilder Um das Bilder-Handling einfach zu machen, gibt es 2 Regeln für Bilder Entweder es gibt nur ein Bild pro Node. Dann B der Bildname den selben Dateinamen wie die Node haben nur mit einer anderen Extension: =for newslide └── src ├── blog │   ├── %%some_post%%.**txt** │   └── %%some_post%%.@@jpg@@ =for newslide Oder es gibt mehrere Bilder pro Node. Dann B die Bilder in einem Verzeichnis mit dem selben Namen wie die Node, plus "_images" liegen: =for newslide └── src ├── blog │   ├── %%other_post%%.**txt** │   └── **other_post_images** │   ├── 01_some_image.jpg │   └── 02_next_image.jpg =for newslide Von den Bildern werden automatisch Thumbnails erstellt. Anzeigen kann man sie zB so: =for newslide [% IF node.has_images %]
    [% FOREACH image IN node.sorted_images %]
  • an image named [% image.url %]
  • [% END %]
[% END %] =head3 Content aus anderen Quellen Wenn man ein eigenes F Script schreibt, kann man auch einfach Content aus anderen Quellen einspeisen zB aus einer Datenbank (SQLite) Ich erfasse zB meine Schallplatten in einer kleinen Datenbank und inkludiere diese Daten in etwa so: =for newslide my $vinyl = $blio->nodes_by_url->{'vinyl.html'}; my $DBH = DBI->connect( "dbi:SQLite:dbname=sqlite/vinyl.db" ); my $sth = $DBH->prepare( "select * from vinyl order by buy DESC,id DESC" ); $sth->execute; while (my $r=$sth->fetchrow_hashref) { my $title = $r->{artist}.' - '.$r->{name}; my $id = $r->{id}; my $url = "vinyl/$id.html"; my $node = Blio::Node->new( base_dir => $blio->source_dir, source_file => file($vinyldb), id=>'vinyl/'.$id, url=>$url, title=>$title, date=>$r->{date}, content=>$r->{content}, ); $blio->nodes_by_url->{$url}=$node; $vinyl->add_child($node); $node->parent($vinyl); } =head2 Deployment Das praktische an einer statischen Website ist, dass man sie gemütlich am eigenen Rechner bauen kann und dann mit C, C oder sogar C auf einen Server spielt. =for newslide Ebenfalls praktische geht das mit einem C Hook. Da man sowieso alles halbwegs wichtige in ein git-repo packen sollte ist die Webseite vermutlich eh schon ge-git-et Ein C macht auch dann Sinn, wenn man C nicht beim "Kunden" installieren kann oder will Oder der "Kunde" eine irrationale Abneigung gegen die Verwendung von Commandline-Tools hat... =for newslide Sinnvollerweise verwendet man in so einem Fall C. Dann installiert man im jeweiligen C F Verzeichnis einen C Hook, zb git@plix.at:~/repositories/wochentags.plix.at.git/hooks/post-receive =for newslide ROOT=/var/wochentags.plix.at/ cd $ROOT unset GIT_DIR git pull perl $ROOT/build.pl --configfile $ROOT/blio.ini =for newslide **ROOT**=/var/wochentags.plix.at/ cd $ROOT unset GIT_DIR git pull perl $ROOT/build.pl --configfile $ROOT/blio.ini Ein checkout des Repos ROOT/out ist das DocumentRoot des Webservers =for newslide ROOT=/var/wochentags.plix.at/ **cd** @@$ROOT@@ unset GIT_DIR git pull perl $ROOT/build.pl --configfile $ROOT/blio.ini =for newslide ROOT=/var/wochentags.plix.at/ cd $ROOT **unset GIT_DIR** git pull perl $ROOT/build.pl --configfile $ROOT/blio.ini sehr wichtig, damit C klappt =for newslide ROOT=/var/wochentags.plix.at/ cd $ROOT unset GIT_DIR **git pull** perl $ROOT/build.pl --configfile $ROOT/blio.ini =for newslide ROOT=/var/wochentags.plix.at/ cd $ROOT unset GIT_DIR git pull perl $ROOT/**build.pl** --@@configfile@@ $ROOT/blio.ini =for newslide Jetzt wird nach jedem C die Website neu gebaut. Yay! Lazy! =head2 Dynamicification Wenn doch dynamische Elemente benötigt werden (klassischerweise Kommentare) kann man diese leicht über JavaScript einbauen und/oder externe Dienstleister einbinden. =for newslide Für Kommentare ist zB disqus.com recht brauchbar =for newslide =for img disqus.com.png =for newslide
=for newslide =for img domm_comment.png =head2 __END__ uff... Fragen?