How to setup SyntaxHighlighter in Rails 3.1.1
Posted by Jim Morris on Sat Nov 12 01:36:29 -0800 2011
Or how to get Rails 3.1.1 assets in vendor/assets
to work in
production.
I find the new Assets stuff very tricky to make work in production, they seem to work fine in development, but after they have been precompiled and deployed all sorts of stuff goes wrong, eve though it works fine in development.
This Blog Engine uses SyntaxHighlighter to highlight the code snippets. Porting to Rails 3.1(.1) turned out to be tricky.
I initially put all the SyntaxHighlighter files in
/vendor/assets/syntaxhighlighter
as that is the recommended place to
put it. Then I used javascript_include_tag
to include the various
files I needed, and that worked fine in development, but in production
it doesn't work as vendor/assets
do not automatically get precompiled
into public/assets/application.js
nor do the subdirectories under
vendor/assets
get copied to public/assets
when precompiled.
As these scripts are needed for virtually all pages they can just as
well get put in application.js
, and that is how I got it to work.
The vendor tree looks like this...
vendor/
├── assets
│ └── syntaxhighlighter
│ ├── shAutoloader.js
│ ├── shBrushAppleScript.js
│ ├── shBrushAS3.js
│ ├── shBrushBash.js
│ ├── shBrushColdFusion.js
│ ├── shBrushCpp.js
│ ├── shBrushCSharp.js
│ ├── shBrushCss.js
│ ├── shBrushDelphi.js
│ ├── shBrushDiff.js
│ ├── shBrushErlang.js
│ ├── shBrushGroovy.js
│ ├── shBrushJavaFX.js
│ ├── shBrushJava.js
│ ├── shBrushJScript.js
│ ├── shBrushPerl.js
│ ├── shBrushPhp.js
│ ├── shBrushPlain.js
│ ├── shBrushPowerShell.js
│ ├── shBrushPython.js
│ ├── shBrushRuby.js
│ ├── shBrushSass.js
│ ├── shBrushScala.js
│ ├── shBrushSql.js
│ ├── shBrushVb.js
│ ├── shBrushXml.js
│ ├── shCore.css
│ ├── shCore.js
│ ├── shLegacy.js
│ ├── shThemeDefault.css
│ ├── shThemeDjango.css
│ ├── shThemeEclipse.css
│ ├── shThemeEmacs.css
│ ├── shThemeFadeToGrey.css
│ ├── shThemeMDUltra.css
│ ├── shThemeMidnight.css
│ ├── shThemeRDark.css
│ └── syntaxhighlighter.js
└── plugins
I added syntaxhighlighter.js
to the tree which contains this...
//= require ./shCore.js
//= require ./shBrushBash.js
//= require ./shBrushCpp.js
//= require ./shBrushCss.js
//= require ./shBrushDiff.js
//= require ./shBrushErlang.js
//= require ./shBrushGroovy.js
//= require ./shBrushJava.js
//= require ./shBrushJScript.js
//= require ./shBrushPerl.js
//= require ./shBrushPhp.js
//= require ./shBrushPlain.js
//= require ./shBrushPython.js
//= require ./shBrushRuby.js
//= require ./shBrushSass.js
//= require ./shBrushScala.js
//= require ./shBrushSql.js
//= require ./shBrushXml.js
Basically I include only the .js files I need.
Then I added the line //= require syntaxhighlighter
to
app/assets/javascripts/application.js
and it gets precompiled into
application.js
when deployed to production.
//= require jquery
//= require jquery_ujs
//= require jquery-ui
//= require syntaxhighlighter
//= require_tree .
This now works both in development and production.
The final pieces to get this to work are to add
:javascript
SyntaxHighlighter.all();
To the head (if you are using HAML) and add...
*= require shCore
*= require shThemeDefault
to app/assets/stylesheets/application.css
.
Obviously you can specify whatever theme you want.
I would still like to know the best way to include the syntax
highlighter files only in specific pages, I know how to do it in the
pre-assets era, but now it seems everything needs to be precompiled
somewhere, and I don't see a way to get a syntaxhighlighter.js
precompiled and copied into public/assets
so I can just do a
javascript_include_tag 'syntaxhighlighter'
in specific view pages.
One way I guess is to modify config/environments/production.rb
by
adding
config.assets.precompile += %w( syntaxhighlighter.js )
but it seems a little ugly.
The point of including it all the time is that the file gets downloaded once and cached in the web browser for subsequent calls. If you had it compile and download a different subset for different pages, you would force the browser to constantly download new js every time, making it slower.
Yes true, if the javascript and css is needed on every page it is an advantage, and in this case that is true, which is why the above method is probably the best solution. However there are cases where you only want some javascript loaded (or css) with a specific page. It is briefly mentioned in the rails guides on assets, but with no examples or details. An example is in my post on authentication, where I only want to load the auth.js and sha1.js when the login page is loaded. I show a solution there.
This post is more to show how to get js and css in vendor/assets to work in production, which is not documented anywhere I can find.