1

I'm trying to get started learning BackboneJS but a bit stuck off the bat.

I'm using SailsJS as the backend framework. So far, I've generated a new sails project using my Mac terminal.

I've also added backbone to my package.json file and done:

npm install

In my sails project folder, I've added a file called "backbone.js" into the folder "js".

I've also added a new file called "dashboard.ejs" in my "views" folder.

My questions are:

  1. do I need to do var backbone = require('backbone'); inside my backbone.js file ?
  2. how do I include my backbone.js code into dashboard.ejs file? Do I use some sort of Grunt injection thing or do I manually type <script src="js/backbone.js"></script>

Update

I've manually copied the backbone-min.js file from my node_modules/backbone folder into my js/dependencies folder and re-ran:

sails lift

It injected the backbone-min.js into my HTML.

Is that the proper way to do it ?

It doesn't feel right to me........(that I have to manually copy backbone-min.js to the js/dependencies folder.)

Update 2

Also copied underscore-min.js to the js/dependencies folder and edited the pipeline.js file to inject the underscore-min.js first before backbone-min.js.

// 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',
  'js/dependencies/underscore-min.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'
];

My code seems to work now...

Update 3

Please see my answer below. I found a way to install, manage and automate injecting the front end libraries.

Zhang
  • 11,549
  • 7
  • 57
  • 87

1 Answers1

2

:)

Alright!

I some how managed to stumble on a decent solution that does what I want - automatically inject all the front end dependencies that I installed using a front end dependency manager so that when I run:

sails lift

My layout.ejs or index.html (whatever you want to use) automatically contains:

<script src="../bower_components/jquery/dist/jquery.js"></script>
<script src="../bower_components/underscore/underscore.js"></script>
<script src="../bower_components/backbone/backbone.js"></script>

In the correct location.

Hopefully this helps others who are on the same boat as me.

So I got it working using the following guides:

Important Note

Before anything else, please ensure your .sailsrc file looks like this:

{
  "generators": {
    "modules": {}
  },
  "hooks": {
  }
}

and NOT like this:

{
  "generators": {
    "modules": {}
  },
  "hooks": {
    "grunt": false // this line needs to be deleted
  }
}

That line prevents Grunt from doing its thing.

Stuff To Install First

So some important tools we'll need to install first:

  1. Bower (http://bower.io/)
  2. Grunt-Wiredep (https://github.com/stephenplusplus/grunt-wiredep)

Bower

Bower is the front end dependency manager that will fetch and install our front end libraries like jQuery and Backbone.

Install this first using:

[sudo] npm install -g bower

You might or might not need to use the sudo command in front of npm install depending on your computer setup.

The important thing to do now is to do:

bower init

This will take you through a command line setup of your bower.json file and generate it. I just press enter a few times to certain questions and choose 'y' for certain answers like automatically add commonly ignore files.

One last important bower step we need to do. Create a new file called .bowerrc and add this code:

{
    "directory": "assets/bower_components"
}

This tells bower where to install the "bower_components" folder when you run the command bower install.

The thing with SailsJS is the actual javascript, css and images are served from the .tmp/public folder, so if we had bower_components folder outside of the assets folder, our bower_components will not be copied to the .tmp/public folder. We'll get 404 Not Found errors later if we omit this step.

Grunt-Wiredep

Grunt-Wiredep is the tool that will help us inject the installed bower components (front end libraries like jQuery and Backbone) into our HTML templates layout files

We install this next after setting up the Bower manager. Install Grunt-Wiredep using:

[sudo] npm install --save-dev grunt-wiredep

Installing Our Frontend Javascript Libraries

OK, so now with Bower, we can install our javascript front end libraries using command:

bower install jquery --save

and

bower install backbone --save

This will install jQuery and Backbone libraries into the bower_components folder.

Our bower.json file should show:

{
  ...
  "license": "MIT",
  "ignore": [
    "**/.*",
    "node_modules",
    "bower_components",
    "test",
    "tests"
  ],
  "dependencies": {
    "jquery": "~2.1.4",
    "backbone": "~1.2.1"
  }
}

Notice how the dependencies section has two new entries for jquery and backbone respectively.

Bower Injection Point

Rightio, so all our important tools are installed. We now need to tell Wiredep where to inject our jQuery and Backbone tags.

In my case, I have a file called layout.ejs and I tell bower to inject the javascript libraries using:

    ...

    <!-- bower:js -->
    <!-- endbower -->

    <!--SCRIPTS-->
    <!--SCRIPTS END-->
  </body>
</html>

Please note the order of the injection placeholders which is important. Here, I've specified to inject our "bower" libraries like jQuery and Backbone BEFORE Sails default "jsToInject" files.

When I write my Javascript files, I put them inside the assets/js folder. I like to think of these javascript files as my "front-end logic javascripts" and NOT the javascript libraries like jQuery and Backbone.

So if I were to put the bower script placeholder after Sails's default SCRIPTS placeholder, I would get errors if I tried to use jQuery before the jQuery library was included:

Adding WireDep Grunt Task

I don't know how to explain what Grunt is, as far as I understand, it's what SailsJS use to automate tasks like copy javascript files, images, css to the appropriate folders.

One of the Grunt task we want SailsJS to do is inject the installed Bower components from the bower_components folder into our HTML files for us automatically, rather us manually typing it in.

So, first thing is create a new file called wiredep.js inside the tasks/config folder. My wiredep.js looks like this:

module.exports = function(grunt) {
    grunt.config.set('wiredep', {
        task: {
            // Point to the files that should be updated when
            // you run 'grunt wiredep'
            src: [
                'views/**/*.ejs',   // .html support...
            ],

            // we need this line so injection is correct path
            ignorePath: '../assets',

            options: {
                // See wiredep's configuration documentation for the options
                // you may pass:

                // https://github.com/taptapship/wiredep#configuration
            }
        }
    });

    grunt.loadNpmTasks('grunt-wiredep');
};

The important line in the above grunt task file is:

ignorePath: '../assets',

Wiredep searches for the location of the "bower_components" folder and uses that as the prefix for injecting our javascript libraries.

Recall earlier we told bower to install the bower_components folder in the assets folder so that Sails pipeline.js copies the content in the assets folder to the .tmp/public folder but this conflicts with Wiredep's default injection path prefix.

i.e. The default Wiredep inject will become:

// Sails does not serve files from the assets folder!
<script src="../assets/bower_components/backbone/backbone.js"></script>

We need it to become:

// bower_components is in the .tmp/public folder where Sails serves content
<script src="/bower_components/backbone/backbone.js"></script>

Grunt-Wiredep Injection

At this point, we can test to see if wiredep is injecting.

In my Mac terminal, when I run (at the root of my sailsjs project):

grunt wiredep

I can see in my layout.ejs (my Sailsjs template file), I have

<!-- bower:js -->
<script src="/bower_components/jquery/dist/jquery.js"></script>
<script src="/bower_components/underscore/underscore.js"></script>
<script src="/bower_components/backbone/backbone.js"></script>
<!-- endbower -->

Which is what we want.

If you delete the three lines of <script></script> tags that was injected in the above code and try running:

sails lift

You'll probably notice wiredep isn't injecting the javascript libraries. We definitely don't want to have to type grunt wiredep before we run sails lift every time.

Automate Grunt Wiredep Command

The last step is to automate grunt wiredep command so wiredep injects the javascript libraries automagically when we run sails lift.

We do this by registering the task in the file:

tasks/register/default.js

My default.js looks like this:

module.exports = function (grunt) {
    grunt.registerTask('default', ['wiredep', 'compileAssets', 'linkAssets',  'watch']);
};

Now after adding wiredep to the default tasks, when we run:

sails lift

We can inspect our layout.ejs file and see, once again, our javascript libraries are automagically injected into our HTML.

Community
  • 1
  • 1
Zhang
  • 11,549
  • 7
  • 57
  • 87