Asset pipelining

With the new v4 the asset pipelining was changed.

I tried to import the sprockets gem without being able to use it.
Every time I reference the sprokects.method in the code I get a sprockets variable name has not been initialised.

If I do activate it, an exception for double reference is raised.

Anybody so kind to post some guidelines on how to do the asset pipelining in v4?

I simply need multiple CSS or JS to be grouped into one file as I was doing in v3.

Many thanks
Andrea

+1 Perhaps I’m not looking in the right place, but I haven’t found any useful documentation on how the new external pipeline works. The two examples provided in the docs are understandable, but doesn’t go into detail about what options/arguments exist.

@andrea_moro So far, I’ve been writing my CSS as sass partials in the ‘stylesheets’ directory. For example if you have two sass partials, stylesheets/_foo.scss and stylesheets/_bar.scss, I @import them in site.css.scss, which get automatically compiled by MM into a single css file.

Thanks @sksea I’ve figured out this the other day, though I haven’t had time to update my answer. Glad you topped up with your comment, in the hope somebody else will find this useful.

To continue using sprockets in v4 you need to do the following :

In Gemfile

gem "middleman-sprockets", github: "middleman/middleman-sprockets",      branch: "master"

In Config.rb

# Sprockets
activate :sprockets

after_configuration do
    sprockets.append_path File.join( root, "bower_components/" )
end

in main.scss you can either @import or use the sprockets

//= require "_bower"

in JS

//= require jquery/dist/jquery.min

You can also find an example of Webpack being used in the middleman guides site @

Although I am still learning these techniques and they do not cover the SCSS part as of yet.

Would be nice if Middleman documented one full proof asset management tool in the docs - and I think they should still document the sprockets methods even though its being removed.

1 Like

I’ve got external pipeline working well using Gulp.js.

You can download a gulp-ized version of a (mostly) default middleman init project here: https://github.com/NathanBowers/mm-template/releases/tag/v1.0.0

Note that I’ve locked the MM gem to 4.1.2 because there’s apparently a bug in 4.1.3 with external pipeline and Gulp. https://github.com/middleman/middleman/issues/1844

Another thing is you’ll likely need to increase BrowserSync’s reloadDelay: 200 to 500 or more.

1 Like

How are you handling front end dependancies like Bootstrap or Font Awesome ? Through NPM or Bower? Would be great to expand your template to include loading in a couple of these.

many thanks

I don’t use bootstrap or font awesome. Imagine there are plenty of resources on how though.

There aren’t :frowning:

I’m trying to play with with Middleman today. It’s very frustrating that something that trivial as installing jQuery and bootstrap is so painful. Also, since there is a folder ‘javascripts’ I would assume that other files in this folder would get included in all.js. But they don’t… kinda wtf moment.

@AndreiMotinga @andrea_moro I’m a recent convert from Jekyll after spending a day wrestling with Jekyll’s latest release and pipelined assets. Long story short, Jekyll 3 + jekyll-assets + a site containing Compass libraries proved to be a massive time sink.

I was also a bit surprised to read the following in the Middleman docs:

The Rails Asset Pipeline has been removed from the core of Middleman v4. Its future is in flux. If you heavily rely on this feature, we are looking for community maintainers to keep it running in v4. Please contact us.

Sprockets is such a mature and well developed platform that I can’t imagine managing assets without it. While the Middleman docs weren’t explicit in explaining this approach, I find tremendous value in using rails-assets.org [Rails Assets is the frictionless proxy between Bundler and Bower] to manage Bower-based assets through my existing Gemfile, and then letting the asset pipeline handle the rest.

Here’s what worked quickly and easily for me on a new Middleman 4 site:

  1. Go to rails-assets.org and identify your dependency and version. Chances are it’s already there; rails-assets then packages your dependency as a gem on demand for consumption by Bundler.

  2. In Gemfile, add sprockets and a rails-assets block with the gemfiles chosen from step 1:

# Gemfile
gem 'middleman-sprockets', '4.0.0.rc.3'

source 'https://rails-assets.org' do
  gem 'rails-assets-bootstrap-autohidingnavbar', '1.0.0'
  gem 'rails-assets-jquery', '2.1.1'
  gem 'rails-assets-slick.js', '1.5.7'
end
  1. In your config.rb, add the following block to enable the asset pipeline and add RailsAssets gems to your load path:
# config.rb
# General configuration
activate :sprockets

if defined? RailsAssets
  RailsAssets.load_paths.each do |path|
    sprockets.append_path path
  end
end
  1. run bundle install

  2. Add the necessary import statements to your site.css.scss and all.js files. Note that rails-assets may suggest a sprockets //= slick.js import statement, but if the library is packaged with SASS, you likely want to use a SASS import @import "slick.js"; instead.

Relative to a completely separate infrastructure for managing frontend dependencies, I don’t know what could possibly be easier.

The only issues I’ve run into are edge cases where the assets are not packaged in a traditional way, or if I only need a subset of the library’s functionality. In those cases, a quick

cd `bundle show gemname`

and opening up the library in my text editor shows me the necessary path & file information. In the example above, since slick.js ends with .js, make sure you specify the javascript import as //= require slick.js.js

Finally, note that you can still use traditional hand-packaged gems like bootstrap-sass and font-awesome-sass in your Gemfile as well. Here’s a complete Gemfile for reference:

# If you do not have OpenSSL installed, change
# the following line to use 'http://'
source 'https://rubygems.org'

# For faster file watcher updates on Windows:
# gem 'wdm', '~> 0.1.0', platforms: [:mswin, :mingw]

# Windows does not come with time zone data
# gem 'tzinfo-data', platforms: [:mswin, :mingw, :jruby]

# Middleman Gems
gem 'middleman', '>= 4.0.0'
gem 'middleman-livereload'
gem 'middleman-compass', '>= 4.0.0'
gem 'middleman-sprockets', '4.0.0.rc.3'

gem 'bootstrap-sass'
gem 'font-awesome-sass'

source 'https://rails-assets.org' do
  gem 'rails-assets-bootstrap-autohidingnavbar', '1.0.0'
  gem 'rails-assets-jquery', '2.1.1'
  gem 'rails-assets-slick.js', '1.5.7'
end

Long live sprockets!

5 Likes

Thank you for mentioning rails-assets! Looking forward to using this.

How would one switch to sassc? Is sass a part of middleman-sprockets?

Edit: middleman-sprockets already uses sassc :slight_smile:

Wow, it really works. Thanks for making my day!

@andreimoment @lawso017 @iwarner

Really old conversation I know, but I couldn’t find time to get this solved last time, and by attempting now I still get problems.

Regardless of the different settings I have tried (e.g. changing the js_dir path) as soon as I add a line like this sprockets.append_path File.join( root, "bower_components/" ) my site stops working.

It seems like all the .js files are attempted to be parsed by the sprocket engine somehow producing errors like the one below.

jquery.min.js:1 Uncaught Error: Sprockets::FileNotFound: en/js/jquery.min.js
  on line 37 of /Users/andreamoro/.rbenv/versions/2.3.1/lib/ruby/gems/2.3.0/bundler/gems/middleman-sprockets-9b77b2b56d28/lib/middleman-sprockets/resource.rb)
    at jquery.min.js:1

And strangely I have also one .css file for which an error is thrown.

Any idea?

Would you mind posting the source code on GitHub, so it is easier to help you debug the problem?

Don’t really use Git and to create a smaller testing site it would take a while. Not that I don’t want to share though.

By the time I add the activate :sprockets (and nothing else), and the gem reference gem "middleman-sprockets", "~> 4.1.0" as far as I’ve seen every hit to a .js file doesn’t work anymore.
And this is neither related how the file is referenced nor its content. In fact, simply hitting a .js in the address bar return something like

throw Error("Sprockets::FileNotFound: en/js/all.js\n on line 37 of /Users/andreamoro/.rbenv/versions/2.3.1/lib/ruby/gems/2.3.0/gems/middleman-sprockets-4.1.0/lib/middleman-sprockets/resource.rb)")

Content of all.js file is as simple as //= require "_imageSupport", but even a proper js file with real script raise the same exception.

No idea what to do.

The most annoying part is that I have just created a blank new project to see whether I would have been able to reproduce.
Unfortunately on the new project everything works fine.

Any idea on what I could do to debug @vvasabi?

OK, I nailed it down!

The problem exist when the :js_dir is mapped out to something different. In my case I had to move the javascript folder underneath the content folder for a project running with the i18n, so to have the full set of files available in the different versions of the site.

I updated a demo site below to demonstrate the problem.
https://github.com/andreamoro/middleman-sprockets-test

Suggestions are welcome

I cloned the repo and was able to reproduced the problem after uncommenting this line:

set :js_dir, config[:dir] + 'javascripts'

I had to comment out these 2 lines since the function did not exist within the repo:

moveJSDir('en', false)  
moveJSDir('it', true)

The problem went away after I changed this line in site.js:

//= require _socialButtonsInit.js

to:

//= require ./_socialButtonsInit

Hope this helps.

Thanks @vvasabi.

I had a look into it, and even on my existing git I can’t get sprocket “generating” the error anymore as well as the expected result.

In any case, provided it was a fault of mine in adding the .js extension, could you point out on why the ./ in front of the file declaration played a role on your end?

Isn’t the ./ telling middleman to look at the file in the source/javascript folder? If so, that’s not what I need. I need the file to be looking into the source/en/javascript.
This is for simplicity at the deployment time, because my /en and /it subfolders will be hosted in two separate environments, hence I need all files grouped.

./ makes Sprockets look for the required file from where the file that needs it is, thus solving the FileNotFound issue. Otherwise, Sprockets will look for the required file from the js_dir that you configure and, if that fails, all the include paths you configure via sprockets.append_path.

.js extension is optional and can be omitted. It does not break or fix your particular issue.

I looked at the GitHub issue you have created, and I am wondering if the JS files at both /en and /it sites will actually have the same content. If so, it might be better to keep the configuration simple and just copy files to /en and /it folders after build.