Gulp Front Matter +Markdown through Nunjucks - gulp

I'm working on adding some simple Markdown processing to my Gulp process, but I can't quite get the pieces to work together. I seem to be missing the step between getting the front matter content, and determining which Nunjuck template to apply.
Here's the section in my Gulp file:
gulp.task('pages:md', function() {
gulp.src('./content/**/*.md')
.pipe(frontMatter({ // optional configuration
property: 'frontMatter', // property added to file object
remove: true // should we remove front-matter header?
}))
.pipe(marked({
// optional : marked options
}))
.pipe(nunjucks({
// ?? Feels like I need to specify which template applies based on the front matter "layout" property?
}))
.pipe(gulp.dest('build/'))
});
The markdown file looks like this:
---
title: Title
layout: layout.html
nav_active: home
---
...markdown content...
I feel like it's going the right direction but being able to visualise where that front matter data has gone, and how to expose it to the Nunjucks rendering, is not clear. Any help?

You need gulp-wrap and original nunjucks.
gulp-nunjucks is a tool for compiling the stream of nunjucks templates, but what you need to do is to wrap your contents in a nunjucks template and that is what gulp-wrap is for.
Try npm install gulp-wrap nunjucks in addition to other settings and then the following should work.
gulpfile
var gulp = require('gulp')
var wrap = require('gulp-wrap')
var frontMatter = require('gulp-front-matter')
var marked = require('gulp-marked')
var fs = require('fs')
gulp.task('pages:md', function() {
gulp.src('./content/**/*.md')
.pipe(frontMatter())
.pipe(marked())
.pipe(wrap(function (data) {
return fs.readFileSync('path/to/layout/' + data.file.frontMatter.layout).toString()
}, null, {engine: 'nunjucks'}))
.pipe(gulp.dest('build/'))
});
markdown
---
title: Title
layout: layout.nunjucks
nav_active: home
---
...markdown content...
layout.nunjucks
<h1>{{ file.frontMatter.title }}</h1>
<p>{{ contents }}</p>

You might want to have a look a the plugin gulp-ssg. I don't know what it's worth, but it was mentionned in this issue for someone who had the same problem as you.
Not exactly what you're looking, but for this kind of work, I've had success using metalsmith. You can even mix it with gulp if, like me, you have more complex processing for your javascripts resources for example.

Related

Looking for a Gulp plugin that will skip markdown files based on particular header attributes

I have markdown files that look like this
---
name: Some Name
date: '2013-09-09'
isCool: true
---
really cool text
I want to have a gulp task that only lets markdown through that has a particular property, for example isCool = true.
So I would imagine something like this
gulp.src('source/content/*/*.md')
.pipe(mdPrune({
isCool: true
}))
.pipe(gulp.dest('build/content/cool'));
then only the markdown that had an isCool attribute in the header would end up the build/content/cool folder.
gulp-filter would work.
const filter = require('gulp-filter');
gulp.task('default', function () {
// return true if want the file in the stream
const myFilter = filter(function (file) {
let contents = file.contents.toString();
return contents.match('isCool: true');
});
return gulp.src(['./src/*.md'])
.pipe(myFilter)
.pipe(gulp.dest('md'));
});
That will allow the file through if isCool: true is anywhere in the file. If that is a problem, just work on the regex to restrict it to the line after the date entry for example.
[The filter could also be defined outside of any task if it might be reused elsewhere or you just prefer it that way.

How to build a list of links to html files in Gulp?

How can you use Gulp to gather in one html file a list of all the pages that are in the directory?
For example, in the build directory I have two files contact.html with title "Contacts" and faq.html with the title "Frequently asked questions", I need to get them and create a ui.html which would be a list of links to files of the form:
Frequently asked questions
Contacts
Well, with the addition of step your design (a connected css file).
Found the gulp-listing module, but it can not be customized, there it is as follows:
gulp.task('scripts', function() {
return gulp.src('./src/*.html')
.pipe(listing('listing.html'))
.pipe(gulp.dest('./src/'));
});
I used two gulp modules for do this.
gulp-filelist - for create file list
gulp-modify-file - for update this file
gulp
.src(['./html/**/*.html'])
.pipe(require('gulp-filelist')('filelist.js', { relative: true }))
.pipe(require('gulp-modify-file')((content) => {
const start = 'var list = '
return `${start}${content}`
}))
.pipe(gulp.dest('js'))
After run gulp, you got in js/filelist.js something like this:
var list = [
"Cancellation/template.html",
"Cancellation/email.html",
]
You can add this script in your html file, and with js display all info.

How to get gulp-html-minifier's output into gulp-inject-stringified-html?

I'm trying to use these two gulp plugins together:
gulp-html-minifier
gulp-inject-stringified-html
Or put differently, I'm trying to inject the contents of files containing html fragments into my javascript files after they're minified.
When I'm trying to run a straight up gulp build I get this:
Error: ENOENT: no such file or directory, open 'C:\path\to\.temp\template.html'
Here's a repro of my situation. My folder structure:
/src/app.js
/src/template.html
/gulpfile.js
/package.json
My gulpfile.js:
var gulp = require('gulp');
var injectHtml = require('gulp-inject-stringified-html');
var htmlmin = require('gulp-html-minifier');
gulp.task('minify', [], function() {
gulp.src('src/*.html')
.pipe(htmlmin())
.pipe(gulp.dest('.temp'));
});
gulp.task('default', ['minify'], function() {
gulp.src('src/*.js')
.pipe(injectHtml())
.pipe(gulp.dest('.build'));
});
The template.html file:
<div>My Template</div>
The app.js file:
var html = { gulp_inject: "../.temp/template.html" };
Now, if I run minify manually first, things will work as expected. From this I speculate I'm not using Gulp correctly. I reckon I'd need to pipe the result of htmlmin into the injectHtml method. But I fail to see how.
How can I get these two plugins to play together nicely?
You are missing a return in the minify task. It should look like that:
gulp.task('minify', [], function() {
return gulp.src('src/*.html')
.pipe(htmlmin())
.pipe(gulp.dest('.temp'));
});
Without return, the default task doesn't have any way to know that minify finished, so it may start before the minified html file was created.

How to use gulp to organize the different js file in different html?

How to use gulp to organize the different js file in different html?
is the only way I can do is to define each page to gulp task ? Or gulp have a better way can detect file automatically?
This is my situation below.
I have two html 'index.html','content.html'
index.html need plugin_A.js
content.html need plugin_B.js
And my gulp file:
gulp.task('index_concat', function() {
return gulp.src('./app/js/plugin_A.js')
.pipe(concat('index.js'))
.pipe(gulp.dest('./build/js/'));
});
gulp.task('content_concat', function() {
return gulp.src('./app/js/plugin_B.js')
.pipe(concat('content.js'))
.pipe(gulp.dest('./build/js/'));
});
If I had 100 pages, the tasks were too big!!!
I think this is a stupid way to define each page, but I have no idea how to get better. Please give me some advice.
You could use some name convention for your plugins like pluginName_index.js and pluginName_content.js . So you be able to do something like that:
function yourFunction(pluginName,targetName){
return gulp.src('./app/js/'+pluginName)
.pipe(concat(targetName))
.pipe(gulp.dest('./build/js/'));
}
fs.readdirSync('.app/js/pluginFolder')
.filter(function(fileName) {
var fileNameParts = fileName.split('_');
yourFunction(fileName,fileNameParts[1]);
});

Angular and JSON syntax getting confused with {}

I am new to angular and trying to integrate it within my application. I am attempting to use a simple ng-repeat (which works perfectly in an example project i setup). However, in the current project, i am using the Swig templating language, which fetches data from a .JSON file using {{ }} e.g:
person.html file:
<div> {{ myFirstName }} </div>
<div> {{ mySurName }} </div>
person.json file:
{
"myFirstName" : "Joe",
"mySurName" : "Bloggs",
}
I think the problem i am facing, is that Swig uses {{ }} to get data from .JSON files, and Angular uses {{ }} too.
Here is my simple ng-repeat:
<ul ng-controller="MyCtrl">
<li ng-repeat="country in countries">
{{country.name}} has population of {{country.population}}
</li>
</ul>
Here is my simple controller:
require(['app'], function(app) {
'use strict';
app.controller("MyCtrl", function($scope) {
$scope.countries = [
{name: 'France', population: 63.1},
{name: 'United Kingdom', population: 61.8}
];
});
});
When opening my HTML page, all that is displayed is:
has population of
has population of
Any ideas of how i can get around this?
Thanks
UPDATE
I would like angular to retrieve the data from the .JSON file
UPDATE Folloiw David Beech's recommendation
Application Tree:
- application
- resources
- CSS
- img
- JS
- data
- countries-data.json
- pages
- countries.html
In the example solution below my $http.get was
$scope.countries = [];
$http.get('/resources/data/countries-data.json', function(data){
Error shown in Firebug: "NetworkError: 404 Not Found - http: // localhost:8000/resources/data/countries-data.json"
To answer part 2 of your question and get angular to retrieve the json file use the $http service. http://docs.angularjs.org/api/ng/service/$http
app.controller("MyCtrl", function($scope, $http) {
$scope.countries = [];
$http.get('/path/to/data.json', function(data){
$scope.countries = data;
}, function(error) {
//handle error here
});
});
And to answer part 1:
I'm not familiar with swig and after a quick google I notice this is available server-side on node or client side and you don't specify how you are using it.
If you are using it server-side I would recommend you check it's documentation about escaping certain bindings to ensure pages are being delivered with the bindings in the html (you can check this by 'view page source' option in chrome).
UPDATE: http://paularmstrong.github.io/swig/docs/api/#SwigOpts
I notice here you can set the varControls binding to something other then '{{' and '}}'.
If you are using it client side then I would ask why you need it at all.. angular works best when you give it as close to complete and exclusive control over the DOM as possible. I'm sure anything that is possible in most templating engines is possible in angular with a little more learning and training and there are plenty of resources for that if you just do a little googling.
Hope this helps.
You can change the start and end interpolation tags using interpolateProvider service.
angular.module('myApp', []).config(function($interpolateProvider){
$interpolateProvider.startSymbol('{[{').endSymbol('}]}');
}
);
http://docs.angularjs.org/api/ng.$interpolateProvider