{"version":"https://jsonfeed.org/version/1","title":"🔥 Updates","home_page_url":"https://aoba-test.netlify.app/","feed_url":"https://aoba-test.netlify.app/feed.json","description":"A blog to follow the updates of Lume, the static site generator for Deno","items":[{"id":"https://aoba-test.netlify.app/posts/lume-1.19.0-release-notes/","url":"https://aoba-test.netlify.app/posts/lume-1.19.0-release-notes/","title":"Lume 1.19.0 release notes","content_html":"<p>Lume 1.19.0 was released! Hopefully, it will be the last minor version of 1.x\nbefore the incoming Lume 2. This is a summary of the changes and new features.</p>\n<!-- more -->\n<h2 id=\"favicon-plugin\" tabindex=\"-1\"><a href=\"https://aoba-test.netlify.app/posts/lume-1.19.0-release-notes/#favicon-plugin\" class=\"header-anchor\">Favicon plugin</a></h2>\n<p>The favicon is a common task we have to do every time we build a new website.\nIt's not as easy as should be because there are different formats, sizes,\nresolutions, etc. The new <code>favicon</code> plugin was created to make it more simple.</p>\n<p>You only have to specify an input file (by default <code>favicon.svg</code>) and the plugin\nautomatically creates the files <code>/favicon.ico</code>, <code>/favicon-16.png</code>,\n<code>/favicon-32.png</code> and <code>/apple-touch-icon.png</code> and adds the <code>&lt;link&gt;</code> elements\nneeded in all HTML pages.</p>\n<p>As any other Lume plugin, the installation can't be easier: just import the\nplugin and use it:</p>\n<pre><code class=\"language-ts\">import lume from &quot;lume/mod.ts&quot;;\nimport favicon from &quot;lume/plugins/favicon.ts&quot;;\n\nconst site = lume();\nsite.use(favicon());\n\nexport default site;\n</code></pre>\n<p>See <a href=\"https://lume.land/plugins/favicon/\">the favicon plugin documentation</a>.</p>\n<h2 id=\"reading-info-plugin\" tabindex=\"-1\"><a href=\"https://aoba-test.netlify.app/posts/lume-1.19.0-release-notes/#reading-info-plugin\" class=\"header-anchor\">Reading info plugin</a></h2>\n<p>This plugin was created by <a href=\"https://github.com/jrson83\">Jrson</a> and available in\nthe\n<a href=\"https://github.com/lumeland/experimental-plugins\">experimental plugins repo</a>\nsince a time ago, under the name <code>reading_time</code>. It's a simple plugin to\ncalculate the time required to read the content of a page.</p>\n<p>Due the plugin is being used in several projects (among them, this blog), it was\nmoved to Lume repo and renamed to <code>reading_info</code>. The reason of the new name is\nthe plugin not only returns the time, but also other interesting info like the\nnumber of words. Maybe we can include more interesting info in the future, let\nme know your suggestions.</p>\n<p>It uses the\n<a href=\"https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Intl/Segmenter\"><code>Int.Segmenter</code></a>\nstandard function to count the words, using the page variable <code>lang</code> to detect\nthe language. The data is stored in the variable <code>readingInfo</code>, so you can use\nit in your templates in this way:</p>\n<pre><code class=\"language-vento\">&lt;h1&gt;{{ title }}&lt;/h1&gt;\n&lt;p&gt;{{ readingInfo.words }} words / {{ readingInfo.minutes }} min read&lt;/p&gt;\n</code></pre>\n<p>See\n<a href=\"https://lume.land/plugins/reading_info/\">the reading_info plugin documentation</a></p>\n<h2 id=\"improved-the-picture-plugin\" tabindex=\"-1\"><a href=\"https://aoba-test.netlify.app/posts/lume-1.19.0-release-notes/#improved-the-picture-plugin\" class=\"header-anchor\">Improved the <code>picture</code> plugin</a></h2>\n<p>The <a href=\"https://lume.land/plugins/picture/\">picture plugin</a> has received many\nimprovements and bug fixes. The most notable:</p>\n<h3 id=\"changed-the-src-value-of-the-original-img-element\" tabindex=\"-1\"><a href=\"https://aoba-test.netlify.app/posts/lume-1.19.0-release-notes/#changed-the-src-value-of-the-original-img-element\" class=\"header-anchor\">Changed the <code>src</code> value of the original <code>img</code> element</a></h3>\n<p>In previous versions, the <code>src</code> value of the <code>img</code> element referred to the\noriginal image. But this image isn't always exported so it returns a <code>404</code>\nerror. As of Lume 1.19, the last <code>source</code> element will be used as the value for\nthe <code>img</code>:</p>\n<pre><code class=\"language-html\">&lt;!-- Source code --&gt;\n&lt;img src=&quot;/images/test.jpg&quot; imagick=&quot;jpg webp 600&quot;&gt;\n\n&lt;!-- Previous output: --&gt;\n&lt;picture&gt;\n  &lt;source srcset=&quot;/images/test-600w.webp&quot; type=&quot;image/webp&quot;&gt;\n  &lt;source srcset=&quot;/images/test-600w.jpg&quot; type=&quot;image/jpeg&quot;&gt;\n  &lt;img src=&quot;/images/test.jpg&quot;&gt;\n&lt;/picture&gt;\n\n&lt;!-- New output: --&gt;\n&lt;picture&gt;\n  &lt;source srcset=&quot;/images/test-600w.webp&quot; type=&quot;image/webp&quot;&gt;\n  &lt;img src=&quot;/images/test-600w.jpg&quot;&gt;\n&lt;/picture&gt;\n</code></pre>\n<h3 id=\"formats-sorted-automatically\" tabindex=\"-1\"><a href=\"https://aoba-test.netlify.app/posts/lume-1.19.0-release-notes/#formats-sorted-automatically\" class=\"header-anchor\">Formats sorted automatically</a></h3>\n<p>In the previous version, the <code>source</code> elements were created in the same order as\ndefined in the <code>imagick</code> attribute. For example:</p>\n<pre><code class=\"language-html\">&lt;img src=&quot;/images/test.jpg&quot; imagick=&quot;jpg webp avif 600&quot;&gt;\n</code></pre>\n<p>This outputs the <code>source</code> elements in the same order (<code>jpg</code>, <code>webp</code> and <code>avif</code>):</p>\n<pre><code class=\"language-html\">&lt;picture&gt;\n  &lt;source srcset=&quot;/images/test-600w.jpg&quot; type=&quot;image/jpeg&quot;&gt;\n  &lt;source srcset=&quot;/images/test-600w.webp&quot; type=&quot;image/webp&quot;&gt;\n  &lt;source srcset=&quot;/images/test-600w.avif&quot; type=&quot;image/avif&quot;&gt;\n  &lt;img src=&quot;/images/test.jpg&quot;&gt;\n&lt;/picture&gt;\n</code></pre>\n<p>Because <code>jpg</code> is a format widely supported, it will be choosen by all browsers\nbecause it's the first in the list, even if better formats like <code>webp</code> or <code>avif</code>\nare there. As of Lume 1.19 the formats are sorted automatically. By default the\norder is: <code>jxl, avif, webp, png, jpg</code> (from the most modern to the most\nsupported). So the new output is:</p>\n<pre><code class=\"language-html\">&lt;picture&gt;\n  &lt;source srcset=&quot;/images/test-600w.avif&quot; type=&quot;image/avif&quot;&gt;\n  &lt;source srcset=&quot;/images/test-600w.webp&quot; type=&quot;image/webp&quot;&gt;\n  &lt;img src=&quot;/images/test-600w.jpg&quot;&gt;\n&lt;/picture&gt;\n</code></pre>\n<h3 id=\"allow-to-define-only-formats\" tabindex=\"-1\"><a href=\"https://aoba-test.netlify.app/posts/lume-1.19.0-release-notes/#allow-to-define-only-formats\" class=\"header-anchor\">Allow to define only formats</a></h3>\n<p>From now on, the <code>imagick</code> attribute can have only formats, sizes are no longer\nmandatory. It's useful if you don't want to resize the image, just provide\ndifferent formats:</p>\n<pre><code class=\"language-html\">&lt;!-- Source code --&gt;\n&lt;img src=&quot;/images/test.jpg&quot; imagick=&quot;avif jpg webp&quot;&gt;\n\n&lt;!-- Ouputs: --&gt;\n&lt;picture&gt;\n  &lt;source srcset=&quot;/images/test.avif&quot; type=&quot;image/avif&quot;&gt;\n  &lt;source srcset=&quot;/images/test.webp&quot; type=&quot;image/webp&quot;&gt;\n  &lt;img src=&quot;/images/test.jpg&quot;&gt;\n&lt;/picture&gt;\n</code></pre>\n<h3 id=\"don't-create-a-new-picture-just-for-one-source\" tabindex=\"-1\"><a href=\"https://aoba-test.netlify.app/posts/lume-1.19.0-release-notes/#don't-create-a-new-picture-just-for-one-source\" class=\"header-anchor\">Don't create a new picture just for one source</a></h3>\n<p>If the image has only one format, no <code>picture</code> element will be created:</p>\n<pre><code class=\"language-html\">&lt;!-- Source code --&gt;\n&lt;img src=&quot;/images/test.jpg&quot; imagick=&quot;avif 300&quot;&gt;\n\n&lt;!-- Previous output: --&gt;\n&lt;picture&gt;\n  &lt;source srcset=&quot;/images/test-300.avif&quot; type=&quot;image/avif&quot;&gt;\n  &lt;img src=&quot;/images/test.jpg&quot;&gt;\n&lt;/picture&gt;\n\n&lt;!-- New ouput: --&gt;\n&lt;img src=&quot;/images/test-300.avif&quot;&gt;\n</code></pre>\n<h3 id=\"support-for-size-attribute\" tabindex=\"-1\"><a href=\"https://aoba-test.netlify.app/posts/lume-1.19.0-release-notes/#support-for-size-attribute\" class=\"header-anchor\">Support for <code>size</code> attribute</a></h3>\n<p>The plugin now supports the <code>size</code> attribute:</p>\n<pre><code class=\"language-html\">&lt;!-- Source code --&gt;\n&lt;img src=&quot;img.png&quot; imagick=&quot;avif png 100@2&quot; sizes=&quot;(width &lt; 700px) 100px, 200px&quot;&gt;\n\n&lt;!-- Previous output: --&gt;\n&lt;picture&gt;\n  &lt;source srcset=&quot;img-100w.avif, img-100w@2.avif 2x&quot; type=&quot;image/avif&quot;&gt;\n  &lt;source srcset=&quot;img-100w.png, img-100w@2.png 2x&quot; type=&quot;image/png&quot;&gt;\n  &lt;img src=&quot;img.png&quot; /&gt;\n&lt;/picture&gt;\n\n&lt;!-- New output: --&gt;\n&lt;picture&gt;\n  &lt;source srcset=&quot;img-100w.avif, img-100w@2.avif 2x&quot; type=&quot;image/avif&quot; sizes=&quot;(width &lt; 700px) 100px, 200px&quot;&gt;\n  &lt;img src=&quot;img-100w.png&quot; srcset=&quot;img-100w@2.png 2x&quot; sizes=&quot;(width &lt; 700px) 100px, 200px&quot;&gt;\n&lt;/picture&gt;\n</code></pre>\n<h2 id=\"new-functions-to-site-instance\" tabindex=\"-1\"><a href=\"https://aoba-test.netlify.app/posts/lume-1.19.0-release-notes/#new-functions-to-site-instance\" class=\"header-anchor\">New functions to <code>site</code> instance</a></h2>\n<h3 id=\"mergekey\" tabindex=\"-1\"><a href=\"https://aoba-test.netlify.app/posts/lume-1.19.0-release-notes/#mergekey\" class=\"header-anchor\">mergeKey</a></h3>\n<p>Lume allows to customize the way some keys are merged with the variable\n<code>mergedKeys</code>. You can see a\n<a href=\"https://lume.land/docs/core/merged-keys/\">detailed explanation of this feature</a>\nin the documentation.</p>\n<p>The function <code>site.mergeKey()</code> allows to define this value in the _config.ts\nfile, which is more useful specially for plugins that register new merge\nstrategies for some keys automatically.</p>\n<p>For example, let's say you want to merge the keys <code>categories</code> using the\n<code>stringArray</code> strategy:</p>\n<pre><code class=\"language-ts\">site.mergeKey(&quot;categories&quot;, &quot;stringArray&quot;);\n</code></pre>\n<h3 id=\"page\" tabindex=\"-1\"><a href=\"https://aoba-test.netlify.app/posts/lume-1.19.0-release-notes/#page\" class=\"header-anchor\">page</a></h3>\n<p>The <code>site.page()</code> function allows to create new pages dynamically from the\n<code>_config.ts</code> file, without having a page file in the disk. You only have to set\nthe data object of the page, for example:</p>\n<pre><code class=\"language-ts\">site.page(\n  {\n    url: &quot;/about-me/&quot;,\n    layout: &quot;about-page.njk&quot;,\n    content: &quot;Hello, my name is Óscar&quot;,\n  },\n);\n</code></pre>\n<p>By default, the context of the page is the root directory (<code>/</code>), so any shared\ndata defined in <code>_data</code> files/folders is accessible to this page. You can change\nthe scope of the page in the second argument:</p>\n<pre><code class=\"language-ts\">site.page(\n  {\n    url: &quot;/about-me/&quot;,\n    layout: &quot;about-page.njk&quot;,\n    content: &quot;Hello, my name is Óscar&quot;,\n  },\n  &quot;/pages&quot;,\n);\n</code></pre>\n<p>Now the page is scoped to the <code>/pages</code> directory, so it can access to the data\nstored in the <code>/pages/_data.yml</code> file, for example.</p>\n<h2 id=\"upgrade-pagefind-to-v1.0\" tabindex=\"-1\"><a href=\"https://aoba-test.netlify.app/posts/lume-1.19.0-release-notes/#upgrade-pagefind-to-v1.0\" class=\"header-anchor\">Upgrade pagefind to v1.0</a></h2>\n<p>The great <a href=\"https://pagefind.app/\">Pagefind</a> library, used by the\n<a href=\"https://lume.land/plugins/pagefind/\">pagefind plugin</a> is now 1.0🎉. This new\nversion brings\n<a href=\"https://github.com/CloudCannon/pagefind/releases/tag/v1.0.0\">new awesome features</a>,\nbut also some changes:</p>\n<ul>\n<li>The option to configure the binary file was removed. The plugin use the <code>npm</code>\nversion that downloads the binary automatically in the Deno cache folder. No\nmore <code>_bin</code> folders!</li>\n<li>The option <code>indexing.bundleDirectory</code> was renamed to <code>outputPath</code>.</li>\n<li>Added the option <code>customRecords</code> that allows to add additional records to the\npagefind database in addition to those generated by the output pages.</li>\n</ul>\n<p>See the\n<a href=\"https://github.com/lumeland/lume/blob/v1.19.0/CHANGELOG.md\">CHANGELOG.md file</a>\nfor the full list of changes.</p>\n","date_published":"Mon, 25 Sep 2023 18:25:59 GMT"},{"id":"https://aoba-test.netlify.app/posts/improved-plugins-docs/","url":"https://aoba-test.netlify.app/posts/improved-plugins-docs/","title":"Improved plugins docs","content_html":"<p>Documentation is possibly one of the most important things for the adoption of\nany OSS project. No matter if your software is good and easy to use: if you\ndon't communicate it well, most people won't spend time figuring out how to use\nit.</p>\n<!-- more -->\n<p>Lume was very clear about that from the beginning and a lot of effort was put\ninto the documentation website. But one of the difficulties is to keep it\nupdated with the new changes because <strong>wrong documentation is worse than no\ndocumentation.</strong></p>\n<h2 id=\"plugins-documentation\" tabindex=\"-1\"><a href=\"https://aoba-test.netlify.app/posts/improved-plugins-docs/#plugins-documentation\" class=\"header-anchor\">Plugins documentation</a></h2>\n<p>Documentation is especially challenging for the\n<a href=\"https://lume.land/plugins/\">plugins section</a>: A lot of plugins, each one with\nits configuration, many of them depend on external libraries (like nunjucks,\npug, etc.) which have more configuration, etc. Maintaining all this info up to\ndate is a hard time-consuming job.</p>\n<p>But Lume is built on top of Deno, and Deno is supposed to make our life better,\nright? (at least our life as developers). <strong>And it does!</strong> because Deno includes\na\n<a href=\"https://deno.land/manual@v1.36.3/tools/documentation_generator\">Documentation generator</a>\nthanks to <code>deno doc</code>, which can extract a lot of interesting info from\nTypeScript files. It's used to build automatically the modules' documentation in\ndeno.land/x repository. Take a look at\n<a href=\"https://deno.land/x/lume@v1.18.5/plugins/date.ts?s=Options\">the options for the date plugin</a>.</p>\n<h2 id=\"deno-doc-%2B-aldara\" tabindex=\"-1\"><a href=\"https://aoba-test.netlify.app/posts/improved-plugins-docs/#deno-doc-%2B-aldara\" class=\"header-anchor\">Deno Doc + Aldara</a></h2>\n<p>With this idea in mind, I started working on a tool to generate this kind of\ndocumentation automatically to be displayed inside the lume.land website. Most\nLume plugins export the following two elements:</p>\n<ul>\n<li><a href=\"https://github.com/lumeland/lume/blob/5e03f8c13d9e0af6c3737bd2813449d59d2084e6/plugins/code_highlight.ts#L6-L18\">The <code>Options</code> interface</a>\nwith the types of plugin options</li>\n<li><a href=\"https://github.com/lumeland/lume/blob/5e03f8c13d9e0af6c3737bd2813449d59d2084e6/plugins/code_highlight.ts#L21-L31\">The <code>defaults</code> object</a>\nwith the default options.</li>\n</ul>\n<p>The idea is to use these two elements to build automatically the documentation\nfor every plugin. This not only saves time but also ensures the documentation is\nalways up to date.</p>\n<p>The command <code>deno doc --json</code> outputs the info in JSON format, perfect for\nprocessing. I've created the\n<a href=\"https://github.com/oscarotero/aldara\">aldara library</a> that gets the types from\nDeno Doc, transforms the JSON to a more easy-to-consume structure and even\ncompletes some missing info with any JsDoc content found. Then, it can set the\ndefault values from the <code>defaults</code> object exported by the plugin and that's all!</p>\n<p>The code do all this stuff it is very simple:</p>\n<pre><code class=\"language-ts\">import analyze, {\n  mergeDefaults,\n} from &quot;https://deno.land/x/aldara@v0.1.1/mod.ts&quot;;\n\nasync function getScheme(mod: string) {\n  const url = `https://deno.land/x/lume@v1.18.5/${mod}`;\n  const { defaults } = await import(url);\n  const { Options } = await analyze(url, { maxDepth: 2 });\n\n  mergeDefaults(Options, defaults);\n  return Options.children;\n}\n</code></pre>\n<p>You can see an example in the\n<a href=\"https://lume.land/plugins/minify_html/\">Minify HTML plugin documentation</a>.</p>\n<h2 id=\"future\" tabindex=\"-1\"><a href=\"https://aoba-test.netlify.app/posts/improved-plugins-docs/#future\" class=\"header-anchor\">Future</a></h2>\n<p>This is only the first version, there's a lot of room for improvement. I've\nfound some issues in <code>deno doc</code> that I hope they were fixed at some point soon:</p>\n<ul>\n<li><code>npm:</code> dependencies are not supported, so the types provided by NPM packages\nare not included.</li>\n<li>There are memory issues with circular dependencies\n(<a href=\"https://github.com/denoland/deno_doc/issues/303\">issue #303</a>), so private\ntypes (those that are not exported) cannot be displayed.</li>\n</ul>\n<p>Anyway, even with these issues, I think the plugin documentation is now much\nbetter than it was. Please, let me know if you have any questions or have found\nany issues.</p>\n","date_published":"Fri, 01 Sep 2023 13:54:48 GMT"},{"id":"https://aoba-test.netlify.app/posts/lume-1.18.0-release-notes/","url":"https://aoba-test.netlify.app/posts/lume-1.18.0-release-notes/","title":"Lume 1.18.0 release notes","content_html":"<p>This is a summary of the new features introduced in Lume (<strong>1.18.0</strong>).</p>\n<!-- more -->\n<h2 id=\"picture-plugin\" tabindex=\"-1\"><a href=\"https://aoba-test.netlify.app/posts/lume-1.18.0-release-notes/#picture-plugin\" class=\"header-anchor\">Picture plugin</a></h2>\n<p>Adding images to web pages is a hard task nowadays. There are new modern image\nformats like AVIF and JPEG XL with better quality and compression but they are\nnot supported by all browsers.</p>\n<p>In order to make this work more easy, Lume has the <code>picture</code> plugin that\nconverts any regular <code>&lt;img&gt;</code> element to a full featured <code>&lt;picture&gt;</code> element\ncreating all <code>&lt;source srcset&gt;</code> needed to support all formats and resolutions.\nThis plugin relies on the <code>imagick</code> plugin to make the transformations, so you\nneed the two plugins installed in this exact order:</p>\n<pre><code class=\"language-ts\">import lume from &quot;lume/mod.ts&quot;;\nimport picture from &quot;lume/plugins/picture.ts&quot;;\nimport imagick from &quot;lume/plugins/imagick.ts&quot;;\n\nconst site = lume();\nsite.use(picture());\nsite.use(imagick());\n\nexport default site;\n</code></pre>\n<p>Once installed, the plugin will search for all HTML elements with the <code>imagick</code>\nattribute and will convert the images to the specified formats. For example:</p>\n<pre><code class=\"language-html\">&lt;img src=&quot;/flowers.jpg&quot; imagick=&quot;avif webp jpg 300@2&quot;&gt;\n</code></pre>\n<p>The <code>imagick</code> attribute of this image contains the desired formats (<code>avif</code>,\n<code>webp</code> and <code>jpg</code>) and the different sizes (<code>300</code> which means 300 pixels). The\n<code>@2</code> suffix indicates that this size should support also the <code>2x</code> resolution.\nThe output HTML code is:</p>\n<pre><code class=\"language-html\">&lt;picture&gt;\n  &lt;source srcset=&quot;/flowers-300w.avif, /flowers-300w@2.avif 2x&quot; type=&quot;image/avif&quot;&gt;\n  &lt;source srcset=&quot;/flowers-300w.webp, /flowers-300w@2.webp 2x&quot; type=&quot;image/webp&quot;&gt;\n  &lt;source srcset=&quot;/flowers-300w.jpg, /flowers-300w@2.jpg 2x&quot; type=&quot;image/jpeg&quot;&gt;\n  &lt;img src=&quot;/flowers.jpg&quot;&gt;\n&lt;/picture&gt;\n</code></pre>\n<p><a href=\"https://lume.land/plugins/picture/\">See the documentation</a> for more info about\nthis plugin.</p>\n<h2 id=\"symlinks-support\" tabindex=\"-1\"><a href=\"https://aoba-test.netlify.app/posts/lume-1.18.0-release-notes/#symlinks-support\" class=\"header-anchor\">Symlinks support</a></h2>\n<p>Lume 1.18.0 introduces symlinks support in the <code>src</code> directory. This means that\nyou can include symlinks targeting files and folders outside of the <code>src</code> (for\nexample a page or a folder with templates) and Lume will follow them and will\nuse those files to build the site.</p>\n<p>This can be useful if you want to reuse the same files for different projects.\nInstead of copying the files for each project, you can store them in a single\nplace and add symlinks from the different projects.</p>\n<p>Keep in mind that the Lume watcher doesn't detect changes in these files.</p>\n<h2 id=\"vento-plugin\" tabindex=\"-1\"><a href=\"https://aoba-test.netlify.app/posts/lume-1.18.0-release-notes/#vento-plugin\" class=\"header-anchor\">Vento plugin</a></h2>\n<p><a href=\"https://github.com/oscarotero/vento\">Vento</a> is a new template engine designed\nto use the best ideas from Nunjucks, Liquid, Eta/EJS and Mustache. Some\nhighlighted features are:</p>\n<ul>\n<li>Async friendly</li>\n<li>Simple API</li>\n<li>Allows to write JavaScript code in the templates</li>\n</ul>\n<p>To use it, you must import it in the _config file:</p>\n<pre><code class=\"language-js\">import lume from &quot;lume/mod.ts&quot;;\nimport vento from &quot;lume/plugins/vento.ts&quot;;\n\nconst site = lume();\nsite.use(vento());\n\nexport default site;\n</code></pre>\n<p>Vento template engine has been created by me (Óscar Otero, also the Lume\ncreator) and I'm thinking of making it the default engine (replacing Nunjucks)\nat some point. I would like to know your thoughts.</p>\n<p><a href=\"https://lume.land/plugins/vento/\">See more info about this plugin</a> in the\ndocumentation.</p>\n<h2 id=\"lightningcss-bundler\" tabindex=\"-1\"><a href=\"https://aoba-test.netlify.app/posts/lume-1.18.0-release-notes/#lightningcss-bundler\" class=\"header-anchor\">LightningCSS bundler</a></h2>\n<p>Until now, the <code>lightningcss</code> plugin only transformed the CSS code but\n<a href=\"https://github.com/lumeland/lume/issues/273\">it couldn't bundle it</a> (inline the\n<code>@import</code>'ed styles to output a single file with all the code). The reason is\nLightningCSS is an NPM package that didn't work properly on Deno due the lack of\nsupport of some NAPI functions so Lume had to use the WASM version\n<a href=\"https://github.com/parcel-bundler/lightningcss/issues/277\">that only transform the code but not bundle it</a>.</p>\n<p>Deno team finally improved support for NAPI and now it's possible to use the NPM\nversion of <code>lightningcss</code> and bundle the code. In fact, as of Lume 1.18 the\nplugin <strong>bundles the CSS code by default</strong>.</p>\n<p>If you want to disable the bundler and only transform the code (back to the\nprevious behavior), just add a <code>includes: false</code> option in the _config file:</p>\n<pre><code class=\"language-js\">import lume from &quot;lume/mod.ts&quot;;\nimport lightningcss from &quot;lume/plugins/lightningcss.ts&quot;;\n\nconst site = lume();\nsite.use(lightningcss({\n  includes: false, // Disable the bundler\n}));\n\nexport default site;\n</code></pre>\n<h2 id=\"support-for-jsonc-and-toml\" tabindex=\"-1\"><a href=\"https://aoba-test.netlify.app/posts/lume-1.18.0-release-notes/#support-for-jsonc-and-toml\" class=\"header-anchor\">Support for JSONC and TOML</a></h2>\n<p>Thanks to <a href=\"https://github.com/kwaa\">@kwaa</a> for working on the JSONC and TOML\nsupport for Lume. Now you not only can use YAML format in the front matter but\nalso JSON and TOML formats.</p>\n<p>To use JSON (or JSONC) in the front matter:</p>\n<pre><code>{\n  &quot;title&quot;: &quot;Hello world&quot;\n}\n\nPage content\n</code></pre>\n<p>To use TOML in the front matter:</p>\n<pre><code>+++\ntitle = Hello world\n+++\n\nPage content\n</code></pre>\n<p>JSONC is enabled by default for pages and data files. So any file with the\nextension <code>.tmpl.jsonc</code> or a data file <code>_data.jsonc</code> or <code>_data/*.jsonc</code> is\nloaded by default.</p>\n<p>TOML files can also be used for pages and data files but this format is not\nenabled by default (probably it will in Lume 2.0). To enable it, just import the\nplugin in the _config file:</p>\n<pre><code class=\"language-js\">import lume from &quot;lume/mod.ts&quot;;\nimport toml from &quot;lume/plugins/toml.ts&quot;;\n\nconst site = lume();\nsite.use(toml());\n\nexport default site;\n</code></pre>\n<p>See the\n<a href=\"https://github.com/lumeland/lume/blob/v1.18.0/CHANGELOG.md\">CHANGELOG.md file</a>\nfor the full list of changes.</p>\n","date_published":"Thu, 22 Jun 2023 12:51:21 GMT"},{"id":"https://aoba-test.netlify.app/posts/lume-1.17.0-release-notes/","url":"https://aoba-test.netlify.app/posts/lume-1.17.0-release-notes/","title":"Lume 1.17.0 release notes","content_html":"<p>This is a brief summary of the main changes introduced in Lume (<strong>1.17.0</strong>).</p>\n<!-- more -->\n<h2 id=\"new-plugin%3A-feed\" tabindex=\"-1\"><a href=\"https://aoba-test.netlify.app/posts/lume-1.17.0-release-notes/#new-plugin%3A-feed\" class=\"header-anchor\">New plugin: <code>feed</code></a></h2>\n<p>One of the most common things to do when developing a web site is the RSS feed.\nIt's almost mandatory for blogs but it can also be useful for any website with\nsome regular updates. In the same way that there was a\n<a href=\"https://lume.land/plugins/sitemap/\"><code>sitemap</code> plugin</a> to build the sitemap of\nthe site, Lume 1.17 introduces the new\n<a href=\"https://lume.land/plugins/feed/\"><code>feed</code> plugin</a> to build a feed in <code>RSS</code> or\n<code>JSON Feed</code> format.</p>\n<p>🔥🔥 Thanks to\n<a href=\"https://github.com/lumeland/lume/pull/413\">adb-sh for his initial pull request</a>.</p>\n<p>To use this plugin, just import it in your <code>_config.ts</code> and configure it:</p>\n<pre><code class=\"language-ts\">import lume from &quot;lume/mod.ts&quot;;\nimport feed from &quot;lume/plugins/feed.ts&quot;;\n\nconst site = lume();\n\nsite.use(feed({\n  output: [&quot;/posts.rss&quot;, &quot;/posts.json&quot;],\n  query: &quot;type=post&quot;,\n  sort: &quot;date=desc&quot;,\n  limit: 10,\n  info: {\n    title: &quot;My awesome blog&quot;,\n    description: &quot;Post updates of my blog&quot;,\n  },\n  items: {\n    title: &quot;=title&quot;,\n    description: &quot;=excerpt&quot;,\n  },\n}));\n\nexport default site;\n</code></pre>\n<p>In this example, Lume creates two Feed files defined in the <code>output</code> key:\n<code>/posts.rss</code> (in RSS format) and <code>/posts.json</code> (in\n<a href=\"https://www.jsonfeed.org/\">JSON Feed format</a>). The file extensions determines\nthe format to use.</p>\n<p>The <code>query</code>, <code>sort</code> and <code>limit</code> options are the same as you typically use in the\n<a href=\"https://lume.land/plugins/search/\"><code>search.pages()</code></a> API.</p>\n<p>The <code>info</code> object has the description of the Feed (like title, description, etc)\nand the <code>items</code> object the description of every item in the Feed. Both objects\nuse the\n<a href=\"https://lume.land/plugins/metas/#field-aliases\">same aliases as <code>metas</code> plugin</a>:\nany value starting with <code>=</code> represents a variable name that will be used to\nextract this info. In our example, the title and description is the same as the\ntitle and excerpt variables of the page.</p>\n<p>It's also possible to extract the info using CSS selectors. For example, let's\nsay we want to generate a RSS with the same content as the div <code>.post-content</code>.\nWe just have to start the value of the code with <code>$</code>:</p>\n<pre><code class=\"language-ts\">import lume from &quot;lume/mod.ts&quot;;\nimport feed from &quot;lume/plugins/feed.ts&quot;;\n\nconst site = lume();\n\nsite.use(feed({\n  output: [&quot;/posts.rss&quot;, &quot;/posts.json&quot;],\n  query: &quot;type=post&quot;,\n  sort: &quot;date=desc&quot;,\n  limit: 10,\n  info: {\n    title: &quot;My awesome blog&quot;,\n    description: &quot;Post updates of my blog&quot;,\n  },\n  items: {\n    title: &quot;=title&quot;,\n    description: &quot;=excerpt&quot;,\n    content: &quot;$.post-content&quot;,\n  },\n}));\n\nexport default site;\n</code></pre>\n<p>If you want to create more than one feed, just use the plugin once per feed:</p>\n<pre><code class=\"language-ts\">site.use(feed({\n  output: &quot;/posts.rss&quot;,\n  // Posts feed configuration\n}));\n\nsite.use(feed({\n  output: &quot;/articles.rss&quot;,\n  // Articles feed configuration\n}));\n</code></pre>\n<h2 id=\"sass-supports-remote-files\" tabindex=\"-1\"><a href=\"https://aoba-test.netlify.app/posts/lume-1.17.0-release-notes/#sass-supports-remote-files\" class=\"header-anchor\">SASS supports remote files</a></h2>\n<p>In this version, Lume got a big refactoring of how the files in the <code>src</code>\ndirectory are scanned, loaded and refreshed. This change fixed some existing\nbugs and open the door for new possibilities, because now it will be easier to\nimplement new features.</p>\n<p>Thanks to this refactoring, SASS plugin supports\n<a href=\"https://lume.land/docs/core/remote-files/\">remote files</a>, so you can load your\nvariables and mixings from a remote URL to use them in your build:</p>\n<pre><code class=\"language-ts\">import lume from &quot;lume/mod.ts&quot;;\nimport sass from &quot;lume/plugins/sass.ts&quot;;\n\nconst site = lume();\nsite.use(sass());\n\nsite.remoteFile(\n  &quot;/_includes/variables.scss&quot;,\n  &quot;https://example.com/theme/variables.scss&quot;,\n);\n\nexport default site;\n</code></pre>\n<pre><code class=\"language-css\">@import &quot;variables.scss&quot;;\n\nbody {\n  color: $main-color;\n}\n</code></pre>\n<p>The're a breaking change in the SASS plugin: the <code>includes</code> option accepts only\na string instead of an array of paths.</p>\n<h2 id=\"allow-to-pass-extra-data-to-on-demand-pages\" tabindex=\"-1\"><a href=\"https://aoba-test.netlify.app/posts/lume-1.17.0-release-notes/#allow-to-pass-extra-data-to-on-demand-pages\" class=\"header-anchor\">Allow to pass extra data to on demand pages</a></h2>\n<p>The <a href=\"https://lume.land/plugins/on_demand/\">on_demand plugin</a> allows to render a\npage on request time, instead of build time. This is useful to insert dynamic\ncontent and reduce the build time specially for big sites. Lume 1.17 introduces\na way to insert additional variables to the page before rendering.</p>\n<p>The <code>onDemand</code> plugin has the new option <code>extraData</code> which accepts a function\nthat must return an object with the extra data to be passed to the page. For\nexample, let's say we want to pass the search parameters of the request's url:</p>\n<pre><code class=\"language-ts\">import lume from &quot;lume/mod.ts&quot;;\nimport onDemand from &quot;lume/plugins/on_demand.ts&quot;;\n\nsite.use(onDemand({\n  extraData(request: Request) {\n    const searchParams = new URL(request.url).searchParams;\n    const params = Object.fromEntries(searchParams.entries());\n\n    return {\n      params,\n    };\n  },\n}));\n\nexport default site;\n</code></pre>\n<p>Now, the on demand pages will have the <code>params</code> key with the search params\nvalues. For example, in a Nunjucks page:</p>\n<pre><code class=\"language-njk\">---\nlayout: layout.njk\nondemand: true\nurl: /example/\n---\n\nHello {{ params.name }}\n</code></pre>\n<p>The URL <code>/example/?name=Óscar</code> will return <code>Hello Òscar</code>.</p>\n<p>Note that on-demand pages works better on Deno CLI than Deno Deploy. There's a\n<a href=\"https://aoba-test.netlify.app/posts/lume-1.17.0-release-notes/ondemand-plugin-november-2022.md\">post explaining the current limitations on Deno Deploy</a>,\nso you should consider this plugin as highly experimental.</p>\n<h2 id=\"removed-old-code\" tabindex=\"-1\"><a href=\"https://aoba-test.netlify.app/posts/lume-1.17.0-release-notes/#removed-old-code\" class=\"header-anchor\">Removed old code</a></h2>\n<p>A few versions ago, Lume removed the ability to be installed globally (with\n<code>deno install ...</code>) in benefit of <code>deno task</code>. Some old files were keept for\nbackward compatibility when upgrading from an old version. Now these files were\nremoved (<code>ci.ts</code>, <code>install.ts</code>). If you get any issue running Lume (specially in\nCI environments), please update your script to use <code>deno task lume</code>.</p>\n<p>There are more changes in Lume 1.17, like bug fixes in some plugins, dependency\nupdates, etc. See the\n<a href=\"https://github.com/lumeland/lume/blob/v1.17.0/CHANGELOG.md\">CHANGELOG.md file</a>\nfor the full list of changes.</p>\n","date_published":"Fri, 05 May 2023 00:00:00 GMT"},{"id":"https://aoba-test.netlify.app/posts/lume-1.16.0-release-notes/","url":"https://aoba-test.netlify.app/posts/lume-1.16.0-release-notes/","title":"Lume 1.16.0 release notes","content_html":"<p>Hi everyone! This is a brief summary of what the new version of Lume\n(<strong>1.16.0</strong>) brings.</p>\n<!-- more -->\n<h2 id=\"breaking-change%3A-multilanguage-plugin-refactor\" tabindex=\"-1\"><a href=\"https://aoba-test.netlify.app/posts/lume-1.16.0-release-notes/#breaking-change%3A-multilanguage-plugin-refactor\" class=\"header-anchor\">BREAKING CHANGE: <code>multilanguage</code> plugin refactor</a></h2>\n<p>The <code>multilanguage</code> plugin was created to simplify the creation of sites in\nmultiple languages. But the way it worked so far was a bit confusing and not\nvery practical. Lume 1.16 introduce some changes that (sadly) breaks some\ncompatibility with the previous version. But I think the new behavior is much\nmore clear and easy to use and understand. Some of the most important changes:</p>\n<h3 id=\"you-need-to-specify-the-available-languages-in-the-_config-file\" tabindex=\"-1\"><a href=\"https://aoba-test.netlify.app/posts/lume-1.16.0-release-notes/#you-need-to-specify-the-available-languages-in-the-_config-file\" class=\"header-anchor\">You need to specify the available languages in the _config file</a></h3>\n<p>In the old plugin, each page defined its own languages. There wasn't a place to\nspecify the available languages for the whole site. This makes the plugin to\nwork inconsistently for each page, because it depended on the number of\nlanguages defined in every case. The new version requires to specify the\nlanguages in the _config file, so it will work in the same way with all pages.</p>\n<pre><code class=\"language-ts\">site.use(multilanguage({\n  languages: [&quot;en&quot;, &quot;gl&quot;],\n}));\n</code></pre>\n<h3 id=\"the-language-prefix-is-automatically-added-to-the-urls.\" tabindex=\"-1\"><a href=\"https://aoba-test.netlify.app/posts/lume-1.16.0-release-notes/#the-language-prefix-is-automatically-added-to-the-urls.\" class=\"header-anchor\">The language prefix is automatically added to the urls.</a></h3>\n<p>The new plugin automatically prepend the <code>/${lang}/</code> prefix to all urls. If you\nhave the following page:</p>\n<pre><code class=\"language-md\">---\nlang: en\nurl: /hello-world/\n---\n\n# Hello world\n</code></pre>\n<p>The output file is <code>/en/hello-world/</code>. This ensure all pages in the same\nlanguage are in the same subdirectory.</p>\n<p>It's possible to define a language as default, so all pages in this language\nwon't have this prefix. For example, let's say our site is in english and\ngalician but we want to set english as the main language:</p>\n<pre><code class=\"language-ts\">site.use(multilanguage({\n  languages: [&quot;en&quot;, &quot;gl&quot;],\n  defaultLanguage: &quot;en&quot;,\n}));\n</code></pre>\n<p>With this configuration, the english version of the page is <code>/hello-world/</code> but\nthe galician version is <code>/gl/hello-world/</code>.</p>\n<h3 id=\"use-id-to-relate-pages-in-different-languages\" tabindex=\"-1\"><a href=\"https://aoba-test.netlify.app/posts/lume-1.16.0-release-notes/#use-id-to-relate-pages-in-different-languages\" class=\"header-anchor\">Use <code>id</code> to relate pages in different languages</a></h3>\n<p>In the old version, to setup multiple versions of the same page in individual\nfiles, you had to follow some strict instructions:</p>\n<ul>\n<li>All files must be in the same folder.</li>\n<li>They must have the same name, suffixed with the language.</li>\n</ul>\n<p>For example:</p>\n<pre><code>- /about-me_en.md\n- /about-me_gl.md\n</code></pre>\n<p>The new plugin removes this behavior. You have to use the <code>id</code> variable to\nrelate different pages.</p>\n<p>For example, the english version:</p>\n<pre><code class=\"language-md\">---\nlang: en\nurl: /about-me/\nid: about\n---\n\n# About me\n</code></pre>\n<p>The galician version:</p>\n<pre><code class=\"language-md\">---\nlang: gl\nurl: /acerca-de-min/\nid: about\n---\n\n# Acerca de min\n</code></pre>\n<p>The new plugin interprets these two pages as the same content but in different\nlanguages, because they have the same id (<code>about</code>). You don't need to have all\nfiles in the same folder with a specific name.</p>\n<p>See the\n<a href=\"https://lume.land/plugins/multilanguage/\">complete plugin documentation</a>.</p>\n<h2 id=\"new-nav-plugin\" tabindex=\"-1\"><a href=\"https://aoba-test.netlify.app/posts/lume-1.16.0-release-notes/#new-nav-plugin\" class=\"header-anchor\">New <code>nav</code> plugin</a></h2>\n<p>The <code>nav</code> plugin builds automatically a menu of your site using the URLs to\ndefine the hierarchy. For example, let's say we have a site which exports the\nfollowing pages:</p>\n<ul>\n<li><code>/</code></li>\n<li><code>/articles/</code></li>\n<li><code>/articles/first-article/</code></li>\n<li><code>/articles/second-article/chapter-1/</code></li>\n<li><code>/articles/second-article/chapter-2/</code></li>\n</ul>\n<p>This plugin register the <code>nav</code> variable in your templates, similar to\n<a href=\"https://lume.land/plugins/search/\"><code>search</code></a> but intended for navigation stuff.\nThe <code>nav</code> variable has some useful functions:</p>\n<h3 id=\"menu\" tabindex=\"-1\"><a href=\"https://aoba-test.netlify.app/posts/lume-1.16.0-release-notes/#menu\" class=\"header-anchor\">Menu</a></h3>\n<p>The <code>nav.menu()</code> function returns an object with the site structure, so you can\nbuild a tree menu:</p>\n<pre><code class=\"language-ts\">const tree = nav.menu();\n\nconsole.log(tree);\n\n{\n  slug: &quot;&quot;,\n  data: Data,\n  children: [\n    {\n      slug: &quot;articles&quot;,\n      data: Data,\n      children: [\n        {\n          slug: &quot;first-article&quot;,\n          data: Data,\n        },\n        {\n          slug: &quot;second-article&quot;,\n          children: [\n            {\n              slug: &quot;chapter-1&quot;,\n              data: Data,\n            },\n            {\n              slug: &quot;chapter-2&quot;,\n              data: Data,\n            },\n          ],\n        },\n      ],\n    },\n  ];\n}\n</code></pre>\n<ul>\n<li>The <code>data</code> property contains the page data object. So you can access to any\npage variable like <code>data.title</code> or <code>data.url</code>.</li>\n<li>The item with the slug <code>second-article</code> doesn't have the <code>data</code> value because\nthere isn't any page with the url <code>/articles/second-article/</code>. Note that there\nare pages inside this url (<code>/articles/second-page/chapter-1/</code> and\n<code>/articles/second-page/chapter-2/</code>) that do have the <code>data</code> value.</li>\n</ul>\n<h3 id=\"breadcrumb\" tabindex=\"-1\"><a href=\"https://aoba-test.netlify.app/posts/lume-1.16.0-release-notes/#breadcrumb\" class=\"header-anchor\">Breadcrumb</a></h3>\n<p>The <code>nav.breadcrumb()</code> function returns all parent pages of a specific page. For\nexample:</p>\n<pre><code class=\"language-ts\">const breadcrumb = nav.breadcrumb(&quot;/articles/second-article/chapter-2/&quot;);\n\nconsole.log(breadcrumb);\n\n[\n  {\n    slug: &quot;chapter-2&quot;,\n    data: Data,\n  },\n  {\n    slug: &quot;second-article&quot;,\n    children: ...\n  },\n  {\n      slug: &quot;articles&quot;,\n      data: Data,\n      children: ...\n  },\n  {\n    slug: &quot;&quot;,\n    data: Data,\n    children: ...\n  },\n]\n</code></pre>\n<p>You can see an example of the nav plugin in the\n<a href=\"https://lumeland.github.io/theme-simple-wiki/posts/firstpost/\">Simple Wiki theme</a>.</p>\n<ul>\n<li>The lateral menu is built with <code>nav.menu()</code>\n(<a href=\"https://github.com/lumeland/theme-simple-wiki/blob/main/src/_includes/templates/menu.njk\">see the code</a>)</li>\n<li>The breadcrumb above the title is built with <code>nav.breadcrumb()</code>\n(<a href=\"https://github.com/lumeland/theme-simple-wiki/blob/main/src/_includes/templates/breadcrumb.njk\">see the code</a>)</li>\n</ul>\n<p>See the <a href=\"https://lume.land/plugins/nav/\">plugin documentation</a> for more details.</p>\n<h2 id=\"new-copyremainingfiles-function\" tabindex=\"-1\"><a href=\"https://aoba-test.netlify.app/posts/lume-1.16.0-release-notes/#new-copyremainingfiles-function\" class=\"header-anchor\">New <code>copyRemainingFiles</code> function</a></h2>\n<p>Until now, the only way to copy static files was using the <code>site.copy()</code>\nfunction, that allows to specify a file/folder or an array of extensions. This\nworks fine if you know in advance all files that must be copied, because they\nare in a specific folder like <code>/static</code> or have a known extension (<code>.jpg</code>,\n<code>.png</code>, etc).</p>\n<p>But it's not practical when your static files are distributed in random folders\nor can have any extension. For example, imagine you have a website with\narticles, and every article is stored in it's folder that can contain static\nfiles of any extension:</p>\n<pre><code>|_ articles/\n    |_ article-1/\n    |   |_ index.md\n    |   |_ picture.jpg\n    |   |_ document.pdf\n    |   |_ foo32.gif\n    |_ article-2/\n        |_ index.md\n        |_ journey.mp4\n        |_ download.zip\n</code></pre>\n<p>The <code>site.copy()</code> function it's not very helpful because if we copy the\n<code>/articles/</code> folder, the <code>index.md</code> files won't be processed (they will be\ntreated as static files). We can select the files by extension with\n<code>site.copy([&quot;.jpg&quot;, &quot;.pdf&quot;, &quot;.gif&quot;, &quot;.mp4&quot;, &quot;.zip&quot;])</code> but every time a new\nextension is uploaded, we have to remember to include it in the <code>_config</code> file.</p>\n<p>The <code>copyRemainingFiles()</code> basically says: <strong>when you find a file and don't know\nwhat to do, just copy it.</strong> You can include a function to filter which files\nwill be copied. For example:</p>\n<pre><code class=\"language-ts\">site.copyRemainingFiles((path: string) =&gt; path.startsWith(&quot;/articles/&quot;));\n</code></pre>\n<p>Now, only the remaining files inside the <code>/articles/</code> folder will be copied.</p>\n<p>More info\n<a href=\"https://lume.land/docs/configuration/copy-static-files/#copy-remaining-files\">in the documentation site</a>.</p>\n<h2 id=\"page.data.children-property\" tabindex=\"-1\"><a href=\"https://aoba-test.netlify.app/posts/lume-1.16.0-release-notes/#page.data.children-property\" class=\"header-anchor\"><code>page.data.children</code> property</a></h2>\n<p>Let's say you have a blog and want to list all posts with their content. It's\npossible with this code:</p>\n<pre><code class=\"language-njk\">{% for post in search.pages(&quot;type=post&quot;) %}\n  &lt;h1&gt;{{ post.data.title }}&lt;/h1&gt;\n  {{ post.data.content | md | safe }}\n{% endfor %}\n</code></pre>\n<p>If the post are written in Markdown, the variable <code>post.data.content</code> of the\npage has the unrendered markdown code, so you have to use the <code>md</code> filter to\nrender it to HTML. This has the drawback of every post need to be rendered\ntwice, one to build the post page and other to build this list of posts.</p>\n<p>If your posts are in <code>MDX</code> this is even worse, because there's no filter to\nconvert <code>mdx</code> code to HTML. It's possible to get the rendered content of the\npage from <code>post.content</code> but it includes not only the HTML of the post but also\nthe layout used in this page.</p>\n<p>As of version 1.16, Lume will save the rendered content into the <code>children</code>\nproperty, so you can use it in other pages in this way:</p>\n<pre><code class=\"language-njk\">{% for post in search.pages(&quot;type=post&quot;) %}\n  &lt;h1&gt;{{ post.data.title }}&lt;/h1&gt;\n  {{ post.data.children | safe }}\n{% endfor %}\n</code></pre>\n<p>The content will be rendered only once and no filter is needed.</p>\n<p>There are more interesting things in Lume v1.16.0. See the\n<a href=\"https://github.com/lumeland/lume/blob/v1.16.0/CHANGELOG.md\">CHANGELOG.md file</a>\nfor the full list of changes.</p>\n","date_published":"Tue, 21 Mar 2023 00:00:00 GMT"},{"id":"https://aoba-test.netlify.app/posts/lume-1.15.0-release-notes/","url":"https://aoba-test.netlify.app/posts/lume-1.15.0-release-notes/","title":"Lume 1.15.0 - Release notes","content_html":"<p>The version <strong>1.15.0</strong> is full of exciting new features.</p>\n<!-- more -->\n<h2 id=\"archetypes\" tabindex=\"-1\"><a href=\"https://aoba-test.netlify.app/posts/lume-1.15.0-release-notes/#archetypes\" class=\"header-anchor\">Archetypes</a></h2>\n<p><a href=\"https://gohugo.io/content-management/archetypes/\">Hugo has a nice feature called <strong>archetypes</strong></a>,\ntemplates used when creating new content. The most obvious example is a post:\ninstead of creating a new markdown file from scratch everytime you want to\ncreate a new post, you can run an archetype that creates the post file for you\nwith a preconfigured front matter and content.</p>\n<p>In Lume, an archetype is just a JavaScript or TypeScript file that export a\nfunction returning an object with the file path and the file content. The\narchetype must be saved in the <code>_archetypes</code> directory, inside the <code>src</code> folder.\nFor example:</p>\n<pre><code class=\"language-ts\">// _archetypes/example.js\n\nexport default function () {\n  return {\n    path: &quot;/pages/example.md&quot;,\n    content: &quot;Content of the file&quot;,\n  };\n}\n</code></pre>\n<p>The archetypes are invoked with the command\n<code>deno task lume new [archetype-name]</code> (or <code>lume new [archetype-name]</code> with the\nnew <a href=\"https://aoba-test.netlify.app/posts/lume-1.15.0-release-notes/lume-cli.md\">Lume CLI</a>). If you run <code>lume new example</code> to run this\narchetype, the file <code>/pages/example.md</code> will be created.</p>\n<p>See the <a href=\"https://lume.land/docs/core/archetypes/\">archetypes documentation</a> to\nlearn more about how to generate different formats, pass arguments or create\nmultiple files.</p>\n<h2 id=\"tailwindcss\" tabindex=\"-1\"><a href=\"https://aoba-test.netlify.app/posts/lume-1.15.0-release-notes/#tailwindcss\" class=\"header-anchor\">Tailwindcss</a></h2>\n<p><a href=\"https://tailwindcss.com/\">Tailwind</a> support is a recurring request for Lume.\nUntil now it was not possible to use Tailwind in Deno, so the only alternative\navailable was <a href=\"https://lume.land/plugins/windi_css/\">Windi CSS</a>.</p>\n<p>The support of <code>npm:</code> packages in Deno allowed to use many NPM packages that\nuntil now only work on Node. Still, there were errors in Tailwind due the\n<a href=\"https://www.npmjs.com/package/acorn-node\"><code>acorn-node</code></a> dependency that doesn't\nwork on Deno.</p>\n<p>The <a href=\"https://www.npmjs.com/search?q=%40lumeland\"><code>@lumeland</code></a> organization in\nNPM contains modified versions of the packages that don't work in Deno.\n<a href=\"https://www.npmjs.com/package/@lumeland/tailwindcss\"><code>@lumeland/tailwindcss</code></a>\nis the same code as <a href=\"https://www.npmjs.com/package/tailwindcss\"><code>tailwindcss</code></a>\nbut replacing that dependency. When this is fixed in the official library, this\nmodified version will be deprecated.</p>\n<p>The Tailwindcss plugin depends on <code>postcss</code>, so you need to use both plugins in\nthis exact order:</p>\n<pre><code class=\"language-ts\">import lume from &quot;lume/mod.ts&quot;;\nimport tailwind from &quot;lume/plugins/tailwindcss.ts&quot;;\nimport postcss from &quot;lume/plugins/postcss.ts&quot;;\n\nconst site = lume();\n\nsite.use(tailwind());\nsite.use(postcss());\n\nexport default site;\n</code></pre>\n<h2 id=\"context-data\" tabindex=\"-1\"><a href=\"https://aoba-test.netlify.app/posts/lume-1.15.0-release-notes/#context-data\" class=\"header-anchor\">Context data</a></h2>\n<p>The function <code>site.data()</code> allows to insert arbitrary data in your site from the\n<code>_config.ts</code> file:</p>\n<pre><code class=\"language-ts\">site.data(&quot;layout&quot;, &quot;main.njk&quot;);\n</code></pre>\n<p>The context of this data is global: is available to all pages of the site. It's\nequivalent to having a <code>_data.*</code> file in the root of your site. As of Lume\n1.15.0, it's possible to specify the directory of the data in the third\nargument, for example:</p>\n<pre><code class=\"language-ts\">site.data(&quot;layout&quot;, &quot;main.njk&quot;, &quot;/posts&quot;);\n</code></pre>\n<p>Now, the <code>layout</code> value is available only to the pages inside the <code>/posts</code>\ndirectory. Equivalent to creating a <code>/posts/_data.yml</code> file with this value.</p>\n<p>You can assign data not only to directories but also to specific files:</p>\n<pre><code class=\"language-ts\">site.data(&quot;layout&quot;, &quot;main.njk&quot;, &quot;/posts/hello-world.md&quot;);\n</code></pre>\n<h2 id=\"%F0%9F%92%A3-breaking-changes-in-the-plugin-date\" tabindex=\"-1\"><a href=\"https://aoba-test.netlify.app/posts/lume-1.15.0-release-notes/#%F0%9F%92%A3-breaking-changes-in-the-plugin-date\" class=\"header-anchor\">💣 Breaking changes in the plugin <code>date</code></a></h2>\n<p>The <code>date</code> plugin use the\n<a href=\"https://deno.land/x/date_fns@v2.15.0\">Deno version of <code>date_fns</code></a> to transform\nthe dates. That version wasn't updated in 2 years so I decided to switch to\n<a href=\"https://www.npmjs.com/package/date-fns\">the Node version</a>. Everything should\nwork fine, the only difference is the locales configuration, that need to be\nimported from npm in the _config file. For example, if you have this\nconfiguration:</p>\n<pre><code class=\"language-ts\">site.use(date({\n  locales: [&quot;gl&quot;, &quot;pt&quot;],\n}));\n</code></pre>\n<p>You need to change it to:</p>\n<pre><code class=\"language-ts\">import gl from &quot;npm:date-fns/locale/gl/index.js&quot;;\nimport pt from &quot;npm:date-fns/locale/pt/index.js&quot;;\n\n//...\nsite.use(date({\n  locales: { gl, pt },\n}));\n</code></pre>\n<h2 id=\"other-changes\" tabindex=\"-1\"><a href=\"https://aoba-test.netlify.app/posts/lume-1.15.0-release-notes/#other-changes\" class=\"header-anchor\">Other changes</a></h2>\n<ul>\n<li>The <code>sass</code> plugin uses now a\n<a href=\"https://www.npmjs.com/package/@lumeland/sass\">modified version</a> of the\nofficial NPM package.</li>\n<li>The <code>relations</code> plugin has been improved and there are some breaking changes\nin the configuration API.\n<a href=\"https://lume.land/plugins/relations/\">See the plugin page</a> for the updated\ndocumentation.</li>\n<li>Dependency update and bugfixes.</li>\n</ul>\n<p>See the\n<a href=\"https://github.com/lumeland/lume/blob/v1.15.0/CHANGELOG.md\">CHANGELOG.md file</a>\nfor the full list of changes.</p>\n","date_published":"Tue, 10 Jan 2023 00:00:00 GMT"},{"id":"https://aoba-test.netlify.app/posts/lume-cli/","url":"https://aoba-test.netlify.app/posts/lume-cli/","title":"Lume CLI","content_html":"<p>Happy new year, Lumers!</p>\n<p>2022 was a great year for Lume, it reached to 1K stars in GitHub and many of you\nhave collaborated in form of pull requests, promoting Lume in your blogs and\nsocial networks or\n<a href=\"https://github.com/sponsors/oscarotero/\">even sponsoring me</a>. I want to thank\nyou and promise to keep working hard to make Lume even better.</p>\n<p>🔥🔥🔥🔥🔥🔥🔥🔥🔥</p>\n<!-- more -->\n<h2 id=\"introducing-lume-cli\" tabindex=\"-1\"><a href=\"https://aoba-test.netlify.app/posts/lume-cli/#introducing-lume-cli\" class=\"header-anchor\">Introducing Lume CLI</a></h2>\n<p>The best way to run Lume is using the Deno tasks. It's the most portable way to\nrun Lume without installing anything else but Deno, and it ensures that the Lume\nversion is the same as specified in the <code>import_map.json</code> file. In fact,\n<a href=\"https://github.com/lumeland/lume/issues/232\">there's a plan to remove the CLI interface</a>\ncompletely.</p>\n<p>The only drawback of using Deno tasks is they are more verbose to type. Instead\nof simply running <code>lume -s</code> or <code>lume run my-script</code> you have to type\n<code>deno task lume -s</code> and <code>deno task lume run my-script</code>.</p>\n<p>In order to keep using tasks to run Lume and, at the same time, having a more\nergonomic way to run the commands, I have released the new\n<a href=\"https://deno.land/x/lume_cli\">Lume CLI</a>.</p>\n<p>To install it, just run:</p>\n<pre><code>deno install --allow-run --name lume --force --reload https://deno.land/x/lume_cli/mod.ts\n</code></pre>\n<p>Lume CLI is just a small script to add the <code>deno task</code> words at the beginning of\nyour lume commands. For example, if you run <code>lume -s</code>, the CLI will run\n<code>deno task lume -s</code>.</p>\n<p>It's an independent module, separated from the Lume repository, so it's up to\nyou to use it or not.</p>\n<p>It also includes two additional commands:</p>\n<ul>\n<li><code>lume init</code>: To initialise Lume in the current directory. It's like running\n<code>deno run -Ar https://deno.land/x/lume/init.ts</code>.</li>\n<li><code>lume ugrade-cli</code>: As you may guess, it will upgrade the Lume CLI to the\nlatest version.</li>\n</ul>\n<p>Lume CLI combines the best of the two worlds and opens the door to removing the\nold CLI interface in the Lume repo sometime soon.</p>\n","date_published":"Fri, 06 Jan 2023 00:00:00 GMT"},{"id":"https://aoba-test.netlify.app/posts/lume-1.14.0-release/","url":"https://aoba-test.netlify.app/posts/lume-1.14.0-release/","title":"Lume 1.14.0 is out","content_html":"<p>Lume <code>1.14.0</code> was released. This is a list of the main changes and new features.</p>\n<!-- more -->\n<h2 id=\"new-functions-to-(pre)process-all-pages-at-the-same-time\" tabindex=\"-1\"><a href=\"https://aoba-test.netlify.app/posts/lume-1.14.0-release/#new-functions-to-(pre)process-all-pages-at-the-same-time\" class=\"header-anchor\">New functions to (pre)process all pages at the same time</a></h2>\n<p>The functions <code>site.process()</code> and <code>site.preprocess()</code> are used to modify pages\nafter or before rendering. For example, to process the HTML pages, you can do:</p>\n<pre><code class=\"language-js\">site.process([&quot;.html&quot;], (page) =&gt; my_processor(page));\n</code></pre>\n<p>This callback is executed once per page, so if you have 200 pages, the callback\nis executed 200 times.</p>\n<p>This is great to transform pages individually, but sometimes it's better to run\nthe function only once to all pages at the same time. Two new functions were\nadded for this purpose: <code>processAll()</code> and <code>preprocessAll()</code>. They are similar\nto <code>process()</code> and <code>preprocess()</code> but will receive all matched pages in the\nfirst argument:</p>\n<pre><code class=\"language-js\">site.processAll([&quot;.html&quot;], (pages) =&gt; {\n  pages.forEach((page) =&gt; my_processor(page));\n  console.log(`Processed ${pages.length} HTML pages!`);\n});\n</code></pre>\n<p>In previous versions, the only way to do something like that was through events\nlike <code>afterRender</code>, <code>beforeRender</code>, <code>beforeSave</code>, etc. The advantage of using\nthe new <code>processAll</code> and <code>preprocessAll</code> is they respect the order of the other\nprocessors:</p>\n<pre><code class=\"language-js\">site.process([&quot;.html&quot;], first_processor);\nsite.processAll([&quot;.html&quot;], second_processor);\nsite.process([&quot;.html&quot;], third_processor);\n</code></pre>\n<p>In this example, <code>second_processor</code> is run after <code>first_processor</code> and before\n<code>third_processor</code>.</p>\n<h2 id=\"introducing-hooks\" tabindex=\"-1\"><a href=\"https://aoba-test.netlify.app/posts/lume-1.14.0-release/#introducing-hooks\" class=\"header-anchor\">Introducing <code>hooks</code></a></h2>\n<p>Hooks are functions registered by some plugins that can be invoked by other\nplugins or by yourself in the <code>_config</code> file. Hooks are stored in <code>site.hooks</code>\nand are useful to change a plugin configuration after the installation. For\nexample, the <code>postcss</code> plugin sets the hook <code>addPostcssPlugin</code>. You can create a\nLume plugin to, for example, minify the css code with\n<a href=\"https://cssnano.co/\">CSS Nano</a>:</p>\n<pre><code class=\"language-js\">import cssnano from &quot;npm:cssnano@5.1.14&quot;;\n\nexport default function () {\n  return (site) =&gt; {\n    if (!site.hooks.addPostcssPlugin) {\n      throw new Error(&quot;This plugin depends on postcss&quot;);\n    }\n\n    site.hooks.addPostcssPlugin(cssnano);\n  };\n}\n</code></pre>\n<p>Now, you can use this plugin in the <code>_config.ts</code> file:</p>\n<pre><code class=\"language-ts\">import lume from &quot;lume/mod.ts&quot;;\nimport postcss from &quot;lume/plugins/postcss.ts&quot;;\nimport nanocss from &quot;./plugins/nanocss.ts&quot;;\n\nconst site = lume();\n\nsite.use(postcss());\nsite.use(nanocss());\n\nexport default site;\n</code></pre>\n<h2 id=\"support-for-splitting-mode-for-esbuild\" tabindex=\"-1\"><a href=\"https://aoba-test.netlify.app/posts/lume-1.14.0-release/#support-for-splitting-mode-for-esbuild\" class=\"header-anchor\">Support for <code>splitting</code> mode for esbuild</a></h2>\n<p><a href=\"https://esbuild.github.io/api/#splitting\">Code splitting</a> is a bundle technique\nthat creates separate files with common code shared by multiple entry points.\nFor example, if both entry points <code>a.ts</code> and <code>b.ts</code> imports <code>c.ts</code>, instead of\nincluding the <code>c.ts</code> code in both files (which would be duplicated), the code is\nsaved into a <em>chunk</em> file that is imported by both files.</p>\n<p>To generate the <em>chunk</em> files, we need to know all entry points first. But\nthanks to the implementation of <code>processAll()</code> function (previously explained)\nthis is now possible in Lume. To enable the splitting mode, just need to\nconfigure the esbuild plugin in this way:</p>\n<pre><code class=\"language-js\">site.use(esbuild({\n  options: {\n    splitting: true,\n  },\n}));\n</code></pre>\n<h2 id=\"improved-metas-plugin\" tabindex=\"-1\"><a href=\"https://aoba-test.netlify.app/posts/lume-1.14.0-release/#improved-metas-plugin\" class=\"header-anchor\">Improved <code>metas</code> plugin</a></h2>\n<p>A couple of improvements have been added to <code>metas</code>:</p>\n<h3 id=\"no-need-for-mergedkeys\" tabindex=\"-1\"><a href=\"https://aoba-test.netlify.app/posts/lume-1.14.0-release/#no-need-for-mergedkeys\" class=\"header-anchor\">No need for <code>mergedKeys</code></a></h3>\n<p>The <code>metas</code> plugin needs a <code>mergedKeys</code> to customise the merging mode of the\n<code>metas</code> key:</p>\n<pre><code class=\"language-yml\">metas:\n  site: Site title\n  icon: /img/icon.png\n  lang: en\n\n# Customise the merging mode of &quot;metas&quot;\nmergedKeys:\n  metas: object\n</code></pre>\n<p>You no longer need to add this value manually. The plugin inserts it\nautomatically for you.</p>\n<h3 id=\"field-aliases\" tabindex=\"-1\"><a href=\"https://aoba-test.netlify.app/posts/lume-1.14.0-release/#field-aliases\" class=\"header-anchor\">Field aliases</a></h3>\n<p>Field aliases are the new way to reuse a value in the <code>metas</code>. For example:</p>\n<pre><code class=\"language-yml\">title: This is the title\n\nmetas:\n  title: &quot;=title&quot; # Alias to the title value\n</code></pre>\n<p>Any value starting with <code>=</code> is considered an alias to another field. You can use\ndots for subvalues:</p>\n<pre><code class=\"language-yml\">title: This is the title\nintro:\n  text: Page description\nmetas:\n  title: &quot;=title&quot;\n  description: &quot;=intro.text&quot;\n</code></pre>\n<p>Field aliases are way more powerful than the <code>defaultPageData</code> option of the\nplugin, which <strong>is deprecated and will be removed in the future</strong>.</p>\n<ul>\n<li>Field aliases supports subvalues.</li>\n<li>They can be configured at page or folder level with <code>_data</code> files.</li>\n</ul>\n<h2 id=\"changes-to-prism-plugin\" tabindex=\"-1\"><a href=\"https://aoba-test.netlify.app/posts/lume-1.14.0-release/#changes-to-prism-plugin\" class=\"header-anchor\">Changes to <code>prism</code> plugin</a></h2>\n<p>The <a href=\"https://lume.land/plugins/prism/\">prism plugin</a> now loads the\n<a href=\"https://prismjs.com/\">Prism</a> library from <code>npm:</code>. This change removes the\n<code>languages</code> option so if you need to load additional languages, you have to\nimport them in your <code>_config.ts</code> file:</p>\n<pre><code class=\"language-ts\">import lume from &quot;lume/mod.ts&quot;;\nimport prism from &quot;lume/plugins/prism.ts&quot;;\n\n// Additional prism languages\nimport &quot;npm:prismjs@1.29.0/components/prism-less.js&quot;;\nimport &quot;npm:prismjs@1.29.0/components/prism-git.js&quot;;\n\nconst site = lume();\nsite.use(prism());\n\nexport default site;\n</code></pre>\n<p>The good news is you can also <a href=\"https://prismjs.com/#plugins\">load plugins</a>.</p>\n<h2 id=\"new-plugin-filter_pages\" tabindex=\"-1\"><a href=\"https://aoba-test.netlify.app/posts/lume-1.14.0-release/#new-plugin-filter_pages\" class=\"header-anchor\">New plugin <code>filter_pages</code></a></h2>\n<p>This plugin is the first step to deprecate the <code>--dev</code> mode of Lume (that\nignores the pages with <code>draft=true</code>). The new plugin <code>filter_pages</code> filters\npages using a callback and provides more flexibility. For example, let's say you\nwant to ignore the <code>draft</code> pages in the production environment:</p>\n<pre><code class=\"language-ts\">import lume from &quot;lume/mod.ts&quot;;\nimport filter_pages from &quot;lume/plugins/filter_pages.ts&quot;;\n\nconst site = lume();\nconst isProd = Deno.env.get(&quot;DENO_ENV&quot;) === &quot;prod&quot;;\n\nsite.use(filter_pages({\n  fn: (page) =&gt; !isProd || !page.data.draft,\n}));\n\nexport default site;\n</code></pre>\n<p>See the\n<a href=\"https://github.com/lumeland/lume/blob/v1.14.0/CHANGELOG.md\">CHANGELOG.md file</a>\nfor the full list of changes.</p>\n","date_published":"Mon, 12 Dec 2022 00:00:00 GMT"},{"id":"https://aoba-test.netlify.app/posts/ondemand-plugin-november-2022/","url":"https://aoba-test.netlify.app/posts/ondemand-plugin-november-2022/","title":"How to use the \"on demand\" plugin in November 2022","content_html":"<p>The <a href=\"https://lume.land/plugins/on_demand/\"><code>on_demand</code> plugin</a> is the attempt of\nLume to provide some server-side rendering behaviour to a static site. The idea\nis simple: omit some pages in the build process (with <code>ondemand: true</code>) in order\nto build them when they are requested.</p>\n<!-- more -->\n<p>This allows insert dynamic content in the pages like\n<a href=\"https://lume-ondemand.deno.dev/\">in this example</a>, a site with the pages\nshowing the current time. You can see the\n<a href=\"https://github.com/lumeland/test-lume-ondemand\">code repository</a>, where the\ncurrent time is defined as a\n<a href=\"https://github.com/lumeland/test-lume-ondemand/blob/0ea72e6449cd7e6d5ca7013d2a2b0ca0d5e3f5a5/_config.ts#L8\">helper in the <code>_config.ts</code> file</a>\nand then\n<a href=\"https://github.com/lumeland/test-lume-ondemand/blob/0ea72e6449cd7e6d5ca7013d2a2b0ca0d5e3f5a5/_includes/layout.njk#L14\">called in the Nunjucks layout</a>\nused by both pages.</p>\n<p>This plugin was tested only in Deno Deploy but it should work on any hosting\nwith Deno. But it is not all rosy in the garden, because Deno Deploy has some\nlimitations that makes more difficult to use this plugin, compared with the Deno\nCLI that you have installed locally:</p>\n<h2 id=\"no-support-for-dynamic-imports\" tabindex=\"-1\"><a href=\"https://aoba-test.netlify.app/posts/ondemand-plugin-november-2022/#no-support-for-dynamic-imports\" class=\"header-anchor\">No support for dynamic imports</a></h2>\n<p>One of the\n<a href=\"https://github.com/denoland/deploy_feedback/issues/1\">most requested features</a>\nin Deno Deploy is the ability to import modules dynamically. One year and half\nsince the issue was created, it's still not possible and looks like it won't be\nin the short term. Lume uses dynamic imports to load pages and data in\nJavaScript, JSX and TypeScript, so if your on demand pages use any of these\nformats, they will fail on Deno Deploy. The only way to skip this limitation is\nby generating a file that imports statically all files that, under normal\nconditions, would be imported dynamically (this file is generated automatically\n<a href=\"https://lume.land/plugins/on_demand/#preload-modules\">by the ondemand plugin</a>).\nIt's not an elegant solution but it's the only solution that works at this\nmoment.</p>\n<h2 id=\"no-support-for-npm-modules\" tabindex=\"-1\"><a href=\"https://aoba-test.netlify.app/posts/ondemand-plugin-november-2022/#no-support-for-npm-modules\" class=\"header-anchor\">No support for NPM modules</a></h2>\n<p>As of version 1.12.0, Lume uses <code>npm:</code> modules for some dependencies. NPM\nespecifiers\n<a href=\"https://github.com/denoland/deploy_feedback/issues/314\">are not yet supported in Deno Deploy</a>.\nFortunately we can use import maps to use the esm.sh version of the NPM\npackages. In the repository of the plugin demo, you can\n<a href=\"https://github.com/lumeland/test-lume-ondemand/blob/0ea72e6449cd7e6d5ca7013d2a2b0ca0d5e3f5a5/import_map.json\">see the import_map.json file</a>\nneeded to map all NPM lume dependencies to the esm.sh equivalent.</p>\n<p>And this is the state of the dynamic pages in Lume for now. I hope these\nlimitations disappear in the short term (I guess NPM modules will be supported\nsoon). If you know of other hosting providers with Deno support and you get the\n<code>on demand</code> plugin to work there, please, let me know.</p>\n","date_published":"Tue, 22 Nov 2022 00:00:00 GMT"},{"id":"https://aoba-test.netlify.app/posts/lume-1.13.0-release/","url":"https://aoba-test.netlify.app/posts/lume-1.13.0-release/","title":"Lume 1.13.0 is out","content_html":"<p>I'm happy to announce that Lume <code>1.13.0</code> was released with some interesting\nadditions and changes. Let's see the highlights.</p>\n<!-- More -->\n<h2 id=\"mdx-support\" tabindex=\"-1\"><a href=\"https://aoba-test.netlify.app/posts/lume-1.13.0-release/#mdx-support\" class=\"header-anchor\">MDX support</a></h2>\n<p><a href=\"https://mdxjs.com/\">MDX</a> support for Lume was requested for a long time. Now\nthat Deno can handle <code>npm</code> imports, it's more easy to bring support for this\nlibrary. The new <code>mdx</code> plugin allows to create your pages in <code>.mdx</code>, so you can\ncombine markdown and JSX components in a single file.</p>\n<p>To enable MDX in your site, you only need to import the <code>mdx</code> plugin and any of\nthe JSX plugins available (<code>jsx</code> to use React, <code>jsx_preact</code> to use Preact). This\nis an example with Preact:</p>\n<pre><code class=\"language-js\">import lume from &quot;lume/mod.ts&quot;;\nimport jsx from &quot;lume/plugins/jsx_preact.ts&quot;;\nimport mdx from &quot;lume/plugins/mdx.ts&quot;;\n\nconst site = lume();\n\nsite.use(jsx());\nsite.use(mdx());\n\nexport default site;\n</code></pre>\n<p>Now you can create <code>.mdx</code> files that imports JSX components or use the Lume's\ncomponents from the global <code>comp</code> variable:</p>\n<pre><code class=\"language-md\">---\ntitle: Hello world\ndescription: This is a description\n---\n\nimport Image from &quot;./_includes/Image.tsx&quot;;\n\n&lt;comp.Header title={title} description={description}/&gt;\n\n## Hello world\n\nThis is a markdown file with the title **{ title }**.\n\n&lt;Image alt=&quot;foo&quot; /&gt;\n</code></pre>\n<p><a href=\"https://lume.land/plugins/mdx/\">See more info in the documentation</a></p>\n<h2 id=\"new-sitemap-plugin\" tabindex=\"-1\"><a href=\"https://aoba-test.netlify.app/posts/lume-1.13.0-release/#new-sitemap-plugin\" class=\"header-anchor\">New <code>sitemap</code> plugin</a></h2>\n<p>The <code>sitemap</code> plugin was created by <a href=\"https://github.com/jrson83\">Jrson</a> some\ntime ago in the\n<a href=\"https://github.com/lumeland/experimental-plugins\">experimental plugins repo</a>.\nIt creates a <code>sitemap.xml</code> file and a <code>robots.txt</code> file with a link to the\nsitemap file.</p>\n<p>This plugin is now included in Lume 1.13.0, so you can import it via\n<code>lume/plugins/sitemap.ts</code>.</p>\n<p><a href=\"https://lume.land/plugins/sitemap/\">See more info in the documentation</a></p>\n<h2 id=\"improved-the-multilanguage-plugin\" tabindex=\"-1\"><a href=\"https://aoba-test.netlify.app/posts/lume-1.13.0-release/#improved-the-multilanguage-plugin\" class=\"header-anchor\">Improved the <code>multilanguage</code> plugin</a></h2>\n<p>The <code>multilanguage</code> plugin allows to create multiple language versions of the\nsame page. In Lume <code>v1.13.0</code> it's possible to save the language versions in\ndifferent files. To be identified by the plugin as language versions of the same\npage, the files must fulfill the following requirements:</p>\n<ul>\n<li>They must be saved in the same directory.</li>\n<li>They must have the <code>lang</code> variable defined.</li>\n<li>They must have the same filename ending with the <code>_[lang]</code> suffix.</li>\n</ul>\n<p>For example:</p>\n<pre><code>|_ /posts\n  |_ /my-first-post_en.md\n  |_ /my-first-post_es.md\n</code></pre>\n<p>These two files contains the same post but in different languages and Lume will\ngenerate the pages <code>/en/posts/my-first-post/</code> and <code>/es/posts/my-first-post/</code>.</p>\n<p>It's possible to have one page without the language suffix, useful if you\nalready have a site with only one language and want to add other languages\nprogressively without affeting to the existing urls. For example:</p>\n<pre><code>|_ /posts\n  |_ /my-first-post.md\n  |_ /my-first-post_es.md\n</code></pre>\n<p>In this case, Lume detects they are the same posts but the URLs generated are\n<code>/posts/my-first-post/</code> and <code>/es/posts/my-first-post/</code>.</p>\n<h2 id=\"deprecated-page.dest-and-page.updatedest\" tabindex=\"-1\"><a href=\"https://aoba-test.netlify.app/posts/lume-1.13.0-release/#deprecated-page.dest-and-page.updatedest\" class=\"header-anchor\">Deprecated <code>page.dest</code> and <code>page.updateDest</code></a></h2>\n<p>All pages in Lume have the property <code>dest</code> with info about the destination file.</p>\n<p>The destination is calculated according to the <code>page.data.url</code> value (if\ndefined) or the source file name. More info\n<a href=\"https://lume.land/docs/creating-pages/page-files/\">in the Lume docs</a>.</p>\n<p>The problem is whenever the URL of a page is changed, it's necessary to change\nthe value in two places, <code>page.data.url</code> and <code>page.dest</code>. For example, a SASS\nplugin that modifies the extension of the files from <code>.scss</code> to <code>.css</code>:</p>\n<pre><code class=\"language-js\">// Extremely simplified code:\nsite.process([&quot;.scss&quot;], (page) =&gt; {\n  page.content = processSASS(page.content);\n\n  // Change the page URL\n  page.data.url = page.data.url.replace(/\\.scss$/, &quot;.css&quot;);\n\n  // Change the destination extension\n  page.dest.ext = &quot;.css&quot;;\n});\n</code></pre>\n<p>There's the <code>page.updateDest</code> function that changes the <code>page.dest</code> and\n<code>page.data.url</code> values accordingly, ensuring both properties are consistent:</p>\n<pre><code class=\"language-js\">// Extremely simplified code:\nsite.process([&quot;.scss&quot;], (page) =&gt; {\n  page.content = processSASS(page.content);\n\n  // Change the page URL and destination\n  page.updateDest({ ext: &quot;.css&quot; });\n});\n</code></pre>\n<p>I never felt confortable with this, because it's duplicating the same value in\ntwo different places. Originally it has been created in this way because they\nhave different purposes and they can have different values (like a page with the\nurl <code>/about-us/</code> but the destination file is <code>/about-us/index.html</code>).</p>\n<p>In Lume 1.13.0 the <code>page.dest</code> and <code>page.updateDest</code> are deprecated (and\nprobably removed in 1.14.0). Now you only have to change the value in one place:\n<code>page.data.url</code>.</p>\n<p>More simple and intuitive.</p>\n<h2 id=\"new-option-returnpagedata-to-search-helper\" tabindex=\"-1\"><a href=\"https://aoba-test.netlify.app/posts/lume-1.13.0-release/#new-option-returnpagedata-to-search-helper\" class=\"header-anchor\">New option <code>returnPageData</code> to <code>search</code> helper</a></h2>\n<p>The global helper <code>search.pages()</code> returns an array of pages. But in most cases\nyou don't need the page instance, only its data. The new <code>returnPageData</code> option\nallows to change this behavior to return only the <code>page.data</code> object. This will\nbe the default behavior in Lume 2.0, but for compatibility it's disabled by\ndefault. See\n<a href=\"https://github.com/lumeland/lume/issues/251\">more info in this issue</a>.</p>\n<p>To enable it, just configure the plugin in the <code>_config.ts</code> file.</p>\n<pre><code class=\"language-js\">import lume from &quot;lume/mod.ts&quot;;\n\nconst search = { returnPageData: true };\n\nconst site = lume({}, { search });\n\nexport default site;\n</code></pre>\n<p>Once configured, the following code:</p>\n<pre><code class=\"language-liquid\">{% for article in search.pages(&quot;type=article&quot;, &quot;date=desc&quot;) %} \n&lt;a href=&quot;{{ article.data.url }}&quot;&gt;\n  &lt;h1&gt;{{ article.data.title }}&lt;/h1&gt;\n&lt;/a&gt;\n{% endfor %}\n</code></pre>\n<p>needs to be changed to:</p>\n<pre><code class=\"language-liquid\">{% for article in search.pages(&quot;type=article&quot;, &quot;date=desc&quot;) %} \n&lt;a href=&quot;{{ article.url }}&quot;&gt;\n  &lt;h1&gt;{{ article.title }}&lt;/h1&gt;\n&lt;/a&gt;\n{% endfor %}\n</code></pre>\n<h2 id=\"removed-no-html-extension-option-for-prettyurls\" tabindex=\"-1\"><a href=\"https://aoba-test.netlify.app/posts/lume-1.13.0-release/#removed-no-html-extension-option-for-prettyurls\" class=\"header-anchor\">Removed <code>no-html-extension</code> option for prettyUrls</a></h2>\n<p>Pretty URLs configuration allowed the <code>no-html-extension</code> value. It exports the\npage as regular html (like <code>/article.html</code>) but the url of these pages are\n<code>/article</code> (without extension). You can see more info\n<a href=\"https://github.com/lumeland/lume/issues/193\">in this issue</a>.</p>\n<p>This option was removed in Lume 1.13.0 because it's not needed. If you want this\nfunctionality, just use the <code>modify_urls</code> plugin to remove the extension to the\nHTML links:</p>\n<pre><code class=\"language-js\">import lume from &quot;lume/mod.ts&quot;;\nimport modifyUrls from &quot;lume/plugins/modify_urls.ts&quot;;\n\nconst site = lume({\n  prettyUrls: false, //To export the pages as example.html\n});\n\nsite.use(modifyUrls({\n  fn: (url) =&gt; url.replace(/\\.html$/, &quot;&quot;),\n}));\n\nexport default site;\n</code></pre>\n<h2 id=\"new-emptydest-option\" tabindex=\"-1\"><a href=\"https://aoba-test.netlify.app/posts/lume-1.13.0-release/#new-emptydest-option\" class=\"header-anchor\">New <code>emptyDest</code> option</a></h2>\n<p>Lume needs to load all pages in order to build the site. This may be a problem\nfor large sites with 50K or more pages that cause out of memory issues.</p>\n<p>A solution is to build these large sites in several steps, creating different\nbuilds exporting to the same <code>dest</code> directory, so the site can be built\nincrementally. Lume automatically empty the <code>dest</code> folder before any build, so\nthe new <code>emptyDest</code> option allows to change this behavior:</p>\n<pre><code class=\"language-ts\">const site = lume({\n  emptyDest: false, // Don't empty the dest folder\n});\n</code></pre>\n<h2 id=\"removed-timestamp-detection-in-the-filename\" tabindex=\"-1\"><a href=\"https://aoba-test.netlify.app/posts/lume-1.13.0-release/#removed-timestamp-detection-in-the-filename\" class=\"header-anchor\">Removed timestamp detection in the filename</a></h2>\n<p>Lume can\n<a href=\"https://lume.land/docs/creating-pages/page-files/#page-date\">extract dates from the page's filename</a>\n(for instance <code>2022-10-02_post-title.md</code>).</p>\n<p>If there's a number (like <code>23_post-title.md</code>), it's interpreted as a timestamp.\nThis behavior was removed because it's a too generical pattern\n(<a href=\"https://github.com/lumeland/lume/issues/284\">See this issue</a>). If you need\nthis feature back, you can create a preprocessor for that:</p>\n<pre><code class=\"language-ts\">site.preprocess([&quot;.md&quot;], (page) =&gt; {\n  const [date, url] = myCustomFileParse(page.data.url);\n  page.data.date = date;\n  page.data.url = url;\n});\n</code></pre>\n<p>See the\n<a href=\"https://github.com/lumeland/lume/blob/v1.13.0/CHANGELOG.md\">CHANGELOG.md file</a>\nfor a full list of changes.</p>\n","date_published":"Wed, 16 Nov 2022 00:00:00 GMT"}]}