permalink

38

Custom Sublime Text Build Systems For Popular Tools And Languages

Sublime Text is currently the text editor of choice for a number of developers in the open-source community. It’s sophisticated, has powerful text selection and customization support and also includes a feature not used by many – its build system. In this post, I’d like to take you through the Sublime build system and share build scripts for working with many of the languages and tools we use today.

These will include scripts for Grunt, CoffeeScript, SASS and others.

Introduction

Sublime Text build systems can be considered simplistic, but highly customizable. The basic idea is that each type of Build profile is powered by a “.sublime-build” file – a JSON representations of the commands, paths and configuration needed to build a project using a specific tool or set of tools.

Builds can be executed using a keyboard shortcut (Command+B on Mac is the default on Mac or F7 on Windows), via the Tools menu or when a file is saved. If a project is currently open, the build system we last selected (e.g grunt) will be remembered.

When Sublime is passed references to external tools/binaries via a “.sublime-build” files, it can execute these applications with any arguments or flags that may be necessary. It is also able to pipe back the output of calling any of these apps using the built-in console in Sublime. Effectively this allows us to easily build projects without the need to leave our editor.

Adding a custom Build System

Sublime populates its Tools/Build System menu based on the “.sublime-build” files stored in the Sublime “Packages” directory. Should one need to locate this, it can be found in “~/Library/Application Support/Sublime Text 2/Packages/User” (if using OS X) or the corresponding Packages/User directory on other platforms.

A basic “.sublime-build” file could be represented in key/value form as follows:

{
    "cmd": ["command", "argument", "--flag"],
    "selector": ["source.js"],
    "path": "/usr/local/bin",
    "working_dir": "/projects/"
}

Keys supported include:

  • cmd - An array containing a command to run and its desired arguments and flags. Note that Sublime will search your PATH for any tools listed unless an absolute path has been used to point to them.
  • selector – An optional string used to locate the best builder to use for the current file scope. This is only relevant if Tools/Build System/Automatic is true.
  • path – An optional string that replaces your current process’s PATH before calling the commands listed.
  • working_dir – An optional string defining a directory to switch the current directory to prior to calling any commands.
  • shell - An optional boolean that defines whether commands should be run through the shell (e.g bash).
  • file_regex – An optional regular expression used to capture error output from commands.

For a comprehensive list of keys supported in Sublime build scripts, see the unofficial docs.

Build Variables:

In addition, Sublime supports variable substitutions in build files such as $file_path (for the path to the current file) and more. These include:

  • $file_path – the directory of the current file being viewed
  • $file_name - only the name portion of the current file (extension included)
  • $file_base_name - the name portion of the current file (extension excluded)
  • $project_path - the directory path to the current project
  • $project_name – the name portion of the current project

A complete list of substitutions supported is also available.

Grouping build tasks

Some developers also like to group together tasks within an external bash script (or equivalent). For example, here’s a simple git-ftp deploy script you can use with Sublime to commit and push your latest changes with git and then upload your latest files to FTP.

Example: Commit, Push And Upload To FTP

deployment.sh:

#!/bin/bash
git add . && git commit -m 'deployment' && git push && git ftp init -u username  -p password - ftp://host.example.com/public_html

deployment.sublime-build:

{
  "cmd": ["deployment"],
  "working_dir": "${project_path:${folder}}"
}

If you haven’t used git-ftp before, Alex Fluger has a solid article about using it that may be of interest.

Targeting Platforms:

Sublime build files also support specifying configuration data for specific platforms (namely, OS X, Windows and Linux). Targeting a platform can easily be done by specifying another element in our config with the name of the platform. e.g

{
    "cmd": ...
    ...
    "windows":
    {
        "cmd":  ...
    },
    "osx":
    {
            "cmd": ...
    },
    "linux":
    {
            "cmd": ...
    }
}

Build files for popular front-end tools

To help you get started, I’ve written a collection of “.sublime-build” files for some of the front-end tools I’m aware web developers are using these days below.

Most of these will function fine without the need to specify path, but if you run into an issue with paths, try including it to your config (e.g "path": "/usr/local/bin").

grunt:

{
    "cmd": ["grunt", "--no-color"],
    "selector": ["source.js", "source.less", "source.json"]
}

Node Build Script:

{
    "cmd": ["h5bp", "--no-color"],
    "selector": ["source.js", "source.less", "source.json"]
}

CoffeeScript:

{
    "cmd": ["coffee","-c", "$file"],
    "selector" : "source.coffee"
}

SASS:

{
    "cmd": ["sass", "--watch", ".:."],
    "working_dir": "$file_path",
    "selector": ["source.scss", "source.sass"]
}

Whilst a more verbose version with automatic minification and watch config could be written:

{
    "cmd": ["sass", "--watch", "sass:stylesheets", "--style", "compressed"],
    "working_dir": "$project_path",
    "selector": ["source.scss", "source.sass"]
}

LESS:

{
    "cmd": ["lessc", "-x", "$file", "$file_path/$file_base_name.css", "--verbose"],
    "shell" : true,
    "selector": "source.css.less"
}

Stylus:

{
    "cmd": ["stylus", "$file"],
    "file_regex": ".",
    "selector": "source.stylus"
}

(a more comprehensive version of this can be found in the LESS-build-sublime project.)

Jade:

{
   "cmd": ["cmd", "/c", "jade", "$file"],
   "selector": "source.jade"
}

r.js (RequireJS Optimizer):

{
    "cmd": ["node", "r.js", "-o", "app.build.js"],
    "working_dir": "$project_path",
    "selector": "source.js"
}

UglifyJS:

{
   "cmd": [ "node", "uglifyjs", "-o", "${file_path}/${file_base_name}.min.js", "$file"],
   "selector": "source.js"
}

Node (just passing in directly):

{
     "cmd": ["node", "$file"],
     "file_regex": "^[ ]*File \"(...*?)\", line ([0-9]*)",
     "selector": "source.js"
}

Pandoc (Markdown to HTML):

{
    "cmd": ["pandoc", "-S", "-s", "-f", "markdown", "-t", "html", "-o", "$file_base_name.html", "$file"],
    "selector": "text.html.markdown"
}

(and when it’s released, Yeoman):

{
     "cmd": ["yeoman", "build", "--no-color"],
     "selector": ["source.js", "source.scss", "source.sass", "source.html"]
}

JSHint:

I imagine most web developers would want to run JSHint from within a broader build process, but if you’d also like to run it standalone via a Sublime build file, the sublime-jshint package has a build file that will work fine on both OS X and Windows.

Build files for specific programming languages

I also thought that while we were looking at build files, it would be useful to demonstrate how these can be used to build/compile with some popular programming languages. These may differ to those included with Sublime by default, but are useful for reference:

Ruby (using RVM):

{
    "cmd": ["~/.rvm/bin/rvm-auto-ruby", "$file"],
    "file_regex": "^(...*?):([0-9]*):?([0-9]*)",
    "selector": "source.ruby"
}

Python:

{
    "cmd": ["python", "-u", "$file"],
    "file_regex": "^[ ]*File \"(...*?)\", line ([0-9]*)",
    "selector": "source.python"
}

PHP:

{
    "cmd": ["/usr/bin/php", "-l", "$file"], <- Couldn't just use "php" ?
    "file_regex": "^Parse error: .* in (.*?) on line ([0-9]*)",
    "selector": "source.php"
}

Java:

{
    "cmd": ["javac", "$file_name", "&&", "java", "$file_base_name"],
    "working_dir": "${project_path:${folder}}",
    "selector": "source.java",
    "shell": true
}

.Net (Windows):

{
    "cmd": ["%WINDIR%\\Microsoft.NET\\Framework\\v4.0.30319\\msbuild", "${project_base_name}.sln"],
    "shell": true,
    "working_dir": "${project_path:${folder}}"
}

C:

{
    "cmd": ["make && ./a.out"],
    "path": "/usr/bin:/usr/local/bin:...",
    "shell": true
}

C++ (via g++):

(Note that we’re also able to specify OS-specific configurations too, as in the below):

{
    "cmd": ["g++", "$file", "-o", "$file_base_name", "-I/usr/local/include"],
    "selector": "source.c++",
    "windows": {
       "cmd": ["cl", "/Fo${file_path}", "/O2", "$file"]
    }
}

Haskell:

{
    "cmd": ["runhaskell", "$file"],
    "file_regex": "^(...*?):([0-9]*):?([0-9]*)",
    "selector": "source.haskell"
}

Conclusions

Sublime build systems are awesome and can help you avoid the need to manually switch between your editor and external build tools regularly. As you’ve hopefully now learned, putting together your own custom build systems is a straight-forward process and I’d recommend trying it out if Sublime happens to be your editor of choice.

(Technically reviewed by Sindre Sorhus)

38 Comments

  1. Nice article again Addy, have been suing Sublime for sometime with build system and it’s awesome, left using the old IDE (WebStorm)

    Thanks for the “.sublime-build” files collection, just added to my Sublime Text, going to play around soon.

  2. Thanks for the list! This will help a lot, and keep me from needing to setup a watch script on every folder with a compiled language.

    I’m using Google Closure templates here at work, and so I’ve got a ST2 build system that we use frequently shared here: https://gist.github.com/3381516

  3. The java build isn’t working. I’ve heard that it’s not possible to compile and then run from a single build, that you need a shell script of some sort to make it work. Could you please look into it?

  4. the automatic build selecting doesn’t seem to work for me, with multiple extensions
    “selector”: ["source.scss", "source.sass"]

    only works with one:
    “selector”: “source.scss”

  5. The –no-color flag for grunt was exactly what I needed! It had always annoyed me that the color flags showed up in the Sublime console.

    “(and when it’s released, Yeoman)”

    Addy you big tease! Any further details on when this is likely to be released?

  6. Pingback: Rounded Corners 394 — One does not simply cancel a print job /by @assaf

  7. I have been trying to run the build configuration you have above on Windows XP. It’s having some really odd behaviors. I made an example project with grunt init:jquery. Then cd to the project, do grunt. It will open up grunt.js for me instead of executing grunt.js. It won’t have this behavior if i run grunt command in bash on windows.

    Does the build script intend to work without modifications?
    I’m getting either
    [Error 2] The system cannot find the file specified
    [cmd: [u'grunt', u'--no-color']]
    [dir: C:\develop\gruntjs\try\src]
    or [Error 6] The Handle Is Invalid.
    I’m not sure if this is a grunt running on windows issue or a sublime cmd issue on windows.

  8. Sorry to use this space as a help desk but this issue is driving me crazy!

    On Win7, the Pandoc build throws this: [Decode error - output not utf-8]; however, using Pandoc with the same parameters in a command prompt works.

    Any ideas how to solve this?

    I’ve tried adding “encoding”: “utf8″ without success. Sublime’s forum has some threads regarding similar issues, but the ‘solutions’ are unrelated or there is no response. What’s more, I’ve experimented with all the variants that I could find to this build, but unsurprisingly all gave the same error.

    And that’s how I’ve stumble at this post, and why I’m begging for some guidance.

  9. Nothing like a good night of sleep to help solve this kind of problems.

    I’ll leave the solution here just in case:

    1) Run ‘chcp’ in a command prompt, it’ll return the page code (eg. 850);

    2) Edit the “.sublime-build”, adding “encoding”: “cp850″ (as per example).

  10. Can you specify more than one cmd? I have tried this but it only fires nodemon

    “cmd”: ["nodemon", "--debug", "$project_path/app.js", "&", "node-inspector"],

  11. UPDATE: I have this working like so:

    “shell”: true,
    “cmd”: ["nodemon --debug $project_path/app.js & node-inspector"],

  12. Addy is happening to me an error when I try to compile. SCSS

    [Error 2] The system can not find the file specified
    [cmd: [u'sass ', u'- watch' u '.:.']]

    I need to install the ruby something? Thank you.

  13. Regarding the grouping build tasks example “Commit, Push And Upload To FTP”

    git add . && git commit -m ‘deployment’ && git push && git ftp init -u username -p password – ftp://host.example.com/public_html

    Am I mistaken or should it be git ftp push and not init ? You do have to do your initial git ftp but after that you should be continually doing pushes to the ftp server, correct ?

  14. Howdy very nice site!! Guy .. Excellent .. Wonderful .

    . I will bookmark your site and take the feeds additionally?
    I’m satisfied to find so many useful information here within the post, we want work out more strategies on this regard, thanks for sharing. . . . . .

  15. I think that is among the most important info for me.
    And i’m glad studying your article. But wanna remark on some normal issues, The site style is ideal, the articles is truly nice : D. Excellent job, cheers

  16. Hello,
    How can I navigate to this directory (/usr/local/CrossPack-AVR/bin) to run those commands:
    avr-gcc -mmcu=atmega328p -Wall -Os -o main.elf main.c
    avr-objcopy -j .text -j .data -O ihex main.elf main.hex

    Thanks

  17. Hey, i know this post is a little outdated but, i can’t call “cmd” 2 two times. Sublime just run one and ignores the other. How can i run two programs at the same time on Sublime Text Build Systems?

    • What is supported is just a concatenation of the elements in the array, separated by spaces. This means you can enter multiple commands, with a separator that your OS understands. You should also be able to do `shell:true` and use `&&` to pass multiple commands:

      {
         "shell":true,
         "cmd":["check.sh $file_path && make PROJECTNAME+=$file_base_name install"]
      }
      

Leave a Reply

Required fields are marked *.