In my Jekyll project, I have the following in my _config.yml file:
colors:
- name: red
hex: '#FF0000'
- name: yellow
hex: '#FFFF00'
- name: blue
hex: '#0000FF'
In assets/css/colors.scss, I want to create classes for the colors as follows:
{% for color in site.colors %}
.{{ color.name }} {
color: {{ color.hex }};
}
{% endfor %}
I want to #import the colors.scss file into main.scss, but I when I do so, I get the following error:
Error in _assets/css/background-test.scss:6 Invalid CSS after "}": expected selector or at-rule, was "{% for color in..."
Liquid Exception: Invalid CSS after "}": expected selector or at-rule, was "{% for color in..." in _includes/head.html, included in _layouts/default.html
jekyll 3.0.1 | Error: Invalid CSS after "}": expected selector or at-rule, was "{% for color in..."
Is there a way to get Liquid to process the values from the _config.yml file in the SCSS partial?
Only your main.scss will be parsed by Jekyll.
Once parsed with Liquid it is passed to sass/scss processor. So, any #imported file will not be parsed by Liquid.
Related
With Nunjucks I use the throwOnUndefined option to see where I use an undefined or null value in my output.
In my code structure I have a main file, and import files containing macro's for the actual rendering of output.
I want to report errors on, but the errors are always reported on the main file. Both in my own code, and when I use for example nunjucks-cli.
An example with nunjucks-cli:
file options.json:
{
"throwOnUndefined": true,
}
file test.njk:
{% import "macro.njk" as doit %}
{{ doit.giveError("x") }}
file macro.njk, containing an error because writing value of y:
{% macro giveError(x) %}
{{ y }}
{% endmacro %}
Nunjucks commando:
nunjucks test.njk --path . --options options.json
Error output:
Template render error: (C:\Q\nunjucks-errorreporting\test.njk) [Line 1, Column 17]
Template render error: (C:\Q\nunjucks-errorreporting\test.njk) [Line 2, Column 4]
attempted to output null or undefined value
Both errors are reported on test.njk. The first error on Line 1, Column 17, but on both files there is no relevance on column 17. The second error is Line 2, Column 4, which matches with writing out {{ y }} in the macro.njk file, but is reported on test.njk.
I get the same behaviour in my custom code.
Is there a way to get correct error reporting on the correct files, because I have file importing files, importing other files...
Update:
Based on input Lesha Ogonkov I added "dev": true to the options.json.
This results in the following output:
Error: attempted to output null or undefined value
at new TemplateError (C:\Q\nunjucks-errorreporting\node_modules\nunjucks\src\lib.js:89:17)
at Object.ensureDefined (C:\Q\nunjucks-errorreporting\node_modules\nunjucks\src\runtime.js:242:11)
at Object.eval (eval at _compile (C:\Q\nunjucks-errorreporting\node_modules\nunjucks\src\environment.js:631:18), <anonymous>:18:38)
at Object.giveError (C:\Q\nunjucks-errorreporting\node_modules\nunjucks\src\runtime.js:131:17)
at Context.<anonymous> (C:\Q\nunjucks-errorreporting\node_modules\nunjucks\src\runtime.js:259:23)
at Object.callWrap (C:\Q\nunjucks-errorreporting\node_modules\nunjucks\src\runtime.js:273:14)
at eval (eval at _compile (C:\Q\nunjucks-errorreporting\node_modules\nunjucks\src\environment.js:631:18), <anonymous>:13:88)
at C:\Q\nunjucks-errorreporting\node_modules\nunjucks\src\environment.js:613:9
at Template.root [as rootRenderFunc] (eval at _compile (C:\Q\nunjucks-errorreporting\node_modules\nunjucks\src\environment.js:631:18), <anonymous>:29:1)
at Template.getExported (C:\Q\nunjucks-errorreporting\node_modules\nunjucks\src\environment.js:609:10) {
lineno: 2,
colno: 4,
firstUpdate: false,
Update: [Function: Update]
}
I still not see a relation to the file where the error is occurring.
Try to set dev flag next to throwOnUndefined. It is undocumented nunjucks feature, that prevent stacktrace collapse.
I'm trying to pass one site collection to my page's layout, in order to be able to make my nav menu according to the sections I pass.
In my _config.yml
collections:
tt:
output: true
In my index.md page:
---
layout: mylayout
title: My Great Homepage
icon: fa-home
order: 1
sec: "{{site.tt}}"
---
In my layout:
---
layout: mylayout
---
{%- assign _sections = page.sec | flatify -%}
{%- include header.html scrolly_nav=_sections -%}
<!-- Main -->
<div id="main">
{{page.sec | flatify}} <!-- just to debug -->
</div>
Flatify is under _plugins/flatify.rb:
module Jekyll
module ExpandNestedVariableFilter
def flatify(input)
Liquid::Template.parse(input).render(#context)
end
end
end
Liquid::Template.register_filter(Jekyll::ExpandNestedVariableFilter)
In my layout, using {%- assign _sections = site.sec | flatify -%} works perfectly, but when I pass the collection from the page to the layout, it's not working.
If I do the exact same thing passing site.title instead of site.tt from the page to the layout, everything works just fine. But when I try to pass a collection, it's not working.
Thanks for your help.
Your flatify plugin is cool, but it does not reflect real life.
You cannot use liquid vars in front matter because they are not parsed.
In your page's front matter :
---
sec: "tt"
---
Then, from the page or the layout, you can just call :
{%- assign _sections = site[page.sec] -%}
{%- include header.html scrolly_nav=_sections -%}
If you want to debug, you can use inspect filter, which just outputs variable content.
{{ page.sec | inspect }} or {{ site[page.sec] | inspect }}
My post template in jekyll renders a presentation either of Google slides or of a jupyter notebook html. For this purpose, I use the markdown structure shown below:
---
layout: post
title: title
date: 2018-10-28 00:00:00 -0500
categories: category
author: author
medium: jupyter
link: [//]: # (Here I insert the presentation url)
lang: en
---
<div>
{% if page.medium == 'jupyter' %}
{% include jupyter.html link=page.link %}
{% elsif page.medium == 'gslides' %}
{% include gslides.html link=page.link %}
{% else %}
{% include nodata.html %}
{% endif %}
</div>
This generates the desired result. However, during the bundle creation, jekyll outputs this error for each post file:
Error: A Liquid tag in the excerpt of ./file.markdown couldn't be parsed.
Error: could not read file ./file.markdown: undefined method `ancestors' for nil:NilClass
I have already looked for any syntax errors along with this and other files, and all seems to be ok. Does someone has gone through a similar problem?
EDIT: I've taken the elif and the else clause of the statement, only then the problem ceases.
I run bundle exec jekyll serve --trace on Windows 10. I got the following console message:
D:\MyPorfolio\perrot.github.io>bundle exec jekyll serve
Configuration file: D:/MyPorfolio/perrot.github.io/_config.yml
Source: D:/MyPorfolio/perrot.github.io
Destination: D:/MyPorfolio/perrot.github.io/_site
Incremental build: disabled. Enable with --incremental
Generating...
Liquid Exception: Liquid syntax error (line 8): Syntax Error in 'for loop' - Valid syntax: for [item] in [collection] in 2018-09-14-Rendering a python dict in jinja2.markdown
jekyll 3.7.3 | Error: Liquid syntax error (line 8): Syntax Error in 'for loop' - Valid syntax: for [item] in [collection]
Does anyone know how to fix that problem? Thanks in advance.
The file 2018-09-14-Rendering a python dict in jinja2.markdown content is:
---
layout: post
title: "Rendering a python dict in jinja2"
date: 2018-09-14 00:01:57 +0800
categories: python jinja2
---
```python
url_list = [{'target': 'http://10.58.48.103:5000/', 'clicks': '1'},
{'target': 'http://slash.org', 'clicks': '4'},
{'target': 'http://10.58.48.58:5000/', 'clicks': '1'},
{'target': 'http://de.com/a', 'clicks': '0'}]
#Python 2.7
{% for key, value in url_list.iteritems() %}
<li>{{ value["target"] }}</li>
{% endfor %}
#Python 3
{% for key, value in url_list.items() %}
<li>{{ value["target"] }}</li>
{% endfor %}
```
Liquid tries to process your source code, particularly the jinja2 control tags, for that you need to tell Liquid to avoid processing it with the raw tags:
{% highlight python %}
{% raw %}
url_list = [{'target': 'http://10.58.48.103:5000/', 'clicks': '1'},
{'target': 'http://slash.org', 'clicks': '4'},
{'target': 'http://10.58.48.58:5000/', 'clicks': '1'},
{'target': 'http://de.com/a', 'clicks': '0'}]
#Python 2.7
{% for key, value in url_list.iteritems() %}
<li>{{ value["target"] }}</li>
{% endfor %}
#Python 3
{% for key, value in url_list.items() %}
<li>{{ value["target"] }}</li>
{% endfor %}
{% endraw %}
{% endhighlight %}
1 - The {% raw %} tag is part of the solution for you python code in this post and this post.
2 - The other part of the solution can be a bug in the way Jekyll manages excerpts.
Remove empty lines in your code, and it will work.
Does anyone have a workflow for developing Shopify themes with Compass and Sass? I am really close, I just need to figure out how to not make Sass barf on the CSS liquid tags.
Here's what I've got:
A sass/compass project in directory (ex:, "/newwebsite/)
A subdirectory containing my Shopify theme ("/newwebsite/newwebsite-theme/")
A Compass config.rb that points the css,_dir images_dir and javascripts_dir all to the them's assets folder ("/newwebsite/newwebsite-theme/assets/")
Compass watch on
shopify_theme gem also watch on, uploading theme files to shopify (https://github.com/Shopify/shopify_theme)
EDIT Sass interpolations (see anser below)
EDIT Compass callback to rename to .css.liquid
The problem: Compass barf's when you need to use Shopify's liquid templating tags, for example, a background image - example, background: url( "{{ "splash-1.jpg" | asset_url }}")
Does anyone know how to instruct Compass / Sass to spit out the liquid template tags as they are into the CSS? If I have that, then I have a solid workflow of editing Sass locally, and realizing the changes momentarily after on the shopify shop.
Thanks
EDIT:
By using Hopper's answer below for the liquid tags in Sass, and renaming the Compass output .css file to .css.liquid, I now have an instantaneous workflow for designing a Shopify theme with Compass and Sass!
Here is the code for the Compass callback that goes in the config.rb:
on_stylesheet_saved do |filename|
s = filename + ".liquid"
puts "copying to: " + s
FileUtils.cp(filename, s)
puts "removing: " + filename
end
I'm not familiar with Shopify or liquid tags, but I do know that in SASS you can use interpolations to output plain CSS as-is. For example, the SASS here:
.test {
background: url( #{'{{ "splash-1.jpg" | asset_url }}'} )
}
Would be compiled to:
.test {
background: url({{ "splash-1.jpg" | asset_url }}); }
Does that get you close to what you're looking for?
How do you keep Compass from barfing on liquid logic between properties? E.g. any time there's a liquid if statement I get errors, and using #{'...'} doesn't seem to help.
This is a test I can't get to work:
#container {
width:884px;
margin:0px auto;
min-height:500px;
position:relative;
padding:0 40px;
{% if settings.page_bg_transparent %}
background:transparent;
{% else %}
background:{{ settings.page_bg_color }};
{% endif %}
}
UPDATE weirdly, commenting liquid logic works:
#container {
width:884px;
margin:0px auto;
min-height:500px;
position:relative;
padding:0 40px;
/* {% if settings.page_bg_transparent %} */
background:transparent;
/* {% else %} */
background:#{'{{ settings.page_bg_color }}'};
/* {% endif %} */
}
For asset url you can also use SCSS custom functions.
Put this in your config.rb file
module Sass::Script::Functions
def shopify_image_url(string)
assert_type string, :String
Sass::Script::String.new("url({{'#{string.value}' | asset_url}})")
end
end
And then use it in your styles.scss like this
background: shopify_image_url('image.png');
I found it useful to remove the original output file after save so you don't have that extra, non liquid file floating in the assets dir.
on_stylesheet_saved do |filename|
s = filename + ".liquid"
puts "copying to: " + s
FileUtils.cp(filename, s)
puts "removing: " + filename
FileUtils.remove_file(filename)
end
Building on hopper's answer, for anyone using autoprefixer to process sass output, you would need to add an additional pair of quotes because url( {{ ... }} ) causes autoprefixer's parser to choke.
Do this:
background: url( "#{'{{ "splash-1.jpg" | asset_url }}'}" )
Which becomes this in the *.css.liquid file :
background: url( '{{ "splash-1.jpg" | asset_url }}' )
If you wish to preserve the ".scss.liquid" extension for the new responsive checkout use:
on_stylesheet_saved do |filename|
FileUtils.mv filename, "#{File.dirname(filename)}/#{File.basename(filename,'.*')}.scss.liquid"
end
It renames the files instead of copying and then removing.
I wrote an article describing the methods I used to get Compass and Sass working well with Shopify. This is the same approach of DOMUSNETWORK's answer. I go into a little more detail on file structure.
http://www.mealeydev.com/blog/shopify-and-sass/
This worked for me, partially - however I found that the Shopify Theme app a lot of times didn't want to upload my edited .css.liquid file, because apparently it didn't recognize that the file had been edited.
What solved it for me was to use the following code in my config.rb, instead of the code in the question above:
on_stylesheet_saved do |filename|
move_to = filename + ".liquid"
puts "Moving from #{filename} to #{move_to}"
FileUtils.mv(filename, move_to)
end
Shameless plug...
I think #nick is on the right track.
scss is better when it's compiled before sending to Shopify.
For others who find this answer, I think Quickshot is the tool you are looking for.
You will still need to interpolate for asset urls, but quickshot will automatically recompile your scss and upload the result to shopify in one step. Which also gives you the ability to use #include in your scss files.
http://quickshot.io/
https://github.com/internalfx/quickshot