How can I minify included json files with Jekyll plugins? - json

I have a static website generated by Jekyll. I was able to get sass converter + minification and HTML minification working using Jekyll built-in features or plugins. The json files included are not minified though, how can I achieve that?
I'm using Jekyll 3.8.5. I'm hosting and serving the website with GitLab pages. As far as the sass pipeline going, it is taken care by the | scssify Liquid filter and the _config.yml setting:
sass:
style: compressed
HTML minification is taken care by compress front-end matter in the default.html layout:
---
layout: compress
---
My problem is that I have multiple json format data which is included in my templates. For example the structured data information or the analytics parameters. The metadata.json contains my structured data:
{
"#context": "http://schema.org",
"#type": "NewsArticle",
"mainEntityOfPage": "{{ page.url | replace:'index.html','' | absolute_url }}",
"headline": "{% if page.title %}{{ page.title | escape | strip_newlines }}{% else %}{{ site.title | escape | strip_newlines }}{% endif %}",
"datePublished": "{% if page.date %}{{ page.date | date_to_xmlschema }}{% else %}{{ site.time | date_to_xmlschema }}{% endif %}",
"dateModified": "{% if page.date %}{{ page.date | date_to_xmlschema }}{% else %}{{ site.time | date_to_xmlschema }}{% endif %}",
"description": "{% if page.teaser %}{{ page.teaser | strip_html | strip_newlines | truncate: 160 }}{% else %}{{ site.description | strip_html | strip_newlines }}{% endif %}",
"author": {
"#type": "Person",
"name": "{{ site.author | strip_newlines }}"
},
"publisher": {
"#type": "Organization",
"name": "{{ site.organization }}",
"logo": {
"#type": "ImageObject",
"url": "{{ site.portrait | absolute_url }}",
"width": "350",
"height": "350"
}
},
"image": {
"#type": "ImageObject",
"url": "{{ site.portrait | absolute_url }}",
"height": "350",
"width": "350"
}
}
And I include this in the head.html like this:
<script type="application/ld+json">
{% include metadata.json %}
</script>
Or this is the analytics parameter json file:
{
"vars" : {
"gtag_id": "{{ site.gtag }}",
"config" : {
"{{ site.gtag }}": { "groups": "default" }
}
}
}
And it is included in the template by:
<amp-analytics type="gtag" data-credentials="include">
<script type="application/json">
{% include analytics.json %}
</script>
</amp-analytics>
Both json files are in the _includes directory since they gonna be included. This might be important, because they don't appear as they are in the generated _site content, they are only indirectly included.
I do have jekyll-minifier plugin, and theoretically it supports json minification by default (compress_json: true), see https://github.com/digitalsparky/jekyll-minifier. I even added a configuration section to _config.yml which redundantly re-defines default settings:
jekyll-minifier:
remove_spaces_inside_tags: true
remove_multi_spaces: true
remove_comments: true
remove_intertag_spaces: true
remove_quotes: false
compress_css: true
compress_javascript: true
compress_json: true
But when I verify the content the JSON sections are not minified. I'm not a Jekyll expert, I haven't ever written a Jekyll plugin. I'm looking at https://github.com/digitalsparky/jekyll-minifier/blob/master/lib/jekyll-minifier.rb and wonder if the problem is that the output file is an HTML in that case? So maybe the jekyll-minifier modifications don't happen because these files are not outputted into _site as a json, but just indirectly included? How can I minify them still? Everything else is minified now and it's annoying that they are the only things which aren't. I'm primarily looking for a Jekyll plugin (package or custom) solution since I don't have any gulp pipeline in my build right now.
Bonus question: can I minify manifest.webmanifest somehow? It's a json file but it doesn't have the json extension due to Progressive Web App standards.

Related

filtering key and value of json data in jinja2

i have json file from url that i want to filter using jinja. The json file is loaded in my ansible as a variable "get_devices". Here is the json file :
{
"vni": {
"13": {
"192.168.13.2": {
"mac": "50:00:00:10:00:03",
"state": "active",
"type": "local"
},
"192.168.13.3": {
"mac": "50:00:00:05:00:03",
"remoteVtep": "10.0.0.6",
"state": "active",
"type": "remote"
},
"fe80::5200:ff:fe05:3": {
"mac": "50:00:00:05:00:03",
"remoteVtep": "10.0.0.6",
"state": "active",
"type": "remote"
},
"fe80::5200:ff:fe10:3": {
"mac": "50:00:00:10:00:03",
"state": "active",
"type": "local"
}
}
}
}
I'm new at using jinja, so the template might contain many mistakes and error. The template is like this :
{% for item in get_devices.json.results -%}
{% for key, value in item.vni.iteritems() %}
VNI Data
VNI Number : {{ key }}
{% for key, value in value.iteritems() %}
- IP : {{ key }}
{% for key, value in value.iteritems() %}
{{ value }}
{% endfor %}
{% endfor %}
{% endfor %}
{% endfor %}
And the expected result is like this :
VNI DATA
VNI Number : 13
- IP : 192.168.13.3
50:00:00:10:00:03
10.0.0.6
active
local
- IP : fe80::5200:ff:fe05:3
50:00:00:10:00:03
10.0.0.6
active
local
and so on. However, notice that some of the data don't have the remoteVtep so to keep the order of the resulting "values" in the same line, I want to replace remoteVtep with "-" if the data doesn't have remoteVtep. How to declare this in jinja2? This is an example of the desired output (of data that don't have remoteVtep):
- IP : 192.168.13.2
50:00:00:10:00:03
-
active
local
What changes are needed to achieve this? Thank you.

Jinja2 filter nested dictionary based on boolean value

I have the following dict variable users in Jinja2:
"users": {
"user1": {
"alive": true,
"age": 22
},
"user2": {
"alive": false,
"age": 34
}
}
and I want to filter all alive users with jinja filter, but after a long search I am still not able to achieve that on such nested structure. Could anyone please help?
For now, I am just passing all users with {{ users }}, but I guess it should be possible to filter it with built in Jinja filters. Just cannot figure out the right sequence of them.
users: {'user1': {'alive': True, 'age': 22}, 'user2': {'alive': False, 'age': 34}}
this j2 file does the job:
{% for user in users if users[user].alive %}
{{ user }}: {{ users[user] }}
{% endfor %}
result:
user1: {'alive': True, 'age': 22}

Is there a way to insert raw escaped json in json body in ansible

See below first call which works. This is an example of how I create a template on my system. Notice I have to use {% raw %} ... {% endraw %} so ansible doesn't try to interpret the variables in my template.
- name: Create a template : OK
uri:
url: https://{{ ip }}/api/v1/templates
method: POST
headers:
Authorization: "{{ token }}"
Content-Type: application/json
body: |
{
"name": "{{ template_name }}",
"type": "v1",
"description": "{{ template_name }}",
"content": "template: | {% raw %}\n {\n \"class\": \"ABC\",\n \"param\": {{param1::integer}}\n }{% endraw %}"
}
body_format: json
timeout: 60
status_code: 202
validate_certs: false
register: json_response
Output OK:
ok: [notahost] => {
"invocation": {
"module_args": {
"body": {
"content": "template: | \n {\n \"class\": \"ABC\",\n \"param\": {{param1::integer}}\n }",
"description": "test1",
"name": "test1",
"type": "v1"
},
"body_format": "json",
Now, I am trying to move the content of the template outside in a file called template1.j2.
template1.j2:
{% raw %}
{
"class": "ABC",
"param": {{param1::integer}}
}
{% endraw %}
I insert the template template1.j2 into my JSON body (noticed I added the {% raw %} ... {% endraw %} inside the template).
- name: Create a template NOK
uri:
url: https://{{ ip }}/api/v1/templates
method: POST
headers:
Authorization: "{{ token }}"
Content-Type: application/json
body: |
{
"name": "{{ template_name }}",
"type": "v1",
"description": "{{ template_name }}",
"content": "template: | {{ lookup('file','template1.j2') }}"
}
body_format: json
timeout: 60
status_code: 202
validate_certs: false
register: json_response
Output NOK:
fatal: [notahost]: FAILED! => {
"content": "{\"message\":\"request body has an error: failed to decode request body: invalid character '\\\\n' in string literal\"}\n",
"invocation": {
"module_args": {
"body": "{\n \"name\": \"test2\",\n \"type\": \"v1\",\n \"description\": \"test2\",\n \"content\": \"template: | \n{\n \"class\": \"ABC\",\n \"param\": {{param1::integer}}\n} \n\"\n}\n",
"body_format": "json",
For some reason, it looks like the way I am doing this doesn't work, ansible still try to interpret the variable in my template at creation.
Any idea on how to get his work with my template outside the ansible task?
PS: I have tried to load the template file using the shell ansible module and that did not help.
Thanks & Regards,
Romain
Use lookup 'file' instead of 'template', e.g. the template (that you actually don't want to use as a template in this task)
shell> cat template1.j2
param: {{param1.integer}}
and the play
- hosts: localhost
vars:
param1:
integer: 99
tasks:
- debug:
msg: |
{{ lookup('template', 'template1.j2') }}
{{ lookup('file', 'template1.j2') }}
gives
msg: |-
param: 99
param: {{param1.integer}}
Given the template
shell> cat template1.j2
{
"class": "ABC",
"param": {{param1::integer}}
}
The play below shows how to create a body with and without the template
- hosts: localhost
vars:
template_name: test1
body1: |
{
"name": "{{ template_name }}",
"type": "v1",
"description": "{{ template_name }}",
"content": "template: | {% raw %}\n {\n \"class\": \"ABC\",\n \"param\": {{param1::integer}}\n }{% endraw %}"
}
body2:
{
"name": "{{ template_name }}",
"type": "v1",
"description": "{{ template_name }}",
"content": "template: | \n{{ lookup('file','template1.j2') }}"
}
tasks:
- debug:
var: body1|type_debug
- debug:
var: body1
- debug:
var: body2|type_debug
- debug:
var: body2
gives
ok: [localhost] =>
body1|type_debug: dict
ok: [localhost] =>
body1:
content: |-
template: |
{
"class": "ABC",
"param": {{param1::integer}}
}
description: test1
name: test1
type: v1
ok: [localhost] =>
body2|type_debug: dict
ok: [localhost] =>
body2:
content: |-
template: |
{
"class": "ABC",
"param": {{param1::integer}}
}
description: test1
name: test1
type: v1

Using two JSON sources for Jekyll output

Suppose I have a list of projects (let's call that proj.json) and a list of smaller sub-projects (sub_proj.json) that are associated with the list of projects. The files are as follows:
proj.json
[{
"title": "Project 1",
"description": "aaa.",
"subproj": ["RefSP1", "RefSP2"]
},
{
"title": "Project 2",
"description": "aaa.",
"subproj": ["RefSP3"]
}]
sub_proj.json
[{
"title": "Sub Project 1",
"description": "aaa.",
"key": "RefSP1"
},
{
"title": "Sub Project 2",
"description": "aaa.",
"key": "RefSP2"
},
{
"title": "Sub Project 3",
"description": "aaa.",
"key": "RefSP3"
}]
But in the output.html, I seem to be missing something. The code is below: (I removed it of formatting for simplicity)
{% for item in site.data.proj %}
{{ item.title }}
{% assign key_array = item.subproj %}
{% for sub in key_array %}
{% assign subproject = site.data.sub_proj | where:"key",sub %}
{{ subproject.title | inspect }}
{% endfor %}
I seem to get the correct number of subprojects using {{ subproject.title | inspect }}, but they're all nil. Adding jsonify doesn't really do anything.
edit:
Printing out {{ item | inspect }}
results in
{ "title"=>"Project 1","description"=>"aaa.","subproj"=>["RefSP1","RefSP2"]}
But {{ subproject | inspect }}
comes out as
[{"title"=>"Sub Project 1","description"=>"aaa.","key"=>"RefSP1"}] [{"title"=>"Sub Project 2","description"=>"aaa.","key"=>"RefSP2"}]
The square brackets are the main difference. I tried removing them through filters, still nothing.

jinja2 template for loop idention error in json file

I'm trying to use a jinja2 template to render a json file. The structure is similar to:
"rows": [
{% for product in products %}
{
"id": {{ loop.index }},
"name": {{ product }},
"available": true
}{% if not loop.last %},
{% else %}
{% endif %}
{% endfor %}
],
[...]
The problem is that the output json is rendered as:
"rows": [
{
"id": {{ loop.index }},
"name": {{ product }},
"available": true
},
{
"id": {{ loop.index }},
"name": {{ product }},
"available": true
}
],
[...]
Note the bad indentation in the first { of each row. How can I solve this?
Thank you.
You can add a - to the Jinja2 enclosure to discard spaces in that direction:
{%- for product in products %}
Please read the documentation of Whitespace Control for details.