A place to cache linked articles (think custom and personal wayback machine)
Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

4 лет назад
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123
  1. title: Introducing Lektor — A Static File Content Management System For Python
  2. url: http://lucumr.pocoo.org/2015/12/21/introducing-lektor/
  3. hash_url: b83377f25e572457d7ab9ed5411034c9
  4. <p>The longer I'm programming and creating software, the more I notice that I
  5. build a lot of stuff that requires maintenance even though it should not.
  6. In particular a topic that just keeps annoying me is how quickly
  7. technology moves forward and how much effort it is to maintain older code
  8. that still exist but now stands on ancient foundations.</p>
  9. <p>This is not a new discovery mind you. This blog you're reading started
  10. out as a Django application many, many years ago, made a transition to
  11. WordPress because I could not be bothered with updating Django and then
  12. turned into two different static site generators because I did not want to
  13. bother with making database updates and rather wanted to track my content
  14. in a git repository.</p>
  15. <p>I like static website generators quite a bit. As everything needs a
  16. website these days — it's impossible to escape the work to create one.
  17. For programmers it's possible to get away with building something with
  18. static website generators like Jekyll, Hexo, Hugo, Pelican, Hyde, Brunch,
  19. Middleman, Harp, Expose, …</p>
  20. <p>As you can see the list of tools available is endless. Unfortunately
  21. though these tools are all aimed at programmers and it's very hard to use
  22. them as a someone without programming experience. Worse though: many of
  23. those are clones of each other just written in different programming
  24. languages with very similar designs. There is very little innovation in
  25. that space and that's a bit unfortunate because I like the flexibility I
  26. get from frameworks like Flask at times.</p>
  27. <div class="section" id="so-i-built-my-own">
  28. <h2>So I Built My Own</h2>
  29. <p>This is by far not the first time I built a static website generator but I
  30. hope it will be the last time. This one however is different from any
  31. project I built before. The reason it exists is quite frankly that it's
  32. impossible to escape family duties. For me that means helping out with
  33. the website of my parents. I knew that I did not want that to be
  34. WordPress or something that needs security updates so about two years ago
  35. I started to investigate that options there are.</p>
  36. <p>After a ton of toying around I ended up using <a class="reference external" href="http://pythonhosted.org/Frozen-Flask/">Frozen-Flask</a> for that project. It was neat
  37. because it allowed me to structure the website exactly like I wanted.
  38. However it also meant that whenever text started to change I needed to
  39. spend time on it. Thus I had to investigate CMS solutions again.
  40. Countless weekends were wasted trying to make WordPress work again and
  41. looking at Statamic. However I found them quite a bit more complex to
  42. customize than what I was used to with Frozen-Flask and they did not
  43. really fit the format at all. Especially WordPress feels much more like a
  44. blog engine than a CMS.</p>
  45. <p>Finally I decided to sit down and build something completely different: a
  46. content management system that uses flat files as source files like most
  47. other systems, but it has a locally hosted admin panel that a non
  48. programmer can use. You install the application, double click on the
  49. project, a browser opens and you can edit the pages. It builds in the
  50. background into static HTML files and there is a publish button to ship it
  51. up to a server. For collaboration one can use Dropbox.</p>
  52. </div>
  53. <div class="section" id="enter-lektor">
  54. <h2>Enter Lektor</h2>
  55. <p>I called this system Lektor and Open Sourced it initially a few months ago
  56. after not having cared about it in a year or so. However I had another
  57. run-in with a project which was the Sentry documentation. Sentry uses
  58. Sphinx for the documentation and customizing the docs for what we had in
  59. mind there turned out to be a complete waste of time and sanity. While
  60. Lektor is currently not in a position where it could replace Sphinx for
  61. Sentry it gave me enough motivation to hack on it again on weekends.</p>
  62. <p>So I figured I might retry Open Sourcing it and made a website for it with
  63. documentation and cleaned up some bad stuff in it.</p>
  64. <p>Here is what it looks like when you open up the admin panel:</p>
  65. <img alt="https://raw.githubusercontent.com/lektor/lektor-archive/master/screenshots/admin.png" src="https://raw.githubusercontent.com/lektor/lektor-archive/master/screenshots/admin.png"/>
  66. </div>
  67. <div class="section" id="lektor-is-a-framework">
  68. <h2>Lektor is a Framework</h2>
  69. <p>But what makes Lektor so much fun to work with is that Lektor is (while
  70. very opinionated) very, very flexible. It takes a lot of inspiration from
  71. ORMs like Django's. Instead there being a "blog component" you can model
  72. your own blog posts and render them with the templates you want to use.
  73. There is not a single built-in template that you have to use. The only
  74. thing it gives you is a quickstart that sets up the folders and copies
  75. default minimalistic templates over.</p>
  76. <p>As an example, here is how a blog index template looks like:</p>
  77. <div class="highlight"><pre><span class="cp">{%</span> <span class="k">extends</span> <span class="s2">"blog_layout.html"</span> <span class="cp">%}</span>
  78. <span class="cp">{%</span> <span class="k">from</span> <span class="s2">"macros/pagination.html"</span> <span class="k">import</span> <span class="nv">render_pagination</span> <span class="cp">%}</span>
  79. <span class="cp">{%</span> <span class="k">block</span> <span class="nv">title</span> <span class="cp">%}</span>My Blog<span class="cp">{%</span> <span class="k">endblock</span> <span class="cp">%}</span>
  80. <span class="nt">&lt;h1&gt;</span>My Blog<span class="nt">&lt;/h1&gt;</span>
  81. <span class="nt">&lt;ul</span> <span class="na">class=</span><span class="s">"blog-index"</span><span class="nt">&gt;</span>
  82. <span class="cp">{%</span> <span class="k">for</span> <span class="nv">post</span> <span class="k">in</span> <span class="nv">this.pagination.items</span> <span class="cp">%}</span>
  83. <span class="nt">&lt;li&gt;</span>
  84. <span class="nt">&lt;a</span> <span class="na">href=</span><span class="s">"</span><span class="cp">{{</span> <span class="nv">post</span><span class="o">|</span><span class="nf">url</span> <span class="cp">}}</span><span class="s">"</span><span class="nt">&gt;</span><span class="cp">{{</span> <span class="nv">post.title</span> <span class="cp">}}</span><span class="nt">&lt;/a&gt;</span> —
  85. by <span class="cp">{{</span> <span class="nv">post.author</span> <span class="cp">}}</span>
  86. on <span class="cp">{{</span> <span class="nv">post.pub_date</span><span class="o">|</span><span class="nf">dateformat</span> <span class="cp">}}</span>
  87. <span class="cp">{%</span> <span class="k">endfor</span> <span class="cp">%}</span>
  88. <span class="nt">&lt;/ul&gt;</span>
  89. <span class="cp">{%</span> <span class="k">if</span> <span class="nv">this.pagination.pages</span> <span class="o">&gt;</span> <span class="m">1</span> <span class="cp">%}</span>
  90. <span class="cp">{{</span> <span class="nv">render_pagination</span><span class="o">(</span><span class="nv">this.pagination</span><span class="o">)</span> <span class="cp">}}</span>
  91. <span class="cp">{%</span> <span class="k">endif</span> <span class="cp">%}</span>
  92. <span class="cp">{%</span> <span class="k">endblock</span> <span class="cp">%}</span>
  93. </pre></div>
  94. <p>The system understands what the blog is, that it has child record, that
  95. those records are paginated, it can provide pagination etc. However there
  96. is nothing in there that makes it a blog in itself. It just has a very
  97. flexible ORM inspired component that gives access to the structured files
  98. on the file system. Programming for Lektor feels very much like
  99. programming something with Flask or Django.</p>
  100. </div>
  101. <div class="section" id="learn-more">
  102. <h2>Learn More</h2>
  103. <p>If you want to learn more about it, there are quite a few resources at
  104. this point:</p>
  105. </div>
  106. <div class="section" id="final-words">
  107. <h2>Final Words</h2>
  108. <p>I hope people find it useful. I know that I enjoy using it a ton and I
  109. hope it makes others enjoy it similarly. Because I run so many Open
  110. Source projects and maintenance of all of them turns out to be tricky I
  111. figured I do this better this time around. Lektor belongs to a separate
  112. org and the project does not use any resources only I have access to
  113. (other than the domain name and the server travis-CI deploys to). So in
  114. case people want to help out, there is no single point of failure!</p>
  115. <p>I hope I can spend some time over Christmas to do the same to my other
  116. projects to alter the bus factor of those.</p>
  117. <p>There is far too much in Lektor to be able to cover it in a single blog
  118. post so I will probably write a bit more about some of the really cool
  119. things about in in the next few weeks. Enjoy!</p>