0
votes

I am working on building a Sails.js app. I am quite new to Sails.js, Node.js environment and HTML templating engines. I would like to use Handlebars as my templating engine. While the basic rendering "works" (that is, data passed from the server is rendered appropriately and the base layout works), I cannot get the sails-linker to inject my client-side scripts and styles into the templates. I have searched, looked at Sail's documentation, and tried various settings but to no avail.

This is my pipeline file:

    /**
 * grunt/pipeline.js
 *
 * The order in which your css, javascript, and template files should be
 * compiled and linked from your views and static HTML files.
 *
 * (Note that you can take advantage of Grunt-style wildcard/glob/splat expressions
 * for matching multiple files, and ! in front of an expression to ignore files.)
 *
 * For more information see:
 *   https://github.com/balderdashy/sails-docs/blob/master/anatomy/myApp/tasks/pipeline.js.md
 */


// CSS files to inject in order
//
// (if you're using LESS with the built-in default config, you'll want
//  to change `assets/styles/importer.less` instead.)
var cssFilesToInject = [
    'styles/src/**/*.scss'
];


// Client-side javascript files to inject in order
// (uses Grunt-style wildcard/glob/splat expressions)
var jsFilesToInject = [

    // Load sails.io before everything else
    'js/dependencies/sails.io.js',

    // Dependencies like jQuery, or Angular are brought in here
    'js/dependencies/**/*.js',

    // All of the rest of your client-side js files
    // will be injected here in no particular order.
    'js/**/*.js'
];


// Client-side HTML templates are injected using the sources below
// The ordering of these templates shouldn't matter.
// (uses Grunt-style wildcard/glob/splat expressions)
//
// By default, Sails uses JST templates and precompiles them into
// functions for you.  If you want to use jade, handlebars, dust, etc.,
// with the linker, no problem-- you'll just want to make sure the precompiled
// templates get spit out to the same file.  Be sure and check out `tasks/README.md`
// for information on customizing and installing new tasks.
var templateFilesToInject = [
    '**/*.handlebars'
];

// Default path for public folder (see documentation for more information)
var tmpPath = '.tmp/public/';

// Prefix relative paths to source files so they point to the proper locations
// (i.e. where the other Grunt tasks spit them out, or in some cases, where
// they reside in the first place)
module.exports.cssFilesToInject = cssFilesToInject.map(function(cssPath) {
    // If we're ignoring the file, make sure the ! is at the beginning of the path
    if (cssPath[0] === '!') {
        return require('path').join('!.tmp/public/', cssPath.substr(1));
    }
    return require('path').join('.tmp/public/', cssPath);
});
module.exports.jsFilesToInject = jsFilesToInject.map(function(jsPath) {
    // If we're ignoring the file, make sure the ! is at the beginning of the path
    if (jsPath[0] === '!') {
        return require('path').join('!.tmp/public/', jsPath.substr(1));
    }
    return require('path').join('.tmp/public/', jsPath);
});
module.exports.templateFilesToInject = templateFilesToInject.map(function(tplPath) {
    // If we're ignoring the file, make sure the ! is at the beginning of the path

    if (tplPath[0] === '!') {
        return require('path').join('views/', tplPath.substr(1));
    }
    return require('path').join('views/', tplPath);
});

I have added a handlebars.js task underneath tasks/config

    // tasks/config/handlebars.js
// --------------------------------
// handlebar task configuration.

module.exports = function(grunt) {

    // We use the grunt.config api's set method to configure an
    // object to the defined string. In this case the task
    // 'handlebars' will be configured based on the object below.
    grunt.config.set('handlebars', {
        dev: {
            // We will define which template files to inject
            // in tasks/pipeline.js
            files: {

                '.tmp/public/templates.js': require('../pipeline').templateFilesToInject
            }
        }
    });

    // load npm module for handlebars.

    grunt.loadNpmTasks('grunt-contrib-handlebars');
}

My sails-linker.js file (also underneath tasks/config):

   /**
 * `sails-linker`
 *
 * ---------------------------------------------------------------
 *
 * Automatically inject <script> tags and <link> tags into the specified
 * specified HTML and/or EJS files.  The specified delimiters (`startTag`
 * and `endTag`) determine the insertion points.
 *
 * #### Development (default)
 * By default, tags will be injected for your app's client-side JavaScript files,
 * CSS stylesheets, and precompiled client-side HTML templates in the `templates/`
 * directory (see the `jst` task for more info on that).  In addition, if a LESS
 * stylesheet exists at `assets/styles/importer.less`, it will be compiled to CSS
 * and a `<link>` tag will be inserted for it.  Similarly, if any Coffeescript
 * files exists in `assets/js/`, they will be compiled into JavaScript and injected
 * as well.
 *
 * #### Production (`NODE_ENV=production`)
 * In production, all stylesheets are minified into a single `.css` file (see
 * `tasks/config/cssmin.js` task) and all client-side scripts are minified into
 * a single `.js` file (see `tasks/config/uglify.js` task).  Any client-side HTML
 * templates, CoffeeScript, or LESS files are bundled into these same two minified
 * files as well.
 *
 * For usage docs see:
 *   https://github.com/Zolmeister/grunt-sails-linker
 *
 */
module.exports = function(grunt) {

    grunt.config.set('sails-linker', {
        devJs: {
            options: {
                startTag: '<!--SCRIPTS-->',
                endTag: '<!--SCRIPTS END-->',
                fileTmpl: '<script src="%s"></script>',
                appRoot: '.tmp/public'
            },
            files: {
                '.tmp/public/**/*.html': require('../pipeline').jsFilesToInject,
                'views/**/*.html': require('../pipeline').jsFilesToInject,
                '.tmp/public/templates.js': require('../pipeline').jsFilesToInject,
                'views/**/*.handlebars': require('../pipeline').jsFilesToInject
            }
        },

        devJsRelative: {
            options: {
                startTag: '<!--SCRIPTS-->',
                endTag: '<!--SCRIPTS END-->',
                fileTmpl: '<script src="%s"></script>',
                appRoot: '.tmp/public',
                relative: true
            },
            files: {
                '.tmp/public/**/*.html': require('../pipeline').jsFilesToInject,
                'views/**/*.html': require('../pipeline').jsFilesToInject,
                '.tmp/public/templates.js': require('../pipeline').jsFilesToInject,
                'views/**/*.handlebars': require('../pipeline').jsFilesToInject
            }
        },

        prodJs: {
            options: {
                startTag: '<!--SCRIPTS-->',
                endTag: '<!--SCRIPTS END-->',
                fileTmpl: '<script src="%s"></script>',
                appRoot: '.tmp/public'
            },
            files: {
                '.tmp/public/**/*.html': ['.tmp/public/min/production.min.js'],
                'views/**/*.html': ['.tmp/public/min/production.min.js'],
                'views/**/*.handlebars': ['.tmp/public/min/production.min.js']
            }
        },

        prodJsRelative: {
            options: {
                startTag: '<!--SCRIPTS-->',
                endTag: '<!--SCRIPTS END-->',
                fileTmpl: '<script src="%s"></script>',
                appRoot: '.tmp/public',
                relative: true
            },
            files: {
                '.tmp/public/**/*.html': ['.tmp/public/min/production.min.js'],
                'views/**/*.html': ['.tmp/public/min/production.min.js'],
                'views/**/*.handlebars': ['.tmp/public/min/production.min.js']
            }
        },

        devStyles: {
            options: {
                startTag: '<!--STYLES-->',
                endTag: '<!--STYLES END-->',
                fileTmpl: '<link rel="stylesheet" href="%s">',
                appRoot: '.tmp/public'
            },

            files: {
                '.tmp/public/**/*.html': require('../pipeline').cssFilesToInject,
                'views/**/*.html': require('../pipeline').cssFilesToInject,
                '.tmp/public/templates.js': require('../pipeline').jsFilesToInject,
                'views/**/*.handlebars': require('../pipeline').cssFilesToInject
            }
        },

        devStylesRelative: {
            options: {
                startTag: '<!--STYLES-->',
                endTag: '<!--STYLES END-->',
                fileTmpl: '<link rel="stylesheet" href="%s">',
                appRoot: '.tmp/public',
                relative: true
            },

            files: {
                '.tmp/public/**/*.html': require('../pipeline').cssFilesToInject,
                'views/**/*.html': require('../pipeline').cssFilesToInject,
                '.tmp/public/templates.js': require('../pipeline').jsFilesToInject,
                'views/**/*.handlebars': require('../pipeline').cssFilesToInject
            }
        },

        prodStyles: {
            options: {
                startTag: '<!--STYLES-->',
                endTag: '<!--STYLES END-->',
                fileTmpl: '<link rel="stylesheet" href="%s">',
                appRoot: '.tmp/public'
            },
            files: {
                '.tmp/public/index.html': ['.tmp/public/min/production.min.css'],
                'views/**/*.html': ['.tmp/public/min/production.min.css'],
                'views/**/*.handlebars': ['.tmp/public/min/production.min.css']
            }
        },

        prodStylesRelative: {
            options: {
                startTag: '<!--STYLES-->',
                endTag: '<!--STYLES END-->',
                fileTmpl: '<link rel="stylesheet" href="%s">',
                appRoot: '.tmp/public',
                relative: true
            },
            files: {
                '.tmp/public/index.html': ['.tmp/public/min/production.min.css'],
                'views/**/*.html': ['.tmp/public/min/production.min.css'],
                'views/**/*.handlebars': ['.tmp/public/min/production.min.css']
            }
        },

        // Bring in JST template object
        devTpl: {
            options: {
                startTag: '<!--TEMPLATES-->',
                endTag: '<!--TEMPLATES END-->',
                fileTmpl: '<script type="text/javascript" src="%s"></script>',
                appRoot: '.tmp/public'
            },
            files: {
                '.tmp/public/index.html': ['.tmp/public/jst.js'],
                'views/**/*.html': ['.tmp/public/jst.js'],
                'views/**/*.handlebars': ['.tmp/public/jst.js']
            }
        },

        devJsJade: {
            options: {
                startTag: '// SCRIPTS',
                endTag: '// SCRIPTS END',
                fileTmpl: 'script(src="%s")',
                appRoot: '.tmp/public'
            },
            files: {
                'views/**/*.jade': require('../pipeline').jsFilesToInject
            }
        },

        devJsRelativeJade: {
            options: {
                startTag: '// SCRIPTS',
                endTag: '// SCRIPTS END',
                fileTmpl: 'script(src="%s")',
                appRoot: '.tmp/public',
                relative: true
            },
            files: {
                'views/**/*.jade': require('../pipeline').jsFilesToInject
            }
        },

        prodJsJade: {
            options: {
                startTag: '// SCRIPTS',
                endTag: '// SCRIPTS END',
                fileTmpl: 'script(src="%s")',
                appRoot: '.tmp/public'
            },
            files: {
                'views/**/*.jade': ['.tmp/public/min/production.min.js']
            }
        },

        prodJsRelativeJade: {
            options: {
                startTag: '// SCRIPTS',
                endTag: '// SCRIPTS END',
                fileTmpl: 'script(src="%s")',
                appRoot: '.tmp/public',
                relative: true
            },
            files: {
                'views/**/*.jade': ['.tmp/public/min/production.min.js']
            }
        },

        devStylesJade: {
            options: {
                startTag: '// STYLES',
                endTag: '// STYLES END',
                fileTmpl: 'link(rel="stylesheet", href="%s")',
                appRoot: '.tmp/public'
            },

            files: {
                'views/**/*.jade': require('../pipeline').cssFilesToInject
            }
        },

        devStylesRelativeJade: {
            options: {
                startTag: '// STYLES',
                endTag: '// STYLES END',
                fileTmpl: 'link(rel="stylesheet", href="%s")',
                appRoot: '.tmp/public',
                relative: true
            },

            files: {
                'views/**/*.jade': require('../pipeline').cssFilesToInject
            }
        },

        prodStylesJade: {
            options: {
                startTag: '// STYLES',
                endTag: '// STYLES END',
                fileTmpl: 'link(rel="stylesheet", href="%s")',
                appRoot: '.tmp/public'
            },
            files: {
                'views/**/*.jade': ['.tmp/public/min/production.min.css']
            }
        },

        prodStylesRelativeJade: {
            options: {
                startTag: '// STYLES',
                endTag: '// STYLES END',
                fileTmpl: 'link(rel="stylesheet", href="%s")',
                appRoot: '.tmp/public',
                relative: true
            },
            files: {
                'views/**/*.jade': ['.tmp/public/min/production.min.css']
            }
        },

        // Bring in JST template object
        devTplJade: {
            options: {
                startTag: '// TEMPLATES',
                endTag: '// TEMPLATES END',
                fileTmpl: 'script(type="text/javascript", src="%s")',
                appRoot: '.tmp/public'
            },
            files: {
                'views/**/*.jade': ['.tmp/public/jst.js']
            }
        }
    });

    grunt.loadNpmTasks('grunt-sails-linker');
};

Lastly, my compileAssets.js file

   /**
 * `compileAssets`
 *
 * ---------------------------------------------------------------
 *
 * This Grunt tasklist is not designed to be used directly-- rather
 * it is a helper called by the `default`, `prod`, `build`, and
 * `buildProd` tasklists.
 *
 * For more information see:
 *   http://sailsjs.org/documentation/anatomy/my-app/tasks/register/compile-assets-js
 *
 */
module.exports = function(grunt) {
    grunt.registerTask('compileAssets', [
        'clean:dev',
        'copy:dev',
        "handlebars:dev",
        "sass:dev",
        "ts:dev",

    ]);
};

I have several .handlebars files underneath the views directory including layout.handlebars. The content is being rendered correctly; my style and scripts tags are simply not being injected.

Thanks much for any guidance.

1

1 Answers

0
votes

For sails linker to work, you need to make some changes in your handlebars layouts

In the head of the body add <!--STYLES--> and <!--STYLES END--> likes this

and add <!--SCRIPTS-->, <!--SCRIPTS END--> at the end of body

Then sails linker will be able to inject the styles and scripts to your layout.