How can I get the full path to image src for eleventy-img if I use glob collections? - filepath

Problem:
I'm using the shortcode in /technical-seo/using-science-philosophy-organize-semantic-web.md {% image "grocery-isle.jpg", "Google Photos – Aisle 5, Faversham Sainsbury’s", "320, 640, 1024", "img-responsive" %}
`TemplateContentRenderError` was thrown
[11ty] > (./technical-seo/using-science-philosophy-organize-semantic-web.md)
EleventyShortcodeError: Error with Nunjucks shortcode `image`
`Template render error` was thrown
[11ty] > ENOENT: no such file or directory, open '/home/denverpr/repositories/yada-11ty-themesgrocery-isle.jpg'
It's an image folder in each glob collection. I need the collection path to be included. The true path is /home/denverpr/repositories/yada-11ty-themes/technical-seo/images/grocery-isle.jpg
My current structure:
├── technical-seo
├── create-jump-to-links-serp.md
├── ecommerce-site-structure-for-semantic-search.md
├── images
│ ├── grocery-isle.jpg
│ ├── optimize-local-seo.jpg
│ ├── science-semantic-web.png
│ ├── serp-jump-to-links-1.png
│ ├── serp-jump-to-links-2.png
│ ├── serp-jump-to-links-3.png
│ └── serp-jump-to-links.png
├── index.njk
├── optimizing-local-search.md
├── technical-seo.11data.js
└── using-science-philosophy-organize-semantic-web.md
My eleventy-img code:
module.exports = function(src, alt, widths, sizes, classattr) {
// src input same as 'normal' site-relative path for convenience, so add base path:
src = path.dirname(__dirname) + src;

In the error message, it shows that it's looking for the image at /home/denverpr/repositories/yada-11ty-themesgrocery-isle.jpg but not finding anything, which makes sense given that the image is located at /home/denverpr/repositories/yada-11ty-themes/technical-seo/images/grocery-isle.jpg.
You can also see why that incorrect path is generated. src will be /home/denverpr/repositories/yada-11ty-themes (the dirname thing) + grocery-isle.jpg.
To fix this, you can either update the image shortcode with the full path to the image, or add in the correct path to your image code. The best approach will depend on your specific situation.
Approach 1 - update shortcode (and also fix the generated path):
{% image "technical-seo/images/grocery-isle.jpg", ... %}
module.exports = function(src, alt, widths, sizes, classattr) {
// src input same as 'normal' site-relative path for convenience, so add base path:
src = path.dirname(__dirname) + "/" + src;
Approach 2 - fix path in image code:
module.exports = function(src, alt, widths, sizes, classattr) {
// src input same as 'normal' site-relative path for convenience, so add base path:
src = path.dirname(__dirname) + "/technical-seo/images/" + src;

Related

How to use Sass to generate various theme sets with minor differences

I have a solution which server various customers. Each customer has it's own theme, meaning a set of CSS files. There are a couple of elements, which are changing from customer to customer, so I'm using Sass to generate CSS files, using variables. Is there any solution to simplify below setup as it seems too complex,
├sass
│ ├CUSTOMER1
│ │ ├login.scss
│ │ ├style.scss
│ │ ├variable.scss
│ ├CUSTOMER2
│ │ ├login.scss
│ │ ├style.scss
│ │ ├variable.scss
│ ├login-base.scss
│ └style-base.scss
└compilerconfig.json
login-base.scss and style-base.scss contain the actual CSS, where variables are used.
Content of each login.scss (so the same file is present in each and every customer folder):
#import "variable";
#import "../login-base.scss";
Content of each style.scss (so the same file is present in each and every customer folder):
#import "variable";
#import "../style-base.scss";
variable.css varies across customers.
Content of compilerconfig.json:
[
//CUSTOMER1
{
"outputFile": "(MyProjectPath)/themes/CUSTOMER1/login.css",
"inputFile": "sass/CUSTOMER1/login.scss"
},
{
"outputFile": "(MyProjectPath)/themes/CUSTOMER1/style.css",
"inputFile": "sass/CUSTOMER1/style.scss"
},
//CUSTOMER2
{
"outputFile": "(MyProjectPath)/themes/CUSTOMER2/login.css",
"inputFile": "sass/CUSTOMER2/login.scss"
},
{
"outputFile": "(MyProjectPath)/themes/CUSTOMER2/style.css",
"inputFile": "sass/CUSTOMER2/style.scss"
}
]
Is there any way to simplify above setup? All my login.scss and style.scss files are exactly the same in all customer directories, which is redundant.
Whenever a new customer comes (and we are serving tens of customers, potentially hundreds), I need to create a new folder, place all the files in the folder, make changes to the compilerconfig.json and change set the variable.scss content according to customers needs. So I'm doing a lot of steps, creating a good amount of files, but only one file really changes: variable.scss.
In my opinion you could make a separate variables.scss file for all of the users, but every other scss files could be in the same directory like this.
├sass
| |GLOBAL
| | |login.scss
| | |styles.scss
│ ├CUSTOMER1
│ │ ├variable.scss
│ ├CUSTOMER2
│ │ ├variable.scss
│ ├login-base.scss
│ └style-base.scss
└compilerconfig.json
in your variables.scss files you could write global vars as CSS variables like this:
:root{
--primary-color: blue;
--secondary-color: red;
--font-family: sans-serif
/* etc. */
}
and in your scss files, you could use these vars without duplicate anything like this:
.my-button{
background-color: var(--primary-color);
}
or like this
$primary-color: var(--primary-color);
.my-button{
background-color: $primary-color
}
after that you just have to generate each user variables.css files, but the page will use the same styles.scss and login.scss files like that:
<link rel="stylesheet" href="variables.css"> <!-- variables needs to be the first one -->
<link rel="stylesheet" href="login.css">
<link rel="stylesheet" href="styles.css">
your config file should look like this:
[
//GLOBAL
{
"outputFile": "(MyProjectPath)/themes/GLOBAL/login.css",
"inputFile": "sass/Global/login.scss"
},
{
"outputFile": "(MyProjectPath)/themes/GLOBAL/styles.css",
"inputFile": "sass/Global/styles.scss"
},
//CUSTOMER1
{
"outputFile": "(MyProjectPath)/themes/CUSTOMER1/variables.css",
"inputFile": "sass/CUSTOMER1/variables.scss"
},
//CUSTOMER2
{
"outputFile": "(MyProjectPath)/themes/CUSTOMER2/variables.css",
"inputFile": "sass/CUSTOMER2/variables.scss"
},
]
hope it helps!

How to automatically import a SASS partials to two different main non-partial SASS files

I have a Gulp-based SASS compilation in place. Here's my structure:
├── _bootstrap-custom.scss
├── _variables.scss
├── base
│   ├── _button.scss
│   ├── _fonticon.scss
│   ├── _form.scss
│   ├── _grid.scss
│   ├── _helpers.scss
│   ├── _layout.scss
│   ├── _misc.scss
│   ├── _panels.scss
│   ├── _responsive_mixin.scss
│   ├── _tabs.scss
│   └── _typography.scss
├── components
│   ├── _footer.scss
│   └── _header.scss
├── frontpage.scss
├── main.scss
└── mixins
├── _buttons.scss
└── _mixins.scss
Here is main.scss
#import "variables.scss";
#import "bootstrap-custom";
#import "mixins/mixins";
#import "base/responsive_mixin";
#import "base/button";
#import "base/panels";
#import "base/helpers";
#import "base/form";
#import "base/layout";
#import "base/fonticon";
#import "base/typography";
#import "base/misc";
#import "base/tabs";
#import "components/footer";
#import "components/header";
And here is frontpage.scss
#import "variables.scss";
// import other page-specific partials..
Here is my gulpfile SASS part:
var config = {
sass: {
src: './data/rocket/themes/rocket/sass',
dest: './data/rocket/themes/rocket/css'
},
css: {
dest: 'css/'
},
bootstrap: {
src: './node_modules/bootstrap-sass/assets/stylesheets'
}
};
gulp.task('sass', function(){
let files = `${config.sass.src}/**/*.scss`;
let dest = `${config.sass.dest}`;
console.log('=== Compiling SASS ===');
return gulp.src(files)
.pipe(sourcemaps.init())
.pipe(sass({
outputStyle: 'expanded',
precision: 10,
errLogToConsole: true,
includePaths: config.bootstrap.src
}).on('error', sass.logError))
.pipe(sourcemaps.write())
.pipe(gulp.dest(dest));
});
Question : Is there any way to automatically include _variables.scss in all non-partial SASS files so I don't have to manually add it?
(main/frontpage are page-specific files so they're loaded separately)

Gulp sass compiles to wrong directory only when triggered by gulp watch

This one has me scratching my head for sure. I have my project set up like so
.
├── app
| └── styles
| ├── foundation
| | └── foundatipn.scss
| └── app.scss
├── build
| └── styles
└ └── app.css
My gulp-sass task compiles the app.scss correct and places the final file in build.styles.
However, when the sass task is triggered by gulp watch it puts a css file in app/styles/. It still compiles the correct file to build/styles.
Relevant code below
var gulp = require('gulp'),
browserSync = require('browser-sync').create(),
notify = require('gulp-notify'),
include = require('gulp-include'),
autoprefixer = require('gulp-autoprefixer'),
sass = require('gulp-ruby-sass'),
sourcemaps = require('gulp-sourcemaps'),
cssnano = require('gulp-cssnano'),
browserify = require('browserify'),
source = require('vinyl-source-stream');
var reload = browserSync.reload;
var dest = './build';
var src = './app';
gulp.task("sass", function(cb){
//Compile Foundation SCSS to CSS
var stream = sass('app/styles/app.scss',{
loadPath: ['app/styles/foundation'],
})
//.pipe(notify("Compiling SCSS, Autoprefixeing, Minifying and Creating Sourcemaps"))
.pipe(sourcemaps.init())
.pipe(autoprefixer({
browsers: ['last 2 versions', 'ie >= 9', 'and_chr >= 2.3']
}))
.pipe(cssnano())
.pipe(sourcemaps.write('/'))
.pipe(gulp.dest(dest + '/styles'))
.pipe(reload({stream: true}));
return stream;
});
gulp.task('watch', function(){
gulp.watch('app/**/*.html', ['markup']);
gulp.watch('app/styles/**/*.scss', ['sass']);
gulp.watch('app/scripts/**/*.js',['js']);
gulp.watch('app/images/**/*.png', ['images']);
});
depending on what version of gulp / gulp sass you are using it could be your "base".
Something about gulp using /**/ to set it's base for dest files/folders.
see this post:
how base option affects gulp.src & gulp.dest
More importantly this line:
If you want to avoid this you have to explicitly specify the base option:
gulp.src('some/path/**/js/*.js', {base:'.'})
.pipe(gulp.dest('output'));
I hope it helps.

how to rewrite relative url in minified css with cssmin?

I've been looking for a solution to my issue and I've found posts with similar problems, but not the same. I have the following folder structure:
js
└── GUIFramework
├── external
└── WaspFramework
├── Core
└── GUI
└── Controls
└── WaspMask
├── css
│ └── WaspMask.css
└── resources
└── default_loader_circle.gif
Inside WaspMask.css file I have this rule:
.wasp-loader-default {
background-image: url("../resources/default_loader_circle.gif");
}
Well, I've tried to minify it (combined with other css files) with cssmin plugin. My gruntfile is placed in WaspFramework folder, and I want generate the minified css there. The gruntfile file looks like this:
module.exports = function (grunt) {
var _sources = grunt.file.readJSON('./sources.json');
var _filesCSS = _sources.css;
grunt.initConfig({
cssmin: {
wasp: {
options: {
keepSpecialComments: 0
},
files: {
'wasp-bundle.min.css': _filesCSS
}
}
}
});
// load plugins
grunt.loadNpmTasks('grunt-contrib-cssmin');
// register at least this one task
grunt.registerTask('default', ['cssmin']);
};
In _filesCSS I have the paths of all the files to minify and combine, WaspMask.css included.
My problem is that with this configuration of cssmin, the url of the wasp-loader-default class hasn't changed so, obviously, the output file can't find the image. I've tried changing the cssmin options, adding the root property:
options: {
keepSpecialComments: 0,
root: '.',
},
It changes the url to /GUI/Controls/WaspMask/resources/default_loader_circle.gif, but it doesn't work because of the first slash of the path. I would need to get a relative path to the output file (GUI/Controls/WaspMask/resources/default_loader_circle.gif should work) because my application is published under a virtual directory. So I can't use a full path from the root of the application. I've even tried to set other values to root but some of them change the url to a full path and others add the first slash to the returned path.
Any idea about how to solve this?
After being looking for a solution to my problem, I've found the property I need in this issue of the 'cssmin' plugin:
https://github.com/gruntjs/grunt-contrib-cssmin/pull/47
Although I've found a little issue while I was compressing the 'bootstrap.css' file in my vendor's bundle file. This issue and a possible solution (basically, setting "noAdvanced" property to true in the task's options) is explained deeply in the post I did yesterday:
https://github.com/gruntjs/grunt-contrib-cssmin/issues/103
EDIT:
Here is my grunt file:
module.exports = function (grunt) {
var conf = grunt.file.readJSON('sources.json');
grunt.initConfig({
cssmin: {
options: {
keepSpecialComments: 0,
target: 'commonDir',
noAdvanced: true
},
test: {
files: {
'test.min.css': conf.css
}
}
}
});
// load plugins
grunt.loadNpmTasks('grunt-contrib-cssmin');
// register at least this one task
grunt.registerTask('default', ['cssmin']);
};
The target property is the common physical directory to all the files to minify (I load those files through a json file which contains their paths).
noAdvanced property is the option I use to avoid the problem I've explained with bootstrap.css, although in the last comment by #XhmikosR posted in https://github.com/gruntjs/grunt-contrib-cssmin/issues/103, he says that there is a patch to fix it. I've not checked it yet.

Paths of the generated pages with assemble

I am struggling with the grunt-assemble grunt task configuration which looks like this:
assemble: {
options: {
flatten: false,
expand: true,
assets: '',
layout: 'default.hbs',
layoutdir: 'templates/layouts',
partials: ['templates/includes/*.hbs'],
helpers: ['templates/helpers/*.js'],
data: ['templates/data/*.{json,yml}']
},
dev: {
src: 'templates/pages/**/*.hbs',
dest: 'build/'
}
The scaffolding of the project templates for assemble.io looks like:
templates
├── helpers
├── includes
│   ├── page-footer.hbs
│   ├── page-header.hbs
│   └── scripts.hbs
├── layouts
│   └── default.hbs
└── pages
├── en
│   └── index.hbs
├── fr
│   └── index.hbs
└── index.hbs
My wish is go get something like:
build
├── en
│   └── index.html
├── fr
│   └── index.html
└── index.html
But instead I get something like:
build
└── templates
└── pages
├── en
│   └── index.html
├── fr
│   └── index.html
└── index.html
I did try a few (a lot actually) of combinations (with the flatten and expand as well as the cwd options) but I am stuck.
Using flatten has for consequence to make the index.html files to overwrite each others.
So I actually do the rendering into a .tmp directory and then move the files to the build directory.
I do not like that solution because then, the page.assets is still broken (its value would be ../../.., for the root index.html).
grunt-assemble
(Note that this information refers specifically to grunt-assemble 0.4.x, which is the grunt plugin for assemble but has a completely different API)
#doowb almost has it right, try adding expand: true and ext: '.html' to the files config:
assemble: {
options: {
flatten: false,
expand: true,
assets: '',
layout: 'default.hbs',
layoutdir: 'templates/layouts',
partials: ['templates/includes/*.hbs'],
helpers: ['templates/helpers/*.js'],
data: ['templates/data/*.{json,yml}']
},
dev: {
files: [
{expand: true, cwd: 'templates/pages/', src: '**/*.hbs', dest: 'build/', ext: '.html'}
]
}
}
Also take a look at https://github.com/assemble/assemble-contrib-permalinks
assemble 0.7.x
Collections are first-class in assemble 0.7.0, as are plugins, so things like generating relative links, building pagination, and creating custom permalinks are much easier to do.
If you're using assemble 0.7.x and up, assemble-permalinks is the plugin you'd want to use.
Did you try using the expanded files object for grunt targets with the cwd property?
assemble: {
options: {
flatten: false,
expand: true,
assets: '',
layout: 'default.hbs',
layoutdir: 'templates/layouts',
partials: ['templates/includes/*.hbs'],
helpers: ['templates/helpers/*.js'],
data: ['templates/data/*.{json,yml}']
},
dev: {
files: [
{ cwd: 'templates/pages/', src: '**/*.hbs', dest: 'build/' }
]
}
}

Resources