<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Adrien Joly</title>
    <description>The latest articles on DEV Community by Adrien Joly (@adrienjoly).</description>
    <link>https://dev.to/adrienjoly</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F18295%2F7a0908ee-e916-44b3-901f-14b1fb9f3f46.jpg</url>
      <title>DEV Community: Adrien Joly</title>
      <link>https://dev.to/adrienjoly</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/adrienjoly"/>
    <language>en</language>
    <item>
      <title>Things We Wish We Knew When We Started</title>
      <dc:creator>Adrien Joly</dc:creator>
      <pubDate>Sun, 20 Mar 2022 14:39:50 +0000</pubDate>
      <link>https://dev.to/adrienjoly/things-we-wish-we-knew-when-we-started-h53</link>
      <guid>https://dev.to/adrienjoly/things-we-wish-we-knew-when-we-started-h53</guid>
      <description>&lt;p&gt;Hi! Our names are Adrien, Benjamin, Fabien, Florent, Johan, Laurent and Rainer. We have been working in the software industry for several years. We share a growth mindset and always enjoy taking a step back to retrospect on what we've learned.&lt;/p&gt;

&lt;p&gt;During &lt;a href="https://github.com/SoCraTes-FR/socrates-fr.github.io"&gt;SoCraTes France 2022&lt;/a&gt;, we decided to put together a few words of advice to our younger selves. Tips we wish we were given when we started in the profession. We hope that they will be helpful to newcomers of our industry.&lt;/p&gt;

&lt;h2&gt;
  
  
  Write Tests
&lt;/h2&gt;

&lt;p&gt;Writing code that does what we intend is hard. So we regularly test these intended behaviors. As code evolves, new bugs will appear, and old bugs may re-appear. Writing automated tests helps us find bugs before they impact the users of our software.&lt;/p&gt;

&lt;p&gt;Automated tests give us trust in our code, and a feeling of safety when we change that code. Seeing automated tests pass is addictively satisfying. Automated tests make our lives better. We love getting continuously better at writing them.&lt;/p&gt;

&lt;p&gt;Working on legacy code convinces us of the importance of automated tests. They help us understand and improve code for the long run, and reduce the risk of causing bugs while doing so.&lt;/p&gt;

&lt;p&gt;Test-driven development (TDD) helps us develop our skills, by encouraging us to write higher quality code.&lt;/p&gt;

&lt;h2&gt;
  
  
  Code With Your Teammates
&lt;/h2&gt;

&lt;p&gt;Code is rarely meant to be read and changed by just one person. We write code that our current and future colleagues can understand easily.&lt;/p&gt;

&lt;p&gt;Preferences are personal. There is no winner in the "tabs versus spaces" debate. Using both makes a codebase look bad. Consistency makes code look the most clean and professional.&lt;/p&gt;

&lt;p&gt;We discuss preferences with the team. Agree on common guidelines, then stick to them. If your preference is not agreed upon, remind yourself that this is not about you. Also, remind yourself that your preferences will evolve.&lt;/p&gt;

&lt;p&gt;When we feel stuck by a technical problem, it's most likely a people problem. We don't jump to conclusions. We don't jump to solutions. We explain our problem to the team, ask for their help, then find a solution together.&lt;/p&gt;

&lt;p&gt;Pair programming is not a waste of time. It helps find better solutions to problems, faster. Pair programming is an opportunity to learn and grow. It makes us converge to design decisions, instead of having to defend our choices after implementing them.&lt;/p&gt;

&lt;p&gt;Ensemble programming (a.k.a. mob programming) is pair programming at scale. With more brains involved, we find more adequate solutions. By programming all together regularly, we won't have to document or repeat ourselves as much.&lt;/p&gt;

&lt;h2&gt;
  
  
  Learn, Chat, Share
&lt;/h2&gt;

&lt;p&gt;Loving to code motivates us to practice and learn. Building software with a team helps us have a bigger impact. Confronting our ideas, opinions and experiences to other developers helps us develop our craft.&lt;/p&gt;

&lt;p&gt;At local "meetup" communities, conferences and un-conferences (like SoCraTes), we learn about new practices. We share our experiences. We make new friends. These discoveries help us orient and improve our career. Friends sometimes become team-mates.&lt;/p&gt;

&lt;p&gt;We learn about the history of computer science to better understand why things are the way they are. We learn about fundamentals to avoid reinventing the wheel. We discuss principles and methodologies to feel wherever and whenever it's appropriate to not follow them. We play with different languages to discover new mental models that may become handy someday.&lt;/p&gt;

&lt;p&gt;We ask our peers to recommend good books to read. We form skills and opinions by practicing what we discover. We help other developers grow by sharing our learnings with them. It's never too early to start sharing. And there are various ways to do so.&lt;/p&gt;

&lt;h2&gt;
  
  
  Improve the Collaboration Progressively
&lt;/h2&gt;

&lt;p&gt;Building software is not a sprint, it's a marathon. Our goal as developers is to solve problems by writing code. After some time, that code may become the source of new problems. We are mindful of the consequences of our choices. We inform our colleagues of the implied costs and risks, so we can adjust the strategy if necessary.&lt;/p&gt;

&lt;p&gt;Deadlines are artificial. If we feel we can deliver a requested feature on time, we go for it. Otherwise, we negociate the deadline. Or propose alternatives. Understanding the objective or constraints behind a deadline usually helps.&lt;/p&gt;

&lt;p&gt;We collaborate well with our squad. Contemplate how features are brought to life, from ideation to production. Understand how our contribution fits in the production cycle. Get to know our collaborators, stakeholders and the users of our software.&lt;/p&gt;

&lt;p&gt;Whenever something is missing to do our part well, we ask. Whenever we are not sure to understand what is being built, for whom, or why, we ask. Whenever we are not sure about something, we are not afraid to say "I don't know".&lt;/p&gt;

&lt;p&gt;We are not afraid to fail. Retrospectively talk about failure (without blaming) is how we learn and improve. We just strive to not commit the same mistake twice.&lt;/p&gt;

&lt;p&gt;When leading a team, it can be tempting to point out several problems about the codebase, the processes and/or the team that made it. Bringing change is difficult and takes time. We don't change too many things at the same time. Instead, we start with the most critical or impactful change, then proceed with the next. We pick our battles.&lt;/p&gt;

&lt;h2&gt;
  
  
  Design Slowly
&lt;/h2&gt;

&lt;p&gt;Software grows quickly. While growing, its complexity also grows. We strive to keep complexity to a minimum, by properly understanding and modeling the domain of application of the software. Domain-Driven Design (DDD) is one way to remain connected to users and stakeholders, and to keep the corresponding complexity in check.&lt;/p&gt;

&lt;p&gt;We don't let technical details impact the domain logic. We design our code in a way to make it easy to replace external dependencies: databases, caches and 3rd-party APIs, without impact on our domain logic.&lt;/p&gt;

&lt;p&gt;Performance is not always a priority. Unless needed otherwise, we prefer code legibility and separation of concerns. We design services that can scale independently rather than optimize code prematurely.&lt;/p&gt;

&lt;p&gt;When we are considering a solution to a problem, we discuss its pros and cons. We keep a trace of our decisions in Architecture Decision Records, to help our future colleagues understand what compromises we agreed to make, and why. &lt;/p&gt;

&lt;h2&gt;
  
  
  You Are In Control
&lt;/h2&gt;

&lt;p&gt;We are not servants to our employers, clients or managers. We negociate each job or mission opportunity towards a win-win partnership. Salary is just one among many variables to discuss. There are many others: opportunities to learn, to discover an interesting business domain, to try out a new role, to work with exceptional colleagues, to find the right work-balance, etc...&lt;/p&gt;

&lt;p&gt;Sleep is not a luxury. Our job requires a healthy brain. To be productive and creative, our brain needs a lot of time to rest.&lt;/p&gt;

&lt;p&gt;Health is not a commodity. We take care of our physical and mental health. If work ever compromises it, we seek medical assistance and take measures to resolve the situation as soon as possible. No job is worth sacrificing our health, sanity or dignity.&lt;/p&gt;

&lt;p&gt;When a colleague seems to loose control, we propose assistance. We don't tolerate harrassment or abuse of any kind. We stand together against it.&lt;/p&gt;

&lt;h2&gt;
  
  
  That's all, folks!
&lt;/h2&gt;

&lt;p&gt;Take great care of yourself, and of your community. Take the time to figure out what you love doing most, and why. Be proud to stand by your values. Strive to bring and sustain a positive impact for your collaborators, stakeholders, users, without ever compromising on quality, honesty and humility.&lt;/p&gt;

&lt;p&gt;Authors:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Laurent Bossavit, Technical Advisor at CodeWorks&lt;/li&gt;
&lt;li&gt;Fabien Giannesini, Software Crafter at SHODO&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://twitter.com/benjaminhugot"&gt;Benjamin Hugot&lt;/a&gt;, Software Crafter at SHODO&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://twitter.com/adrienjoly"&gt;Adrien Joly&lt;/a&gt;, Software Crafter at SHODO&lt;/li&gt;
&lt;li&gt;
&lt;a href="http://martinsson-johan.blogspot.com/"&gt;Johan Martinsson&lt;/a&gt;, Tech Coach&lt;/li&gt;
&lt;li&gt;Florent Pellet, Software Crafter&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://twitter.com/matschmann"&gt;Rainer Standke&lt;/a&gt;, DevOps Engineer at DB Systel&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>socrates</category>
      <category>softwarecraft</category>
      <category>advice</category>
    </item>
    <item>
      <title>Let's turn an Openwhyd playlist into a static Jekyll site</title>
      <dc:creator>Adrien Joly</dc:creator>
      <pubDate>Sun, 22 Jul 2018 16:12:39 +0000</pubDate>
      <link>https://dev.to/adrienjoly/lets-turn-an-openwhyd-playlist-into-a-static-jekyll-site-341a</link>
      <guid>https://dev.to/adrienjoly/lets-turn-an-openwhyd-playlist-into-a-static-jekyll-site-341a</guid>
      <description>&lt;p&gt;Today I'm giving a coding challenge to myself:&lt;br&gt;
Make &lt;a href="https://openwhyd.org/adrien"&gt;my openwhyd.org profile&lt;/a&gt; playable from a pure client-side HTML page (i.e. without API/back-end server), using Jekyll.&lt;/p&gt;
&lt;h1&gt;
  
  
  Why?
&lt;/h1&gt;

&lt;p&gt;Openwhyd is a platform on which music lovers collect songs that they've found online, on Youtube, Soundcloud, Bandcamp and several other streaming platforms. It allows them to make cross-source playlists, to play them from their laptop or iPhone, and to share their discoveries with other music lovers who subscribed to them.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--F1JLGtAn--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/l8kz1srasn617in3brht.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--F1JLGtAn--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/l8kz1srasn617in3brht.png" alt="screenshot of my openwhyd profile" width="880" height="508"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Behind the scenes, Openwhyd is a web application powered by Node.js and MongoDB. This means that we have to pay our hosting provider a monthly bill to keep it running on a server. (FYI, this costs $15/month)&lt;/p&gt;

&lt;p&gt;So far, we have been lucky enough to be sponsored by DigitalOcean: they gave us 1 year of free hosting! But this gift will not last forever, we will soon have to ask users again for donations, in order to pay the hosting bills. Which is not a fun thing to do, for us, nor for our users. (see &lt;a href=""&gt;our OpenCollective page&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;This situation got me thinking: &lt;strong&gt;would it be possible to keep using Openwhyd without having to pay for hosting?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;As I'm a big fan of GitHub Pages, the first solution that came to mind was to get rid of the back-end part of Openwhyd. Turning it into a pure client-side web app (a.k.a. static web app), in which the database would be replaced by data files rendered with Jekyll.&lt;/p&gt;

&lt;p&gt;Of course, it would be very complicated to cover all the features of Openwhyd without using a back-end. (e.g. adding tracks to playlists from the web UI, and fetching the stream of latest tracks from users you subscribed to)&lt;/p&gt;

&lt;p&gt;But I figured that just being able to play your own playlists would be a good compromise between utility for users and technical complexity to make it work.&lt;/p&gt;

&lt;p&gt;If I get this to work, it would allow some Openwhyd users to still be able to play the tracks that they spent years collecting, even if our back-end were to go offline some day.&lt;/p&gt;
&lt;h1&gt;
  
  
  Design of the technical solution
&lt;/h1&gt;

&lt;p&gt;Here's what currently happens when a user wants to play tracks from their profile, or any of their playlists:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;They open a browser tab to the corresponding URL; (e.g. &lt;a href="https://openwhyd.org/adrien"&gt;https://openwhyd.org/adrien&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;The back-end fetches the 20 latest tracks of that playlist and renders a HTML page containing that list of tracks;&lt;/li&gt;
&lt;li&gt;The user's browser displays the page and loads a bunch of JavaScript files, notably &lt;code&gt;WhydPlayer.js&lt;/code&gt; that is responsible to making any listed track playable;&lt;/li&gt;
&lt;li&gt;When the user clicks on one of the tracks, &lt;code&gt;WhydPlayer.js&lt;/code&gt; extracts the source of that track (stored in the DOM node corresponding to that track) and streams it from there;&lt;/li&gt;
&lt;li&gt;When reaching the end of the track being currently played back, &lt;code&gt;WhydPlayer.js&lt;/code&gt; plays the following track; (still by extracting data from the DOM)&lt;/li&gt;
&lt;li&gt;When reaching the last track of the page, &lt;code&gt;WhydPlayer.js&lt;/code&gt; asks the back-end for the next page of tracks and appends them to the list.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Based on this (simplified) flow, we can notice that the back-end is only solicited on steps 2 and 6: to fetch and render tracks from the playlists. The rest is done by &lt;code&gt;WhydPlayer.js&lt;/code&gt; and other client-side logic.&lt;/p&gt;

&lt;p&gt;Step 2 could easily be done on a static web hosting provider like GitHub Pages: we would just have to store the user's playlists as HTML pages. The &lt;code&gt;WhydPlayer.js&lt;/code&gt; would still work from it, as long as the DOM structure contains all the data that it needs to stream the music of each track.&lt;/p&gt;

&lt;p&gt;Step 6 could be worked around: if HTML pages contain the full list of tracks, there would be no need to fetch pages of next tracks!&lt;/p&gt;

&lt;p&gt;Now, let's propose an action plan:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Clone Openwhyd's repository, and get rid of its back-end files;&lt;/li&gt;
&lt;li&gt;Create a HTML page that holds one track, and make it playable with &lt;code&gt;WhydPlayer.js&lt;/code&gt;;&lt;/li&gt;
&lt;li&gt;Download the track listing of an Openwhyd profile (or playlist);&lt;/li&gt;
&lt;li&gt;Turn the HTML page into a Jekyll template that will render the track list;&lt;/li&gt;
&lt;li&gt;Patch the UI, so that the user can navigate between their profile and playlist pages.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Constraint: I'm going to do my best to apply as few alterations as I can to Openwhyd's codebase (including its file structure), in order to these steps reproducible on its future versions too.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note: I'm writing this article while following these steps.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h1&gt;
  
  
  Step 1. Clone (and clean) Openwhyd's repository
&lt;/h1&gt;

&lt;p&gt;Let's head to Openwhyd's official open source repository: &lt;a href="https://github.com/openwhyd/openwhyd"&gt;github.com/openwhyd/openwhyd&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;From there, git noobs will be happy to download it as a &lt;code&gt;zip&lt;/code&gt; file, thanks to the "Clone and download" button. The pros will use the command line:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;git clone https://github.com/openwhyd/openwhyd.git
&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;openwhyd
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You'll see several folders and files in the resulting &lt;code&gt;openwhyd&lt;/code&gt; directory. Let's get rid of everything that is not relevant for our static version of Openwhyd:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;rm &lt;/span&gt;Dockerfile
&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;rm &lt;/span&gt;docker-compose.yml
&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; scripts
&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; whydMisc
&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; whydJS/test
&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; whydJS/config
&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; whydJS/screenshots
&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; whydJS/app/controllers
&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; whydJS/app/data
&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; whydJS/app/emails
&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; whydJS/app/lib
&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; whydJS/app/models
&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; whydJS/app/workers
&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; whydJS/app/views
&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;rm &lt;/span&gt;whydJS/app/&lt;span class="k"&gt;*&lt;/span&gt;.&lt;span class="k"&gt;*&lt;/span&gt;

&lt;span class="c"&gt;# delete all files from whydJS/, except package.json&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;find whydJS/&lt;span class="k"&gt;*&lt;/span&gt; &lt;span class="nt"&gt;-type&lt;/span&gt; f &lt;span class="nt"&gt;-maxdepth&lt;/span&gt; 0 | egrep &lt;span class="nt"&gt;-v&lt;/span&gt; &lt;span class="s2"&gt;"package&lt;/span&gt;&lt;span class="se"&gt;\.&lt;/span&gt;&lt;span class="s2"&gt;json"&lt;/span&gt; | xargs &lt;span class="nb"&gt;rm&lt;/span&gt;

&lt;span class="c"&gt;# delete all folders from public/, except a few ones&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;find whydJS/public/&lt;span class="k"&gt;*&lt;/span&gt; &lt;span class="nt"&gt;-maxdepth&lt;/span&gt; 0 | egrep &lt;span class="nt"&gt;-v&lt;/span&gt; &lt;span class="s2"&gt;"css|fonts|html|images|js|swf"&lt;/span&gt; | xargs &lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt;

&lt;span class="c"&gt;# delete all folders from images/&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;find whydJS/public/images/&lt;span class="k"&gt;*&lt;/span&gt; &lt;span class="nt"&gt;-type&lt;/span&gt; d &lt;span class="nt"&gt;-maxdepth&lt;/span&gt; 0 | xargs &lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt;

&lt;span class="c"&gt;# delete all files from public/css, except a few ones&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;find whydJS/public/css/&lt;span class="k"&gt;*&lt;/span&gt; &lt;span class="nt"&gt;-maxdepth&lt;/span&gt; 0 | egrep &lt;span class="nt"&gt;-v&lt;/span&gt; &lt;span class="s2"&gt;"[^-]common|userPlaylistV2|userProfileV2"&lt;/span&gt; | xargs &lt;span class="nb"&gt;rm&lt;/span&gt;

&lt;span class="c"&gt;# delete public/html/*, except a few ones&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;find whydJS/public/html/&lt;span class="k"&gt;*&lt;/span&gt; &lt;span class="nt"&gt;-maxdepth&lt;/span&gt; 0 | egrep &lt;span class="nt"&gt;-v&lt;/span&gt; &lt;span class="s2"&gt;"channel|&lt;/span&gt;&lt;span class="se"&gt;\b&lt;/span&gt;&lt;span class="s2"&gt;YoutubePlayerIframe"&lt;/span&gt; | xargs &lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt;

&lt;span class="c"&gt;# delete public/js/*, except a few ones&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;find whydJS/public/js/&lt;span class="k"&gt;*&lt;/span&gt; &lt;span class="nt"&gt;-maxdepth&lt;/span&gt; 0 | egrep &lt;span class="nt"&gt;-v&lt;/span&gt; &lt;span class="s2"&gt;"autoresize|&lt;/span&gt;&lt;span class="se"&gt;\b&lt;/span&gt;&lt;span class="s2"&gt;jquery|mustache|playem|soundmanager|swfobject|ui|whyd&lt;/span&gt;&lt;span class="se"&gt;\.&lt;/span&gt;&lt;span class="s2"&gt;js|Player&lt;/span&gt;&lt;span class="se"&gt;\.&lt;/span&gt;&lt;span class="s2"&gt;js"&lt;/span&gt; | xargs &lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt;

&lt;span class="c"&gt;# delete whydJS/app/templates/*, except a few ones&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;find whydJS/app/templates/&lt;span class="k"&gt;*&lt;/span&gt; &lt;span class="nt"&gt;-maxdepth&lt;/span&gt; 0 | egrep &lt;span class="nt"&gt;-v&lt;/span&gt; &lt;span class="s2"&gt;"feed&lt;/span&gt;&lt;span class="se"&gt;\.&lt;/span&gt;&lt;span class="s2"&gt;html|mainTemplate|posts&lt;/span&gt;&lt;span class="se"&gt;\.&lt;/span&gt;&lt;span class="s2"&gt;html|userPlaylistV2&lt;/span&gt;&lt;span class="se"&gt;\.&lt;/span&gt;&lt;span class="s2"&gt;html|userProfileV2&lt;/span&gt;&lt;span class="se"&gt;\.&lt;/span&gt;&lt;span class="s2"&gt;html|whydPlayer"&lt;/span&gt; | xargs &lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt;

&lt;span class="c"&gt;# let's see the tree of remaining folders&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;ls&lt;/span&gt; &lt;span class="nt"&gt;-R&lt;/span&gt; | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="s2"&gt;":$"&lt;/span&gt; | &lt;span class="nb"&gt;sed&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s1"&gt;'s/:$//'&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s1"&gt;'s/[^-][^\/]*\//--/g'&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s1"&gt;'s/^/   /'&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s1"&gt;'s/-/|/'&lt;/span&gt;
   |-docs
   |---img
   |-whydJS
   |---app
   |-----templates
   |---public
   |-----css
   |-----fonts
   |-----html
   |-----images
   |-----js
   |-----swf
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ok, now we have much fewer files to distract us from our mission!&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2. Create a HTML page with a playable track
&lt;/h2&gt;

&lt;p&gt;Let's try a naive move: save a playlist page from openwhyd.org to a HTML file and see if we can play a track from it.&lt;/p&gt;

&lt;p&gt;For that, I'm gonna open &lt;a href="https://openwhyd.org/adrien"&gt;my profile page&lt;/a&gt; on Google Chrome, and press &lt;code&gt;Cmd-S&lt;/code&gt; to save it as a "Simple HTML file":&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--6e1pdyUu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/m5sliwng4hwy08mpcdm6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--6e1pdyUu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/m5sliwng4hwy08mpcdm6.png" alt="saving my openwhyd profile page into a HTML file" width="880" height="206"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Of course, if I try to open that download file in my browser, it looks completely broken and it's impossible to play tracks from it. That is because all the references to JavaScript, CSS and image files are broken.&lt;/p&gt;

&lt;p&gt;Extract from the resulting HTML file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;    &lt;span class="nt"&gt;&amp;lt;title&amp;gt;&lt;/span&gt;Adrien Joly's tracks - Openwhyd&lt;span class="nt"&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;link&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"/css/common.css?1.1.1"&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;"stylesheet"&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"text/css"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;link&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"/css/browse.css?1.1.1"&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;"stylesheet"&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"text/css"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;link&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"/css/tipsy.css?1.1.1"&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;"stylesheet"&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"text/css"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;link&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"/css/userProfileV2.css?1.1.1"&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;"stylesheet"&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"text/css"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;link&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"/css/userPlaylistV2.css?1.1.1"&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;"stylesheet"&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"text/css"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;link&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"/css/dlgEditProfileCover.css?1.1.1"&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;"stylesheet"&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"text/css"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"/js/jquery-1.10.2.min.js"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"/js/jquery-migrate-1.2.1.js"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"text/javascript"&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"/js/jquery.history.js"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"/js/soundmanager2-nodebug-jsmin.js"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see, that page uses absolute paths to all its assets. So we're gonna have to setup a web server locally that will give access to these resources from these paths.&lt;/p&gt;

&lt;p&gt;In order to respect that file structure, it would make sense to move the HTML file in the &lt;code&gt;whydJS/public/&lt;/code&gt; folder. That way, we can consider that is folder is gonna be the root of our web server, making both our HTML file and the asset subfolders accessible through it.&lt;/p&gt;

&lt;p&gt;So I'm running the following commands:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# (assuming that you are still in the openwhyd folder we created earlier)&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; ./whydJS/public
&lt;span class="nv"&gt;$ &lt;/span&gt;move ~/Downloads/my-openwhyd-profile-playlist.html 
&lt;span class="nv"&gt;$ &lt;/span&gt;python &lt;span class="nt"&gt;-m&lt;/span&gt; SimpleHTTPServer &lt;span class="c"&gt;# to start python's http server&lt;/span&gt;
Serving HTTP on 0.0.0.0 port 8000 ...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, let's open &lt;code&gt;http://0.0.0.0:8000/my-openwhyd-profile-playlist.html&lt;/code&gt; in Google Chrome:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--SpnA1YDM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/5m42tfhar8yuq293yq9k.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--SpnA1YDM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/5m42tfhar8yuq293yq9k.png" alt="screenshot of the HTML page of my openwhyd profile after opening it from my local server" width="880" height="462"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As you can see, some elements of the UI still look broken, but the layout is working and you may even be able to play some of the tracks by clicking on them! &lt;/p&gt;

&lt;p&gt;...Except Youtube tracks, because Openwhyd's Youtube player was patched to play tracks through another domain name. In our case, we don't want this behaviour, so let's make the patch script think that we're running locally (even if we're not):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# let's force `var isLocal = true;`, in whydJS/public/js/playem-youtube-iframe-patch.js
$ sed -i -e "s/var isLocal = /var isLocal = true; /" ./whydJS/public/js/playem-youtube-iframe-patch.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This should make it work better, after refreshing the page!&lt;/p&gt;

&lt;h1&gt;
  
  
  3. Store the track listing into a data file
&lt;/h1&gt;

&lt;p&gt;So far, we have a static HTML page in which the tracks are hard-coded. As we will want to turn that page into a template that will be able to render any playlist, let's download a playlist in raw format, without the HTML rendering.&lt;/p&gt;

&lt;p&gt;Fortunately, Openwhyd makes it easy to download a raw track list in JSON format, from any page. We just have to add the &lt;code&gt;?format=json&lt;/code&gt; suffix to the URL of that page.&lt;/p&gt;

&lt;p&gt;In my case, I want the track list of my profile, so I am going to download the JSON content of &lt;code&gt;https://openwhyd.org/adrien?format=json&lt;/code&gt; and save it to &lt;code&gt;openwhyd/whydJS/public/_data/tracks.json&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The contents of the file should look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="nl"&gt;"_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"5b4b6b81314fcb64d074e462"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"uId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"4d94501d1f78ac091dbc9b4d"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"uNm"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"Adrien Joly"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"text"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"pl"&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"classical &amp;amp; epic"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"Max Richter - November"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"eId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"/yt/2Bb0k9HgQxc"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"ctx"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"bk"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"img"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"https://i.ytimg.com/vi/2Bb0k9HgQxc/default.jpg"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"src"&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"https://totoromoon.wordpress.com/2018/07/13/max-richter-november-sarajevo/"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"MAX RICHTER November &amp;amp;amp; Sarajevo | totoromoon"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="nl"&gt;"nbP"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"nbR"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"lov"&lt;/span&gt;&lt;span class="p"&gt;:[]},{&lt;/span&gt;&lt;span class="nl"&gt;"_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"5b34c9731db44a36a795f96a"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"uId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"4d94501d1f78ac091dbc9b4d"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"uNm"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"Adrien Joly"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"text"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"pl"&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"epic coding session soundtrack"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;53&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"alexanderbrandon - sunrise on vanaar"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"eId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"/bc/alexanderbrandon/sunrise-on-vanaar#https://t4.bcbits.com/stream/6b5b84ad5900cbb22b532a778f63701d/mp3-128/3200645745?p=0&amp;amp;ts=1530272235&amp;amp;t=01ec41132994dcb46b2a5f5c213a53c39cddb5dc&amp;amp;token=1530272235_39982de236fdfd2e66cf14379f8ba69b44f02f51"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"ctx"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"bk"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"img"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"//s0.bcbits.com/img/bclogo.png"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"src"&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"https://alexanderbrandon.bandcamp.com/album/aven-colony-original-game-soundtrack"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"▶︎ Aven Colony (Original Game Soundtrack) | Alexander Brandon"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="nl"&gt;"lov"&lt;/span&gt;&lt;span class="p"&gt;:[]},{&lt;/span&gt;&lt;span class="nl"&gt;"_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"5b326e261db44a36a795f844"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"uId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"4d94501d1f78ac091dbc9b4d"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"uNm"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"Adrien Joly"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"text"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"smiling band from cuba, fantastic female drummer !"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"pl"&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"Jazz meets World"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;61&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"Yissy García &amp;amp; Bandancha: NPR Music Tiny Desk Concert"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"eId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"/yt/Y1Kv_sFZHqI"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"ctx"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"bk"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"img"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"https://i.ytimg.com/vi/Y1Kv_sFZHqI/default.jpg"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"src"&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"https://www.youtube.com/watch?v=Y1Kv_sFZHqI&amp;amp;feature=youtu.beq"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"Yissy García &amp;amp;amp; Bandancha: NPR Music Tiny Desk Concert - YouTube"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="nl"&gt;"nbP"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"lov"&lt;/span&gt;&lt;span class="p"&gt;:[]},{&lt;/span&gt;&lt;span class="nl"&gt;"_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"5b2e34f51db44a36a795f4ff"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"uId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"4d94501d1f78ac091dbc9b4d"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"uNm"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"Adrien Joly"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"text"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"pl"&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"rock"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"collabId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"KADAVAR - Come Back Life (OFFICIAL MUSIC VIDEO)"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"eId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"/yt/4xgi91s7zf8"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"img"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"https://i.ytimg.com/vi/4xgi91s7zf8/0.jpg"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"repost"&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;&lt;span class="nl"&gt;"pId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"520de33ae4d15ab75a0030f5"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"uId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"51e92a777e91c862b2af478a"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"uNm"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"Thomas Radioyes"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="nl"&gt;"lov"&lt;/span&gt;&lt;span class="p"&gt;:[],&lt;/span&gt;&lt;span class="nl"&gt;"nbR"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"nbP"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;},{&lt;/span&gt;&lt;span class="nl"&gt;"_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"5b2b72c11db44a36a795f361"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"uId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"4d94501d1f78ac091dbc9b4d"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"uNm"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"Adrien Joly"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"text"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"chiptune"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"pl"&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"epic coding session soundtrack"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;53&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"Ujico*/Snail's House - Hello [Ordinary Songs
[...]
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Feel free to reformat this JSON file using &lt;a href="https://jsonformatter.org/json-pretty-print"&gt;JSON Pretty Print&lt;/a&gt;, or to convert it to YAML using &lt;a href="https://www.json2yaml.com/"&gt;json2yaml.com&lt;/a&gt; if you want, but this is not required for the Jekyll template to work.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note: if you don't remember your Openwhyd username, you can also use the URL &lt;code&gt;https://openwhyd.org/me?format=json&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h1&gt;
  
  
  4. Turn the HTML page into a Jekyll template
&lt;/h1&gt;

&lt;p&gt;In step 2, we had made Openwhyd's player work on the list of tracks that were dumped in a static HTML file. Now, let's turn this HTML file into a template, so that the list of tracks can be loaded from our JSON file. (like we had done in my previous tutorial: &lt;a href="https://dev.to/adrienjoly/how-to-maintain-a-collection-of-music-albums-online-using-jekyll-and-github-pages-3hd6"&gt;How to maintain a collection of music albums online, using Jekyll and Github Pages&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;Basically, what we want to do is to delete the elements that represent tracks from our HTML file, and replace them by a Jekyll template.&lt;/p&gt;

&lt;p&gt;In Openwhyd, tracks are displayed using &lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt; elements with the &lt;code&gt;post&lt;/code&gt; classname:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# (assuming that you are in the openwhyd/whydJS/public, where your HTML file is)&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="s1"&gt;'&amp;lt;div class="post'&lt;/span&gt; &lt;span class="k"&gt;*&lt;/span&gt;.html

                &amp;lt;div &lt;span class="nv"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"posts"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&amp;lt;div &lt;span class="nv"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"post "&lt;/span&gt; data-pid&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"5b546297314fcb64d074e8d3"&lt;/span&gt;
&amp;lt;div &lt;span class="nv"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"post "&lt;/span&gt; data-pid&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"5b4b6b81314fcb64d074e462"&lt;/span&gt;
&amp;lt;div &lt;span class="nv"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"post "&lt;/span&gt; data-pid&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"5b34c9731db44a36a795f96a"&lt;/span&gt;
&lt;span class="o"&gt;[&lt;/span&gt;...]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;First, using our favorite code editor, let's cut and paste all these &lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt; elements into a separate HTML file (e.g. &lt;code&gt;posts.html&lt;/code&gt;), so that we can use this HTML code as an example when we'll write our Jekyll template.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--P4RQYge4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/7nb38i0vsm1o4fnzkpls.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--P4RQYge4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/7nb38i0vsm1o4fnzkpls.png" alt="moving post divs from the playlist's html file to an external file" width="880" height="465"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After doing this operation, your playlist's HTML file should contain a &lt;code&gt;&amp;lt;div class="posts"&amp;gt;&lt;/code&gt; element that just contains the &lt;code&gt;&amp;lt;!-- TRACKS TAB CONTENT --&amp;gt;&lt;/code&gt; comment. That's where we are now going to add our Jekyll template.&lt;/p&gt;

&lt;p&gt;In order to make it easier to build that template, let's copy the code of one of the posts that we moved out of our HTML file, except its child nodes that have the classes &lt;code&gt;ago&lt;/code&gt;, &lt;code&gt;stats&lt;/code&gt;, &lt;code&gt;btns&lt;/code&gt; and &lt;code&gt;ext&lt;/code&gt;, back under the &lt;code&gt;&amp;lt;div class="posts"&amp;gt;&lt;/code&gt; element.&lt;/p&gt;

&lt;p&gt;After re-formating the HTML, it should look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"posts"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

  &lt;span class="c"&gt;&amp;lt;!-- TRACKS TAB CONTENT --&amp;gt;&lt;/span&gt;

  &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"post "&lt;/span&gt;
        &lt;span class="na"&gt;data-pid=&lt;/span&gt;&lt;span class="s"&gt;"5b546297314fcb64d074e8d3"&lt;/span&gt;
        &lt;span class="na"&gt;data-initialpid=&lt;/span&gt;&lt;span class="s"&gt;"5b540c4d314fcb64d074e891"&lt;/span&gt; 
        &lt;span class="na"&gt;data-time=&lt;/span&gt;&lt;span class="s"&gt;"1532256919000"&lt;/span&gt; &lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

    &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"playBar"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/div&amp;gt;&lt;/span&gt;

    &lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"thumb"&lt;/span&gt;
        &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"//youtube.com/watch?v=u8rVPIV-Y4Y"&lt;/span&gt;
        &lt;span class="na"&gt;target=&lt;/span&gt;&lt;span class="s"&gt;"_blank"&lt;/span&gt;
        &lt;span class="na"&gt;data-eid=&lt;/span&gt;&lt;span class="s"&gt;"/yt/u8rVPIV-Y4Y"&lt;/span&gt;
        &lt;span class="na"&gt;onclick=&lt;/span&gt;&lt;span class="s"&gt;"return playTrack(this);"&lt;/span&gt;
        &lt;span class="na"&gt;style=&lt;/span&gt;&lt;span class="s"&gt;"background-image:url('https://i.ytimg.com/vi/u8rVPIV-Y4Y/default.jpg');"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"https://i.ytimg.com/vi/u8rVPIV-Y4Y/default.jpg"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"play"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;

    &lt;span class="nt"&gt;&amp;lt;h2&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"/c/5b546297314fcb64d074e8d3"&lt;/span&gt;
          &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"no-ajaxy"&lt;/span&gt;
          &lt;span class="na"&gt;onclick=&lt;/span&gt;&lt;span class="s"&gt;"toggleComments('5b546297314fcb64d074e8d3');return false;"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
          Paraphon Tree - Firefly (Official Music Video)&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/h2&amp;gt;&lt;/span&gt;

    &lt;span class="nt"&gt;&amp;lt;p&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"author"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;span&lt;/span&gt; &lt;span class="na"&gt;style=&lt;/span&gt;&lt;span class="s"&gt;"background-image:url('/img/u/4d94501d1f78ac091dbc9b4d');"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"/u/4d94501d1f78ac091dbc9b4d"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Adrien Joly&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt; added this track
      to &lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"/u/4d94501d1f78ac091dbc9b4d/playlist/12"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;post-rock / progressive&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
      via &lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"/u/544c39c3e04b7b4fca803438"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Stefanos Mavrogenis&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, let's turn this sample post into a Jekyll template that can be used to render any track.&lt;/p&gt;

&lt;p&gt;In order to do that, we replace all the hard-coded values by &lt;em&gt;mustache&lt;/em&gt; placeholders that contain the path of that value in any track from our &lt;code&gt;tracks.json&lt;/code&gt; file.&lt;/p&gt;

&lt;p&gt;For example, I replace the following HTML code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"/u/4d94501d1f78ac091dbc9b4d"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Adrien Joly&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt; added this track
to &lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"/u/4d94501d1f78ac091dbc9b4d/playlist/12"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;post-rock / progressive&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;... by this template code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"/profile"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;{{ track.uNm }}&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt; added this track
to &lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"/playlist-{{ track.pl.id }}"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;{{ track.pl.name }}&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It should end up like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"posts"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

  &lt;span class="c"&gt;&amp;lt;!-- TRACKS TAB CONTENT --&amp;gt;&lt;/span&gt;

  {% for track in site.data.tracks %}
  &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"post"&lt;/span&gt;
        &lt;span class="na"&gt;data-pid=&lt;/span&gt;&lt;span class="s"&gt;"{{ track._id }}"&lt;/span&gt;
        &lt;span class="na"&gt;data-initialpid=&lt;/span&gt;&lt;span class="s"&gt;"{{ track.repost.pId }}"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

    &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"playBar"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/div&amp;gt;&lt;/span&gt;

    &lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"thumb"&lt;/span&gt;
        &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"#"&lt;/span&gt;
        &lt;span class="na"&gt;data-eid=&lt;/span&gt;&lt;span class="s"&gt;"{{ track.eId }}"&lt;/span&gt;
        &lt;span class="na"&gt;onclick=&lt;/span&gt;&lt;span class="s"&gt;"return playTrack(this);"&lt;/span&gt;
        &lt;span class="na"&gt;style=&lt;/span&gt;&lt;span class="s"&gt;"background-image:url('{{ track.img }}');"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"{{ track.img }}"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"play"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;

    &lt;span class="nt"&gt;&amp;lt;h2&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"#"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;{{ track.name }}&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/h2&amp;gt;&lt;/span&gt;

    &lt;span class="nt"&gt;&amp;lt;p&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"author"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;span&lt;/span&gt; &lt;span class="na"&gt;style=&lt;/span&gt;&lt;span class="s"&gt;"background-image:url('{{ user.img }}');"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"/profile"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;{{ track.uNm }}&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt; added this track
      to &lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"/playlist-{{ track.pl.id }}"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;{{ track.pl.name }}&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
      via &lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"https://openwhyd.org/u/{{ track.repost.uId }}"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;{{ track.repost.uNm  }}&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
  {% endfor %}

&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In order to test the rendering of this template, the &lt;code&gt;python -m SimpleHTTPServer&lt;/code&gt; that we ran above will not help. So let's stop it (press &lt;code&gt;Ctrl-C&lt;/code&gt;) and use Jekyll instead.&lt;/p&gt;

&lt;p&gt;Here is how I set Jekyll up from my &lt;code&gt;openwhyd/whydJS/public/&lt;/code&gt; folder:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# let's make sure we have ruby installed&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;ruby &lt;span class="nt"&gt;-v&lt;/span&gt;
ruby 2.3.7p456 &lt;span class="o"&gt;(&lt;/span&gt;2018-03-28 revision 63024&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;x86_64-darwin15]

&lt;span class="c"&gt;# let's install jekyll in openwhyd/whydJS/public/&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;bundle init
&lt;span class="nv"&gt;$ &lt;/span&gt;bundle &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--path&lt;/span&gt; vendor/bundle
&lt;span class="nv"&gt;$ &lt;/span&gt;bundle add jekyll
&lt;span class="nv"&gt;$ &lt;/span&gt;bundle &lt;span class="nb"&gt;install&lt;/span&gt;

&lt;span class="c"&gt;# this command installs jekyll in ./vendor/bundle =&amp;gt; let's git-ignore it (optional)&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; /whydJS/public/vendor &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;../../.gitignore
&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; /whydJS/public/_site &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;../../.gitignore
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When it's fully set up, we can run the Jekyll server by typing this command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;bundle &lt;span class="nb"&gt;exec &lt;/span&gt;jekyll serve
    Server address: http://127.0.0.1:4000
  Server running... press ctrl-c to stop.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's open &lt;code&gt;http://127.0.0.1:4000/my-openwhyd-profile-playlist.html&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--uxROQApX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/dff1qzrwhpfr374d26j8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--uxROQApX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/dff1qzrwhpfr374d26j8.png" alt="screenshot of the Jekyll template failing to render" width="880" height="473"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The good news is that our page is properly served by Jekyll. The bad news is that our template failed to render. It looks like Jekyll did not interpret the template from the HTML file.&lt;/p&gt;

&lt;p&gt;I looked up online to see what's Jekyll process (and criteria) to render templates, and found this:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Jekyll looks for files with front matter tags (the two sets of dashed lines --- like those in index.md) and processes the files (populating site variables, rendering any Liquid, and converting Markdown to HTML).&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;(source: &lt;a href="https://jekyllrb.com/tutorials/convert-site-to-jekyll/"&gt;Convert an HTML site to Jekyll | Jekyll&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;So let's add two sets of dashed lines at the very top of our HTML file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;---
---
&lt;span class="cp"&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;html&lt;/span&gt; &lt;span class="na"&gt;lang=&lt;/span&gt;&lt;span class="s"&gt;"en"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
[...]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Normally, the &lt;code&gt;jekyll serve&lt;/code&gt; command should have detected this modification, and the track list should be rendered correctly from the JSON file, when opening/refreshing &lt;code&gt;http://127.0.0.1:4000/my-openwhyd-profile-playlist.html&lt;/code&gt; in your web browser!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--5HCCyPRH--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/rkfj96tx0uikhlugsytu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--5HCCyPRH--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/rkfj96tx0uikhlugsytu.png" alt="jekyll is rendering the track list from our JSON file" width="880" height="491"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Great job!&lt;/p&gt;

&lt;h1&gt;
  
  
  Next steps
&lt;/h1&gt;

&lt;p&gt;I'm now done with my objective of the day: we turned an Openwhyd profile into a static Jekyll site. The list of tracks was downloaded in JSON format and used by Jekyll to render it into HTML, following the template that we wrote.&lt;/p&gt;

&lt;p&gt;The next step will be to fix the navigation, so that visitors of the static version of my Openwhyd profile can also browse my playlists, following the same principle.&lt;/p&gt;

&lt;p&gt;In order to do that, I intend to use &lt;a href="https://jekyllrb.com/docs/collections"&gt;Jekyll collections&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Until I get back to writing the sequel to this article, let me know in the comments if you have alternative ideas on how to make this work!&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>tutorial</category>
      <category>jekyll</category>
      <category>music</category>
      <category>youtube</category>
    </item>
    <item>
      <title>Make your Static Site Searchable with Jekyll-Algolia</title>
      <dc:creator>Adrien Joly</dc:creator>
      <pubDate>Tue, 17 Jul 2018 15:34:26 +0000</pubDate>
      <link>https://dev.to/adrienjoly/make-your-static-site-searchable-with-jekyll-algolia-edh</link>
      <guid>https://dev.to/adrienjoly/make-your-static-site-searchable-with-jekyll-algolia-edh</guid>
      <description>&lt;p&gt;About two weeks ago, I published a tutorial called "&lt;a href="https://dev.to/adrienjoly/how-to-maintain-a-collection-of-music-albums-online-using-jekyll-and-github-pages-3hd6"&gt;How to maintain a collection of music albums online, using Jekyll and Github Pages&lt;/a&gt;".&lt;/p&gt;

&lt;p&gt;By the end of that tutorial, we were able to generate a 100% static, 100% freely-hosted and well-looking website out of a YAML list of albums, thanks to a Jekyll template. It looked like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff36vzorq4iqeiy9gqsyd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff36vzorq4iqeiy9gqsyd.png" alt="screenshot of album collection made with Jekyll and github pages" width="800" height="650"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We saw that maintaining that collection of albums was quite easy and convenient: we just have to edit the &lt;code&gt;_data/albums.yaml&lt;/code&gt;, which is in an almost plain-text format.&lt;/p&gt;

&lt;p&gt;You can find the source code what we produced in that github repository: &lt;a href="https://github.com/adrienjoly/jekyll-tutorial" rel="noopener noreferrer"&gt;github.com/adrienjoly/jekyll-tutorial&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Now that we're able to edit a list and render it in HTML, let's make our collection of albums &lt;strong&gt;searchable&lt;/strong&gt;!&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note: Written for experienced developers and beginners alike, this tutorial also covers the parts that unexpectedly went wrong. My intention is to also share my problem-solving process, so that beginners can learn how to solve their own problems, down the road. Thanks for your understanding! 🤓&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h1&gt;
  
  
  Proposed solution
&lt;/h1&gt;

&lt;p&gt;After joining Algolia, I discovered that one of my colleagues had released a plug-in to make Jekyll sites searchable: &lt;a href="https://github.com/algolia/jekyll-algolia" rel="noopener noreferrer"&gt;Jekyll-Algolia&lt;/a&gt;. (License: MIT)&lt;/p&gt;

&lt;p&gt;So, yeah, I'm definitely biased on this one, but I'm gonna go ahead and try it!&lt;/p&gt;

&lt;h1&gt;
  
  
  Step 1. Integrate the plug-in
&lt;/h1&gt;

&lt;p&gt;Ok, let's start with the prerequisites mentioned in the README file: "&lt;em&gt;the plugin requires at least Jekyll 3.6.0 and Ruby 2.3.0&lt;/em&gt;".&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;jekyll &lt;span class="nt"&gt;-v&lt;/span&gt;
jekyll 3.6.2

&lt;span class="nv"&gt;$ &lt;/span&gt;ruby &lt;span class="nt"&gt;-v&lt;/span&gt;
ruby 2.1.4p265 &lt;span class="o"&gt;(&lt;/span&gt;2014-10-27 revision 48166&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;x86_64-darwin14.0]
&lt;span class="c"&gt;# ❌ Oops... Let's upgrade ruby!&lt;/span&gt;

&lt;span class="nv"&gt;$ &lt;/span&gt;curl &lt;span class="nt"&gt;-sSL&lt;/span&gt; https://get.rvm.io | bash &lt;span class="nt"&gt;-s&lt;/span&gt; stable

&lt;span class="c"&gt;# ⚡️ Let's restart the terminal, as suggested by https://stackoverflow.com/a/38194139/592254&lt;/span&gt;

&lt;span class="nv"&gt;$ &lt;/span&gt;rvm &lt;span class="nb"&gt;install &lt;/span&gt;2.3
&lt;span class="c"&gt;# (Ended up compiling from its source code, maybe because I'm still on El Capitan?)&lt;/span&gt;

&lt;span class="nv"&gt;$ &lt;/span&gt;ruby &lt;span class="nt"&gt;-v&lt;/span&gt;
ruby 2.3.7p456 &lt;span class="o"&gt;(&lt;/span&gt;2018-03-28 revision 63024&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;x86_64-darwin15]
&lt;span class="c"&gt;# ✅ We're good to go!&lt;/span&gt;

&lt;span class="nv"&gt;$ &lt;/span&gt;rvm use 2.3 &lt;span class="nt"&gt;--default&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, let's install the plug-in into our codebase: "&lt;em&gt;add the &lt;code&gt;jekyll-algolia&lt;/code&gt; gem to your &lt;code&gt;Gemfile&lt;/code&gt;, in the &lt;code&gt;:jekyll_plugins&lt;/code&gt; section&lt;/em&gt;"&lt;/p&gt;

&lt;p&gt;✋ Blocker: I don't have a &lt;code&gt;Gemfile&lt;/code&gt; yet!&lt;/p&gt;

&lt;p&gt;So, let's follow the corresponding steps suggested by GitHub's tutorial: &lt;a href="https://help.github.com/articles/setting-up-your-github-pages-site-locally-with-jekyll/#step-2-install-jekyll-using-bundler" rel="noopener noreferrer"&gt;Setting up your GitHub Pages site locally with Jekyll&lt;/a&gt;, first.&lt;/p&gt;

&lt;p&gt;I end up with a &lt;code&gt;Gemfile&lt;/code&gt; at the root directory of my project, with the following contents:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Gemfile

source 'https://rubygems.org'
gem 'github-pages', group: :jekyll_plugins

group :jekyll_plugins do
  gem 'jekyll-algolia', '~&amp;gt; 1.0'
end
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Back to Jekyll-Algolia's instructions: "&lt;em&gt;download all dependencies with &lt;code&gt;bundle install&lt;/code&gt;&lt;/em&gt;".&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;bundle &lt;span class="nb"&gt;install&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Step 2. Set up the search index
&lt;/h1&gt;

&lt;p&gt;Let's follow the &lt;a href="https://github.com/algolia/jekyll-algolia#basic-configuration" rel="noopener noreferrer"&gt;Basic Configuration&lt;/a&gt; section of the instructions.&lt;/p&gt;

&lt;p&gt;I already have an account on algolia.com, so I'm gonna use that one. You may need to create one for yourself.&lt;/p&gt;

&lt;p&gt;Our next step is to create an "&lt;a href="https://www.algolia.com/manage/applications" rel="noopener noreferrer"&gt;application&lt;/a&gt;", there. As our codebase will remain open source, we can safely pick the "Community" plan, free of charge.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F62a9emdyxs5z0t6rvcc7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F62a9emdyxs5z0t6rvcc7.png" alt="screenshot of creating a community algolia application" width="800" height="480"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I'm calling my application "album-shelf", because that's the name of the website on which I want to add search.&lt;/p&gt;

&lt;p&gt;After picking a region (&lt;code&gt;EU WEST&lt;/code&gt;, in my case), let's head to the "API Keys" tab. Copy and paste your &lt;em&gt;Application ID&lt;/em&gt; to the a new &lt;code&gt;_config.yml&lt;/code&gt; at the root of your project, like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# _config.yml&lt;/span&gt;

&lt;span class="na"&gt;algolia&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;application_id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;paste_your_application_id_here'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Also copy the &lt;em&gt;Admin API Key&lt;/em&gt;, necessary to &lt;a href="https://github.com/algolia/jekyll-algolia#run-it" rel="noopener noreferrer"&gt;run&lt;/a&gt; the plug-in, like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ ALGOLIA_API_KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'paste_your_admin_api_key_here'&lt;/span&gt; bundle &lt;span class="nb"&gt;exec &lt;/span&gt;jekyll algolia
&lt;span class="o"&gt;[&lt;/span&gt;✗ Error] No index name defined
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Note: your Admin API Key can be used to read, update and delete your Algolia application =&amp;gt; make sure you keep it for yourself only! (i.e. to store it to your public GitHub repository 😅)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Oops, looks like I need to add the name of my search index in the &lt;code&gt;_config.yml&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# _config.yml&lt;/span&gt;

&lt;span class="na"&gt;algolia&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;application_id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;paste_your_application_id_here'&lt;/span&gt;
  &lt;span class="na"&gt;index_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;albums'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I've picked the name "albums", because that's what I want visitors to be able to search for, on my website. Type any name that you like, there!&lt;/p&gt;

&lt;p&gt;Let's try to run the plug-in again:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ ALGOLIA_API_KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'paste_your_admin_api_key_here'&lt;/span&gt; bundle &lt;span class="nb"&gt;exec &lt;/span&gt;jekyll algolia
&lt;span class="o"&gt;[&lt;/span&gt;✗ Error] No records found

Make sure you did not exclude too many files from indexing using the
&lt;span class="sb"&gt;`&lt;/span&gt;files_to_exclude&lt;span class="sb"&gt;`&lt;/span&gt; option. You are currently excluding the following files:
    index.html, index.markdown, index.mkdown, index.mkdn, index.mkd, index.md
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Damn it!&lt;/p&gt;

&lt;p&gt;Ok, let's remove any possible exclusions, by completing the &lt;code&gt;_config.yml&lt;/code&gt; like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# _config.yml&lt;/span&gt;

&lt;span class="na"&gt;algolia&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;application_id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;paste_your_application_id_here'&lt;/span&gt;
  &lt;span class="na"&gt;index_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;albums'&lt;/span&gt;
  &lt;span class="na"&gt;files_to_exclude&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;... and try to run again:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ ALGOLIA_API_KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'paste_your_admin_api_key_here'&lt;/span&gt; bundle &lt;span class="nb"&gt;exec &lt;/span&gt;jekyll algolia
Configuration file: /Users/adrienjoly/Dev/adrienjoly/jekyll-tutorial/_config.yml
Processing site...
Rendering to HTML &lt;span class="o"&gt;(&lt;/span&gt;100%&lt;span class="o"&gt;)&lt;/span&gt; |&lt;span class="o"&gt;======================================================================&lt;/span&gt;|
Extracting records &lt;span class="o"&gt;(&lt;/span&gt;100%&lt;span class="o"&gt;)&lt;/span&gt; |&lt;span class="o"&gt;=====================================================================&lt;/span&gt;|
Updating settings of index albums
Getting list of existing records
Updating records &lt;span class="k"&gt;in &lt;/span&gt;index albums...
Records to delete: 0
Records to add: 4
✔ Indexing &lt;span class="nb"&gt;complete&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It worked! 🙌&lt;/p&gt;

&lt;p&gt;Let's see how our search index looks, back in our Algolia dashboard:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffiknnj3x9ge66wsjtgro.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffiknnj3x9ge66wsjtgro.png" alt="screenshot of algolia dashboard with index of albums" width="800" height="433"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The good news is that the dashboard displays "Blood sugar sex magik", which is one of the albums listed on my website!&lt;/p&gt;

&lt;p&gt;The bad news is that it contains 4 records, whereas my collection currently contains 2 albums. Something wrong must have happened during the indexing process... 🤔&lt;/p&gt;

&lt;p&gt;Thanks to an error message I had got previously when trying to run &lt;code&gt;bundle exec jekyll algolia&lt;/code&gt; (and that I did not include completely above, for simplicity), I discovered that it was possible to specify what HTML elements should be indexed: the &lt;code&gt;nodes_to_index&lt;/code&gt; property.&lt;/p&gt;

&lt;p&gt;So let's tell Jekyll-Algolia to index our &lt;code&gt;article&lt;/code&gt; elements (as specified in the Jekyll template we had written during &lt;a href="https://dev.to/adrienjoly/how-to-maintain-a-collection-of-music-albums-online-using-jekyll-and-github-pages-3hd6"&gt;the previous tutorial&lt;/a&gt;), by updating our &lt;code&gt;_config.yml&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# _config.yml&lt;/span&gt;

&lt;span class="na"&gt;algolia&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;application_id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;paste_your_application_id_here'&lt;/span&gt;
  &lt;span class="na"&gt;index_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;albums'&lt;/span&gt;
  &lt;span class="na"&gt;files_to_exclude&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[]&lt;/span&gt;
  &lt;span class="na"&gt;nodes_to_index&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;article'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After running the &lt;code&gt;bundle exec jekyll algolia&lt;/code&gt; command again and refreshing the Algolia dashboard, we now have 2 albums in our search index! ✊&lt;/p&gt;

&lt;p&gt;Quick test before moving on: let's search for one of my albums, from Algolia's dashboard:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjqgdk5nvflw9pi5uazh4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjqgdk5nvflw9pi5uazh4.png" alt="testing album search from algolia dashboard" width="800" height="535"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;✅ Working as expected!&lt;/p&gt;

&lt;h1&gt;
  
  
  Step 3. Integrate the search bar
&lt;/h1&gt;

&lt;p&gt;It's very cool to have a search index automatically populated from our website! But it's quite useless before we display a search bar on it. And this new step is beyond the scope of Jekyll-Algolia: we now need to use one of Algolia's search clients into our website.&lt;/p&gt;

&lt;h2&gt;
  
  
  (3.1) Import &lt;code&gt;instantsearch.js&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;Let's head to the "Build Search UI" section of &lt;a href="https://www.algolia.com/doc/" rel="noopener noreferrer"&gt;Algolia's Documentation website&lt;/a&gt;. We are gonna use the easiest and most versatile UI integration: &lt;a href="https://community.algolia.com/instantsearch.js/" rel="noopener noreferrer"&gt;InstantSearch.js&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;As advised in the &lt;a href="https://community.algolia.com/instantsearch.js/v2/getting-started.html" rel="noopener noreferrer"&gt;Getting started&lt;/a&gt; instructions, let's import the CDN-based stylesheets and script into our &lt;code&gt;index.md&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;link&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;"stylesheet"&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"index.css"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;

&lt;span class="gu"&gt;## Albums&lt;/span&gt;

{% for album in site.data.albums %}
  &lt;span class="nt"&gt;&amp;lt;article&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"{{ album.url }}"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"{{ album.img }}"&lt;/span&gt; &lt;span class="na"&gt;alt=&lt;/span&gt;&lt;span class="s"&gt;"{{ album.title }} {{ album.artist }}"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;{{ album.title }}&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;by {{ album.artist }}&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
    {% if release-date %}
      &lt;span class="nt"&gt;&amp;lt;span&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"release-date"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;{{ album.release_date | date: "%b %-d, %Y" }}&lt;span class="nt"&gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
    {% endif %}
  &lt;span class="nt"&gt;&amp;lt;/article&amp;gt;&lt;/span&gt;
{% endfor %}

&lt;span class="c"&gt;&amp;lt;!-- algolia search --&amp;gt;&lt;/span&gt;

&lt;span class="nv"&gt;&amp;lt;link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/npm/instantsearch.js@2.8.1/dist/instantsearch.min.css"&amp;gt;&lt;/span&gt;
&lt;span class="nv"&gt;&amp;lt;link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/npm/instantsearch.js@2.8.1/dist/instantsearch-theme-algolia.min.css"&amp;gt;&lt;/span&gt;

&lt;span class="nv"&gt;&amp;lt;script src="https://cdn.jsdelivr.net/npm/instantsearch.js@2.8.1"&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
  /&lt;span class="ge"&gt;* we are going to add some javascript code here *&lt;/span&gt;/
&lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;

&lt;span class="c"&gt;&amp;lt;!-- end of algolia search --&amp;gt;&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I like to test regularly that I did not break anything:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;bundle &lt;span class="nb"&gt;exec &lt;/span&gt;jekyll serve &lt;span class="nt"&gt;--incremental&lt;/span&gt;

  Server address: http://127.0.0.1:4000
  Server running... press ctrl-c to stop.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When I open &lt;code&gt;http://127.0.0.1:4000&lt;/code&gt; in my browser (Google Chrome), I find the following errors in the JavaScript console:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5vazri6dt5yvyjyd0tqs.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5vazri6dt5yvyjyd0tqs.png" alt="javascript error when trying to import algolia instantsearch from localhost" width="800" height="435"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Refused to apply style from '&lt;a href="https://cdn.jsdelivr.net/npm/instantsearch.js@2.8.1/dist/instantsearch.min.css" rel="noopener noreferrer"&gt;https://cdn.jsdelivr.net/npm/instantsearch.js@2.8.1/dist/instantsearch.min.css&lt;/a&gt;' because its MIME type ('text/plain') is not a supported stylesheet MIME type, and strict MIME checking is enabled.&lt;/li&gt;
&lt;li&gt;Refused to apply style from '&lt;a href="https://cdn.jsdelivr.net/npm/instantsearch.js@2.8.1/dist/instantsearch-theme-algolia.min.css" rel="noopener noreferrer"&gt;https://cdn.jsdelivr.net/npm/instantsearch.js@2.8.1/dist/instantsearch-theme-algolia.min.css&lt;/a&gt;' because its MIME type ('text/plain') is not a supported stylesheet MIME type, and strict MIME checking is enabled.&lt;/li&gt;
&lt;li&gt;GET &lt;a href="https://cdn.jsdelivr.net/npm/instantsearch.js@2.8.1" rel="noopener noreferrer"&gt;https://cdn.jsdelivr.net/npm/instantsearch.js@2.8.1&lt;/a&gt; 404 ()&lt;/li&gt;
&lt;li&gt;Refused to execute script from '&lt;a href="https://cdn.jsdelivr.net/npm/instantsearch.js@2.8.1" rel="noopener noreferrer"&gt;https://cdn.jsdelivr.net/npm/instantsearch.js@2.8.1&lt;/a&gt;' because its MIME type ('text/plain') is not executable, and strict MIME type checking is enabled.&lt;/li&gt;
&lt;li&gt;Uncaught ReferenceError: instantsearch is not defined&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Let's ignore CSS errors for now (1, 2), and start with JavaScript errors (3, 4, 5) instead, because they are the ones that prevent the search from initialising:&lt;/p&gt;

&lt;p&gt;The last error (5) is caused by the fact that the &lt;code&gt;instantsearch.js&lt;/code&gt; could not be loaded (3, 4). And apparently, it was not able to load because the provided URL does not have the expected MIME type. It could be that MIME type checking is enforced when opening a webpage from &lt;code&gt;localhost&lt;/code&gt;, like I'm doing now.&lt;/p&gt;

&lt;p&gt;The same problem seems to happen with CSS files.&lt;/p&gt;

&lt;p&gt;When trying to open theses files in separate browser tabs, I understand that it's not only a matter of MIME types, these URLs are returning pages with an error message: "&lt;em&gt;Couldn't find the requested release version 2.8.1.&lt;/em&gt;"!&lt;/p&gt;

&lt;p&gt;By removing the "@2.8.1" part of these URLs, they seem to work fine! After applying this same change to my &lt;code&gt;index.md&lt;/code&gt; file and refreshing the page, all errors disappeared from the JavaScript console! 😇&lt;/p&gt;

&lt;h2&gt;
  
  
  (3.2) Instantiate the search bar and hits
&lt;/h2&gt;

&lt;p&gt;Now that &lt;code&gt;instantsearch.js&lt;/code&gt; is imported properly, we need to write some code to instantiate our search bar and hits.&lt;/p&gt;

&lt;p&gt;First, we are going to add &lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt; elements in &lt;code&gt;index.md&lt;/code&gt;, so that &lt;code&gt;instantsearch.js&lt;/code&gt; knows where to integrate the search bar and the hits.&lt;/p&gt;

&lt;p&gt;As advised in the "&lt;a href="https://community.algolia.com/instantsearch.js/v2/getting-started.html#add-a-searchbox" rel="noopener noreferrer"&gt;Add a searchbox&lt;/a&gt;" part of Instantsearch's tutorial, we start by adding the following HTML code between our Jekyll template (to display albums) and the section that imports &lt;code&gt;instantsearch.js&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;="search-box"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="c"&gt;&amp;lt;!-- SearchBox widget will appear here --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"hits"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="c"&gt;&amp;lt;!-- Hits widget will appear here --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Remember the &lt;code&gt;/* we are going to add some javascript code here */&lt;/code&gt; comment we had written in a &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt; element of &lt;code&gt;index.md&lt;/code&gt;? The time has come to fill this &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt; element!&lt;/p&gt;

&lt;p&gt;As advised in the "Initialization" and "Display results" of &lt;a href="https://community.algolia.com/instantsearch.js/v2/getting-started.html#initialization" rel="noopener noreferrer"&gt;Instantsearch's tutorial&lt;/a&gt;, let's add the following JavaScript code there:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;search&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;instantsearch&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="c1"&gt;// TODO: enter our own algolia credentials here&lt;/span&gt;
    &lt;span class="na"&gt;appId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;latency&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;apiKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;6be0576ff61c053d5f9a3225e2a90f76&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;indexName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;instant_search&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;routing&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="nx"&gt;search&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addWidget&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;instantsearch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;widgets&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;searchBox&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;container&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#search-box&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;placeholder&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Search for albums&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="nx"&gt;search&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addWidget&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;instantsearch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;widgets&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;hits&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;container&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#hits&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;templates&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;empty&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;No results&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;item&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;&amp;lt;em&amp;gt;Hit {{objectID}}&amp;lt;/em&amp;gt;: {{{_highlightResult.name.value}}}&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="nx"&gt;search&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;start&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, let's refresh the &lt;code&gt;http://127.0.0.1:4000&lt;/code&gt; browser tab to see if it works. (you may need to restart the &lt;code&gt;$ bundle exec jekyll serve --incremental&lt;/code&gt; command)&lt;/p&gt;

&lt;p&gt;That's what I get:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fff6g6azry9p1luj0frrw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fff6g6azry9p1luj0frrw.png" alt="screenshot of instantsearch.js with a curly brace glitch" width="800" height="535"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The search box is displayed nicely, but we're also seeing several &lt;code&gt;Hit : }&lt;/code&gt; lines under it... 🤔&lt;/p&gt;

&lt;p&gt;If we had been more attentive, we would have seen that the &lt;code&gt;bundle exec jekyll serve&lt;/code&gt; command had given us a warning that seems linked to this problem:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Liquid Warning: Liquid syntax error (line 55): Unexpected character { in "{{{_highlightResult.name.value}}" in index.md
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;My hypothesis is that the template I had copy-pasted from Instantsearch's tutorial conflicts with Jekyll's template parser. If this hypothesis is right, moving this JavaScript code to a separate &lt;code&gt;.js&lt;/code&gt; file should fix this problem.&lt;/p&gt;

&lt;p&gt;I can confirm that my hypothesis was right: moving the JavaScript code to a new &lt;code&gt;search.js&lt;/code&gt; file, and importing that file from &lt;code&gt;index.md&lt;/code&gt; using &lt;code&gt;&amp;lt;script src="search.js"&amp;gt;&amp;lt;/script&amp;gt;&lt;/code&gt; does the trick! 😁&lt;/p&gt;

&lt;p&gt;So now, here is what I get:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxwv8gp9np7ydvwxiue7b.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxwv8gp9np7ydvwxiue7b.png" alt="screenshot of instantsearch.js integration with default search index" width="800" height="512"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The list displayed under the search bar does adapt in real-time when I type in it, but the hits are not albums!&lt;/p&gt;

&lt;h2&gt;
  
  
  (3.3) Customise for our search index
&lt;/h2&gt;

&lt;p&gt;We need to plug the right Algolia index to our &lt;code&gt;instantsearch.js&lt;/code&gt; instance. In order to do that, we have to change the values of the &lt;code&gt;appId&lt;/code&gt;, &lt;code&gt;apiKey&lt;/code&gt; and &lt;code&gt;indexName&lt;/code&gt; properties, to match the credentials of our own Algolia index.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note: These credentials will be used by &lt;code&gt;instantsearch.js&lt;/code&gt; just to send search queries, so you should enter your "Search-Only API Key" here. (found on the same page as the "Admin API Key")&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;After doing that, I'm able to search my album collection:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmz6xsopsko9tncdvtd8j.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmz6xsopsko9tncdvtd8j.png" alt="screenshot of instantsearch integration with untitled hits" width="800" height="376"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We're getting some hits when typing words that are part of our albums' names, but the name of the resulting albums are not displayed.&lt;/p&gt;

&lt;p&gt;As you can see on your Algolia dashboard, the title of albums are stored in an attribute called &lt;code&gt;content&lt;/code&gt;. So that's what we should display.&lt;/p&gt;

&lt;p&gt;To do that, we need to update our hit template from &lt;code&gt;search.js&lt;/code&gt;, from:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;      &lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;&amp;lt;em&amp;gt;Hit {{objectID}}&amp;lt;/em&amp;gt;: {{{_highlightResult.name.value}}}&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;... to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;      &lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;&amp;lt;em&amp;gt;Hit {{objectID}}&amp;lt;/em&amp;gt;: {{{_highlightResult.content.value}}}&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That should do! ✊&lt;/p&gt;

&lt;h1&gt;
  
  
  Resulting files
&lt;/h1&gt;

&lt;p&gt;You can find the source code what we produced in that github repository: &lt;a href="https://github.com/adrienjoly/jekyll-tutorial" rel="noopener noreferrer"&gt;github.com/adrienjoly/jekyll-tutorial&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Here are the files that we created or updated in this tutorial:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;Gemfile&lt;/code&gt;:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Gemfile

source 'https://rubygems.org'
gem 'github-pages', group: :jekyll_plugins

group :jekyll_plugins do
  gem 'jekyll-algolia', '~&amp;gt; 1.0'
end
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;_config.yml&lt;/code&gt;:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# _config.yml&lt;/span&gt;

&lt;span class="na"&gt;algolia&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;application_id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;paste_your_application_id_here'&lt;/span&gt;
  &lt;span class="na"&gt;index_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;albums'&lt;/span&gt;
  &lt;span class="na"&gt;files_to_exclude&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[]&lt;/span&gt;
  &lt;span class="na"&gt;nodes_to_index&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;article'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;index.md&lt;/code&gt;:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;link&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;"stylesheet"&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"index.css"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;

## Albums

{% for album in site.data.albums %}
  &lt;span class="nt"&gt;&amp;lt;article&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"{{ album.url }}"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"{{ album.img }}"&lt;/span&gt; &lt;span class="na"&gt;alt=&lt;/span&gt;&lt;span class="s"&gt;"{{ album.title }} {{ album.artist }}"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;{{ album.title }}&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;by {{ album.artist }}&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
    {% if release-date %}
      &lt;span class="nt"&gt;&amp;lt;span&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"release-date"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;{{ album.release_date | date: "%b %-d, %Y" }}&lt;span class="nt"&gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
    {% endif %}
  &lt;span class="nt"&gt;&amp;lt;/article&amp;gt;&lt;/span&gt;
{% endfor %}

## Search

&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"search-box"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="c"&gt;&amp;lt;!-- SearchBox widget will appear here --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"hits"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="c"&gt;&amp;lt;!-- Hits widget will appear here --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;

&lt;span class="c"&gt;&amp;lt;!-- algolia search --&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;link&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;"stylesheet"&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"text/css"&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"https://cdn.jsdelivr.net/npm/instantsearch.js/dist/instantsearch.min.css"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;link&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;"stylesheet"&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"text/css"&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"https://cdn.jsdelivr.net/npm/instantsearch.js/dist/instantsearch-theme-algolia.min.css"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"https://cdn.jsdelivr.net/npm/instantsearch.js"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"search.js"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;

&lt;span class="c"&gt;&amp;lt;!-- end of algolia search --&amp;gt;&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;search.js&lt;/code&gt;:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;search&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;instantsearch&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;appId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;R6Y1H83FNX&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;apiKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;b0f283176b810e5223f70e3ab3ac7c04&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;indexName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;albums&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;routing&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;search&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addWidget&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;instantsearch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;widgets&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;searchBox&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;container&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#search-box&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;placeholder&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Search for albums&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;search&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addWidget&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;instantsearch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;widgets&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;hits&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;container&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#hits&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;templates&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;empty&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;No results&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;item&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;&amp;lt;em&amp;gt;Hit {{objectID}}&amp;lt;/em&amp;gt;: {{{_highlightResult.content.value}}}&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;search&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;start&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Next: Fix the UI
&lt;/h1&gt;

&lt;p&gt;In this tutorial, we:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;created a search index on algolia.com&lt;/li&gt;
&lt;li&gt;setup Jekyll-Algolia to populate this index from our list of albums&lt;/li&gt;
&lt;li&gt;integrated instantsearch.js (despite a CDN issue)&lt;/li&gt;
&lt;li&gt;and plugged our own index to the search components&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We also learned how to upgrade &lt;code&gt;ruby&lt;/code&gt; and how to preview the Jekyll site from &lt;code&gt;localhost&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Despite the fact that we have a working search bar on our album collection, the resulting website is not good looking, nor usable.&lt;/p&gt;

&lt;p&gt;In the next tutorial, we will define what user experience we're aiming for, and implement it. Hopefully, our album collection will look great again, after that!&lt;/p&gt;

&lt;p&gt;Stay tuned, and please share your comments, questions and suggestions, if any!&lt;/p&gt;

</description>
      <category>ghpages</category>
      <category>jekyll</category>
      <category>search</category>
      <category>algolia</category>
    </item>
    <item>
      <title>How to maintain a collection of music albums online, using Jekyll and Github Pages</title>
      <dc:creator>Adrien Joly</dc:creator>
      <pubDate>Sat, 30 Jun 2018 15:26:34 +0000</pubDate>
      <link>https://dev.to/adrienjoly/how-to-maintain-a-collection-of-music-albums-online-using-jekyll-and-github-pages-3hd6</link>
      <guid>https://dev.to/adrienjoly/how-to-maintain-a-collection-of-music-albums-online-using-jekyll-and-github-pages-3hd6</guid>
      <description>&lt;p&gt;I love to make lists.&lt;/p&gt;

&lt;p&gt;Lists of tasks (ToDo), of books to read, of cities I visited, of places I'd like to go, of my favorite restaurants in Paris, of the most recommendable freelancers...&lt;/p&gt;

&lt;p&gt;As a matter of fact, I'm pretty sure that at least half of all the business and productivity apps out there were made to help us maintain lists.&lt;/p&gt;

&lt;h1&gt;
  
  
  The Motivation
&lt;/h1&gt;

&lt;p&gt;One of my lists is very dear to my heart. It's my collection of music albums.&lt;/p&gt;

&lt;p&gt;In the past, it used to be materialised by a stack of cassettes. Then, it turned into a shelf of CDs. Then, it became a list of folders full of MP3 files, stored in the hard-disk of my computer.&lt;/p&gt;

&lt;p&gt;More recently, it's become more convenient to stream music directly from the Internet, without having to own anything, thanks to services like Spotify. Eventually, my collection of albums turned into a very long list of playlists, stacked on the left of my Spotify window, without cover art...&lt;/p&gt;

&lt;p&gt;I've definitely gained in terms of convenience, saving space in my appartment, and reduced fear of losing (or damaging) material records. But what about the pleasure of browsing my collection randomly, while appreciating the beautiful cover art? Lost.&lt;/p&gt;

&lt;p&gt;Let's solve this. Let's bring back the joy of having a beautiful music collection again!&lt;/p&gt;

&lt;h1&gt;
  
  
  Existing solutions
&lt;/h1&gt;

&lt;p&gt;There are many ways to keep an album collection.&lt;/p&gt;

&lt;p&gt;Firstly, Spotify does allow me to &lt;em&gt;Add&lt;/em&gt; an album to my collection, to later find it in the "Albums" page. But unfortunately, this list also includes the album containing each track I've ever liked on Spotify, even though I don't care about the rest of that album... So in the end, it does not really look like a hand-picked collection of albums.&lt;/p&gt;

&lt;p&gt;So let's ask Google: "album collection online". First result is &lt;a href="https://www.discogs.com" rel="noopener noreferrer"&gt;discogs.com&lt;/a&gt;. This website does allow to create a profile and add albums to my collection, with cover art! But it was clearly designed for vinyl disc collectors, as each album is listed in various editions with different track lists, and you have to pick &lt;em&gt;one&lt;/em&gt; of them in order to add it to your collection. Too cumbersome for me... Also, I did not find any way to play the album in one click from there.&lt;/p&gt;

&lt;p&gt;What if I used a more generic service to maintain my collection in a visual manner? Pinterest seems like a good candidate! Unfortunately, Pinterest just provides a full-text description field for each image, making it impossible to browse albums by artist or genre...&lt;/p&gt;

&lt;p&gt;Maybe I should keep my collection in a database, and setup a piece of software to maintain it? A content management system (like Wordpress) with a few plug-ins and a good theme could probably work. But at what cost? I'd need to host it on a PHP server, run software updates, tweak plug-ins and themes that somebody else made, and probably pay for hosting. That seems too complicated.&lt;/p&gt;

&lt;p&gt;What about keeping my list in a static HTML file with simple CSS styling to make it look like a material album collection? That's definitely less complex and costly to publish! But it's also easy to forecast the limitations: having to edit HTML code every time I want to add an album, necessity to add JavaScript / DOM manipulation in order to make it browseable by artist and searchable...&lt;/p&gt;

&lt;p&gt;What if I could maintain my list of albums in a text file, and have HTML files automatically generated from it? 🤔&lt;/p&gt;

&lt;p&gt;Isn't that the promise of Jekyll, supported for free by Github Pages?&lt;/p&gt;

&lt;p&gt;That's it! I finally found a good excuse to learn how to use Jekyll!&lt;/p&gt;

&lt;h1&gt;
  
  
  Designing the solution
&lt;/h1&gt;

&lt;p&gt;Let's recap what I expect from my album collection:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Display cover art in a beautiful gallery&lt;/li&gt;
&lt;li&gt;Play the album in one-click, from Spotify or other&lt;/li&gt;
&lt;li&gt;Browse by artist or genre&lt;/li&gt;
&lt;li&gt;Quick and easy CRUD operations (i.e. Create, Retrieve, Update and Delete albums)&lt;/li&gt;
&lt;li&gt;Fast search&lt;/li&gt;
&lt;li&gt;Low risk of data loss or corruption&lt;/li&gt;
&lt;li&gt;Available online, for the world to see!&lt;/li&gt;
&lt;li&gt;Easily forkable, for other developers who want to make their own collection.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I know that it's quite easy for me to build a HTML+CSS web page that would cover points 1 and 2.&lt;/p&gt;

&lt;p&gt;I've read that Jekyll can generate static HTML pages based on data files expressed in YAML, which is an almost-plain-text structured markup format similar to Markdown. This could cover points 3 and 4.&lt;/p&gt;

&lt;p&gt;I also know that Github Pages is my favorite way to publish web pages for free, and that it supports Jekyll out of the box. Meaning that, if I put Jekyll files in my repository, Github will automatically generate the resulting HTML pages. And of course, I can run Jekyll offline on my laptop as well. That will cover points 6 to 8.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://pages.github.com/" rel="noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F68yc4gyhko7m4id8s5bv.png" alt="Github Pages with Jekyll support"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;What about fast search? Oh, wait! I work for Algolia, and one of my colleagues made a plug-in to make any Jekyll website searchable: &lt;a href="https://community.algolia.com/jekyll-algolia/" rel="noopener noreferrer"&gt;Jekyll-Algolia&lt;/a&gt;!&lt;/p&gt;

&lt;p&gt;That sounds like a realistic and exciting plan! Let's make this a reality!&lt;/p&gt;

&lt;h1&gt;
  
  
  Step 1. Initialise a Jekyll page on Github Pages
&lt;/h1&gt;

&lt;p&gt;To get started, let's set a simple goal to ourselves: make Github Pages render and publish a HTML file out of a simple Markdown file.&lt;/p&gt;

&lt;p&gt;I assume that you have a Github repository (fresh or not) ready to host your Jekyll files. If not, please create one and make sure that you are able to commit and push files to it from your computer. I will follow each step on that one: &lt;a href="https://github.com/adrienjoly/jekyll-tutorial" rel="noopener noreferrer"&gt;github.com/adrienjoly/jekyll-tutorial&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Let's add a &lt;code&gt;index.md&lt;/code&gt; file at the root of the &lt;code&gt;master&lt;/code&gt; branch of our repository, with the following contents:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;Hello world!

This is a &lt;span class="gs"&gt;**markdown**&lt;/span&gt; file.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, let's ask Github Pages to render and publish it as a website. For that, go to your repository's settings page (mine: &lt;a href="https://github.com/adrienjoly/jekyll-tutorial/settings" rel="noopener noreferrer"&gt;https://github.com/adrienjoly/jekyll-tutorial/settings&lt;/a&gt;), and pick the &lt;code&gt;master&lt;/code&gt; branch as "Source", in the "GitHub Pages" section:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Fadrienjoly%2Falbum-shelf%2Fraw%2Fmaster%2Fdocs%2Fgithub-repo-pages.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Fadrienjoly%2Falbum-shelf%2Fraw%2Fmaster%2Fdocs%2Fgithub-repo-pages.png" alt="pick the branch for github pages"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then click "Save".&lt;/p&gt;

&lt;p&gt;Now, you should be able to see your index by opening the URL &lt;code&gt;https://&amp;lt;your_username&amp;gt;.github.com/&amp;lt;your_repo_name&amp;gt;&lt;/code&gt; in your web browser. If everything went well, it must have been rendered in HTML by Github Pages, thanks to Jekyll, and look like that:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F181lwcjbezci8pql3vha.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F181lwcjbezci8pql3vha.png" alt="screenshot of index.md rendered in HTML by github pages and jekyll"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Good job!&lt;/p&gt;

&lt;h1&gt;
  
  
  Step 2. Render a simple list using Jekyll
&lt;/h1&gt;

&lt;p&gt;Now, let's integrate a simple list into that page.&lt;/p&gt;

&lt;p&gt;In order to do that, we will:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;create a &lt;code&gt;.yaml&lt;/code&gt; file in the &lt;code&gt;_data&lt;/code&gt; folder,&lt;/li&gt;
&lt;li&gt;and add a template to integrate its data in &lt;code&gt;index.md&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In my case, I'm going to create a &lt;code&gt;_data/albums.yaml&lt;/code&gt; file with the following contents:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Blood Sugar Sex Magik&lt;/span&gt;
  &lt;span class="na"&gt;artist&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Red Hot Chili Peppers&lt;/span&gt;
  &lt;span class="na"&gt;img&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;https://i.scdn.co/image/5a6a1c6514398dc4004c6348a83d77694a3883d4&lt;/span&gt;
  &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;https://open.spotify.com/album/30Perjew8HyGkdSmqguYyg&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And then, I add the following template to &lt;code&gt;index.md&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gu"&gt;## Albums&lt;/span&gt;

{% for album in site.data.albums %}
&lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;{{ album.title }} by {{ album.artist }}&lt;/span&gt;&lt;span class="p"&gt;](&lt;/span&gt;&lt;span class="sx"&gt;{{&lt;/span&gt; album.url }})
{% endfor %}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This template will render a HTML list item for every item from &lt;code&gt;_data/albums.yaml&lt;/code&gt;. Each item will be render as a hyperlink displaying the title and artist of the album, and linking to its Spotify page.&lt;/p&gt;

&lt;p&gt;Let's refresh &lt;code&gt;https://&amp;lt;your_username&amp;gt;.github.com/&amp;lt;your_repo_name&amp;gt;&lt;/code&gt;. After giving Github a few seconds to re-render the website, the resulting page should look like that:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fq7m3720s0ja6vhpjaljs.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fq7m3720s0ja6vhpjaljs.png" alt="yaml list rendered in html thanks to jekyll"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We're making some progress!&lt;/p&gt;

&lt;p&gt;Of course, you can add as many items in &lt;code&gt;_data/albums.yaml&lt;/code&gt; as you like!&lt;/p&gt;

&lt;p&gt;For more information about the syntax of the YAML format, read &lt;a href="https://symfony.com/doc/current/components/yaml/yaml_format.html" rel="noopener noreferrer"&gt;The YAML Format (Symfony Docs)&lt;/a&gt;.&lt;/p&gt;

&lt;h1&gt;
  
  
  Step 3. Make it look better
&lt;/h1&gt;

&lt;p&gt;Now that we know how to create a list in YAML, and how to render it in Markdown, let's make it look like a proper collection of albums!&lt;/p&gt;

&lt;p&gt;The first thing that is missing is cover art.&lt;/p&gt;

&lt;p&gt;In order to display images, we can of course use the Markdown syntax: &lt;code&gt;![alt](src)&lt;/code&gt;. But, in order to get more flexibility while designing our list, we will use some good old HTML instead. Yes, Jekyll does supports HTML markup in a Markdown files.&lt;/p&gt;

&lt;p&gt;Let's replace the template we had integrated in the previous step by this one:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;{% for album in site.data.albums %}
  &lt;span class="nt"&gt;&amp;lt;article&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"{{ album.url }}"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"{{ album.img }}"&lt;/span&gt; &lt;span class="na"&gt;alt=&lt;/span&gt;&lt;span class="s"&gt;"{{ album.title }} {{ album.artist }}"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;{{ album.title }}&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;by {{ album.artist }}&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
    {% if release-date %}
      &lt;span class="nt"&gt;&amp;lt;span&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"release-date"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;{{ album.release_date | date: "%b %-d, %Y" }}&lt;span class="nt"&gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
    {% endif %}
  &lt;span class="nt"&gt;&amp;lt;/article&amp;gt;&lt;/span&gt;
{% endfor %}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Assuming that you added at least a second album to your list, the resulting page would probably end up looking like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fsragw5z78zqfqpg1mr3u.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fsragw5z78zqfqpg1mr3u.png" alt="list of albums with cover art"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Of course, we can do better by adding a bit of styling in &lt;code&gt;index.css&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;box-sizing&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;border-box&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nt"&gt;article&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;inline-block&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;320px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;420px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;8px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;overflow&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;hidden&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nt"&gt;article&lt;/span&gt; &lt;span class="nt"&gt;img&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;320px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;320px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.markdown-body&lt;/span&gt; &lt;span class="nt"&gt;article&lt;/span&gt; &lt;span class="nt"&gt;p&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;margin-bottom&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.release-date&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;gray&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;font-size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;90%&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But, even after refreshing the resulting page, you'll see that this stylesheet was not automatically picked up by Jekyll...&lt;/p&gt;

&lt;p&gt;So, now that we know that HTML markup is supported on top of Markdown, let's add a &lt;code&gt;&amp;lt;link&amp;gt;&lt;/code&gt; element at the top of &lt;code&gt;index.md&lt;/code&gt;, to load our stylesheet:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;link&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;"stylesheet"&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"index.css"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After refreshing the page, you will hopefully see some UI improvements:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Foc4k59snx3shnyeslcjc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Foc4k59snx3shnyeslcjc.png" alt="album list with cover art and css styling"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Looking good!&lt;/p&gt;

&lt;p&gt;Now, feel free to clean &lt;code&gt;index.md&lt;/code&gt; from our old tests. (e.g. "hello world")&lt;/p&gt;

&lt;h1&gt;
  
  
  Summary of progress
&lt;/h1&gt;

&lt;p&gt;To illustrate our progress, let's update the list of requirements I had proposed at the beginning of this article:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;del&gt;Display cover art in a beautiful gallery&lt;/del&gt; ✅&lt;/li&gt;
&lt;li&gt;
&lt;del&gt;Play the album in one-click, from Spotify or other&lt;/del&gt; ✅&lt;/li&gt;
&lt;li&gt;Browse by artist or genre&lt;/li&gt;
&lt;li&gt;
&lt;del&gt;Quick and easy CRUD operations (i.e. Create, Retrieve, Update and Delete albums)&lt;/del&gt; ✅ (&lt;em&gt;room for improvement&lt;/em&gt;)&lt;/li&gt;
&lt;li&gt;Fast search&lt;/li&gt;
&lt;li&gt;
&lt;del&gt;Low risk of data loss or corruption&lt;/del&gt; ✅&lt;/li&gt;
&lt;li&gt;
&lt;del&gt;Available online, for the world to see!&lt;/del&gt; ✅&lt;/li&gt;
&lt;li&gt;
&lt;del&gt;Easily forkable, for other developers who want to make their own collection.&lt;/del&gt; ✅&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Whoa, we've done quite a lot, with so few lines of code and so little effort! ✊&lt;/p&gt;

&lt;h1&gt;
  
  
  Next steps
&lt;/h1&gt;

&lt;p&gt;So what can we do to make our collection ever better?&lt;/p&gt;

&lt;p&gt;For starters, we have not implemented any way to browse by artist or genre yet. There are many ways to do this, and I'm sure that would make an interesting follow-up to this article!&lt;/p&gt;

&lt;p&gt;You saw that it was quite easy to maintain the collection in YAML. But we can do better. It would be awesome to automatically populate the album data after typing just its name. Maybe we could achieve that by building a command line interface that would query Spotify's API and update &lt;code&gt;albums.yaml&lt;/code&gt; automatically!&lt;/p&gt;

&lt;p&gt;Search is also lacking. It would be interesting to try out &lt;a href="https://community.algolia.com/jekyll-algolia/" rel="noopener noreferrer"&gt;Jekyll-Algolia&lt;/a&gt;, as I proposed earlier.&lt;/p&gt;

&lt;p&gt;One more thing: what if I want to use my album collection while being offline? Worse, what if Github Pages dies? Can we run Jekyll ourselves, to generate the HTML website from our &lt;code&gt;index.md&lt;/code&gt; template and our &lt;code&gt;albums.yaml&lt;/code&gt; data file? Yes, we can! We just need to setup some software tools on our computer, and add a little bit of configuration to the Jekyll website. That's yet another topic that we can explore together in a next article.&lt;/p&gt;

&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;I hope that this article convinced you that Jekyll and Github Pages make a powerful (yet easy to use) duo to maintain beautiful and flexible lists online.&lt;/p&gt;

&lt;p&gt;As a lover of the Web, I wish that more lists were maintained that way, and that we rely less on closed apps to hold our data. This article aims to be a modest contribution towards promoting the DIY (&lt;em&gt;do it yourself&lt;/em&gt;) philosophy to the way we manage our lists of things, and more generally, our data.&lt;/p&gt;

&lt;p&gt;I'd love to read your feedback, ideas, and suggestions after reading this article. Please let me know what you'd like me to write about next!&lt;/p&gt;

</description>
      <category>tutorial</category>
      <category>ghpages</category>
      <category>jekyll</category>
      <category>staticweb</category>
    </item>
    <item>
      <title>Hi, I'm Adrien Joly</title>
      <dc:creator>Adrien Joly</dc:creator>
      <pubDate>Sat, 06 May 2017 12:49:19 +0000</pubDate>
      <link>https://dev.to/adrienjoly/hi-im-adrien-joly</link>
      <guid>https://dev.to/adrienjoly/hi-im-adrien-joly</guid>
      <description>&lt;p&gt;I have been coding for 27 years. (Ok, I kinda started when I was 7!)&lt;/p&gt;

&lt;p&gt;You can find me on GitHub as &lt;a href="https://github.com/adrienjoly" rel="noopener noreferrer"&gt;adrienjoly&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I live in Montreuil, Paris area, France.&lt;/p&gt;

&lt;p&gt;I work for myself by building my own products, and also teach JS programming at EEMI.&lt;/p&gt;

&lt;p&gt;I mostly program in these languages: JavaScript, in Node.js and in web browsers.&lt;/p&gt;

&lt;p&gt;I am currently learning more about how to sell a product (problem validation and marketing).&lt;/p&gt;

&lt;p&gt;Nice to meet you.&lt;/p&gt;

</description>
      <category>introduction</category>
    </item>
  </channel>
</rss>
