User Tools

Site Tools


Action disabled: register
entwine:a_simple_grunt_task

A Simple Grunt Task

Now that we have all the setup done, let's set up a Grunt task. In this example, and all the later ones, we'll assume you have a terminal window open at the top level of your project folder. If you're not sure how to do that, double-check Setting Up a Project.

For starters, let's say you want to get a Twine story you've been editing into the src folder – let's say it's called “My Story.” To do this, we'll need another Grunt plugin to help. Type npm install --save grunt-contrib-copy in your terminal window and press Enter. As you might guess from its name, this plugin copies files from one place to another.

Editing the Gruntfile

Now, we'll need to create a file named Gruntfile.js. This file is where we tell Grunt about the tasks we want it to run for us. Grunt always looks for this file name, with this capitalization, at the top level of your project folder.

Let's start with the bare minimum for a working Gruntfile. In this example, and any others, you don't need to retype what's on the page. Just select the filename tab and it'll download to your computer.

Gruntfile.js
module.exports = function(grunt) {
  require('load-grunt-tasks')(grunt);
};

Now type grunt in your terminal window and press Enter. If everything is correct, then Grunt will respond:

Warning: Task "default" not found. Use --force to continue.

Aborted due to warnings.
  • If instead you see A valid Gruntfile could not be found, then make sure your Gruntfile.js is named correctly, and at the top level of your project, not in src.
  • If instead you see » SyntaxError: missing ) after argument list or anything starting with SyntaxError, double-check the contents of Gruntfile.js. It's likely you are missing a parenthensis or other punctuation.

Even though our Gruntfile is valid, Grunt still gives us a warning because we haven't actually defined any tasks yet. We'll fix that in a moment, but first a quick discussion of what's in this file. Although you can treat this as boilerplate, it can be helpful to understand what's going on, even at a basic level.

A Gruntfile always exports a single function to the outside world – that's what line 1 does. If you're not familiar with JavaScript functions, think of them as just a set of steps that are performed in sequence. Grunt calls this function as part of its setup process. The second line uses a helper module, load-grunt-tasks that does the drudgework of setting up any Grunt plugins we are using. In this case, it makes Grunt aware of the grunt-contrib-copy plugin that we installed.

Adding a Task

Now, let's define a task. Replace your Gruntfile with:

Gruntfile.js
module.exports = function(grunt) {
  require('load-grunt-tasks')(grunt);
 
  grunt.initConfig({
    copy: {
      fromTwine: {
        src: '/Users/Me/Documents/Twine/Stories/My Story.html',
        dest: 'src/'
      }
    }
  });
 
  grunt.registerTask('default', ['copy']);
};

Now, when you run grunt, it should say:

Running "copy:fromTwine" (copy) task


Done.

But nothing will be copied just yet. Before we talk about why, let's talk about what we've added in this version.

grunt.initConfig() is the heart of a Gruntfile. It'll be where we define most of our tasks. It always takes a single JavaScript object as an argument. The object's top-level properties correspond to the Grunt plugins we have installed. In this case, the grunt-contrib-copy plugin uses the copy property for its tasks. Inside that property, we define the individual tasks that make use of the plugin. We only have one, called fromTwine, but you can have as many as you like. Inside the fromTwine task, we say what we want to copy (the src property) and where it should go (the dest property).

Then we define the default task. The task named default is run if you just type grunt, as we have been doing. (If you'd like to run a specific task, you could type grunt copy:fromTwine, or if you'd like to run all tasks belonging to a plugin, grunt copy.)

The reason why we write grunt.registerTask('default', ['copy']) instead of grunt.registerTask('default', 'copy') is that it's possible to make the default task run several tasks in sequence. For example, if we wanted to copy several files than run the tasks belonging to an imaginary plugin named printFiles by default, we could write grunt.registerTask('default', ['copy', 'printFiles']) instead.

It's OK if you don't follow this completely right away. As we go through other examples of Gruntfiles, these ideas will become clearer.

Actually Copying a File

The reason right now why nothing is happening is that we haven't given Grunt the complete path to your Twine story file. To do that, open Twine and choose Show Library from the Twine menu. This will open the folder on your computer where Twine automatically saves your stories as you work. Update Gruntfile.js with this path. On OS X and Linux, it will look similar to the example above:

Gruntfile.js
module.exports = function(grunt) {
  require('load-grunt-tasks')(grunt);
 
  grunt.initConfig({
    copy: {
      fromTwine: {
        src: '/Users/Me/Documents/Twine/Stories/My Story.html',
        dest: 'src/'
      }
    }
  });
 
  grunt.registerTask('default', ['copy']);
};

On Windows, it'll look more like:

Gruntfile.js
module.exports = function(grunt) {
  require('load-grunt-tasks')(grunt);
 
  grunt.initConfig({
    copy: {
      fromTwine: {
        src: 'C:/Users/Me/Documents/Twine/Stories/My Story.html',
        dest: 'src/'
      }
    }
  });
 
  grunt.registerTask('default', ['copy']);
};

If you are using Windows, you should always change the backslashes (e.g. \) in paths to forward slashes (e.g. /) when using Grunt.

If your Gruntfile is set up correctly, running grunt will say:

Running "copy:fromTwine" (copy) task
Copied 1 file

Done.

Congratulations! You've got the basics down.

How did we know about grunt-contrib-copy, and that it was looking for src and dest properties? Grunt maintains a searchable plugin registry of its own. Chances are, for whatever task you can think of, there is a Grunt plugin to help you.
entwine/a_simple_grunt_task.txt · Last modified: 2017/10/09 20:39 (external edit)