Building a Jekyll Site

Back in 2009 I got a brilliant idea into my head: I was going to build a site on top of Joomla. Why? I still don’t exactly understand my own thought process that lead me to that decision. I think it had something to do that it was branded as a content management system and I had some content I wanted to manage. Perhaps it was because it looked serious and enterprisey and I wanted to try something different hoping it would be less of a pain in the ass than WordPress. Or perhaps it was a bout of temporary insanity.

Don’t get me wrong, Joomla is a wonderful CMS with a billion features that will let you do just about anything, but typically in the least convenient and most convoluted manner. I’d be tempted to say that Joomla engineers never actually tested their software on live humans before pushing it out into the public but I suspect that’s wrong. I suspect they have done a ton of usability testing, and purposefully picked the least friendly and the most annoying user experience. Because, fuck you for using Joomla.

Granted, they might have made some great improvements since 2009, but I wouldn’t know because upon slapping it on the server, and vomiting my content all over it, I decided I never actually want to touch anything on the Admin side of it ever again. On day two of my adventure with Joomla I decided that shit needed to go, but since I just manually migrated (read copy and pasted) like dozens of Kilobytes of content into it, I couldn’t be bothered. So I took out my scheduling book, penciled the site upgrade for “when I get around to it” and then threw the book out the window, because scheduling things makes me sad and hungry which is why I never do it.

Fast forward to 2014 and I was still happily “getting around to it”, when my host sent me a nasty-gram saying my Joomla is literally stinking up their data center. I had no clue what they were on about, since the installation was pristine clean, vintage 2009 build in a virgin state of never having been patched, updated or maintained. But since they threatened to shut all of my things down unless I get that shit off their server I decided it was time. I got around to it.

Fist step was straight up deleting Joomla. Second step was picking the right toolkit for the job. I briefly considered WordPress, but that’s a whole other can of worms, but for different reasons. WordPress is actually pretty great as long as no one is reading your blog. As soon as you get readers, the fame goes to it’s head and it decides it owns all the memory and all of the CPU time on the server, and demands a monthly sacrifice of additional Rams as your user base grows. It is literally the bane of shared servers, and most WordPress “optimization” guides start by telling you to abandon all that you know, and run like seventeen layers of load-balanced proxy servers in front of it. Not that Joomla performance is any better, but that site had no readers so it was usable. But since I was getting around to updating it, one of the goals was making it more robust and scalable, rather than trading a nightmarish clustefuck of crap for a moderately unpleasant pile of excrement. I figured I might as well go for broke and trade it for something good: like a mound of fragrant poop or something.

Since the site was on a shared host with a Quintillion users, and I didn’t feel like paying for and setting up yet another droplet I opted for a statically generated site. I tried a few static site generators and Jekyll is the one that did not make me want to punch the wall in the face (if it had a face) so I opted for that. Plus, I already had some basic layout done, so I figured I might as well use it.

The huge benefit of having a static site running on a shared host is that in theory you will never have to touch it, other than to update the content. The host will take care of the updating the underlying OS and web server, and since you have no actual “code” running on your end, there is noting there to break. Once you put it up, it can run forever without framework or plarform upgrades. It is a low effort way to run a site.

As far as front end went, I knew I wanted to work with HTML5 and that I wanted a grid based systems because making floating sidebars is a pain in the ass. So I whipped out Bower and installed Bootstrap 3.

I know what you were going to say: fuck Bootstrap, and I agree. Bootstrap is terrible, awful and overused. In fact, I think the authors of the project realized how much of a crutch it is, which is why they introduced a conflict with Google Custom Search in the latest version. Bootstrap literally breakes Google’s dynamic search box code, because fuck you for using Bootsrap.

But, it’s easy, clean and I love it, so I bowered it. Bootstrap consumes jQuery as a dependency so I got that for free. This is another useful framework people love to shit all over (though for good reasons) but since I already got it I figured I might as well use it for… Something.

One crappy thing about Bower is that when it fetches dependencies it puts all of them in bower_components directory, including useless garbage such as Readme files, build files and etc. Some people package their distributable code for Bower, but most projects don’t give a shit and just use their main repository and give you un-compressed, un-minified files along with all the associated miscellaneous garbage. I loathe having Readme files showing up on a deployment server, so I decided to manually minify and concatenate my scripts and stylesheet with Bootrstrap ones. For
that I needed Grunt. For grunt I needed Node. And so it goes. It is funny how one decision cascades into a dependency tree.

Runtime Dependencies

Pretty much at the onset, I decided I will be using the following:

Only the first item on the list is something you would want to install locally. The rest can be run off a CDN pretty reliably. Actually, you could run jQuery off a CDN too, but I decided not to. This makes your bower.json incredibly simple:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
{
  "name": "My Site",
  "version": "0.0.0",
  "authors": [
    "Luke Maciak <my@email.com>"
  ],
  "description": "Blah blah blah, website",
  "license": "MIT",
  "homepage": "http://example.com",
  "private": true,
  "ignore": [
    "**/.*",
    "node_modules",
    "bower_components",
    "test",
    "tests"
  ],
  "dependencies": {
    "bootstrap": "~3.1.1"
  }
}

This is the nice thing about static sites. Your production does not need a lot of setup – you just copy the files over and your done. All the heavy lifting is done at development time.

Dev Dependencies

Here our list is longer. I need things to build the code, manage the dependencies and some way of deploying it all to a server in a non annoying way.

  1. Ruby and Gems
  2. Jekyll
  3. Node and NPM
  4. Grunt
  5. rsync for moving the files around between servers

I already had Ruby, Jekyll node and Grunt running on my system because… Well, why wouldn’t you. I mean, that’s sort of basic stuff you install on the first day when you get a new computer. So all I had to do was to steal a project.json file from another project and slap it in my directory:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
{
  "author": "Luke Maciak",
  "name": "My Website",
  "version": "1.0.0",
  "dependencies": {},
  "devDependencies": {
    "grunt-html-validation": "~0.1.6",
    "grunt-contrib-watch": "~0.5.3",
    "grunt-contrib-jshint": "~0.1.1",
    "grunt-contrib-uglify": "~0.1.1",
    "grunt-contrib-concat": "~0.1.3",
    "grunt-contrib-cssmin": "~0.5.0",
    "grunt-contrib-csslint": "~0.1.2",
    "grunt-contrib-copy": "~0.4.1",
    "grunt-shell": "^0.7.0"
  }
}

Once it was in place, fetching all the grunt dependencies was a matter of running npm install. Now comes the hard part: setting up your Gruntfile.

Basic Setup

For the sake of completion, here is my complete Gruntfile

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
/*global module:false*/
module.exports = function(grunt) {
 
    // Project configuration.
    grunt.initConfig({
        validation: {
            options: {
                reset: grunt.option('reset') || true,
            },
            files: "_site/**/!(google*).html"
        },
    watch: {
        files: "<config:htmllint.files>",
        tasks: 'validate'
    },
    jshint: {
      files: [  'Ggruntfile.js', 
                'scripts.js'
             ],
      options: {
        white: false,
        curly: true,
        eqeqeq: true,
        immed: true,
        latedef: true,
        newcap: true,
        noarg: true,
        sub: true,
        undef: true,
        boss: true,
        eqnull: true,
        smarttabs: true,
        browser: true,
        globals: {
            $: false,
            jQuery: false,
 
            // Underscore.js
            _: false,
 
            // Chrome console
            console: false,
 
          }
      },
    },
    csslint: {
        lint: {
            options: {
               'ids': false,
               'box-sizing': false
            },
            src: ['style.css']
        }
    },
    cssmin: {
        compress: {
            files: {
                'style.tmp.min.css': ['style.css'],
            }
        }
    },
    concat: {
        options: {
            separator: ';' + grunt.util.linefeed,
            stripBanners: true,
        },
        js: {
            src: [
                    'bower_components/jquery/dist/jquery.min.js',
                    'bower_components/bootstrap/dist/js/bootstrap.min.js',
                    'scripts.tmp.min.js'
            ],
            dest: 'resources/js/scripts.min.js'
        },
        css: {
            src: [
                    'bower_components/bootstrap/dist/css/bootstrap.min.css',
                    'style.tmp.min.css'
            ],
            dest: 'resources/css/style.min.css'
        }
    },
    copy: {
        main: {
            files: [  
                {   expand: true, 
                    flatten: true,
                    src: 'bower_components/bootstrap/dist/fonts/*', 
                    dest: 'resources/fonts', 
                    filter: 'isFile'
                }
            ]
        },
    },
    uglify : {
        main: {
                 src: ['scripts.js'],
                 dest: 'scripts.tmp.min.js'
             }
    },
    shell: {
        jekyll: {
            command: 'jekyll build'
        }
    }
    });
 
    grunt.loadNpmTasks('grunt-contrib-watch');
    grunt.loadNpmTasks('grunt-html-validation');
    grunt.loadNpmTasks('grunt-contrib-uglify');
    grunt.loadNpmTasks('grunt-contrib-jshint');
    grunt.loadNpmTasks('grunt-contrib-concat');
    grunt.loadNpmTasks('grunt-contrib-cssmin');
    grunt.loadNpmTasks('grunt-contrib-csslint');
    grunt.loadNpmTasks('grunt-contrib-copy');
    grunt.loadNpmTasks('grunt-shell');
 
    grunt.registerTask('default', ['jshint', 'uglify', 'csslint', 'cssmin', 'copy', 'concat']);
    grunt.registerTask('all', ['default', 'shell', 'validation']);
};

It is a huge, monolithic pile of configuration so let me explain what I’m trying to accomplish here. In an ideal world, you want to have a single CSS file linked at the top of your page, and a single JavaScript file linked on the bottom. If you use Bower to handle dependencies (as you should) this is not possible, because every little thing you install gets it’s own folder in bower_components folder. So your first task is to pick out the important parts from each of those folders, smush them together into these two files. This is what is happening here.

For example, lines 56-62 run my custom CSS rules (style.css) through a minifier (using grunt-contrib-ccsmin) that removes all the spaces, and makes it super-ugly for the purpose of loading faster. Likes 96-101 do the exact same thing to my custom JavaScript code in scripts.js via grunt-contrib-uglify. So I end up with two very ugly files style.tmp.min.css and scripts.tmp.min.js. All of these files will be excluded from Jekyll compilation via _config.yml exclude list.

Once I have those, I use the grunt-contrib-concat plugin to concatenate my custom stylesheets and scripts with those provided by Bootstrap. You can see that in lines 63-83. I end up with my two ideal production ready files named: style.min.css and scripts.min.css. The new files are placed in resources/ directory.

A side effect of re-locating the Bootstrap script and CSS is that you break the glyphicons. The css files have relative paths to the web-font included in the bootstrap package, so if you want it to work it has to be in the fonts/ directory relative to the css location. This is what the 84-95 section is about. I’m taking all the files from bootstrap_components/dist/fonts/ and placing them in resources/fonts/ like this:

resources/
├── css
│   └── style.min.css
├── fonts
│   ├── glyphicons-halflings-regular.eot
│   ├── glyphicons-halflings-regular.svg
│   ├── glyphicons-halflings-regular.ttf
│   └── glyphicons-halflings-regular.woff
└── js
    └── scripts.min.js

The rest of the file is mostly concerned with linting. I check my css code with grunt-contrib-csslint and my JavaScript with grunt-contrib-jshint which is fairly standard. In both cases I’m relaxing the linting notes a little bit to preserve my own sanity, and to get around ugly hacks. For example ‘box-sizing’: false on line 51 is there to allow me to fix the aforementioned css that completely breaks Google’s Custom Search functionality. Similarly on line 35 I’m declaring $ as a global, because JSHint does not uderstand jQuery and freaks out for no reason.

I’m also using the excellent grunt-html-validation plugin to make sure my HTML is valid.

Finally, here is my _config.yaml file for Jekyll. It is mostly unremarkable, save for the exclusion list where I prevent Jekyll from copying all of the useless files into production.

name: My Site
description: blah blah blah
author: Luke

category_dir: /
url: http://example.com

markdown: rdiscount
permalink: pretty
paginate: 5

exclude: [
            package.json, 
            bower.json, 
            grunt.js,
            Gruntfile.js, 
            node_modules, 
            bower_components,
            validation-report.json, 
            validation-status.json,
            scripts.js, 
            scripts.tmp.min.js,
            style.css,
            style.tmp.min.css,
            lgoo.psd,
            Makefile,
            exclude.rsync,
            README.markdown
         ]

Grunt takes care of compiling and linting all the front end code, while Jekyll builds the site from an assortment of html and markdown files. I already wrote a lengthy article about setting up a basic Jekyll site before, so I won’t bore you with the details here. The basic skeleton looks like this though:

.
├── _config.yml
├── _drafts/
├── _layouts/
│   ├── category_index.html
│   ├── default.html
│   ├── page.html
│   └── post.html
├── _plugins/
│   ├── generate_categories.rb
│   └── generate_sitemap.rb
├── bower.json
├── bower_components/
│   ├── bootstrap/
│   └── jquery/
├── exclude.rsync
├── favicon.ico
├── feed.xml
├── Gruntfile.js
├── imag/
├── index.html
├── Makefile
├── node_modules/
├── package.json
├── README.markdown
├── resources/
│   ├── css/
│   ├── fonts/
│   └── js/
├── robots.txt
├── _site/
├── scripts.js
└── style.css

The bower_components directory as well as the “naked” JavaScript and CSS files are excluded from compilation, in lieu of the resources which contains files generated by Grunt. Other than that this is a fairly standard structure.

Deployment

As I said before I decided to use rsync to deploy the website. There are many ways to deploy a Jekyll website, but this is probably the most efficient tool for the job. In an ideal world, you compile a Jekyll site, and then rsync compares your _site directory to what is on the server and only copies/deletes files that are different. This means you first upload will be massive, but from that point on, you are just going to transfer the deltas.

There is a little caveat here though: by default rsync compares files based on timestamps. This is a problem because Jekyll clobbers the _site directory every time you build your site. This means that every file inside of it will look brand spanking new to rsync even if it has not technically changed. This downgrades our delta-sync tool to just a crude file uploader that is no more sophisticated than an rm -rf command followed by scp _site/* host:~/site.

Fortunately, I found an excellent tip by Nathan Grigg which suggests telling rsync to use checksums instead of timestamps. By force of habit, when setting up an rsync script most of us might be tempted to write something like:

rsync -az --delete _site/* user@host:~/site

This is the traditional and wrong way of doing this. What Nathan suggests instead is:

rsync -crz --delete _site/* user@host:~/site

Or perhaps, more descriptively:

rsync --compress --recursive --checksum --delete _site/* luke@myhost:~/site/

I actually like to use the long arguments when I write scripts, because years down the road they will make it easy to understand what is going on without looking up cryptic letter assignments in the man pages.

To simplify deployment I wrote myself a little Makefile like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
.PHONY: check, deploy, tunnel-deploy, build
 
default: check, build
 
check:
	@command -v ssh >/dev/null 2>&1 || { echo "ERROR: please install ssh"; exit 1; }
	@command -v rsync >/dev/null 2>&1 || { echo "ERROR: please install rsync"; exit 1; }
	@command -v grunt >/dev/null 2>&1 || { echo "ERROR: please install grunt"; exit 1; }
	@command -v jekyll >/dev/null 2>&1 || { echo "ERROR: please install jekyll"; exit 1; }
	@[ -d "_site" ] || { echo "ERROR: Missing the _site folder."; exit 1; }
 
build: check
	grunt
	jekyll build
 
deploy: check, build
	rsync --compress --recursive --checksum --delete --itemize-changes --exclude-from exclude.rsync _site/* luke@myhost:~/site/
	ssh luke@myhost 'chmod -R 755 ~/site'

Tagging

Jekyll kinda supports tags and categories, but those are still rather underdeveloped features. When I build Jekyll sites I like to use Dave Perret’s plugin to get nice category archive pages. It also injects the category names into the “pretty” permalinks adding taxonomy to your url structure.

I have a very specific idea abut how tags and categories should be handled and how they differ. For me, categories group posts of a certain broad type, while tags are used to indicate specific topics/keywords that cut across the categories. So for example, you could have a category named “videos” and bunch of tags like “interview”, “trailer”, etc.. That said, the tag “interview” is not unique to the “videos” category and could also be used to tag posts in other categories like “pictures” for example. I like to have one category per post, but multiple tags. These is not a hard rules and most systems out there allow for more liberal use of both concepts. Dave’s plugin actually allows for multiple categories per post. But I typically stick to one. It is a personal preference of mine.

Categories are big, broad and there are few of them. I will often list them on the sidebar, and use them for navigation. Tags are different – they are more messy. So I opted to have a single page that would essentially be a table of contents by tag.

Michael Lanyon did an excellent writeup on how to alphabetize your tag list using nothing but Liquid tags in your template.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
{% capture site_tags %}{% for tag in site.tags %}{{ tag | first }}{% unless forloop.last %},{% endunless %}{% endfor %}{% endcapture %}
{% assign tag_words = site_tags | split:',' | sort %}
 
<div id="tags">
   <h3>Table of Contents:</h3>
      <ul>
         {% for item in (0..site.tags.size) %}{% unless forloop.last %}
            {% capture this_word %}{{ tag_words[item] | strip_newlines }}{% endcapture %}
               <li>
                  <a class="tag-link" href="#{{ this_word | cgi_escape }}">{{ this_word }} 
                  <span class="badge pull-right">{{ site.tags[this_word].size }}</span></a>
               </li>
            {% endunless %}{% endfor %}
      </ul>
 
   <h3>Posts for each tag:</h3>
 
   <div class="taglisting">
 
      {% for item in (0..site.tags.size) %}{% unless forloop.last %}
         {% capture this_word %}{{ tag_words[item] | strip_newlines }}{% endcapture %}
 
            <div class="tag-list" id="{{ this_word | cgi_escape }}" >
               <h4><i class="glyphicon glyphicon-tag"></i>
                  {{ this_word }}</h4>
 
               <ul class="posts">
                  {% for post in site.tags[this_word] %}{% if post.title != null %}
                     <li>
                        <i class="fa fa-calendar"></i>
                           <time datetime="{{ post.date | date:"%F" }}">
                              {{ post.date | date: "%b %d, %Y" }}</time>
                        <a href="{{site.baseurl}}{{ post.url }}">{{ post.title }}</a></li>
                  {% endif %}{% endfor %}
               </ul>
            </div>
      {% endunless %}{% endfor %}
   </div>
</div>

This works very nicely generating an alphabetized list that is easy to search through. You can link to the list for individual tag using a hashmark in the URL: http://example.com/tags/#tagname and it will take you to that section. That said, it can be a bit confusing for the user to get dumped into the middle of a huge list of unrelated things. So I built upon Dave’s idea and added some Javascript to the mix.

I figured I already have a jQuery dependence, so I might as well use it:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
var MySite = MySite || {};
 
MySite.showSingleTag = function showSingleTag() {
    $(".tag-list").hide();
    $(window.location.hash).show();
};
 
 
$( document ).ready(function() {
    if( window.location.hash )
    {
        MySite.showSingleTag();
    }
 
    $(window).on('hashchange', function() {
        Gigi.showSingleTag();
 
        // scroll to the element
        $('html,body').animate({scrollTop: 
            $(window.location.hash).offset().top},0);
    });       
});

This script detects if there is a hash in the URL, and if so hides all the entries, except the ones related to the relevant tag. I left the list of tags alone, because I figured the user might want to explore what else is available. Because of this a little bit of additional logic was added. If you click on a hash-link the browser page won’t reload, and thus my hashmark check won’t trigger. So on line 15 I check if the URL hash changes, and if so I re-do the hiding, and then I forcefully scroll the user’s viewport back to the tag list.

TL;DR

I have successfully switched from Joomla to Jekyll and it’s great. I’m totally not going to regret this choice 5 years down the road, right? I mean, what could go wrong, other than everything. Actually, I’m already begging to see cracks forming in this master plan. You see, the site has a lot of images. They are mostly low to medium resolution screen-shots, but there are a lot of them, and there will be many more if I actually keep updating this thing more than once a year. As part of the update I added about 100MB worth of images, which is not a terrible lot but it has slowed the Jekyll compilation times quite a bit. So this is bound to get super annoying real quick… But I guess that’s par for the course: all software sucks, and it is a fucking miracle the internet even works seeing how nearly every website in existence is held in place with a digital equivalent of duct tape.

You can see the fruits of my labor at gigiedgleyfansite.com. While it’s not perfect, I think it is a huge improvement over the old Joomla based site. Let me know what you think.

This entry was posted in programming and tagged , , . Bookmark the permalink.



9 Responses to Building a Jekyll Site

  1. I’ve been using Jekyll for almost three years now. I’ve reported in the past that page builds had gotten painfully slow: several minutes for just a couple hundred blog posts. Fortunately it’s gotten a whole lot better over the past year. With 265 posts it only takes a few seconds. Running a giant blog like Terminally Incoherent on Jekyll is probably now practical.


    $ time jekyll build
    Configuration file: ./_config.yml
    Source: ./
    Destination: ./_site
    Generating... done.
    real 0m7.688s
    user 0m4.968s
    sys 0m0.308s

    A third of the time is spent on I/O (with full-disk encryption) with output currently at 117MB.

    The real gotcha now is that Jekyll will quietly break backwards compatibility. You’ll probably have to revisit your configuration after some of the updates to update it along with Jekyll. Suddenly the same exact site that built fine yesterday won’t build today. The Liquid and Markdown syntax changes subtly in undocumented ways as the parsers are tweaked. Sometimes it impacts dozens of posts (for me), requiring manual fixing. Most of the time this isn’t actually Jekyll’s fault directly, but rather Maruku or Liquid or some other dependency.

    Reply  |  Quote
  2. Luke Maciak UNITED STATES Mozilla Firefox Windows Terminalist says:

    @ Chris Wellons:

    Yeah, there are a lot of little quirks here and there. Also, if you are not careful with the encoding of your markdown documents Jekyll may get confused with respect to excerpts. The few posts I created on Windows, defaulted to DOS line endings and the Windows version of Jekyll compiled them as they should. Then I compiled same documents on Ubuntu and Jekyll displayed full posts on the front page because it was looking for \n\n to indicate the end of the excerpt. :P

    Any suggestions on how to deal with large image folders? I’ve been adding image galleries to the site, and each of them is between 10-30MB which is not a lot, but they have started adding up lately. The performance is not terrible yet (about a minute or two to compile the site) but I suspect it will get much, much worse as I add content. How do people deal with multimedia assets?

    Reply  |  Quote
  3. Agn0sis CANADA Mozilla Firefox Linux says:

    Hey Luke,

    I haven’t done any web development in like 10 years. Could you suggest me where to start? HTML5? Javascript? Any good book/site recommendation. I don’t know if the official documentation would be the way to go.

    Thanks

    Reply  |  Quote
  4. @ Luke Maciak:

    I offload my large files, such as videos, onto S3. This speeds up my build slightly, but I mainly do it to avoid using too much space on my GitHub account. That’s probably not very managable for lots of small files, like I suspect you need. (Just how do people organize their CDN content?) Unfortunately I don’t know what else you could do to speed up Jekyll in this situation.

    Looks like there was a discussion about using hardlinks. This would certainly speed things up, but apparently nothing came of it because, checking now, I’m not seeing any hardlinks in my output.

    Reply  |  Quote
  5. Luke Maciak UNITED STATES Google Chrome Linux Terminalist says:

    @ Agn0sis:

    Hmm… Good question. I don’t really know what would be a good starting point since I tend to just pick up things by reading random articles on the web, and just by doing things. That said, CodeCademy tutorials are extremely accessible for just learning basics of HTML5/CSS3 or Javascript.

    Some of the stuff I was talking about above are just best practices and stuff. For example, Twitter Bootstrap is basically a bundle of CSS and Javascript files that define things like fancy buttons, responsive grid and etc.. So instead of lining up headers and sidebars by hand, I just put each in a div, give that div the right class name, and it snaps into place. So I build on a solid skeleton.

    Since Bootstrap is a bundle of files, it stands to reason to use a package manager to handle installing it. That’s where Bower comes in. It’s basically apt-get for web stuff. All you need to do is bower install bootstrap and it will download all the bootstrap files and dependencies (such as jQuery) and put them into a folder in your project directory.

    Then there is Grunt which is a build tool for web designers which lets you lint (or syntax check) your Javascript and CSS and then minify and concatenate it for fast loading.

    Then there are tools like Yeoman which wrap around all of the above, and provide generators that will scaffold websites for you. So you can just be like yo webapp and 30 seconds later you get a basic website with HTML5, Bootstrap (or another framewrk) scaffolded out for you right there in the folder.

    Honestly, just reading the Yeoman page you can learn quite a bit about modern web development workflow. Just read what they provide, and any time you see something unfamiliar, google/research that. At fist it might feel like tumbling down a rabbit hole but eventually you’ll come out with better understanding of how people build websites. Because this was a tool build to abstract all the boring stuff away and get you from 0 to passably looking website skeleton in less than a minute, so that you can spend time drafting out ideas rather than futzing with config files for hours.

    Which is something I still like to do from time to time, because it helps me to understand how these tools interact, and it makes me feel like I have more control over the underlying structure of my page.

    @ Chris Wellons:

    Yeah, hardlinks would work great, though it seems like they are pretty invested in running well on Windows and don’t want to diverge the codebase to much. :(

    I was thinking that if my multimedia folders become too huge I will just rename my img/ directory to _img and then eschew jekyll serve -w and instead use a build script like:

    jekyll build
    ln _img _site/img
    grunt serve

    Or something like that.

    Reply  |  Quote
  6. Agn0sis CANADA Mozilla Firefox Linux says:

    Well, that was a long response, thank you for your time. Yeah, I thought that your approach would be to take a little from here and there. It is just that there is so much information that I didn’t wanted to end in a shitty site giving terrible advice and bad practices. Anyway, sometimes I ask myself if I actually master any languages at all, or if everything I do is learn enough from each tool to get something functional … in fact I don’t even know if that is a good or a bad thing. Man, this world is huge and we have so little time!

    Reply  |  Quote
  7. IceBrain PORTUGAL Mozilla Firefox Windows Terminalist says:

    Ouch, that sounds involved; I’ve used another generator in the past; being a Python guy and since I often like to mess with my tools, I went with Pelican instead, and I don’t remember needing all that configuration. Then again, I barely touched the default templates.

    Regarding the long compile times, I hear Hugo is blazing fast; they talk about generating whole sites in just miliseconds.

    Reply  |  Quote
  8. Luke Maciak UNITED STATES Google Chrome Linux Terminalist says:

    @ Agn0sis:

    I think they say that “mastering” anything takes roughly two years of daily practice. Granted, with programming you always tend to be chasing moving targets and shifting paradigms, which is one of the many reasons programming sucks. :P

    But I find it helpful to think about things that way: mastery is just a matter of practice. No matter what you do, you are going to suck at it at first and you are going to spend a lot of time googling things, and being baffled. But the more you do it, the smoother it gets.

    @ IceBrain:

    I could have made it much simpler on myself, but for some reason I like to build these things from scratch. Jekyll does have pretty sane defaults. The new default template in 2.0 is actually really nice. You can just do:

    jekyll new mywebproject

    What you get is pretty much good to go as far as a simple blogs go. I added complexity to the project myself mainly because:

    - I wanted bootstrap and responsive grid and jQuery
    - I wanted to host the above dependencies locally and not from a CDN
    - I wanted to manage my dependencies with bower
    - I wanted to use Grunt to minify and concatenate my css/js assets
    - I chose not to use Yeoman for all of the above
    - I wanted to write the HTML from scratch rather than use a pre-made template

    If I didn’t want to do any of the above, I could just generated a new basic site and tweaked the standard Jekyll template until I was happy with it.

    Thanks for mentioning Hugo. I have not heard of it before. :)

    Reply  |  Quote
  9. I respect the tech.
    But I decided to use Weebly. Like a boss.

    Reply  |  Quote

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>