feat: move essays of 2014

This commit is contained in:
Stefan Imhoff
2023-06-04 11:40:57 +02:00
parent 79a2b6e94a
commit 2886aafbf9
25 changed files with 2831 additions and 3 deletions

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 8.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

View File

@@ -17,7 +17,7 @@ export const Figure: FunctionalComponent<Props> = ({
...props
}) => {
const classes = cx(
'rounded-4 bg-white/50 p-10 mbe-13 mbs-0 mie-0 mis-0 dark:bg-black/80',
'rounded-4 bg-white/50 p-8 mbe-13 mbs-0 mie-0 mis-0 dark:bg-black/80',
{ 'figure-wide': size === 'wide', 'figure-fullsize': size === 'fullsize' },
className
);

View File

@@ -21,4 +21,6 @@ Each page of the book shows three colors that are always juxtaposed with one or
I took the time to create the RGB palette with the correct color names as an Adobe Exchange file (ASE). This color palette can be used in Photoshop or Illustrator.
<MoreLink href="/traditional-colors-of-japan/" text="See Traditional Colors of Japan" />
<Figure>
<MoreLink href="/traditional-colors-of-japan/" text="See Traditional Colors of Japan" />
</Figure>

View File

@@ -41,4 +41,6 @@ The exact installation instructions are included in the package on GitHub.
<Image src="/assets/images/posts/gitweb-theme-tree.png" alt="Tree View" />
</Figure>
<MoreLink href="https://github.com/kogakure/gitweb-theme/" text="GitWeb Theme on GitHub" />
<Figure>
<MoreLink href="https://github.com/kogakure/gitweb-theme/" text="GitWeb Theme on GitHub" />
</Figure>

View File

@@ -0,0 +1,147 @@
---
title: "Introduction to Gulp.js 1: Intro and Setup"
slug: gulp-tutorial-1-intro-setup
author: Stefan Imhoff
date: 2014-10-18T08:35:47+02:00
description: "The ultimate tutorial and guide for Gulp.js: The first part of my series on Gulp.js. What is Gulp.js? Why use it? And how to install Gulp and Jekyll."
cover: /assets/images/cover/gulp.svg
tags: ["code"]
series: gulp
---
My website is running [Jekyll](https://jekyllrb.com/) now since the beginning of 2014. But I wasnt happy with my build and development process. I started with Rake tasks and chose later [Grunt.js](https://gruntjs.com/) as my build system, but parts of the process were left in Ruby. I used [Compass](http://compass-style.org/) a lot, and [Jekyll Assets](http://ixti.net/jekyll-assets/) was handling my versioning. But Grunt.js and the Jekyll Asset Pipeline didnt play well together. Then a new solution came along: [Gulp.js](https://gulpjs.com/).
## What to expect from this Tutorial
This is the first part in a series of posts where I describe my whole development and build process step-by-step from start to finish. I am sick of all these _Hello World_ tutorials spreading around the Internet, describing the basics and dont show a whole process, going deeper, or sharing things learned during the process.
Ill describe everything **step-by-step** and provide **specific version numbers** for modules, to make sure they will run on your computer. If you have problems, feel free to compare your code to the finished [GitHub repository](https://github.com/kogakure/gulp-tutorial). Each tutorial builds on the things done before. If you need a specific thing, better look at the final codebase. Youll learn how I created my complete development and build process, which I use on this website and my [Ninja & Ninjutsu website](https://www.kogakure.de). The source of both websites can be found on my [GitHub account](https://github.com/kogakure).
When I started with Gulp.js, I fortunately stumbled upon a GitHub project called <del>gulp-starter</del> <ins>[blendid](https://github.com/vigetlabs/blendid)</ins>, that helped me a lot to structure my code and understand Gulp.js. My process is partly derived from this fantastic project.
## What is Gulp.js?
Gulp.js is _the streaming build system_ and its main focus is speed, efficiency, and simplicity. Where Grunt.js uses a lot of configuration with the process hidden in plugins, Gulp.js uses a simple and minimal API. You code your build process by yourself and use JavaScript as the language. You dont have to program everything by yourself, there are nearly 800 plugins ready for Gulp.js. But even more, Node.js modules can be used to build the perfect build and development process for **your** needs.
## Why do I want this at all?
As a front-end developer or web designer you will likely need plenty of things to build a modern website: a development server, a preprocessor for your [Sass](http://sass-lang.com/), [Less](http://lesscss.org/) or [Stylus](http://learnboost.github.io/stylus/) files, automation to bundle your JavaScript, tools to optimize your code, to compress, compile or move things around. And if you change something, you want your files to update automatically, or refresh the browser. You dont want to do this manually, do you?
Its 2014, and we dont copy our files per drag-and-drop to a server via an FTP program, reload our browser by hitting continuously <kbd>F5</kbd> or crunch our images for a smaller file size manually.
## Node.js
Gulp and all plugins are written in JavaScript and use the Node.js® platform. You dont have to know Node.js (but it will help a lot), but basic JavaScript skills are required to follow along. For this tutorial, you need to install Node.js on your computer. This can be done by installing the package on the [Node.js website](https://nodejs.org/). Advanced users may install Node.js with their favorite package installer (Homebrew, nvm, or similar).
## Gulpfile
As with Grunt.js, all you need to start is the main file. In Gulp.js, this file is called `gulpfile.js`. The first thing I learned from `gulp-starter` was to write my project in small parts and dont use a large monolithic file with everything in it. This way I can share my Gulp.js files with other projects or pass individual tasks around.
My base `gulpfile.js` is short:
#### gulpfile.js
```javascript
var requireDir = require("require-dir");
// Require all tasks in gulp/tasks, including subfolders
requireDir("./gulp/tasks", { recurse: true });
```
All this task is doing is loading all tasks that live in `./gulp/tasks` or in any subfolder.
## First Things First
The first thing to do is to install the required Node module `require-dir`. To reinstall all my node modules later, I will need to have a file where this information is saved.
You may use the installation helper by typing the command `npm init`. But I find it faster to create a new file `package.json` and fill it with these values:
#### package.json
```json
{
"name": "gulp-build",
"version": "0.0.1",
"description": "The build process of my website with Gulp.js",
"private": true
}
```
Now I can install Node modules and save them to this file for later reinstallation. Go ahead and install `require-dir`:
```bash
$ npm install --save-dev require-dir@0.3.0
```
This will install our first Node module and place it into a folder with the name `node_modules`. Dont delete this folder, or you will have to reinstall all modules again. This can be done later with `npm install`. The command will install all modules in the `package.json` file.
My Jekyll website lives in a folder called `app`. All my tasks will be placed in a folder with the name `gulp`. Go ahead and create a folder, and within a subfolder with the name `tasks`. After installing the first module, the structure of our project will look like this:
```bash
.
├── app
│   ├── _assets
│   ├── _data
│   ├── _drafts
│   ├── _includes
│   ├── _layouts
│   ├── _plugins
│   ├── _posts
│   └── index.html
├── gulp
│   └── tasks
├── gulpfile.js
├── node_modules
│   └── require-dir
└── package.json
```
## Jekyll
This tutorial uses [Jekyll](https://jekyllrb.com/) to build the HTML of the website. Creating a new Jekyll website is fast and easy:
```bash
$ gem install jekyll
$ jekyll new app
$ cd app
$ jekyll serve
```
I dont install Jekyll globally, but with [Bundler](https://bundler.io/). This way, all my Gems will be installed with my project and I dont have to be concerned about the correct version.
I install Bundler globally:
```bash
$ gem install bundler
```
Now I create an empty file in my projects folder with the name `Gemfile` and add these lines:
```ruby
source "https://rubygems.org"
gem 'jekyll', '~> 2.5.2'
gem 'sass', '>= 3.3'
```
Now I install the Gems by typing:
```bash
$ bundle install
```
If you installed Jekyll with Bundler, run inside your project directory:
```bash
$ bundle exec jekyll new app
```
Did you install it globally? Then drop the `bundle exec` from the command.
## Conclusion
This concludes the 1st part of my series _Introduction to Gulp.js_. We learned what Gulp.js is used for and created the basic folder structure for the project.
<Figure>
<MoreLink href="https://github.com/kogakure/gulp-tutorial" text="View Source on GitHub" />
</Figure>

View File

@@ -0,0 +1,86 @@
---
title: "Introduction to Gulp.js 10: Generating CSS Image Sprites"
slug: gulp-tutorial-10-generating-sprites
author: Stefan Imhoff
date: 2014-10-27T07:40:00+02:00
description: "The ultimate tutorial and guide for Gulp.js: How to generate image sprite maps with Spritesmith."
cover: /assets/images/cover/gulp.svg
tags: ["code"]
series: gulp
---
This is the 10th part of my series, _Introduction to Gulp.js_. Today, I will use Gulp.js to create CSS image sprites.
Just to be sure everybody knows what Im talking about: A CSS image sprite is a collection of images put into a single image. This way, fewer requests are needed, and the website will load faster. The CSS file will move the image for each sprite to the correct position.
CSS image sprites are not used often anymore, because of SVG or vector fonts. But I use them as a fallback for browsers incapable of displaying vector fonts.
I will need a Spritesmith plugin for Gulp.js:
```bash
$ npm install --save-dev gulp.spritesmith@4.1.1
```
#### gulp/config.js
```javascript
sprites: {
src: srcAssets + '/images/sprites/icon/*.png',
dest: {
css: srcAssets + '/scss/base/',
image: srcAssets + '/images/sprites/'
},
options: {
cssName: '_sprites.scss',
cssFormat: 'css',
cssOpts: {
cssClass: function (item) {
// If this is a hover sprite, name it as a hover one (e.g. 'home-hover' -> 'home:hover')
if (item.name.indexOf('-hover') !== -1) {
return '.icon-' + item.name.replace('-hover', ':hover');
// Otherwise, use the name as the selector (e.g. 'home' -> 'home')
} else {
return '.icon-' + item.name;
}
}
},
imgName: 'icon-sprite.png',
imgPath: '/assets/images/sprites/icon-sprite.png'
}
}
```
I split my config into three subsections: The source files (individual icons for the sprite), the destination for the sprite, and the CSS partial and the options for the image sprite. I use a custom `cssClass` which will generate `:hover` states by naming the hover sprites with `-hover`.
#### gulp/tasks/development/sprites.js
```javascript
var gulp = require("gulp");
var spritesmith = require("gulp.spritesmith");
var config = require("../../config").sprites;
/**
* Generate sprite and CSS files from PNGs
*/
gulp.task("sprites", function () {
var spriteData = gulp.src(config.src).pipe(spritesmith(config.options));
spriteData.img.pipe(gulp.dest(config.dest.image));
spriteData.css.pipe(gulp.dest(config.dest.css));
});
```
In the end, I get two files: a partial `_sprites.scss` containing the class attributes and a sprite `icon-sprite.png` containing all images.
All development tasks are done now. We have got a running development server, tasks to create the Jekyll site, and all assets and tasks for linting, sprite, and vector font creation.
Next, I will write the tasks needed to get a production-ready code.
## Conclusion
This concludes the 10th part of my series, _Introduction to Gulp.js_. Today, we learned how to create CSS image sprites with Gulp.js and Spritesmith.
<Figure>
<MoreLink href="https://github.com/kogakure/gulp-tutorial" text="View Source on GitHub" />
</Figure>

View File

@@ -0,0 +1,164 @@
---
title: "Introduction to Gulp.js 11: Production Build, Server and Jekyll"
slug: gulp-tutorial-11-production-build-server-and-jekyll
author: Stefan Imhoff
date: 2014-10-28T07:30:00+02:00
description: "The ultimate tutorial and guide for Gulp.js: How to write the production task for Jekyll and BrowserSync."
cover: /assets/images/cover/gulp.svg
tags: ["code"]
series: gulp
---
This is the 11th part of my series, _Introduction to Gulp.js_. Today I will start writing the production build task, set up a server to view the production code and build the production site with Jekyll.
In development, I used the `default` Gulp.js tasks to run the development server, build the assets, and watch for changes. For production, I will need another entry point.
I decided to name my task `publish`. Later I can get a production build with the command `gulp publish`.
#### gulp/tasks/publish.js
```javascript
var gulp = require("gulp");
/**
* Run task browsersync:production
*/
gulp.task("publish", ["browsersync:production"]);
```
I put this file on the same level as the `default.js` file. This task is short: It does one thing. Start a BrowserSync task for production. This way I can have a look at the production site before deploying it to my server.
## BrowserSync for Production
All production tasks will live in a folder `production/` inside `gulp/tasks/`. I name the tasks of development and production the same but put them in different folders.
#### gulp/config.js
```javascript
browsersync: {
development: {
...
},
production: {
server: {
baseDir: [production]
},
port: 9998
}
}
```
The only differences to the `browsersync` of `development` are these: I serve the production folder and use a different port for the server. This way, I can run `development` and `production` in parallel.
#### gulp/tasks/production/browser-sync.js
```javascript
var gulp = require("gulp");
var browsersync = require("browser-sync");
var config = require("../../config").browsersync.production;
/**
* Start a server and watch changes with BrowserSync
*/
gulp.task("browsersync:production", ["build:production"], function () {
browsersync(config);
});
```
This task is boring. It starts the production build.
## Build Task for Production
#### gulp/tasks/production/build.js
```javascript
var gulp = require("gulp");
var runSequence = require("run-sequence");
/**
* Run all tasks needed for a build in the defined order
*/
gulp.task("build:production", function (callback) {
runSequence(
"delete",
"jekyll:production",
["sass", "scripts", "images", "copy:fonts"],
"base64",
["optimize:css", "optimize:js", "optimize:images", "optimize:html", "copy:fonts:production"],
"revision",
"rev:collect",
callback
);
});
```
A lot is going on in this task: I run tasks in a specific order with `run-sequence`. First, I delete the assets folder for fresh creation. Then I run the Jekyll build for production, and create the development assets as I did in development. And after this is finished, I start with optimizing my assets and revisioning the files.
## Jekyll for Production
The Jekyll task is similar except for two things: I create my site to the production folder and I add another config file `_config.build.yml` as an option (be careful, add no space between two files).
My Jekyll production config overwrites values as the `url`, hide future posts (`future: false`), or hides drafts (`show_drafts: false`).
<Banner summary="Speed up development with Jekyll">
To speed up the generation of your site in development, you may set `limit_post: 5`, which will generate the last five posts.
Additionally, I set `future: true` and `show_drafts: true` to see Drafts and Posts with a future date.
</Banner>
#### gulp/config.js
```javascript
jekyll: {
development: {
...
},
production: {
src: src,
dest: production,
config: '_config.yml,_config.build.yml'
}
}
```
#### gulp/tasks/production/jekyll.js
```javascript
var gulp = require("gulp");
var cp = require("child_process");
var browsersync = require("browser-sync");
var config = require("../../config").jekyll.production;
/**
* Build the Jekyll Site
*/
gulp.task("jekyll:production", function (done) {
browsersync.notify("Compiling Jekyll (Production)");
return cp
.spawn(
"bundle",
[
"exec",
"jekyll",
"build",
"-q",
"--source=" + config.src,
"--destination=" + config.dest,
"--config=" + config.config,
],
{ stdio: "inherit" }
)
.on("close", done);
});
```
## Conclusion
This concludes the 11th part of my series _Introduction to Gulp.js_. Today, I started to work on the production part of my website, including a server to view the production site and generate a production build of my Jekyll site.
<Figure>
<MoreLink href="https://github.com/kogakure/gulp-tutorial" text="View Source on GitHub" />
</Figure>

View File

@@ -0,0 +1,215 @@
---
title: "Introduction to Gulp.js 12: Optimize CSS, JavaScript, Images and HTML"
slug: gulp-tutorial-12-optimize-css-javascript-images-and-html
author: Stefan Imhoff
date: 2014-10-29T08:00:00+02:00
description: "The ultimate tutorial and guide for Gulp.js: How to optimize CSS, JavaScript, images, and HTML to speed up your website."
cover: /assets/images/cover/gulp.svg
tags: ["code"]
series: gulp
---
This is the 12th part of my series, _Introduction to Gulp.js_. Today I will write tasks to optimize the assets of my website: CSS, JavaScript, Images, and HTML.
Every Kilobyte, which has to be loaded, will slow down the loading of my website. Thats why I will minimize all my CSS and JavaScript and run my images through an optimizer, to remove as many bytes as possible. I will also add a task for minimizing HTML, but I dont use this task because the reduction is minimal.
## CSS
First, I will write a task, which will optimize the CSS. Compass can minimize the CSS for production, but this Gulp.js task squeezed another 6 KB out of my files.
I install the needed Gulp.js plugins:
```bash
$ npm install --save-dev gulp-csso@2.0.0 gulp-size@2.0.0
```
#### gulp/config.js
```javascript
optimize: {
css: {
src: developmentAssets + '/css/*.css',
dest: productionAssets + '/css/',
options: {}
}
}
```
#### gulp/tasks/production/optimize-css.js
```javascript
var gulp = require("gulp");
var csso = require("gulp-csso");
var size = require("gulp-size");
var config = require("../../config").optimize.css;
/**
* Copy and minimize CSS files
*/
gulp.task("optimize:css", function () {
return gulp.src(config.src).pipe(csso(config.options)).pipe(gulp.dest(config.dest)).pipe(size());
});
```
This task will copy the CSS files from the assets folder, minimize them, remove comments, output the size of the file, and copy them to the production assets folder.
## JavaScript
Now the CSS is minimized, and the same has to be done to the JavaScript files. I use UglifyJS for this task. If you dont like it, go ahead and use a Google Closure or YUI compressor Gulp.js task.
```bash
$ npm install --save-dev gulp-uglify@1.0.1
```
#### gulp/config.js
```javascript
optimize: {
css: {
...
},
js: {
src: developmentAssets + '/js/*.js',
dest: productionAssets + '/js/',
options: {}
}
}
```
#### gulp/tasks/production/optimize-js.js
```javascript
var gulp = require("gulp");
var uglify = require("gulp-uglify");
var size = require("gulp-size");
var config = require("../../config").optimize.js;
/**
* Copy and minimize JS files
*/
gulp.task("optimize:js", function () {
return gulp
.src(config.src)
.pipe(uglify(config.options))
.pipe(gulp.dest(config.dest))
.pipe(size());
});
```
This task will take the JavaScript files, minimize and optimize them, put them in my production assets folder, and output the size.
## Images
Next, I will work on the images. They need to be copied to the production assets folder and crunched (reduce the size). This may take a while, depending on the size and amount of your images, thats why I optimize the images for production.
<Banner summary="Show more details">
To get a more detailed output in Gulp.js, you may add a flag to your command:
`gulp publish --verbose`. It will list each individual image for the optimized task and how much it was compressed.
</Banner>
Ill need `gulp-imagemin` for my task, which can minify PNG, JPG, GIF, and SVG images:
```bash
$ npm install --save-dev gulp-imagemin@2.3.0
```
#### gulp/config.js
```javascript
optimize: {
css: {
...
},
js: {
...
},
images: {
src: developmentAssets + '/images/**/*.{jpg,jpeg,png,gif}',
dest: productionAssets + '/images/',
options: {
optimizationLevel: 3,
progressive: true,
interlaced: true
}
}
}
```
#### gulp/tasks/production/optimize-images.js
```javascript
var gulp = require("gulp");
var imagemin = require("gulp-imagemin");
var size = require("gulp-size");
var config = require("../../config").optimize.images;
/**
* Copy and minimize image files
*/
gulp.task("optimize:images", function () {
return gulp
.src(config.src)
.pipe(imagemin(config.options))
.pipe(gulp.dest(config.dest))
.pipe(size());
});
```
This task will take my images, optimize them, copy them to the assets folder, and output the size.
## HTML
As said before, I wrote this task, and you can see how to do it, but I dont use it because the reduction is minimal and not worth the messy markup. I like to keep it readable, so other people can learn from it.
```bash
$ npm install --save-dev gulp-htmlmin@1.2.0
```
#### gulp/config.js
```javascript
optimize: {
css: {
...
},
js: {
...
},
images: {
...
},
html: {
src: production + '/**/*.html',
dest: production,
options: {
collapseWhitespace: true
}
}
}
```
#### gulp/tasks/production/optimize-html.js
```javascript
var gulp = require("gulp");
var htmlmin = require("gulp-htmlmin");
var config = require("../../config").optimize.html;
/**
* Minimize HTML
*/
gulp.task("optimize:html", function () {
return gulp.src(config.src).pipe(htmlmin(config.options)).pipe(gulp.dest(config.dest));
});
```
## Conclusion
This concludes the 12th part of my series _Introduction to Gulp.js_. Today we learned how to minimize CSS and JavaScript files and reduce the size of images.
<Figure>
<MoreLink href="https://github.com/kogakure/gulp-tutorial" text="View Source on GitHub" />
</Figure>

View File

@@ -0,0 +1,159 @@
---
title: "Introduction to Gulp.js 13: Revisioning"
slug: gulp-tutorial-13-revisioning
author: Stefan Imhoff
date: 2014-10-30T07:45:00+02:00
description: "The ultimate tutorial and guide for Gulp.js: How to use revisioning to allow long caching of your assets and replace them with hashed file names, that can be cache-busted."
cover: /assets/images/cover/gulp.svg
tags: ["code"]
series: gulp
---
This is the 13th part of my series, _Introduction to Gulp.js_. Today I will write the task to revise my static assets.
## Copy Vector Fonts for Production
Before I can work on the fun part of revisioning my asset files, I first have to write another boring and short task, which is doing one simple thing: Copying the fonts to the production assets folder.
#### gulp/config.js
```javascript
copyfonts: {
development: {
...
},
production: {
src: developmentAssets + '/fonts/*',
dest: productionAssets + '/fonts'
}
}
```
#### gulp/tasks/production/copy-fonts.js
```javascript
var gulp = require("gulp");
var config = require("../../config").copyfonts.production;
/**
* Copy fonts to folder
*/
gulp.task("copy:fonts:production", function () {
return gulp.src(config.src).pipe(gulp.dest(config.dest));
});
```
## Revisioning
Optimizing my assets is done. But one important thing is missing: Revisioning.
For better performance, one should always cache the assets for a long time. Hard drives are huge these days, but the speed for requesting assets isnt that wonderful (on mobile devices). But one problem occurs if you cache the assets on a hard drive of a visitor. If you update a file, the browser will serve the old file. And if you cache it for 10 years, the user will never get the new asset, unless s/he deletes the browser cache manually. Yet what user does this?
Thats why we need to rename every file that has been changed to invalidate the cache. I remember the days when we had to add a number manually to our assets, like `image_r1.png`, or `image_r2.png`. This sucks. Today, reading the content of a file and generating a checksum can achieve this easier. This checksum will always be the same unless something gets changed.
My next task will rename all assets. This way, the `application.css` will become `application-f084d03b.css`. If I change one tiny thing in this file, it will get a new filename.
I install `gulp-rev`, which will handle this renaming of assets:
```bash
$ npm install --save-dev gulp-rev@2.0.1
```
#### gulp/config.js
```javascript
revision: {
src: {
assets: [
productionAssets + '/css/*.css',
productionAssets + '/js/*.js',
productionAssets + '/images/**/*'
],
base: production
},
dest: {
assets: production,
manifest: {
name: 'manifest.json',
path: productionAssets
}
}
}
```
This task will rename all assets and create a JSON file containing all files, which were renamed and their old and new file names.
#### gulp/tasks/production/revision.js
```javascript
var gulp = require("gulp");
var rev = require("gulp-rev");
var config = require("../../config").revision;
/**
* Revision of all asset files and
* write a manifest file
*/
gulp.task("revision", function () {
return gulp
.src(config.src.assets, { base: config.src.base })
.pipe(gulp.dest(config.dest.assets))
.pipe(rev())
.pipe(gulp.dest(config.dest.assets))
.pipe(rev.manifest({ path: config.dest.manifest.name }))
.pipe(gulp.dest(config.dest.manifest.path));
});
```
## Replacing Paths to Assets
The last step of my production build is to replace all occurrences of assets with a revised file name in all files.
This task will need `gulp-rev-collector` to replace the paths names to assets:
```bash
$ npm install --save-dev gulp-rev-collector@0.1.1
```
#### gulp/config.js
```javascript
collect: {
src: [
productionAssets + '/manifest.json',
production + '/**/*.{html,xml,txt,json,css,js}',
'!' + production + '/feed.xml'
],
dest: production
}
```
I replace these paths in files I know could contain paths to assets. Dont include any images or binary files. The revision collector will try to open them and destroy binary files.
#### gulp/tasks/production/rev-collector.js
```javascript
var gulp = require("gulp");
var collect = require("gulp-rev-collector");
var config = require("../../config").collect;
/**
* Replace all links to assets in files
* from a manifest file
*/
gulp.task("rev:collect", function () {
return gulp.src(config.src).pipe(collect()).pipe(gulp.dest(config.dest));
});
```
This task will look into the `manifest.json` file and replace every path to one of the assets in every HTML, CSS, JavaScript, and Text.
The production build is finished! Only one thing is missing to complete this series of tutorials about Gulp.js: Deploying the Website to my server.
## Conclusion
This concludes the 13th part of my series, _Introduction to Gulp.js_. Today we learned how to revise the asset files and replace links to these files.
<Figure>
<MoreLink href="https://github.com/kogakure/gulp-tutorial" text="View Source on GitHub" />
</Figure>

View File

@@ -0,0 +1,85 @@
---
title: "Introduction to Gulp.js 14: Deploying the Website with Rsync"
slug: gulp-tutorial-14-deploying-the-website
author: Stefan Imhoff
date: 2014-10-31T08:00:00+02:00
description: "The ultimate tutorial and guide for Gulp.js: How to deploy your website with rsync to your server."
cover: /assets/images/cover/gulp.svg
tags: ["code"]
series: gulp
---
This is the 14th of my series _Introduction to Gulp.js_. Today I will write a task to sync the files of my Jekyll site to my web server.
## Deploying the Website
There are plenty of possibilities to get a website on the server. You may use FTP, SFTP, SCP, SCP2, Rsync, or Git. I use Rsync because its fast and easy to use.
I write another task as an entry point: `deploy`
#### gulp/tasks/deploy.js
```javascript
var gulp = require("gulp");
/**
* Start rsync task
*/
gulp.task("deploy", ["rsync"]);
```
This will start the `rsync` task. But I could add more tasks, for example, a task, which creates a zip archive of the build and copies it to a backup on my hard drive.
```bash
$ npm install --save-dev gulp-rsync@0.0.5
```
#### gulp/config.js
```javascript
rsync: {
src: production + '/**',
options: {
destination: '~/path/to/my/website/root/',
root: production,
hostname: 'mydomain.com',
username: 'user',
incremental: true,
progress: true,
relative: true,
emptyDirectories: true,
recursive: true,
clean: true,
exclude: ['.DS_Store'],
include: []
}
}
```
This task will grab all files in my production folder, connect to my server, and copy all files recursively to my website root. It will delete old files and add changes to the server.
#### gulp/tasks/production/rsync.js
```javascript
var gulp = require("gulp");
var rsync = require("gulp-rsync");
var config = require("../../config").rsync;
/**
* Copy files and folder to server
* via rsync
*/
gulp.task("rsync", function () {
return gulp.src(config.src).pipe(rsync(config.options));
});
```
## Conclusion
This concludes the series _Introduction to Gulp.js_. Developing and deploying with Gulp.js is fun.
I like the UNIX philosophy of Gulp.js: Having small files, which do one task and connect these to larger workflows. And because I kept my Gulp.js tasks small, pluggable, and shareable, I was able to add Gulp.js to my second website in less than five minutes.
<Figure>
<MoreLink href="https://github.com/kogakure/gulp-tutorial" text="View Source on GitHub" />
</Figure>

View File

@@ -0,0 +1,186 @@
---
title: "Introduction to Gulp.js 15: Performance Improvements with WebP and Gzip"
slug: gulp-tutorial-15-performance-improvements-webp-gzip
author: Stefan Imhoff
date: 2014-12-21T11:15:00+01:00
description: "The ultimate tutorial and guide for Gulp.js: How to improve the speed and performance of your website with WebP and Gzip."
cover: /assets/images/cover/gulp.svg
tags: ["code"]
series: gulp
---
This is the 15th part of my series, _Introduction to Gulp.js_. Today Ill add tasks for performance improvement of the website with WebP for images and Gzip for text files.
## Using WebP for images
[WebP](https://developers.google.com/speed/webp/) is a new image format developed by Google. With WebP, its possible to achieve much better compression with better quality, as with JPEG or PNG. Multiple browsers like **Google Chrome**, **Opera**, or **Konquerer** support this image format.
On my website, I use a header image which is in JPEG format **69 KB** in size, the same image is in WebP **44 KB**. WebP can reduce the size of images by **25-34%**, which is a lot.
Thats why I will create a task, which creates WebP images of my PNG and JPEG images and let the server deliver the smaller format to browsers, which supports it.
First, I install the Gulp.js module for WebP:
```bash
$ npm install --save-dev gulp-webp@2.1.1
```
I add an entry to the configuration file:
#### gulp/config.js
```javascript
webp: {
src: productionAssets + '/images/**/*.{jpg,jpeg,png}',
dest: productionAssets + '/images/',
options: {}
},
```
The task is short and straightforward:
#### gulp/tasks/production/webp.js
```javascript
var gulp = require("gulp");
var webp = require("gulp-webp");
var config = require("../../config").webp;
/**
* Convert images to WebP
*/
gulp.task("webp", function () {
return gulp.src(config.src).pipe(webp(config.options)).pipe(gulp.dest(config.dest));
});
```
This task needs to be run for production and has to be executed after the revisioning of the images is finished because the server will deliver a WebP image of the same name to the browser.
#### gulp/tasks/production/build.js
```javascript
var gulp = require("gulp");
var runSequence = require("run-sequence");
/**
* Run all tasks needed for a build in the defined order
*/
gulp.task("build:production", function (callback) {
runSequence(
"delete",
"jekyll:production",
// ...,
"revision",
"rev:collect",
"webp",
callback
);
});
```
Its necessary to tell the server to rewrite the URLs of our images. There are multiple techniques for this, but Ill use a `.htaccess` file:
#### app/htaccess
```apache
---
layout: null
slug: .htaccess
---
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{HTTP_ACCEPT} image/webp
RewriteCond %{DOCUMENT_ROOT}/$1.webp -f
RewriteRule (.+)\.(jpe?g|png)$ $1.webp [T=image/webp,E=accept:1]
</IfModule>
<IfModule mod_headers.c>
Header append Vary Accept env=REDIRECT_accept
</IfModule>
AddType image/webp .webp
```
It is possible to use a `.htaccess` file and include it in the [configuration file](https://jekyllrb.com/docs/configuration/). Otherwise, Jekyll will ignore hidden files and dont copy them to the target directory.
But I like it more to add [YAML Front Matter](https://jekyllrb.com/docs/frontmatter/) and create the file this way. Another advantage is that the file isnt invisible.
If you sync your production website to a server, it will deliver to browsers, which support WebP the WebP format when requesting a JPEG or PNG.
<Banner summary="It isnt working …">
Dont wonder: The `.htaccess` file wont work with the development server. It will need a server with support for `mod_rewrite` and `mod_headers` and support `.htaccess` files.
</Banner>
## Gzip text files
Many servers compress files by default with Gzip before sending them to the browser. But it is always good to pre-gzip the files because it will be faster, as the server doesnt need to compress the file on every request. And it will need less CPU and the compression rate will be much higher with pre-gzipped files because many servers dont use the maximum compression rate.
First, I install the Gulp.js module:
```bash
$ npm install --save-dev gulp-gzip@1.2.0
```
I add an entry to the configuration file:
#### gulp/config.js
```javascript
gzip: {
src: production + '/**/*.{html,xml,json,css,js}',
dest: production,
options: {}
},
```
Next, I create the task, which is short:
#### gulp/tasks/production/gzip.js
```javascript
var gulp = require("gulp");
var gzip = require("gulp-gzip");
var config = require("../../config").gzip;
/**
* Gzip text files
*/
gulp.task("gzip", function () {
return gulp.src(config.src).pipe(gzip(config.options)).pipe(gulp.dest(config.dest));
});
```
I add the task in my production build file to a JavaScript Array together with the `webp` task because this task and the Gzip task may run in parallel; WebP works with images and Gzip with text files.
#### gulp/tasks/production/build.js
```javascript
var gulp = require("gulp");
var runSequence = require("run-sequence");
/**
* Run all tasks needed for a build in the defined order
*/
gulp.task("build:production", function (callback) {
runSequence(
"delete",
"jekyll:production",
// ...,
"revision",
"rev:collect",
["webp", "gzip"],
callback
);
});
```
## Conclusion
This concludes the 15th part of my series _Introduction to Gulp.js_. We learned how to convert images to the WebP format and how to compress text files with Gzip. Every byte we can reduce will increase the speed of the website.
<Figure>
<MoreLink href="https://github.com/kogakure/gulp-tutorial" text="View Source on GitHub" />
</Figure>

View File

@@ -0,0 +1,310 @@
---
title: "Introduction to Gulp.js 16: PostCSS"
slug: gulp-tutorial-16-postcss
author: Stefan Imhoff
date: 2014-12-30T07:50:29+00:00
description: "The ultimate tutorial and guide for Gulp.js: How to use PostCSS with Gulp to process CSS and how to lint your CSS files with Stylelint."
cover: /assets/images/cover/gulp.svg
tags: ["code"]
series: gulp
---
This is the 16th part of my series _Introduction to Gulp.js_. Today, I will show how to use PostCSS to process CSS files. I will replace Ruby Sass with PostCSS and additionally show how to lint stylesheets automatically in the background while developing with Stylelint.
## Compass, Sass, LESS, Stylus … why do we need more tools?
I use Sass and SCSS now for a long time, started with _Compass_, moved to _Ruby Sass_ and wanted to move to _libSass_, but dependencies on my beloved Gems held me back.
There are numerous Preprocessors, Libraries, and Frameworks, which extend CSS. And a lot of them do good work and I didnt want to miss variables, nesting, or mixins. But Ruby Sass and Compass in particular are **slooooooooow**because Ruby is slow. Compiling my websites styles took 7-8 seconds, but I know of projects where one change will trigger a recompile, which takes **more than a minute**!
## What is PostCSS, and why should I use it?
There is a new kid on the block: [PostCSS](https://github.com/postcss/postcss). I dont care if its a Preprocessor, a Postprocessor, or a Processor. You write something, it will process your files, and it will put out CSS.
Why should you use a new tool, if Sass and its competitors do their job? Because its **fast** ([3-30 times faster](https://github.com/postcss/benchmark)), **modular** and **extendible**. I bet you need a small fraction of your Preprocessors functionality.
With PostCSS, you can choose what you require from currently over [200 plugins](https://www.postcss.parts/). If you dont find the plugin you require, you can write a [plugin](https://github.com/postcss/postcss/blob/master/docs/guidelines/plugin.md) or [syntax](https://github.com/postcss/postcss/blob/master/docs/syntax.md).
**You get it all**: variables, mixins, extends, color helpers, fallbacks, optimizations, grids … you pick. You can even start using future CSS syntax today, let PostCSS transpile it for you.
I swapped out _Ruby Sass_ with PostCSS and my CSS is now transformed in 2-3 seconds. Go and take a look at my [beautiful new code](https://github.com/kogakure/jekyll-stefanimhoff.de). I use Responsive Typography, Autoprefixer, and the fantastic [LostGrid](https://github.com/peterramsing/lost).
## PostCSS
In this part of my series, I will rip out Ruby Sass and add PostCSS instead. So follow me along …
First, I will install all needed Node modules:
```bash
$ npm install gulp-postcss@6.0.1 precss@1.2.3 gulp-cssnano@2.0.0 gulp-util@3.0.6 autoprefixer@6.0.3 css-mqpacker@4.0.0 --save-dev
```
I add basic plugins, but you can add more if you like later. I add [gulp-postcss](https://github.com/postcss/gulp-postcss), [precss](https://github.com/jonathantneal/precss) (which will allow Sass-like syntax), [gulp-cssnano](https://cssnano.co/) (which will compress and optimize the CSS), [autoprexifer](https://github.com/postcss/autoprefixer) for automatic vendor prefixes and [css-mqpacker](https://github.com/hail2u/node-css-mqpacker) for combining media queries.
Next, I will add the configuration for the new task:
#### gulp/config.js
```javascript
styles: {
src: srcAssets + '/styles/*.css',
dest: developmentAssets + '/css',
options: {
precss: {},
autoprefixer: {
browsers: [
'last 2 versions',
'safari 5',
'ie 8',
'ie 9',
'opera 12.1',
'ios 6',
'android 4'
],
cascade: true
},
mqpacker: {}
}
},
```
I add the new task to my `development` folder:
#### gulp/tasks/development/styles.js
```javascript
var gulp = require("gulp");
var postcss = require("gulp-postcss");
var precss = require("precss");
var nano = require("gulp-cssnano");
var plumber = require("gulp-plumber");
var sourcemaps = require("gulp-sourcemaps");
var gutil = require("gulp-util");
var browsersync = require("browser-sync");
var autoprefixer = require("autoprefixer");
var mqpacker = require("css-mqpacker");
var config = require("../../config");
function onError(err) {
gutil.beep();
console.log(err);
this.emit("end");
}
/**
* Run CSS through PostCSS and its plugins
* Build sourcemaps and minimize
*/
var processors = [
precss(config.styles.options.precss),
autoprefixer(config.styles.options.autoprefixer),
mqpacker(config.styles.options.mqpacker),
];
gulp.task("styles", function () {
browsersync.notify("Transforming CSS with PostCSS");
return gulp
.src(config.styles.src)
.pipe(
plumber({
errorHandler: onError,
})
)
.pipe(sourcemaps.init())
.pipe(postcss(processors))
.pipe(nano())
.pipe(sourcemaps.write("."))
.pipe(gulp.dest(config.styles.dest));
});
```
### Rename SCSS files and folders
I rename the `scss` folder to `styles` and create inside this folder a new folder `partials`. I rename all `.scss` files to `.css` and move them into the partials folder (except the `main.css`). Furthermore, I recommend commenting out all lines in this file for now and bringing them back later. Otherwise, it will not run properly because the syntax is different.
### Update the Code
Next, I will need to replace the lines of the old `sass` task with my new `styles` task. If you have never seen a **DIFF** file: a `-` (and red line) in front of a line has to be removed and a `+` (and green line) in front of a line has to be added:
#### gulp/config.js:132
```diff
- sass: srcAssets + '/scss/**/*.{sass,scss}',
+ styles: srcAssets + '/styles/**/*.css',
```
#### gulp/config.js:154
```diff
- css: srcAssets + '/scss/base/',
+ css: srcAssets + '/styles/partials/base/',
```
#### gulp/tasks/development/watch.js:9
```diff
- gulp.watch(config.sass, ['sass', 'scsslint']);
+ gulp.watch(config.styles, ['styles', 'scsslint']);
```
#### gulp/tasks/development/build.js:11
```diff
- 'sass',
+ 'styles',
```
#### gulp/tasks/production/build.js:10
```diff
- 'sass',
+ 'styles',
```
#### gulp/tasks/development/base64.js:8
```diff
- gulp.task('base64', ['sass'], function() {
+ gulp.task('base64', ['styles'], function() {
```
I remove these lines from my `optimize-css.js` task because `cssnano` does the job:
#### gulp/tasks/production/optimize-css.js:2
```diff
- var csso = require('gulp-csso');
```
#### gulp/tasks/production/optimize-css.js:7
```diff
- * Copy and minimize CSS files
+ * Copy CSS files
```
#### gulp/tasks/production/optimize-css.js:11
```diff
- .pipe(minifycss(config.options))
```
FontCustom has to be changed to copy the Vector fonts CSS to the new location and provide CSS instead of SCSS:
#### fontcustom.yml:34
```diff
- css: app/_assets/scss
+ css: app/_assets/styles
```
#### fontcustom.yml:48
```diff
- templates: [ scss, preview ]
+ templates: [ css, preview ]
```
After I updated the FontCustom config file, I have to run the task for creating the Vector Fonts again:
```bash
$ gulp fontcustom
```
The syntax of the different PostCSS plugins is different. I use [PreCSS](https://github.com/jonathantneal/precss), which is a lot like Sass, but things look different. Writing all the changes I made to the CSS would extend the scope of this tutorial too much, as its a long file. But you can have a look, at how I refactored all CSS files with updated syntax in my [GitHub repository](https://github.com/kogakure/gulp-tutorial/commit/fc2398d933e2094832a00ac123b30c772269e08c). If you are interested how I replaced [Singularity](https://github.com/at-import/Singularity) (which is the best Sass grid available) with [LostGrid](https://github.com/peterramsing/lost) and all the other things, look into [my websites source code](https://github.com/kogakure/jekyll-stefanimhoff.de).
You can run `gulp` again now, and PostCSS will process the styles.
## Linting CSS with PostCSS plugins
We want to write clean and beautiful stylesheets. Thats why we should always run a Linter, which checks our CSS.
Until now, a Ruby gem did this job and was checking the SCSS syntax for errors. But now we use CSS and need a better (and faster) solution.
First, I install the Node modules, which are needed:
```bash
$ npm install stylelint@1.2.1 postcss-reporter@1.3.0 --save-dev
```
Now Ill add the configuration for Linting to my Gulp config:
#### gulp/config.js
```javascript
lintStyles: {
src: [
srcAssets + '/styles/**/*.css',
'!' + srcAssets + '/styles/partials/_syntax-highlighting.css',
'!' + srcAssets + '/styles/partials/_sprites.css',
'!' + srcAssets + '/styles/partials/fontcustom.css'
],
options: {
stylelint: {
'rules': {
'string-quotes': [2, 'double'],
'color-hex-case': [2, 'lower'],
'value-no-vendor-prefix': 2,
'declaration-no-important': 0,
'rule-non-nested-empty-line-before': [2, 'always', {
ignore: ['after-comment']
}]
}
},
reporter: {
clearMessages: true
}
}
},
```
I watch all CSS files, except the generated (FontCustom and Sprites) and the syntax highlighting file (which I dont touch).
You can define linting rules for [stylelint](https://github.com/stylelint). These 5 rules are just an example, there are a [lot more](https://github.com/stylelint/stylelint/blob/master/docs/user-guide/rules.md). As CSS style is taste, you should pick the rules you like. `0` means ignore (default), `1` is a warning and `2` is an error. Sometimes rules require additional options.
Next, I will add the Gulp task:
#### gulp/tasks/development/lint-styles.js
```javascript
var gulp = require("gulp");
var postcss = require("gulp-postcss");
var stylelint = require("stylelint");
var reporter = require("postcss-reporter");
var config = require("../../config");
gulp.task("lint-styles", function () {
return gulp
.src(config.lintStyles.src)
.pipe(
postcss([
stylelint(config.lintStyles.options.stylelint),
reporter(config.lintStyles.options.reporter),
])
);
});
```
All I need to do now is replace the linting task in my watch task:
#### gulp/tasks/development/watch.js:9
```diff
- gulp.watch(config.styles, ['styles', 'scsslint']);
+ gulp.watch(config.styles, ['styles', 'lint-styles']);
```
If you run `gulp`, the task will lint your CSS files, save them, and show errors with filename, line number, and broken rule in the Terminal. PostCSS provides even a [plugin](https://github.com/postcss/postcss-browser-reporter) to bring the errors to your browser.
PostCSS will likely have a bright future. Since it got popular, countless people got excited. Companies like Google, Twitter, Alibaba, and Shopify use PostCSS. And Bootstrap v5 will be likely in PostCSS.
Im sure we will see more exciting Plugins in the future.
## Conclusion
This concludes the 16th part of my series _Introduction to Gulp.js_. We learned how to use PostCSS to process our CSS files and how to use Stylelint to lint the CSS files for errors.
<Figure>
<MoreLink href="https://github.com/kogakure/gulp-tutorial" text="View Source on GitHub" />
</Figure>

View File

@@ -0,0 +1,149 @@
---
title: "Introduction to Gulp.js 2: Server with BrowserSync"
slug: gulp-tutorial-2-development-server-browsersync-configuration
author: Stefan Imhoff
date: 2014-10-19T10:17:00+02:00
description: "The ultimate tutorial and guide for Gulp.js: How to set up a development server with BrowserSync."
cover: /assets/images/cover/gulp.svg
tags: ["code"]
series: gulp
---
This is the 2nd part of my series, _Introduction to Gulp.js_. Today I will write the first few Gulp.js tasks and set up a development server with BrowserSync. And I will start to write a configuration file.
## Installing Gulp.js
To run my `gulpfile.js` I need to install gulp:
```bash
$ npm install --save-dev gulp@3.9.0
```
If I run the command `gulp` on my command line, I get an error message <samp>Task 'default' is not in your gulpfile</samp>. This is because I havent written a gulp task until now.
I create inside the `gulp/tasks` folder a file `default.js` and write this code:
#### gulp/tasks/default.js
```javascript
var gulp = require("gulp");
gulp.task("default", function () {
console.log("Hello Gulp.js!");
});
```
I know … I said Im sick of _Hello World_ tutorials, but this wont last very long. Ill soon replace it with valuable code. Stay with me.
If you execute the command `gulp`, this Gulp.js task will output <samp>Hello Gulp.js!</samp> to the console.
I will speed up the pace from now on.
## Watch
Instead of calling a function and outputting text to the console, I can execute tasks. I decided to execute the watch task when running `gulp`. This task will later watch for changes in files and update my files.
#### gulp/tasks/default.js
```javascript
var gulp = require("gulp");
gulp.task("default", ["watch"]);
```
Its possible to run multiple tasks at once, which is why I write my `watch` task in an Array. Be careful: These tasks will run in parallel, not in sequential order. Later I will show how to run tasks in a predefined order.
I will create another folder within my `tasks` folder with the name `development` and put all tasks needed for development in this folder. This is not necessary, but I did so:
#### gulp/tasks/development/watch.js
```javascript
var gulp = require("gulp");
/**
* Start browser-sync task and then watch files for changes
*/
gulp.task("watch", ["browsersync"], function () {});
```
I will come back later to write the `watch` task. For now, the function will be empty, and run another task before running the watch task: `browser-sync`. All tasks within the Array will be executed _before_ the task is executed.
## BrowserSync
You might have heard of [LiveReload](http://livereload.com/), a tool that is watching for changes in your files and automatically reloads the server. With Stylesheets, even reloading is not needed. The page refreshes with the changes instantly.
But [BrowserSync](https://browsersync.io/) is even better: It does all LiveReload does, but you dont need a browser plugin, and it syncs your actions like a scroll, click, refresh, or filling out forms to all browsers connected. This works even with mobile devices. And BrowserSync even has support for a development server. Thats why I will need nothing more than BrowserSync to get a development server with live reloading.
But first, I install BrowserSync:
```bash
$ npm install --save-dev browser-sync@2.9.11
```
I create a new file `browser-sync.js` in `gulp/tasks/development/`. This file will start BrowserSync and the development server.
#### gulp/tasks/development/browser-sync.js
```javascript
var gulp = require("gulp");
var browsersync = require("browser-sync");
var config = require("../../config").browsersync.development;
/**
* Run the build task and start a server with BrowserSync
*/
gulp.task("browsersync", ["build"], function () {
browsersync(config);
});
```
This code does need explanation: First, I load Gulp.js and BrowserSync, which are needed in this task. Then I load the configuration for BrowserSync. I will create this configuration file shortly. Keeping all configurations out of the tasks will make them more usable, and they can be shared between different projects.
The second thing worth mentioning is `['build']`. This does mean before starting BrowserSync it first will run the `build` Gulp.js task (which I will write later). Every Gulp.js task needs a name. As a second parameter, you can either add a JavaScript callback or tasks, or both.
## Configuration
I create a new file `config.js` in the main Gulp.js folder:
#### gulp/config.js
```javascript
var src = "app";
var build = "build";
var development = "build/development";
var production = "build/production";
var srcAssets = "app/_assets";
var developmentAssets = "build/assets";
var productionAssets = "build/production/assets";
module.exports = {
browsersync: {
development: {
server: {
baseDir: [development, build, src],
},
port: 9999,
files: [
developmentAssets + "/css/*.css",
developmentAssets + "/js/*.js",
developmentAssets + "/images/**",
developmentAssets + "/fonts/*",
],
},
},
};
```
First I extract paths needed over and over again later to variables, and then I create a CommonJS module and add an entry for BrowserSync. BrowserSync runs with default options, but I want to override the port and I tell BrowserSync which folders should be served.
Jekyll wipes out all files on recreation and to speed up development I have to be creative because I dont want to recreate all assets on every Jekyll build. Thats why I serve more than one folder. I serve the folder `build/development`, which will hold the files created by Jekyll. The assets I will generate into a different folder, `build/assets` that Jekyll doesnt wipe out. And additionally, the folder `app/_assets` to link source maps later.
BrowserSync watches my asset files, in order that my browser wont reload like hell, every time Jekyll creates one file. I will later write one task, which reloads the Browser one time after the Jekyll build is complete.
## Conclusion
This concludes the 2nd part of my series _Introduction to Gulp.js_. We learned how to install Gulp.js, write a Gulp.js task, run other tasks, and set up a development server with BrowserSync.
<Figure>
<MoreLink href="https://github.com/kogakure/gulp-tutorial" text="View Source on GitHub" />
</Figure>

View File

@@ -0,0 +1,156 @@
---
title: "Introduction to Gulp.js 3: Build, Clean and Jekyll"
slug: gulp-tutorial-3-build-clean-jekyll
author: Stefan Imhoff
date: 2014-10-20T10:00:00+02:00
description: "The ultimate tutorial and guide for Gulp.js: How to write tasks for cleaning files and folders, generating the build and the website with Jekyll."
cover: /assets/images/cover/gulp.svg
tags: ["code"]
series: gulp
---
This is the 3rd part of my series, _Introduction to Gulp.js_. Today I will write the build task, which will execute all other tasks needed for a build, the task to delete assets for a fresh start, and the task to create my Jekyll site.
## Build
Now I create a `build` task. This task will run all other tasks, which are needed to create the site. By default, Gulp.js runs all tasks in parallel. Thats why I will get a problem if a specific order is needed. I will need a node module that runs tasks in a sequence:
```bash
$ npm install --save-dev run-sequence@1.1.4
```
Next, I create the task:
#### gulp/tasks/development/build.js
```javascript
var gulp = require("gulp");
var runSequence = require("run-sequence");
/**
* Run all tasks needed for a build in a defined order
*/
gulp.task("build", function (callback) {
runSequence("delete", ["jekyll", "sass", "scripts", "images", "copy:fonts"], "base64", callback);
});
```
This task will first delete the assets folder (Jekyll is deleted by default), then create in parallel the Jekyll site, CSS files from SASS files, bundle the JavaScript files, copy images to the assets folder and copy vector fonts. After the `sass` task is finished, I replace links to small PNG files with Base64 encoding to inline them in my CSS files.
You should comment out tasks, we havent written until now, or Gulp cannot run. I just included them, so we dont need to come back for each task we write and add a line.
## Delete Assets
To wipe out all files in the asset folder, I use the node module `del`.
```bash
$ npm install --save-dev del@0.1.3
```
I need to add a config for deleting:
#### gulp/config.js
```javascript
browsersync: {
...
},
delete: {
src: [developmentAssets]
}
```
I will shorten all configuration options from now on. Every task will have its option section. These are JavaScript objects, please remember the trailing comma if you add a new configuration option.
The task will look like this:
#### gulp/tasks/development/delete.js
```javascript
var gulp = require("gulp");
var del = require("del");
var config = require("../../config").delete;
/**
* Delete folders and files
*/
gulp.task("delete", function (callback) {
del(config.src, callback);
});
```
If you use a newer version of `del` or run into trouble because `del` doesnt finish, try deleting the `callback` from the function.
## Jekyll
Next, I will write the configuration and the task to create the Jekyll site:
#### gulp/config.js
```javascript
jekyll: {
development: {
src: src,
dest: development,
config: '_config.yml'
}
}
```
#### gulp/config/development/jekyll.js
```javascript
var gulp = require("gulp");
var cp = require("child_process");
var browsersync = require("browser-sync");
var config = require("../../config").jekyll.development;
/**
* Build the Jekyll Site
*/
gulp.task("jekyll", function (done) {
browsersync.notify("Compiling Jekyll");
return cp
.spawn(
"bundle",
[
"exec",
"jekyll",
"build",
"-q",
"--source=" + config.src,
"--destination=" + config.dest,
"--config=" + config.config,
],
{ stdio: "inherit" }
)
.on("close", done);
});
gulp.task("jekyll-rebuild", ["jekyll"], function () {
browsersync.reload();
});
```
There is a gulp plugin for Jekyll, but its alpha and was blacklisted because its not needed, as you can run shell tasks with a node. But I have to send the `done` status when the task is finished.
All this task is doing is running `jekyll build` with some options. I use `app` as the source folder, `build/development` as the target, and point to my `_config.yml`.
I put my `_config.yml` and other configuration files always at the root of my project. If you dont like that, you need to update the configuration to point to the location of your `_config.yml`.
<Banner summary="To bundle or not to bundle">
**Be careful:** If you didnt install Jekyll with a Gemfile youll have to change the Jekyll tasks and remove the `bundle exec` part. Instead of `return cp.spawn('bundle', ['exec', 'jekyll' …` you write `return cp.spawn('jekyll', ['build', '-q' …`. All other options stay the same.
</Banner>
I have a second Jekyll build task `jekyll-rebuild`, which is only a wrapper for a rebuild. All it does is reload the Browser when the build is completed.
## Conclusion
This concludes the 3rd part of my series, _Introduction to Gulp.js_. We learned how to run files in specified order with `run-sequence`, how to delete files and folders, and how to execute a shell task like Jekyll.
<Figure>
<MoreLink href="https://github.com/kogakure/gulp-tutorial" text="View Source on GitHub" />
</Figure>

View File

@@ -0,0 +1,107 @@
---
title: "Introduction to Gulp.js 4: Creating CSS with Sass and Compass"
slug: gulp-tutorial-4-css-generation-sass
author: Stefan Imhoff
date: 2014-10-21T10:30:00+02:00
description: "The ultimate tutorial and guide for Gulp.js: How to create CSS and Source Maps with Sass and Compass."
cover: /assets/images/cover/gulp.svg
tags: ["code"]
series: gulp
---
This is the 4th part of my series, _Introduction to Gulp.js_. Today I will show how to use Sass (and Compass if you want) to create CSS files. Furthermore, I will add vendor prefixes with Autoprefixer and create Source Maps for easier debugging of the Sass files.
## Sass and Autoprefixer
I use [Sass](http://sass-lang.com/) as a preprocessor for my CSS files. If you like to use [Compass](http://compass-style.org/), you have to set an option for this task.
Go ahead and install the npm modules needed:
```bash
$ npm install --save-dev gulp-plumber@1.0.1 gulp-ruby-sass@2.0.4 gulp-filter@3.0.1 gulp-changed@1.0.0 gulp-autoprefixer@3.0.2 gulp-sourcemaps@1.6.0
```
Thats a lot, but this task will do a lot.
#### gulp/config.js
```javascript
sass: {
src: srcAssets + '/scss/**/*.{sass,scss}',
dest: developmentAssets + '/css',
options: {
noCache: true,
compass: false,
bundleExec: true,
sourcemap: true
}
},
autoprefixer: {
browsers: [
'last 2 versions',
'safari 5',
'ie 8',
'ie 9',
'opera 12.1',
'ios 6',
'android 4'
],
cascade: true
}
```
#### gulp/task/development/sass.js
```javascript
var gulp = require("gulp");
var plumber = require("gulp-plumber");
var browsersync = require("browser-sync");
var sass = require("gulp-ruby-sass");
var gulpFilter = require("gulp-filter");
var autoprefixer = require("gulp-autoprefixer");
var sourcemaps = require("gulp-sourcemaps");
var config = require("../../config");
/**
* Generate CSS from SCSS
* Build sourcemaps
*/
gulp.task("sass", function () {
var sassConfig = config.sass.options;
sassConfig.onError = browsersync.notify;
// Dont write sourcemaps of sourcemaps
var filter = gulpFilter(["*.css", "!*.map"], { restore: true });
browsersync.notify("Compiling Sass");
return sass(config.sass.src, sassConfig)
.pipe(plumber())
.pipe(sourcemaps.init())
.pipe(autoprefixer(config.autoprefixer))
.pipe(filter) // Dont write sourcemaps of sourcemaps
.pipe(
sourcemaps.write(".", {
includeContent: false,
sourceRoot: "app/_assets/scss",
})
)
.pipe(filter.restore) // Restore original files
.pipe(gulp.dest(config.sass.dest));
});
```
I load all my files with the suffix of `*.sass` or `*.scss`. First, I pipe the files through _Plumber_. It will keep Gulp.js running if I create a syntax error in one of my files. It would normally crash with an error. The next step creates the CSS files, running the `sass` command. I create source maps and finally put the CSS files to their destination.
And I run the CSS files through Autoprefixer, which will add vendor prefixes. I used the Mixins of Compass a long time, but stopped now and write pure CSS. All vendor prefixes are added later for the browsers I want to support.
You might have guessed: If you wish to use Compass, set the option `compass` to `true`.
## Conclusion
This concludes the 4th part of my series, _Introduction to Gulp.js_. We learned how to keep Gulp.js running, even when we produce errors, how to preprocess SCSS files with Sass, create Source Maps, and add vendor prefixes to the CSS files.
<Figure>
<MoreLink href="https://github.com/kogakure/gulp-tutorial" text="View Source on GitHub" />
</Figure>

View File

@@ -0,0 +1,296 @@
---
title: "Introduction to Gulp.js 5: Bundling JavaScript with Browserify"
slug: gulp-tutorial-5-javascripts-browserify
author: Stefan Imhoff
date: 2014-10-22T08:00:00+02:00
description: "The ultimate tutorial and guide for Gulp.js: How to bundle JavaScript files with Browserify and use CommonJS modules to structure and organize your code."
cover: /assets/images/cover/gulp.svg
tags: ["code"]
series: gulp
---
This is the 5th part of my series, _Introduction to Gulp.js_. Today I will show how to use Browserify to bundle your JavaScript and use CommonJS modules to run node modules in the Browser.
## Browserify
This task is more complex because I use [Browserify](http://browserify.org/) to bundle my JavaScript. If this is too complex for your needs, you may use [gulp-concat](https://www.npmjs.com/package/gulp-concat) to concatenate all your JavaScript files into one file.
Browserify is a wonderful tool, which allows you to use node modules in your browser. Over 70% of the node modules will run! And it will bundle up all of your dependencies. If you want to find out more about writing CommonJS modules for Browserify, have a look at the documentation.
This task I saw in the <del>gulp-starter</del> <ins>[blendid](https://github.com/vigetlabs/blendid)</ins>. Its long but clever. It allows the creation of multiple files with Browserify. I create two files. One file is loaded in the head of my website containing _Modernizr_ and one file with the rest of my JavaScript at the bottom.
## Creating JavaScript files with Browserify
Install the node modules needed for this task:
```bash
$ npm install --save-dev browserify@11.2.0 vinyl-source-stream@1.0.0 watchify@3.4.0 gulp-util@3.0.1 pretty-hrtime@1.0.1 gulp-notify@2.0.0
```
Create the entry in the `config.js` file:
#### gulp/config.js
```javascript
browserify: {
// Enable source maps
debug: true,
// Additional file extensions to make optional
extensions: ['.coffee', '.hbs'],
// A separate bundle will be generated for each
// bundle config in the list below
bundleConfigs: [{
entries: './' + srcAssets + '/javascripts/application.js',
dest: developmentAssets + '/js',
outputName: 'application.js'
}, {
entries: './' + srcAssets + '/javascripts/head.js',
dest: developmentAssets + '/js',
outputName: 'head.js'
}]
}
```
#### gulp/tasks/development/scripts.js
```javascript
var gulp = require("gulp");
var browsersync = require("browser-sync");
var browserify = require("browserify");
var source = require("vinyl-source-stream");
var watchify = require("watchify");
var bundleLogger = require("../../util/bundleLogger");
var handleErrors = require("../../util/handleErrors");
var config = require("../../config").browserify;
/**
* Run JavaScript through Browserify
*/
gulp.task("scripts", function (callback) {
browsersync.notify("Compiling JavaScript");
var bundleQueue = config.bundleConfigs.length;
var browserifyThis = function (bundleConfig) {
var bundler = browserify({
// Required watchify args
cache: {},
packageCache: {},
fullPaths: false,
// Specify the entry point of your app
entries: bundleConfig.entries,
// Add file extensions to make optional in your requires
extensions: config.extensions,
// Enable source maps!
debug: config.debug,
});
var bundle = function () {
// Log when bundling starts
bundleLogger.start(bundleConfig.outputName);
return (
bundler
.bundle()
// Report compile errors
.on("error", handleErrors)
// Use vinyl-source-stream to make the
// stream gulp compatible. Specify the
// desired output filename here.
.pipe(source(bundleConfig.outputName))
// Specify the output destination
.pipe(gulp.dest(bundleConfig.dest))
.on("end", reportFinished)
);
};
if (global.isWatching) {
// Wrap with watchify and rebundle on changes
bundler = watchify(bundler);
// Rebundle on update
bundler.on("update", bundle);
}
var reportFinished = function () {
// Log when bundling completes
bundleLogger.end(bundleConfig.outputName);
if (bundleQueue) {
bundleQueue--;
if (bundleQueue === 0) {
// If queue is empty, tell gulp the task is complete.
// https://github.com/gulpjs/gulp/blob/master/docs/API.md#accept-a-callback
callback();
}
}
};
return bundle();
};
// Start bundling with Browserify for each bundleConfig specified
config.bundleConfigs.forEach(browserifyThis);
});
```
This task has additional utilities for handling errors and logging the bundling process. Put these into a `util` folder in your `gulp` folder:
#### gulp/util/bundleLogger.js
```javascript
/* bundleLogger
------------
Provides gulp style logs to the bundle method in browserify.js
*/
var gutil = require("gulp-util");
var prettyHrtime = require("pretty-hrtime");
var startTime;
module.exports = {
start: function (filepath) {
startTime = process.hrtime();
gutil.log("Bundling", gutil.colors.green(filepath));
},
end: function (filepath) {
var taskTime = process.hrtime(startTime);
var prettyTime = prettyHrtime(taskTime);
gutil.log("Bundled", gutil.colors.green(filepath), "in", gutil.colors.magenta(prettyTime));
},
};
```
#### gulp/util/handleErrors.js
```javascript
var notify = require("gulp-notify");
module.exports = function () {
var args = Array.prototype.slice.call(arguments);
// Send error to notification center with gulp-notify
notify
.onError({
title: "Compile Error",
message: "<%= error.message %>",
})
.apply(this, args);
// Keep gulp from hanging on to this task
this.emit("end");
};
```
## Using CommonJS Modules
Writing CommonJS modules is nice. You export your function, object, string, or integer, you like to export as a module or individually:
#### math.js
```javascript
exports.add = function() {
var sum = 0, i = 0, args = arguments, 1 = args.length;
while (i < 1) {
sum += args[i++];
}
return sum;
};
```
#### navigation.js
```javascript
module.exports = {
toggleNavigation: function() {
...
}
};
```
Later, you import your modules and use them:
#### increment.js
```javascript
var add = require("./math").add;
exports.increment = function (val) {
return add(val, 1);
};
```
#### application.js
```javascript
var navigation = require("./navigation");
var triggerNavigation = document.querySelector(".toggle-navigation");
document.addEventListener("DOMContentLoaded", function () {
triggerNavigation.addEventListener("click", navigation.toggleNavigation);
});
```
## Loading non-CommonJS files
But one problem remains: How do I use JavaScript files, which arent written in CommonJS syntax? Like Modernizr or jQuery?
I need to install `browserify-shim`:
```bash
$ npm install --save-dev browserify-shim@3.8.0
```
I open my `package.json` file and need to add a few lines:
#### package.json
```json
{
"...": "...",
"browser": {
"modernizr": "./app/_bower_components/modernizr/modernizr.js",
"jquery": "./app/_bower_components/jquery/dist/jquery.js"
},
"browserify-shim": {
"modernizr": "Modernizr",
"jquery": "$"
},
"browserify": {
"transform": ["browserify-shim"]
},
"devDependencies": {
"...": "..."
}
}
```
In the section `"browser"` you point `browserify-shim` to the asset you want to shim. I use [Bower](https://bower.io/) and have installed my packages into `app/_bower_components/`. The name you choose is the name you have to require later in your JavaScript.
Within `"browerify-shim"` you decide where to map this `require` to. To include jQuery or Modernizr later you would write:
#### app/assets/javascripts/head.js
```javascript
require("modernizr");
```
#### app/\_assets/javascripts/application.js
```javascript
require("jquery");
$(function () {
console.log("jQuery and Modernizr loaded");
});
```
You have to run `npm install` once you added a new entry to your `package.json` file.
## Conclusion
This concludes the 5th part of my series, _Introduction to Gulp.js_. We learned how to use Browserify to bundle JavaScript files, how to use CommonJS modules to run Node in your Browser, and how to use non-CommonJS JavaScript files.
<Figure>
<MoreLink href="https://github.com/kogakure/gulp-tutorial" text="View Source on GitHub" />
</Figure>

View File

@@ -0,0 +1,183 @@
---
title: "Introduction to Gulp.js 6: Images and Vector Fonts"
slug: gulp-tutorial-6-images-vector-fonts
author: Stefan Imhoff
date: 2014-10-23T08:00:00+02:00
description: "The ultimate tutorial and guide for Gulp.js: How to move images and generate vector fonts from SVG."
cover: /assets/images/cover/gulp.svg
tags: ["code"]
series: gulp
---
This is the 6th part of my series, _Introduction to Gulp.js_. The last post was long and complicated. This time its an easier one: I will show how I move my images and generate vector fonts.
## Images
The image task is a simple one again. All it does for now is copy the images to the asset directory. I will optimize my images later during the production build.
#### gulp/config.js
```javascript
images: {
src: srcAssets + '/images/**/*',
dest: developmentAssets + '/images'
}
```
#### gulp/tasks/development/images.js
```javascript
var gulp = require("gulp");
var changed = require("gulp-changed");
var config = require("../../config").images;
/**
* Copy images to build folder
* if not changed
*/
gulp.task("images", function () {
return gulp
.src(config.src)
.pipe(changed(config.dest)) // Ignore unchanged files
.pipe(gulp.dest(config.dest));
});
```
## Vector Fonts
I use vector fonts for my website. Vector fonts are one option to include high-quality icons on a website. Another option is using SVG directly or to use high-resolution images.
I am using [Font Custom](http://fontcustom.github.io/fontcustom/) to generate my vector fonts. There is a [gulp plugin](https://www.npmjs.com/package/gulp-fontcustom/) for this, but I couldnt get it running. But Im fine with running this task with a shell command (via Gulp.js). I will use Gulp.js later to watch the folder containing the SVG files and recreate the vector fonts if needed.
First, I need to install Font Custom (with Homebrew, you can find more installation methods on the Font Custom website):
```bash
$ brew install fontforge --with-python
$ brew install eot-utils
```
Next, I run the command `bundle exec fontcustom config` inside my main projects directory, which will create a file `fontcustom.yml`. I adjust my file until it looks like this:
#### fontcustom.yml
```yaml
# --------------------------------------------------------------------------- #
# Project Info
# Default values shown. Learn more about these options by running
# `fontcustom help` or visiting <http://fontcustom.com>.
# --------------------------------------------------------------------------- #
font_name: fontcustom
css_selector: .icon-{{glyph}}
css_prefix: icon-
preprocessor_path: "/assets/fonts"
autowidth: false
no_hash: false
force: false
debug: false
quiet: false
# --------------------------------------------------------------------------- #
# Project Paths
# Relative paths are expanded from PROJECT_ROOT (defaults to the directory
# where the fontcustom command is run). INPUT and OUTPUT can be strings or
# hashes or file types/names.
# --------------------------------------------------------------------------- #
#project_root: some/other/place
#manifest: tmp/fontcustom
input:
vectors: vectors # required
# templates: app/assets/fonts/fontcustom/templates
output:
fonts: app/_assets/fonts # required
css: app/_assets/scss
preview: docs
# my-custom-template.yml: config
# --------------------------------------------------------------------------- #
# Templates
# Included in Font Custom:
# preview, css, scss, scss-rails, bootstrap, bootstrap-scss, bootstrap-ie7,
# bootstrap-ie7-scss
# Custom templates should be saved in the INPUT[:templates] directory and
# referenced by their base file name.
# --------------------------------------------------------------------------- #
templates: [scss, preview]
```
Next, I add configuration and the task to copy the fonts to their location:
#### gulp/config.js
```javascript
copyfonts: {
development: {
src: srcAssets + '/fonts/*',
dest: developmentAssets + '/fonts'
}
}
```
#### gulp/tasks/development/copy-fonts.js
```javascript
var gulp = require("gulp");
var config = require("../../config").copyfonts.development;
/**
* Copy fonts to folder
*/
gulp.task("copy:fonts", ["fontcustom"], function () {
return gulp.src(config.src).pipe(gulp.dest(config.dest));
});
```
As you may have seen, before copying the fonts to the asset folder, another task gets executed: `fontcustom`.
Font Custom checks the files for changes and doesnt generate anything if the files are the same.
To execute a shell command, I use the Gulp.js plugin `gulp-shell`:
```bash
$ npm install --save-dev gulp-shell@0.5.0
```
#### gulp/tasks/development/fontcustom.js
```javascript
var gulp = require("gulp");
var shell = require("gulp-shell");
/**
* Generate fonts with Fontcustom
* `brew install fontforge --with-python`
* `brew install eot-utils`
*/
gulp.task("fontcustom", shell.task(["bundle exec fontcustom compile"]));
```
Fontcustom is a Ruby Gem, and youll need to install the Gem either globally or in your Gemfile (if you install it globally, you have to drop the `bundle exec` from your command). I choose to install it with my Gemfile:
#### Gemfile
```ruby
source "https://rubygems.org"
gem 'jekyll', '~> 2.5.2'
gem 'sass', '>= 3.3'
gem 'fontcustom', '~> 1.3.7'
```
After you add the line for `fontcustom` you will have to run `bundle install` again.
## Conclusion
This concludes the 6th part of my series, _Introduction to Gulp.js_. We learned how to move files with Gulp.js (and dont even need a plugin for that), and how I create my vector fonts. Nothing special, but the next part will be more interesting again.
<Figure>
<MoreLink href="https://github.com/kogakure/gulp-tutorial" text="View Source on GitHub" />
</Figure>

View File

@@ -0,0 +1,100 @@
---
title: "Introduction to Gulp.js 7: Base64 Encoded Images"
slug: gulp-tutorial-7-base64
author: Stefan Imhoff
date: 2014-10-24T07:30:00+02:00
description: "The ultimate tutorial and guide for Gulp.js: How to replace small images with base64 encoded images."
cover: /assets/images/cover/gulp.svg
tags: ["code"]
series: gulp
---
This is the 7th part of my series, _Introduction to Gulp.js_. Today, I will use Gulp.js to replace a lot of my URLs with small images with Base64 encoded images.
The last task executed by my `build` task is one, which replaces the URLs of small images in my CSS files with Base64 encoded images. This way, the images get embedded into the CSS file and dont need an additional server request. If the images are not too large, this will speed up the loading of my website a lot.
I use plenty of small patterns on my website because I dont like the _Flat Design_ approach a lot. The physical world isnt flat. Nowhere. There is always structure, pattern, shade, and light. The patterns I use are from the fantastic website [Subtle Pattern](https://www.toptal.com/designers/subtlepatterns/). They have a few hundred nice subtle patterns.
To load the background pattern, I use SCSS like this:
```scss
%pattern-light-grey {
background-color: $background-color;
background-image: url(/assets/images/patterns/light_grey.png);
background-size: 301px 621px;
}
body {
@extend %pattern-light-grey;
}
```
The generated CSS looks like this:
```css
body {
background-color: #fdfdfd;
background-image: url(/assets/images/patterns/light_grey.png);
background-size: 301px 621px;
}
```
After the task ran, the CSS will look like this:
```css
body {
background-color: #fdfdfd;
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAloAAATaBAMAAAB4FdU7AAAA…);
background-size: 301px 621px;
}
```
For this task, I will need another Gulp.js plugin:
```bash
$ npm install --save-dev gulp-base64@0.1.2
```
I add a new configuration entry and create the task:
#### gulp/config.js
```javascript
base64: {
src: developmentAssets + '/css/*.css',
dest: developmentAssets + '/css',
options: {
baseDir: build,
extensions: ['png'],
maxImageSize: 20 * 1024, // bytes
debug: false
}
}
```
I replace images with the ending PNG and if they have a maximum of 20 KB of size. This way, my high-resolution images dont get embedded into the CSS file.
#### gulp/tasks/development/base64.js
```javascript
var gulp = require("gulp");
var base64 = require("gulp-base64");
var config = require("../../config").base64;
/**
* Replace urls in CSS files with base64 encoded data
*/
gulp.task("base64", ["sass"], function () {
return gulp.src(config.src).pipe(base64(config.options)).pipe(gulp.dest(config.dest));
});
```
We are now finished with the development `build` task.
## Conclusion
This concludes the 7th part of my series, _Introduction to Gulp.js_. We learned how to replace URLs to PNGs with Base64 encoded images. And we are now finished with our `build` task.
<Figure>
<MoreLink href="https://github.com/kogakure/gulp-tutorial" text="View Source on GitHub" />
</Figure>

View File

@@ -0,0 +1,80 @@
---
title: "Introduction to Gulp.js 8: Watch for Changes"
slug: gulp-tutorial-8-watch
author: Stefan Imhoff
date: 2014-10-25T10:00:00+02:00
description: "The ultimate tutorial and guide for Gulp.js: How to set up a watch task, which triggers other tasks on file changes."
cover: /assets/images/cover/gulp.svg
tags: ["code"]
series: gulp
---
This is the 8th part of my series, _Introduction to Gulp.js_. Today, I will set up watch tasks for many files with Gulp.js.
Do you remember the `watch` task from the beginning? It started BrowserSync and the development server until now, but didnt watch for anything. I will write these watch tasks now.
`Watch` is part of the API of gulp. It will watch files for changes, addition or deletion, and trigger tasks.
#### gulp/config.js
```javascript
watch: {
jekyll: [
'_config.yml',
'_config.build.yml',
src + '/_data/**/*.{json,yml,csv}',
src + '/_includes/**/*.{html,xml}',
src + '/_layouts/*.html',
src + '/_plugins/*.rb',
src + '/_posts/*.{markdown,md}',
src + '/**/*.{html,markdown,md,yml,json,txt,xml}',
src + '/*'
],
sass: srcAssets + '/scss/**/*.{sass,scss}',
scripts: srcAssets + '/javascripts/**/*.js',
images: srcAssets + '/images/**/*',
sprites: srcAssets + '/images/**/*.png',
svg: 'vectors/*.svg'
}
```
I watch countless different file types for Jekyll. Changes in configuration files, data files, layouts, including plugins, and posts.
The Sass task will watch for changes in files with the suffix `sass` or `scss`. JavaScript gets triggered if I change JavaScript files. You get the point.
#### gulp/tasks/development/watch.js
```javascript
var gulp = require("gulp");
var config = require("../../config").watch;
/**
* Start browsersync task and then watch files for changes
*/
gulp.task("watch", ["browsersync"], function () {
gulp.watch(config.jekyll, ["jekyll-rebuild"]);
gulp.watch(config.sass, ["sass", "scsslint"]);
gulp.watch(config.scripts, ["scripts", "jshint"]);
gulp.watch(config.images, ["images"]);
gulp.watch(config.svg, ["copy:fonts"]);
gulp.watch(config.sprites, ["sprites"]);
});
```
I set up six watch tasks. When a file of the Jekyll watch gets changed, deleted, or added, the `jekyll-rebuild` task gets executed. This task will run the Jekyll build, and after its finished reload the page.
For `SCSS` files, I run the `sass` tasks, and additionally, I run a `scsslint` task, which will check my files for syntax errors.
Changes in JavaScript files trigger the `scripts` tasks and a `jshint` task, which will check my files for syntax errors.
If I add, modify or delete an SVG file, my vector fonts get recreated. And as a fallback for browsers without vector font support, I create a PNG sprite map when I change an image of the sprite. It would be possible to auto-create the PNG files of the SVG files with [gulp-svg2png](https://www.npmjs.com/package/gulp-svg2png/), but I have an additional design on the sprite images, thats why I dont use it.
I miss now three tasks: `scsslint`, `jshint`, and `sprites`.
## Conclusion
This concludes the 8th part of my series, _Introduction to Gulp.js_. We learned how to use Gulp.js to watch for changes, deletion, or creation of files and how to trigger tasks. And the best part is: This is part of the Gulp.js API. We dont need any plugins.
<Figure>
<MoreLink href="https://github.com/kogakure/gulp-tutorial" text="View Source on GitHub" />
</Figure>

View File

@@ -0,0 +1,101 @@
---
title: "Introduction to Gulp.js 9: Syntax-Check of SCSS and JavaScript"
slug: gulp-tutorial-9-linting-scss-and-javascript
author: Stefan Imhoff
date: 2014-10-26T08:10:00+02:00
description: "The ultimate tutorial and guide for Gulp.js: How to check the syntax of SCSS and JavaScript files."
cover: /assets/images/cover/gulp.svg
tags: ["code"]
series: gulp
---
This is the 9th part of my series, _Introduction to Gulp.js_. Today, I will use Gulp.js to automatically check my SCSS and JavaScript files for syntax errors and warnings.
I decided to lint my SCSS files and not the CSS files because its pointless to lint generated CSS. But you can do this with [gulp-csslint](https://www.npmjs.com/package/gulp-csslint/).
```bash
$ npm install --save-dev gulp-scss-lint@0.3.6 gulp-jshint@1.8.5 jshint-stylish@2.0.1
```
Additionally, youll need to install the `scss-lint` Gem and run `bundle install`:
#### Gemfile
```ruby
source "https://rubygems.org"
gem 'jekyll', '~> 2.5.2'
gem 'sass', '>= 3.3'
gem 'scss-lint', '~> 0.31.0'
gem 'fontcustom', '~> 1.3.7'
```
Add the options for `jshint` and `scss-lint`:
#### gulp/config.js
```javascript
scsslint: {
src: [
srcAssets + '/scss/**/*.{sass,scss}',
'!' + srcAssets + '/scss/base/_sprites.scss',
'!' + srcAssets + '/scss/helpers/_meyer-reset.scss'
],
options: {
bundleExec: true
}
},
jshint: {
src: srcAssets + '/javascripts/*.js'
}
```
I ignore files from checking (by adding a `!` in front of the path) because I didnt write them or dont have control over the syntax.
#### gulp/tasks/development/scss-lint.js
```javascript
var gulp = require("gulp");
var scsslint = require("gulp-scss-lint");
var config = require("../../config").scsslint;
/**
* Lint SCSS files
* `gem install scss-lint` needed
*/
gulp.task("scsslint", function () {
return gulp.src(config.src).pipe(scsslint(config.options));
});
```
#### gulp/tasks/development/jshint.js
```javascript
var gulp = require("gulp");
var jshint = require("gulp-jshint");
var stylish = require("jshint-stylish");
var config = require("../../config").jshint;
/**
* Check JavaScript syntax with JSHint
*/
gulp.task("jshint", function () {
return gulp.src(config.src).pipe(jshint()).pipe(jshint.reporter(stylish));
});
```
<Banner summary="Configuration of Syntax Check Tools">
You may change the rules for linting SCSS or JavaScript by adding a hidden file `.scss-lint.yml` for SCSS lint and `.jshintrc` for JSHint to your project root.
To find out which options are available, look into the documentation of [SCSS-Lint](https://github.com/brigade/scss-lint) and [JSHint](https://jshint.com/docs/).
</Banner>
## Conclusion
This concludes the 9th part of my series, _Introduction to Gulp.js_. Today, we learned how to use Gulp.js to check the syntax of SCSS and JavaScript files. This task will run continuously while I write my files and print out errors to my console the moment I created them.
<Figure>
<MoreLink href="https://github.com/kogakure/gulp-tutorial" text="View Source on GitHub" />
</Figure>

View File

@@ -0,0 +1,37 @@
---
title: John Seymours Books on Self-Sufficiency
slug: john-seymour-books
author: Stefan Imhoff
date: 2014-08-03T16:00:00+02:00
description: On John Seymours fantastic, beautifully illustrated books on self-sufficiency, agriculture, and crafts. The optimal equipment for an upcoming zombie apocalypse.
tags: ["book"]
---
My earliest memories of books are that I lie on my parents soft carpet on my stomach in the living room and read the <cite>Atlas of World History</cite> or the books of _John Seymour_. Who was John Seymour, and why did his books remain in my memory?
## John Seymour
Born in England in 1914, he went to boarding school in Switzerland and later began studying agricultural sciences. He went to Africa at the age of 20 to work as a farmer. After serving in World War II in North Africa and Asia, he returned to England and moved to an old remote farm with his family in 1957 and started living solely on home-grown produce. After moving to a farm in Wales in the 1970s, he wrote his world-famous books <cite>The Complete Book of Self-Sufficiency</cite> (<cite lang="de"><AffiliateLink asin="3831015775" text="Das große Buch vom Leben auf dem Lande" /></cite>) and <cite>The Self-Sufficient Gardener</cite> (<cite lang="de"><AffiliateLink asin="3783161452" text="Selbstversorgung aus dem Garten" /></cite>).
<Bookshelf>
<AmazonBook asin="3831015775" />
<AmazonBook asin="3783161452" />
</Bookshelf>
## The Books
In his books, he writes comprehensible for laymen, enriched by beautiful, detailed drawings and illustrations. Whether you run a small garden or a large farm, his books describe well what needs to be done to create a closed and healthy cycle.
In _The New Complete Book of Self-Sufficiency_ he explains the food chain, soil types, and the seasons. He describes various types of gardens, addresses all kinds of fruits and vegetables, tells how to keep animals, cultivate and utilize land, grow long-lasting food, and a huge number of things. His second book, _The New Self-Sufficient Gardener_, goes into more detail and shows how to work with a garden.
## Part of my Survival Kit
I sometimes joke that if the zombie apocalypse arrives or civilization collapsed for other reasons, I first get my [Kukri](https://en.wikipedia.org/wiki/Khukuri), my bow with arrows, and the books of John Seymour. Because all the knowledge that we use every day, be it programming, design, management, spreadsheets, or any other activity of the modern age is then worth nothing. However, the knowledge in his books is almost timeless and will be up-to-date even in the distant future.
John Seymour wrote many more books during his life, for example, the commendable book <cite><AffiliateLink asin="0863181740" text="The National Trust Book of Forgotten Household Crafts" /></cite>. It displays various arts well-illustrated, such as woodcraft, construction, workshop or chores, the tools used, and the products they create.
## Conclusion
Even if you live in the city presently or do not have a garden or a plot of land, it is always a pleasure to page through the books. Therefore, his books should not be missing in any good library.
John Seymour would have turned 100 last month. His books contain valuable knowledge about self-sufficiency and have been expanded over the years. The current version of his bestseller <cite><AffiliateLink asin="1405345101" text="The New Complete Book of Self-Sufficiency" /></cite> has information on wind energy and solar energy. And you will learn how beer is brewed or wine is pressed.

View File

@@ -0,0 +1,83 @@
---
title: Design of My New Logo
slug: logo-design
author: Stefan Imhoff
date: 2014-04-18T19:00:00+02:00
description: "Insight into the design of my new logo and Rakkan: idea, research, and a short digression on the Chinese script."
tags: ["design"]
---
Since a logo is one of the essential elements that recognize a website, I wanted from the beginning to design a logo that fits the theme of the rest of the design of the site.
Although I think that a private person does not need a logo. But without a logo is a nice visual element missing that can be used later in all sorts of places, for example as the favicon.
It was clear to me early that I wanted to use a _Rakkan_ instead of a modern logo.
## Rakkan
A Rakkan (or Hanko) is called in Japan a seal, which is carved in stone, representing the signature of an artist and is stamped under the artwork, and thus works as a signature.
<Figure caption="Imprint of my Rakkan below a symbol for 忍 (Shinobi) written by me.">
<Image src="/assets/images/posts/rakkan.jpg" alt="Rakkan written ink below symbol" />
</Figure>
Even with my [martial arts portal](https://www.kogakure.de/), I use a seal as a logo.
## Research
Before I could start designing my new seal, I first had to conduct research. For this, I have looked at historical stamps in numerous works and studied their style and characteristics.
Stamps use multiple characters, four or even more. They exist in all forms, with the angular shape seeming to be the most common.
The next step was to choose the right font. As a typeface, many artists pick the _small seal script_, which was introduced by the Chinese Emperor Qin Shi Huang about 2200 years ago.
## Tour in Chinese Writing Styles
The first Chinese characters were scratched on potsherds 6000 years ago. The [oracle bone script](https://en.wikipedia.org/wiki/Oracle_bone_script) was developed 3400 years ago during the Shang Dynasty and was used for prophecy with animal bone oracles.
As the bronze casting technique around the 11th century BC the [bronze inscriptions](https://en.wikipedia.org/wiki/Chinese_bronze_inscriptions) were developed, which were used to write texts for politics, trade, military, administration, and oracles.
At the time of the Seven Kingdoms (475-221 BC), brush and ink were invented and written on bamboo, wood, and silk.
However, there were many spellings of the characters, which was not conducive to exchange and trading. King Zhou Xuanwang tried to solve this problem through the [large seal script](https://en.wikipedia.org/wiki/Large_seal_script), but he did not succeed. As Emperor Qin Shin Huang unified the empire in 221 BC, he ordered a uniform font. Chancellor Li Si eliminated characters and reduced strokes, thus founding the [small seal script](https://en.wikipedia.org/wiki/Small_seal_script).
The small seal is indeed beautiful by its curved lines, but was cumbersome to write in everyday use. At the beginning of the Han Dynasty, the [clerical script](https://en.wikipedia.org/wiki/Clerical_script), had much straighter lines and was easier and faster to write. This font further abstracted many characters.
At the same time, the _cursive script_ was invented, which is called [grass font](<https://en.wikipedia.org/wiki/Cursive_script_(East_Asia)>). It was used for private correspondence, but written by the common people. In this font, the strokes are connected. It looks like the brush has not been lifted off the paper.
In the 2nd century AD, scribes who disliked the concept of chancery script developed the [regular script](https://en.wikipedia.org/wiki/Regular_script).
At the end of the Han Dynasty, there was another style for private use besides the grass script: the [semi-cursive script](https://en.wikipedia.org/wiki/Semi-cursive_script).
The next significant change took place in 1956 when the government simplified the text. More than 1000 characters were deleted and with 2200 characters, the number of lines was reduced. This should lead to a better literacy of the population.
## The Meaning of the Characters on My Rakkan
For my new Rakkan, I have taken over the characters of my old Rakkan and then added two more characters. The old character contains the characters 木隠 (kogakure), which is not only the name of my martial arts portal, but my pseudonym on the Internet for many years. Translated, it means <q>hidden behind trees and leaves.</q>
The two new characters to the left of it mean 草 (grass) and 刀 (blade) in the small seal script. The signs allow numerous possibilities of interpretation, which I will not go into here to get anyone bored.
A seal can be created in two different variants: **Yin** or **Yang** (☯). In the Yin variant (as I have it on [kogakure.de](https://www.kogakure.de/)), the letters are carved out of the stone, and the surface remains. This time, I wanted to create a rakkan in the yang variant where everything is cut away except for the letters (and an edge).
## The Creation of the Rakkan
First, I made numerous pencil drawings, first of individual characters that I liked, and later of combinations. I wondered how an artist would carve a traditional stamp, how the letters touch and support to give the seal the necessary stability.
<Figure caption="Moleskine with pencil drawings of characters">
<Image
src="/assets/images/posts/moleskine-pencil-drawings.jpg"
alt="Moleskine with pencil drawings of characters"
/>
</Figure>
After I had developed my final variant, I drew the pencil lines with a thick highlighter (not without almost ruining my bamboo table, since I omitted out of laziness to use a pad). The texture that emerges when ink spreads through the paper looks much like a stone-carved edge.
In the next step, I then digitized the Rakkan and corrected it in Adobe Photoshop to remove unsightly parts or improve the lines.
To create a vector shape from this pixel image, I imported the image into Adobe Illustrator and converted it to a vector shape, then reduced the number of vector points and exported it as an SVG file.
To use my logo as a vector font on the page, I used [Font Custom](http://fontcustom.com/) to convert SVGs into web fonts. Thus, several vector graphics are combined as a single character in a font file. Once the font is loaded, the icons can then be displayed in any size and styled with CSS.
## The Font
Now the Rakkan can be used as a character and can be generated by a CSS class attribute on any element. Then, the character can be colored at will and get the desired font size or text effects (such as a shadow edge).

View File

@@ -0,0 +1,179 @@
---
title: Typography of My Website
slug: website-typography
author: Stefan Imhoff
date: 2014-06-19T10:30:00+02:00
description: "About the typography of my new website: scale, font, vertical rhythm, font size, font size, and sentence width."
tags: ["design", "code", "typography"]
---
Im a _typophile_. But this is nothing for a self-help group because it means to love typography. It was clear to me from the start that I would start with typography for my new website.
Normally, designers pay attention to typography, to the rest of the people typography is unimportant. But typography influences each of us, consciously and subconsciously.
Readability or contrast decides whether the message of a text reaches the reader at all. And since words have incredible power, typography is underestimated.
The right choice of font, font size, weight, layout, sentence width, lead, letter spacing, or many other things unconsciously affects the reader and thus transports the statement. Proper typography can support and reinforce a message that makes the wrong message even meaningless or ridiculous.
Ive always found typography fascinating, but after reading the book <cite><AffiliateLink asin="0881792128" text="The Elements of Typographic Style" /></cite> by _Robert Bringhurst_ I studied the matter more deeply. There is a Web-adapted version of his book on the website [The Elements _of_ Typographic Style Applied _to the_ Web](http://webtypography.net/).
<Bookshelf>
<AmazonBook asin="0881792128" />
</Bookshelf>
## Typography
Selecting good typography does not only mean selecting a scripture but is an art form that I am far from mastering.
It is important to choose the right page layout, the right sentence width, the correct lead, the right combination of fonts, the right scale, the correct font size, and a variety of other guidelines.
## Scale
Several years ago, I stumbled on two interesting lectures by Tim Brown on typography. Tim Brown works as _Type Manager_ for [Adobe Typekit](https://typekit.com/), a platform that offers Web font hosting. In his lectures, he offers a fascinating insight into the history of typography and how to achieve good typography.
I started with the selection of a scale. A typographic scale is the selection of harmonic proportions, which are then applied to font size, sentence width, and other parts.
The most famous proportion is the _Golden Ratio_, which has a ratio of `1:1.618`. But many other proportions have their origins in geometry, music, nature, or history. Tim Brown has even created the website [Modular Scale](http://www.modularscale.com/), on which a scale can be calculated.
However, this was not necessary for my project because Team-Sass offers a [SASS extension](https://github.com/modularscale/modularscale-sass).
So, I add the gem to my Gemfile first:
#### Gemfile
```ruby
source "https://rubygems.org"
group :development do
gem 'modular-scale'
end
```
Then I load the Compass plugin in `config.rb`:
#### config.rb
```ruby
# Require any additional compass plugins here.
require 'modular-scale'
```
Afterward, the module of Compass has to be loaded in a partial:
#### helpers/\_imports.scss
```scss
@import "compass";
@import "compass/reset";
@import "modular-scale";
```
I've decided to use the _golden ratio_ and then select the ideal text size and an important number:
```scss
$ms-base: 16px 18px;
$ms-ratio: $golden;
```
Now the helpers of Gems can be used everywhere in the SCSS. Instead of writing somewhere manually `42px` (`41.887px`) or `2.618em`, I write `modular-scale(4)` to choose the fourth value of the scale:
```scss
$font-scale-h1: modular-scale(4);
```
## Sentence Width
I could have started to choose the sentence width (line length), and then choose the grid appropriately. However, now that a scale has been selected, you can use it for the correct sentence width.
A responsive website with fluid line length is not an optimal prerequisite for a fixed sentence width. All sorts of values are circulating on the Internet, which is an optimal line length. All sorts of truisms such as no less than 45 characters, no more than 85 characters, or similar values can be found there. But nothing is scientifically proven, and one should measure in words rather than in characters because we see word images and not letters.
If the line is too long, the eyes are tired and the readers may lose the connection to the next line, if the line is too short, the constant interruption of the reading flow will be equally severe. There is one thing to say: The correct line length does not exist, it depends on the font, typesetting, and line spacing.
I tried to determine the optimal line length of my website with about 66 characters or about 10 words. Depending on the browser size, the line length then shrinks up to a threshold that I have selected. If this falls below, I select a different number of columns of the grid.
But I make sure that the line length is not wider than I determined to be optimal because as soon as the head has to be moved, the line is too long.
## Vertical Rhythm
Next, I set the line spacing and decided in addition to the technique of _vertical rhythm_. In the case of fonts of different sizes, the line spacing is mathematically changed in such a way that two different-sized fonts would be visually adjacent to each other.
Convenient is that the annoying mathematics behind the formula (which spits out crooked values with many decimal places) does not have to be calculated by yourself. Compass comes with a [module](http://compass-style.org/reference/compass/typography/vertical_rhythm/) for it.
There are some variables to be set:
```scss
$base-font-size: modular-scale(1); // 18px
$base-line-height-count: 1.5;
$base-line-height: $base-font-size * $base-line-height-count; // 27px
$relative-font-sizing: true; // use em and not px
$round-to-nearest-half-line: true; // prevent too big gaps between lines
```
A simple call to this mixin activates the vertical rhythm:
```scss
@include establish-baseline();
```
To adjust the font size, you do not use absolute values anymore, but a mixin. This can be used with the Mixin of _Modular Scale_:
```scss
h1 {
@include adjust-font-size-to(modular-scale(6));
@include trailer(1, modular-scale(6), margin);
}
```
You no longer directly define the distances above or below an element, but use mixins, as in the example `trailer`.
## Fonts
I had the most problems choosing the font, as this is a difficult task. There are tons of fonts, but finding the right one for the occasion is a big hassle. To make matters worse, there are far more bad fonts on the Internet than good fonts.
Creating a font is an immense effort and therefore a license for a font step also costs a lot of money. But to use web typography, the designer of a font must release it for embedding in a website. Beautiful, free fonts are available, for example on [The League of Movable Type](https://www.theleagueofmoveabletype.com/).
In addition to owning the font, there is the possibility to integrate the font of a web service. There are for example pay-as-you-go solutions such as [Adobe Typekit](https://typekit.com/), which offer many professional fonts. Anyone unwilling to regularly pay to use a font can still choose from many fonts that have been freely made available by nice designers.
I first looked at Typekit, but then chose two free fonts that I integrate into my website via [Google Fonts](https://fonts.google.com):
- _Gentium Basic_ for long-running texts
- _Yanone Kaffeesatz_ for headlines and shorter texts, as on the homepage
Gentian Basic is an appealing typeface with serifs and an italic typeface, while Yanone Kaffeesatz is a sans serif typeface. Both fonts in combination offer a harmonious picture.
## Font Size
On November 17, 2006, Oliver Reichenstein wrote on the Blog of Information Architects about the [100% Easy-2-Read Standard](https://ia.net/topics/100e2r), this concept was new to me. At that time, the font on websites was consistently set too small. The browser standard has always been `16px`. But many pages use values between 10 and 12 pixels.
After this blog post, designers started to increase the base font size. I even use `18px` for my floating text font.
## Font Weight
I load _Gentium Basic_ in 400 and 700 and _Yanone Kaffeesatz_ in 200 and 400. I can put bold parts of the body text in 700 and the rest in 400. On the homepage, I use _Yanone Kaffeesatz_. For high-resolution displays (Retina) I use a font width of 200, for all other displays 400.
## Tracking, Widows and Orphans
_Tracking_, the inserting of spaces between individual letters, I use on my website in a few places and _Kerning_, reducing the spacing between individual letters, not at all. Manual kerning on the Internet is a time-consuming task. There are JavaScript solutions, but the whole thing is not worth the effort or load size on the web.
To prevent a single word from being alone on a new line, I have been using JavaScript for a while. Since this jQuery plugin did not work reliably in cases and had a large file size, I removed it after a few weeks.
## Other Typographic Formatting
I use more typographic formatting, such as centered verse blocks, and correct quotation marks for inline citations depending on the language. Ive written myself a Jekyll plugin that ensures that `e.g.`, `1000 €`, or `5 + 3` are provided with invisible spaces so that everything slips as a block in a new line and not character by character.
## Interesting Links About Typography
For those who have become curious about typography, I have put together a small list of recommended links to this topic:
- [The Elements _of_ Typographic Style Applied _to the_ Web](http://webtypography.net/)
- [Thinking with Type](http://thinkingwithtype.com/)
- [Buttericks Practical Typography](https://practicaltypography.com/)
- [Type Basics](http://www.typeworkshop.com/index.php?id1=type-basics)
- [Web Design is 95% Typography](https://ia.net/topics/the-web-is-all-about-typography-period)
- [Five simple steps to better typography](https://markboulton.co.uk/journal/2005-04-13.five-simple-steps-to-better-typography/)
- [Nice Web Type](http://nicewebtype.com/)
- [More Meaningful Typography](https://alistapart.com/article/more-meaningful-typography)
- [A List Apart: Typography](https://alistapart.com/topic/design/typography/)
- [Kerntype](https://type.method.ac/)
- [Modular Scale](http://www.modularscale.com/)
- [Helvetica A Documentary Film by Gary Hustwit](https://www.hustwit.com/helvetica/)