How to use nunjuck `include` in post? - nunjucks

I'm playing around with hexo, I'm testing the nunjuck syntax which work for a small loop. However I can't find how to include a file, I might be wrong in the location of my file (currently next to the .md, in /source/_posts).
Environment Info
Node version(node -v):
node --version; npm --version
v8.9.1
5.5.1
Your site _config.yml (Optional):
# Hexo Configuration
## Docs: https://hexo.io/docs/configuration.html
## Source: https://github.com/hexojs/hexo/
# Site
title: Hexo
subtitle:
description:
author: John Doe
language:
timezone:
# URL
## If your site is put in a subdirectory, set url as 'http://yoursite.com/child' and root as '/child/'
url: http://yoursite.com
root: /
permalink: :year/:month/:day/:title/
permalink_defaults:
# Directory
source_dir: source
public_dir: public
tag_dir: tags
archive_dir: archives
category_dir: categories
code_dir: downloads/code
i18n_dir: :lang
skip_render:
# Writing
new_post_name: :title.md # File name of new posts
default_layout: post
titlecase: false # Transform title into titlecase
external_link: true # Open external links in new tab
filename_case: 0
render_drafts: false
post_asset_folder: false
relative_link: false
future: true
highlight:
enable: true
line_number: true
auto_detect: false
tab_replace:
# Home page setting
# path: Root path for your blogs index page. (default = '')
# per_page: Posts displayed per page. (0 = disable pagination)
# order_by: Posts order. (Order by date descending by default)
index_generator:
path: ''
per_page: 10
order_by: -date
# Category & Tag
default_category: uncategorized
category_map:
tag_map:
# Date / Time format
## Hexo uses Moment.js to parse and display date
## You can customize the date format as defined in
## http://momentjs.com/docs/#/displaying/format/
date_format: YYYY-MM-DD
time_format: HH:mm:ss
# Pagination
## Set per_page to 0 to disable pagination
per_page: 10
pagination_dir: page
# Extensions
## Plugins: https://hexo.io/plugins/
## Themes: https://hexo.io/themes/
theme: landscape
# Deployment
## Docs: https://hexo.io/docs/deployment.html
deploy:
type:
</details>
Hexo and Plugin version(npm ls --depth 0):
"hexo": "^3.2.0",
"hexo-generator-archive": "^0.1.4",
"hexo-generator-category": "^0.1.3",
"hexo-generator-index": "^0.2.0",
"hexo-generator-tag": "^0.2.0",
"hexo-renderer-ejs": "^0.3.0",
"hexo-renderer-stylus": "^0.3.1",
"hexo-renderer-marked": "^0.3.0",
"hexo-server": "^0.2.0"
Directory Structure
tree ./
./
├── include
│ └── colors.html
└── _posts
└── button6.md
Usage
npm install --save --only=prod hexo-include
In button6.md I added
{% include "include/colors.html" %}
Error
Unhandled rejection Template render error: (unknown path)
Error: template not found: include/colors.html
For question
I've this post in _hexo-demo/source/posts/button6.md
---
title: button6
myitems:
- one
- two
---
{% for item in myitems %}
<li> {{ item }}</li>
{% endfor %}
<hr>
{% include "colors.html" %}
Question
Where am I supposed to put my colors.html file in order to be resolve
related: https://github.com/hexojs/hexo/issues/2866

I got a same issue.
It seems hexo-include conflicting with numjack.
I changed lib/index.js following
hexo.extend.tag.register('include_alt', include, {asyn: true});
but it still won't work.
It may be because of rendering timing.
So I changed lib/index.js following
var fs = require('hexo-fs');
var nunjucks = require('nunjucks');
var pathFn = require('path');
// hexo.extend.tag.register('include_alt', include, { asyn: true });
hexo.extend.tag.register('include_alt', function (args) {
var path = pathFn.join(hexo.source_dir, args[0]);
return new Promise(function(resolve, reject) {
nunjucks.render(path, function(err, res) {
if (err) {
return reject(err);
}
resolve(res);
});
});
}, {async: true});
then I use it as
{% include_alt 'some.html' %}
and it works.

There is no native support for that in hexo. Tags are inspired by Octopress and the render_partial tag from octopress is not present in hexo as far as I know.
Good news is there is an hexo plugin for this:
https://github.com/PirtleShell/hexo-include
Once installed, you can simply do
{% include colors.html %}
where colors.html would be at the root of your source folder

Related

How to show README.md in a web page in Laravel?

I hava a laravel project, there is a README.md in the root directory. I can see the render result after pushing to GitHub, but I want to render markdown document in the local development browser.
I am trying two ways:
Read file from markdown file
convert markdown file to html with something like Webpack
Who can give a demo for this?
Since the mail blade templates parse markdown, you can use a similar approach to layout.blade.php which uses Illuminate\Mail\Markdown::parse.
In your template, such as welcome.blade.php, add this:
{{ Illuminate\Mail\Markdown::parse(file_get_contents(base_path() . '/README.md')) }}
Here is a Laravel Mix / Webpack solution, convert markdown file to html, and required in Vue.js, then show it with v-html.
First add markdown-loader
yarn add markdown-loader html-loader
Add config in webpack.mix.js, Laravel Mix can add custom config of Webpack.
mix.webpackConfig({
module: {
rules: [{
test: /\.md$/,
use: ["html-loader", "markdown-loader"],
}]
}
});
Considering README.md is in the root of Project, add a alias in webpack.mix.js
mix.alias({
'#': '/resources/js',
'#root': '/',
});
Now we can use a vue component to show the README.md at the root directory.
<script>
const readme = require('#root/README.md')
export default {
data() {
return {
readme: ""
}
},
created() {
this.readme = readme
}
}
</script>
<template>
<div class="container" ref="container" v-html="readme" />
</template>

How to create a Fusebox project with multiple html pages?

I'm new to bundlers and am currently learning about Fusebox. I really like it so far except that I can't figure out how to use it for a multi-page project. So far I've only been able to find a tutorial on how to do this using webpack, not for fusebox.
Input files in src folder:
index.html
index2.html
index.ts
Desired output in dist folder:
app.js
vendor.js
index.html
index2.html
Actual output in dist folder:
app.js
vendor.js
index.html
Here is my config in the fuse.js file:
Sparky.task("config", () => {
fuse = FuseBox.init({
homeDir: "src",
output: "dist/$name.js",
hash: isProduction,
sourceMaps: !isProduction,
plugins: [
[SassPlugin(), CSSPlugin()],
CSSPlugin(),
WebIndexPlugin({
title: "Welcome to FuseBox index",
template: "src/index.html"
},
WebIndexPlugin({
title: "Welcome to FuseBox index2",
template: "src/index2.html"
},
isProduction && UglifyJSPlugin()
]
});
// vendor should come first
vendor = fuse.bundle("vendor")
.instructions("~ index.ts");
// out main bundle
app = fuse.bundle("app")
.instructions(`!> [index.ts]`);
if (!isProduction) {
fuse.dev();
}
});
Setting WebIndexPlugin twice within plugins doesn't work. What is the correct way to set up a multi-html page project with fusebox?
The WebIndexPlugin can not be configured, to output more than one html file.
But if you don't use a hash for the generated bundles (e.g.: output: "dist/$name.$hash.js"), you don't need the WebIndexPlugin -- you can remove it completly from the plugins option. Because you already know the names of the generated bundles (vendor.js and app.js) you can just include the following lines
<script src="vendor.js"></script>
<script src="app.js"></script>
instead of the placeholder $bundles.
If you want, that both html files are copied from your src directory into your dist directory, you can add the following lines to your fuse.js script:
const fs = require('fs-extra');
fs.copySync('src/index.html', 'dist/index.html');
fs.copySync('src/index2.html', 'dist/index2.html');
Note: Don't forget to add fs-extra:^5.0.0 to your package.json
Might not been the case when the question was asked, but WebIndexPlugin now can be specified multiple times and also takes optional bundles parameter where list of bundles to be included in html can be specified (all bundles are included by default).
For example 2 html files (app1.html, app2.html) where each includes a common library (vendor.js), and different entry points (app1.js and app2.js)
app1.html
vendor.js
app1.js
app2.html
vendor.js
app2.js
Config would look like this:
const fuse = FuseBox.init({
homeDir : "src",
target : 'browser#es6',
output : "dist/$name.js",
plugins: [
WebIndexPlugin({
target: 'app1.html',
bundles:['vendor', 'app1']
}),
WebIndexPlugin({
target: 'app2.html',
bundles:['vendor', 'app2']
})
]
})
// vendor bundle, extracts dependencies from index1 and index2:
fuse.bundle("vendor").instructions("~[index1.ts,index2.ts]")
// app1 and app2, bundled separately without dependencies:
fuse.bundle("app1").instructions("!>index1.ts")
fuse.bundle("app2").instructions("!>index2.ts")

What's wrong with this metalsmith-in-place build script?

I am trying to use metalsmith-in-place to do some in-place templating on files in subdirectories of my source dir. It doesn't work. Template tags are not replaced by the frontmatter.
My build script:
var Metalsmith = require('metalsmith'),
inplace = require('metalsmith-in-place'),
nunjucks = require('nunjucks');
Metalsmith(__dirname)
.source('./source')
.use(inplace({
engine: 'nunjucks',
pattern: '*.html',
directory: 'source/deeper'
}))
.destination('./build')
.build(function(err) {
if (err) {
console.log(err);
}
else {
console.info('Built it.');
}
});
My template:
metalsmith_debug$ cat source/deeper/index.html
---
title: My pets
---
{{title}}
My output:
metalsmith_debug$ cat build/deeper/index.html
{{title}}
It works on files in source; but I need it to work on subdirectories.
A couple of changes:
build.js:
var Metalsmith = require('metalsmith');
var inplace = require('metalsmith-in-place');
// var nunjucks = require('nunjucks');
Metalsmith(__dirname)
.source('./source')
.use(inplace({
engine: 'nunjucks',
pattern: '**/*.html' // modified pattern
// directory: 'source/deeper' // Not needed
}))
.destination('./build')
.build(function(err) {
if (err) {
console.log(err);
}
else {
console.info('Built it.');
}
});
You don't need to require nunjucks within the build file, metalsmith-in-place uses consolidate, this will require it where necessary. (Line can be removed)
Modify pattern within inplace to **/*.html. For more information see Globbing patterns.
directory isn't needed within inplace. (Line can be removed)
... and a minor change to source/deeper/index.html:
---
title: My pets
---
{{ title }}
Added space around the placeholder {{ title }} - Nunjucks seems to think this is important.
Should work now for you, let me know if not.
The accepted answer is outdated now, because metalsmith-in-place switched to use the jstransformer framework instead of consolidate.
I've written an article on how to use the in-place plugin to pair Nunjucks with Metalsmith:
Making Metalsmith to work with Nunjucks
Here's the minified working example:
const Metalsmith = require('metalsmith');
const inPlace = require('metalsmith-in-place');
Metalsmith(__dirname)
.source('./src')
.destination('./build')
.use(inPlace({
pattern: '**/*.njk',
engineOptions: {
path: __dirname + '/src'
}
}))
.build(function (error) {
if (error) {
throw error;
}
})
;
Your pattern in the inplace configuration should most likely be **/*.html rather than just *.html

how to speed up docpad rendering?

I am changing only a couple of pages but docpad seems to render everything again. I'm not using any fancy plugins or dynamic components - just the basic ghost template. Are there some techniques to make less pages render?
maybe its something to do with the timestamp format in the docpad.coffee ?
moment = require('moment')
docpadConfig = {
templateData:
vars:
appserver: 'http://xxx'
site:
title: 'Pocket Tutor'
tagline: 'English language chat tutor'
description: 'Learn english by chatting'
logo: '/uploads/images/corpid/comiceng/96/logo-96.png'
url: 'http://app:9005'
cover: '/img/cover.jpg'
navigation: [
{
name: 'Home',
href: '/',
section: 'home'
},
{
name: 'About',
href: '/about.html',
section: 'about'
},
{
name: 'Lessons',
href: '/tags/lessons.html',
section: 'tag-lessons'
},
{
name: 'Grammar',
href: '/tags/grammar.html',
section: 'tag-grammar'
}
{
name: 'Teachers',
href: '/tags/tech.html',
section: 'tag-tech'
},
]
author:
name: 'Rikai Labs'
img: ''
url: 'http://rikai.co'
website: 'http://RIKAI.co'
location: 'space',
bio: 'we build chat apps'
getPreparedTitle: -> if #document.title then "#{#document.title} | #{#site.title}" else #site.title
getDescription: -> if #document.description then "#{#document.description} | #{#site.description}" else #site.description
bodyClass: -> if #document.isPost then "post-template" else "home-template"
masthead: (d) ->
d = d || #document
if d.cover then d.cover else #site.cover
isCurrent: (l) ->
if #document.section is l.section then ' nav-current'
else if #document.url is l.href then ' nav-current'
else ''
excerpt: (p,w) ->
w = w || 26
if p.excerpt then p.excerpt else p.content.replace(/<%.+%>/gi, '').split(' ').slice(0, w).join(' ')
encode: (s) -> encodeURIComponent(s)
slug: (s) -> return s.toLowerCase().replace(' ', '-')
currentYear: -> new Date().getFullYear()
time: (ts, format) ->
format = format || 'MMMM DO, YYYY'
ts = new Date(ts) || new Date()
moment(ts).format(format)
collections:
posts: ->
#getCollection("html").findAllLive({active:true, isPost: true, isPagedAuto: {$ne: true}}, {postDate: -1}).on "add", (model) ->
model.setMetaDefaults({layout:"post"})
plugins:
tags:
extension: '.html'
injectDocumentHelper: (doc) ->
doc.setMeta { layout: 'tag' }
rss:
default:
collection: 'posts'
url: '/rss.xml'
marked:
gfm: true
environments: # default
development: # default
# Always refresh from server
maxAge: false # default
# Only do these if we are running standalone via the `docpad` executable
checkVersion: process.argv.length >= 2 and /docpad$/.test(process.argv[1]) # default
welcome: process.argv.length >= 2 and /docpad$/.test(process.argv[1]) # default
prompts: process.argv.length >= 2 and /docpad$/.test(process.argv[1]) # default
# Listen to port 9005 on the development environment
port: 9005 # example
production:
port: 9005
maxAge: false # default
}
module.exports = docpadConfig
update: stubbing out the date and time methods
time: -> 'time'
currentYear: -> 'year'
gives a little speed up but still making one edit to one file gives info:
Generated 40/150 files in 7.364 seconds
update2: added
standalone: true
to some pages to test, but still takes
info: Generated 40/150 files in 7.252 seconds
so even a single standalone page triggers a bunch of other stuff.
It is possible to handle the Docpad regeneration process manually. To do this you need to turn off Docpad's watch. That is, run Docpad with the docpad server command. What will happen here is that it doesn't matter how many times you edit a document it will not be loaded into the docpad collection. You will then have to load any updates manually. That is, have some code to load the document.
model = #docpad.getCollection('posts').findOne({someValue: someValue})
model.load()
Following that trigger the regeneration.
#docpad.action 'generate', reset: false, (err) ->
if err
#docpad.log "warn", "GENERATE ERROR"
This is what I do in my posteditor plugin
I suspect this is not really what you are asking for but it does give you full control over the regeneration process.

How to access object from _config.yml with reference from post in Jekyll?

For each post I want to have author and a link to his page. So I need to have username in post like:
---
title: "Some Post"
author: user_x
---
and have something like this in _config.yml
users:
-
user_x:
url: "/some-url"
name: "Full Name"
to have mapping user -> url and name, and how can I display that in a post? I've try this:
{{ site.users[ post.author ].name }}
but got object instead of name value. I've also try to not use - after users but go the same object as result
Use page.author, not post.author:
{{ site.users[page.author].name }}
Your Yaml should look something like this:
users:
user_x:
url: "/some-url"
name: "Full Name"
user_y:
url: "/some-other-url"
name: "A Different Name"
You might want to use assign if you’re using several values from the user:
{% assign user = site.users[page.author] %}
{{ user.name }}
You could write a small plugin for that:
module Jekyll
module AuthorData
def author_name(username)
users = #context.registers[:site].config['users']
users.detect { |hash| hash.keys.include? username }.values.first['name']
end
def author_url(username)
users = #context.registers[:site].config['users']
users.detect { |hash| hash.keys.include? username }.values.first['url']
end
def author(username, value)
users = #context.registers[:site].config['users']
users.detect { |hash| hash.keys.include? username }.values.first[value]
end
end
end
Liquid::Template.register_filter(Jekyll::AuthorData)
Now, inside index.html (that's the page I tested), I was able to use the following code to get the name and url of the author:
{% post.author | author_name %}
{% post.author | author_url %}
Or, you could use the generic filter:
{% post.author | author: 'name' %}
The YAML front-matter:
author: 'user_x'
The _config.yml file:
users:
- user_x:
url: '/test_x'
name: 'User X'
- user_y:
url: '/test_y'
name: 'User Y'
The #context.registers is the way Jekyll provides access to internal data of the app for use in plugins. Checkout the protip below the filters docs.
PS: I think there is some inconsistency in the documentation there—or perhaps, on the version of Jekyll I'm using—but I wasn't able to access the site via context method and had to resort to using the instance variable.

Resources