Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Partial with custom layout not rendering in to {% body %} - empty buffer?... #894

Open
Obscuresounds opened this issue Sep 6, 2016 · 28 comments

Comments

@Obscuresounds
Copy link

version

assemble 0.17.1

description

I have the following code for producing a series of static templates using gulp:

    assemble.create('layouts', { viewType: 'layout', renameKey: keyAsFilename });
    assemble.create('styleguide', { viewType: 'partial', renameKey: keyAsFilename });

    assemble.layouts('./src/views/layouts/*.html');
    assemble.styleguide('./src/views/styleguide.html', {layout: 'module'});

    assemble.toStream('styleguide')
        .pipe(assemble.renderFile())
        .pipe(flatten())
        .pipe(rename('index.html'))
        .pipe(assemble.dest('./dist'));

However I'm getting an edge case where having a custom partial that uses a custom layout (in my case a file called module) it returns a blank space when it tries to inject in to {%body%}.

In the console I get this with the styleguide view:

styleguides: { styleguide: <Styleguide "styleguide"> } }

It looks like its not setting any buffer, or is empty. However, when I take out {layout: 'module'} from the declaration the console returns the following for the same styleguide:

styleguides: { styleguide: <Styleguide "styleguide" <Buffer 3c 64 69 76 20 63 6c 61 73 73 3d 22 6f 2d 63 6f 6e 74 61 69 6e 65 72 22 3e 0a 0a 20 20 20 20 3c 64 69 76 20 63 6c 61 73 73 3d 22 6f 2d 72 6f 77 22 3e ... >> }

Finally, you'll see in the code below that I have a directory of pages that is looped through via a wildcard, and I have told them to use the base layout - these work fine, and content renders as expected. However in the case of styleguide where I'm pointing to a single file and declaring it as a partial type it seems to break.

error message

No error messages - silent.

assemblefile.js

var gulp = require('gulp'),
    assemble = require('assemble')(),
    rename = require('gulp-rename'),
    path = require('path'),
    fs = require('fs'),
    flatten = require('gulp-flatten'),
    gutil = require('gulp-util'),
    helper = require('../lib/helpers'),
    config = require(helper.getGulpConfig());

/**
 * Helper function to set our module key based on the filename.
 */
function keyAsFilename(key, view) {
    var v = view ? view.basename : path.basename(key);
    v = v.split('/').pop().replace('.html', '').replace('.hbs', '');
    return v;
}

gulp.task('server:assemble', function() {

    assemble.data([
        './src/views/partials/**/*.json',
        './src/modules/**/*.json',
        './src/components/**/*.json'
    ]);

    /**
     * Register all of our compiled component templates as partials
     * so we can render them all on the page.
     */
    assemble.create('layouts', { viewType: 'layout', renameKey: keyAsFilename });
    assemble.create('pages', { viewType: 'partial', renameKey: keyAsFilename });
    assemble.create('modules', { viewType: 'partial', renameKey: keyAsFilename });
    assemble.create('partials', { viewType: 'partial', renameKey: keyAsFilename });
    assemble.create('styleguide', { viewType: 'partial', renameKey: keyAsFilename });

    assemble.layouts('./src/views/layouts/*.html');
    assemble.pages('./src/views/pages/*.html', {layout: 'base'});
    assemble.modules('./src/modules/**/views/**/*.html');
    assemble.partials('./src/views/partials/**/*.html');
    assemble.styleguide('./src/views/styleguide.html', {layout: 'module'});

    console.log(assemble.views);

    assemble.toStream('pages')
        .pipe(assemble.renderFile())
        .pipe(assemble.dest('./dist/pages'));

    assemble.toStream('partials')
        .pipe(assemble.renderFile())
        .pipe(assemble.dest('./dist/partials'));

    assemble.toStream('modules')
        .pipe(assemble.renderFile())
        .pipe(assemble.dest('./dist/modules'));

    assemble.toStream('styleguide')
        .pipe(assemble.renderFile())
        .pipe(flatten())
        .pipe(rename('index.html'))
        .pipe(assemble.dest('./dist'));

});
@assemblebot
Copy link

@Obscuresounds Thanks for the issue! If you're reporting a bug, please be sure to include:

  • The version of assemble you are using.
  • Your assemblefile.js (This can be in a gist)
  • The commandline output. (Screenshot or gist is fine)
  • What you expected to happen instead.

If your issue is related to one of the following, please open an issue there:

  • grunt-assemble Issues with using assemble in grunt or the grunt-assemble library.
  • handlebars-helpers Issues with using handlebars helpers from the handlebars-helpers library.

@jonschlinkert
Copy link
Member

I don't think this will fix it, but try moving all of the calls to .create outside of the .task function, so that collections are created before the task is run, but then templates are loaded when the task is run.

Thanks for reporting

@Obscuresounds
Copy link
Author

Hi Jon,

Just tried that now - thanks for the suggestion - sadly didn't fix the issue although probably wise to have separated them up anyway. No problem and I hope its fairly easy to source the problem - loving the way Assemble works.

@jonschlinkert
Copy link
Member

thanks for trying... Hmm. @doowb do you notice anything in the config that I'm missing that would cause this? otherwise this looks like it might be a bug.

@tunnckoCore
Copy link

tunnckoCore commented Sep 6, 2016

I believe it's because of the "asyncness". Why not try to separate them in separate tasks, and they run one task with dependency tasks?

Something like that (I'm not sure for the tasks order)

var gulp = require('gulp'),
  assemble = require('assemble')(),
  rename = require('gulp-rename'),
  path = require('path'),
  fs = require('fs'),
  flatten = require('gulp-flatten'),
  gutil = require('gulp-util'),
  helper = require('../lib/helpers'),
  config = require(helper.getGulpConfig())

/**
 * Helper function to set our module key based on the filename.
 */
function keyAsFilename (key, view) {
  var v = view ? view.basename : path.basename(key)
  v = v.split('/').pop().replace('.html', '').replace('.hbs', '')
  return v
}

/**
 * Register all of our compiled component templates as partials
 * so we can render them all on the page.
 */
assemble.create('layouts', { viewType: 'layout', renameKey: keyAsFilename })
assemble.create('pages', { viewType: 'partial', renameKey: keyAsFilename })
assemble.create('modules', { viewType: 'partial', renameKey: keyAsFilename })
assemble.create('partials', { viewType: 'partial', renameKey: keyAsFilename })
assemble.create('styleguide', { viewType: 'partial', renameKey: keyAsFilename })

assemble.layouts('./src/views/layouts/*.html')
assemble.pages('./src/views/pages/*.html', {layout: 'base'})
assemble.modules('./src/modules/**/views/**/*.html')
assemble.partials('./src/views/partials/**/*.html')
assemble.styleguide('./src/views/styleguide.html', {layout: 'module'})
assemble.data([
  './src/views/partials/**/*.json',
  './src/modules/**/*.json',
  './src/components/**/*.json'
])

gulp.task('server:pages', function () {
  return assemble.toStream('pages')
    .pipe(assemble.renderFile())
    .pipe(assemble.dest('./dist/pages'))
})
gulp.task('server:partials', function () {
  return assemble.toStream('partials')
    .pipe(assemble.renderFile())
    .pipe(assemble.dest('./dist/partials'))
})
gulp.task('server:modules', function () {
  return assemble.toStream('modules')
    .pipe(assemble.renderFile())
    .pipe(assemble.dest('./dist/modules'))
})
gulp.task('server:styleguide', function () {
  return assemble.toStream('styleguide')
    .pipe(assemble.renderFile())
    .pipe(flatten())
    .pipe(rename('index.html'))
    .pipe(assemble.dest('./dist'))
})
gulp.task('server:all', [
  'server:pages',
  'server:partials',
  'server:modules',
  'server:styleguide'
])

Also, what gulp version you use?

@jonschlinkert
Copy link
Member

no you can't do that, you need to load the collections/globs inside a task (specifically because of the asynchrony). I believe this is a bug.

@tunnckoCore
Copy link

You mean assemble.data or assemble.pages/layouts/partials?

you need to load the collections/globs inside a task

hm.. why? You even don't need a tasks to assemble to work?

I believe you can just do (for example with just pages)?

assemble.pages('./src/views/pages/*.html')
assemble.toStream('pages')
    .pipe(assemble.renderFile())
    .pipe(assemble.dest('./dist/pages'))

@Obscuresounds
Copy link
Author

FYI Gulp Versions:
[23:06:32] CLI version 1.2.1
[23:06:32] Local version 3.9.1

@jonschlinkert
Copy link
Member

hm.. why?

watch. We always recommend loading templates inside a task so that watch will work. it's just good practice, so that when watch is added to a config, you don't have to remember to go back and move code inside tasks to make it work.

You even don't need a tasks to assemble to work?

True, so if you don't use tasks, you won't be using .watch and you don't need to do this :)

@tunnckoCore
Copy link

tunnckoCore commented Sep 6, 2016

I understand it's a good thing to be inside, but it should also work and make sense to work outside of the task. That's why I think it's not the case here. Another thing can be to move them to separate task to respect DRY.

gulp.task('loadsetup', function () {
  assemble.layouts('./src/views/layouts/*.html')
  assemble.pages('./src/views/pages/*.html', {layout: 'base'})
  assemble.modules('./src/modules/**/views/**/*.html')
  assemble.partials('./src/views/partials/**/*.html')
  assemble.styleguide('./src/views/styleguide.html', {layout: 'module'})
  assemble.data([
    './src/views/partials/**/*.json',
    './src/modules/**/*.json',
    './src/components/**/*.json'
  ])
})
gulp.task('default', ['loadsetup', 'server:all'])

So it's not the case, I'm sure.

@jonschlinkert
Copy link
Member

jonschlinkert commented Sep 6, 2016

Another thing can be to move them to separate task to respect DRY.

yeah that's a great approach - that's how I do it personally. you can do it however you want, as long as the loading is done inside a task.

but it should also work and make sense to work outside of the task.

I'm not sure what point you're trying to make.

  1. If you want asynchrony to work differently in javascript, that's a problem we're not going to solve in this repository. To ensure that all templates are loaded, or re-loaded before .src is called, it's a best practice to call the collection methods inside a task. If you don't, then we cannot do anything to ensure that code is executed in the order that will produce the desired results.
  2. Moreover, if you don't load templates from inside a task, then templates will always be loaded when node's require() loads the gulpfile.js or assemblefile.js, which means that even when only non-template-related tasks are called, the templates will still be loaded, making your build slower.

As a rule, you should always, always, always make your code as lazy as possible. Don't call functions, loop over objects, or execute any code before it's needed.

Loading templates from inside a task is a very obvious best-practice that is necessary because of how javascript works, not because of assemble or gulp conventions. As such it's not something I want to debate. Plus it's off-topic for this issue.

@tunnckoCore
Copy link

tunnckoCore commented Sep 6, 2016

As a rule, you should always, always, always make your code as lazy as possible.

Totally agree. Let's @Obscuresounds try these things.

I'm all for best practices and great docs, because I always see in the community that most of the issues are because of wrong usage, not because of real bugs.

edit: that's why i always try to do as much as possible, before just consider it easily as bug.

@jonschlinkert
Copy link
Member

because I always see in the community that most of the issues are because of wrong usage, not because of real bugs

very true. as both maintainers and users, we're as guilty of that as any other dev

@doowb
Copy link
Member

doowb commented Sep 6, 2016

@Obscuresounds these are 2 things that I think might make a difference:

  • Use the plural version to load the single template. If this works, then there's a bug with the single version that we can look for.
assemble.styleguide('./src/views/styleguide.html', {layout: 'module'});
// to
assemble.styleguides('./src/views/styleguide.html', {layout: 'module'});
  • Make the styleguide type renderable
assemble.create('styleguide', { viewType: ['partial', 'renderable'], renameKey: keyAsFilename })

@jonschlinkert
Copy link
Member

Make the styleguide type renderable

I knew @doowb would catch something. I think this is the solution.

@Obscuresounds
Copy link
Author

Obscuresounds commented Sep 6, 2016

Hi @tunnckoCore, I tried as per Jon's comments earlier and it sadly made no difference. Here is my adapted code and I will edit the ticket above. If its a user error then please enlighten me?

Hey @doowb, brilliant I'll try this out now, and fingers crossed... I'll let you know if it gets around it.

gulp.task('assemble:create', function() {

    assemble.data([
        './src/views/partials/**/*.json',
        './src/modules/**/*.json',
        './src/components/**/*.json'
    ]);

    /**
     * Register all of our compiled component templates as partials
     * so we can render them all on the page.
     */
    assemble.create('layouts', { viewType: 'layout', renameKey: keyAsFilename });
    assemble.create('pages', { viewType: 'partial', renameKey: keyAsFilename });
    assemble.create('modules', { viewType: 'partial', renameKey: keyAsFilename });
    assemble.create('partials', { viewType: 'partial', renameKey: keyAsFilename });
    assemble.create('styleguide', { viewType: 'partial', renameKey: keyAsFilename });

    assemble.layouts('./src/views/layouts/*.html');
    assemble.pages('./src/views/pages/*.html', {layout: 'base'});
    assemble.modules('./src/modules/**/views/**/*.html');
    assemble.partials('./src/views/partials/**/*.html');
    assemble.styleguide('./src/views/styleguide.html');

});

gulp.task('server:assemble', ['assemble:create'], function() {

    assemble.toStream('pages')
        .pipe(assemble.renderFile())
        .pipe(assemble.dest('./dist/pages'));

    assemble.toStream('partials')
        .pipe(assemble.renderFile())
        .pipe(assemble.dest('./dist/partials'));

    assemble.toStream('modules')
        .pipe(assemble.renderFile())
        .pipe(assemble.dest('./dist/modules'));

    assemble.toStream('styleguide')
        .pipe(assemble.renderFile())
        .pipe(flatten())
        .pipe(rename('index.html'))
        .pipe(assemble.dest('./dist'));

});

@tunnckoCore
Copy link

tunnckoCore commented Sep 6, 2016

Written this why you don't have error handlers, maybe that's why you don't have error? Hm. In anyway, you should return at least one of the streams, or set callback argument and add error listeners. I think gulp tasks are only async? Hm didn't use it for long time. In anyway, at least should add cb() after all the streams.

But yea, maybe @doowb is right here.

@Obscuresounds
Copy link
Author

Obscuresounds commented Sep 7, 2016

@tunnckoCore: I most likely could do, but I'm not too fussed about finessing at this stage. Returning on each task or setting callbacks didn't help here and I did try. If I have time I'll divide these up in to separate functions, but for now its not relevant to the ticket from what I can see.

@doowb thanks for pointing out the pluralized layout name... this seems to have gotten things a bit further down the chain and the buffer was set on output, but theres definitely something going on - when pluralized, the {%body%} content renders but not the layout (so the reverse). Funnily enough I'm now convinced its to do with how options are parsed in via wildcards. On a hunch I changed the direct file call from styleguide.html to *.html (so effectively scan the directory and add it to styleguides), and this DID work as intended with the layout and partial. Any thoughts?

@jonschlinkert
Copy link
Member

On a hunch I changed the direct file call from styleguide.html to *.html (so effectively scan the directory and add it to styleguides), and this DID work as intended with the layout and partial. Any thoughts?

Hmm, I'm not sure what's causing it but I have a hunch. It's definitely a bug though, because the behavior and/or expected result should not differ.

@jonschlinkert
Copy link
Member

on second thought, if the suggestions @doowb made worked, but the behavior is inconsistent between singular and plural collection methods, this wouldn't be an assemble bug. The bug would be in the assemble-loader plugin, which loads globs. In assemble, the plural/singular methods should be identical. but that plugin makes changes that could cause the inconsistency.

@Obscuresounds
Copy link
Author

Obscuresounds commented Sep 10, 2016

Thanks Jon - is it worth me raising the ticket directly on there? After some experimenting I found that when I use {layout:'base'} in assemble 0.11.0 then layouts would render, but in 0.17.1 this is sadly no longer the case, even with I use the pluralized object name. Curious!

What I'll do tomorrow is set up a proper example repo for you guys as a little testing ground.

@jonschlinkert
Copy link
Member

jonschlinkert commented Sep 10, 2016

After some experimenting I found that when I use {layout:'base'} in assemble 0.11.0 then layouts would render,

to be clear, you mean specifically with partials as described in this issue when loading them with the singular glob for collection loader?

edit: e.g. since layouts are very stable and work in general

@Obscuresounds
Copy link
Author

Yep. So assemble.styleguides('./src/views/*.html', {layout: 'module'});` with the layout definition works in 0.10.0 but not 0.17.1.

@jonschlinkert
Copy link
Member

yes then, that would be great. thanks!

@grayghostvisuals
Copy link

@Obscuresounds Are you still in need of assistance or has this issue ben resolved? + @jonschlinkert

@Obscuresounds
Copy link
Author

Hi @grayghostvisuals, I haven't managed to pull the latest repo as I froze Assemble for my project at 0.10.0 but I can try again.

@grayghostvisuals
Copy link

grayghostvisuals commented Jun 25, 2017

@Obscuresounds Yeah if you could update to the latest release and try again that would be great.

@grayghostvisuals
Copy link

@Obscuresounds were u able to try again? can this ticket be closed?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants