Webpacker: Loading scss.erb

Created on 9 Jan 2018  路  5Comments  路  Source: rails/webpacker

Hi!
i have a problem, i can't load my variables from .scss.erb files.

ERROR in ./app/themes/theme1/assets/stylesheets/theme1/variables.scss.erb
Module parse failed: Unexpected token (3:5)
You may need an appropriate loader to handle this file type.
| 
| 
| body {
|   background: blue!important;
| }

The source file contains:

<% color = 'blue' %>

body {
  background: <%=color%>!important;
}

So .erb works, but webpack cannot load it.

js.erb works well after bundle exec rails webpacker:install:erb

How can i fix this problem with scss.erb?

Most helpful comment

This is an old thread, but i had to deal with this problem recently, and it's still number one google result for webpacker scss.erb query.

After struggling for a while, based on @gauravtiwari lead:

// default bundle exec rails webpacker:install:erb

// loaders/erb.js
module.exports = {
  test: /\.erb$/,
  enforce: 'pre',
  exclude: /node_modules/,
  use: [{
    loader: 'rails-erb-loader',
    options: {
      runner: (/^win/.test(process.platform) ? 'ruby ' : '') + 'bin/rails runner'
    }
  }]
}

// environment.js
environment.loaders.prepend('erb', erb)

As stated this works out of the box for .js.erb, not for (scss|sass).erb

My attempt to ship it

// loaders/sass-erb.js
const { environment } = require('@rails/webpacker');
const erbLoader  = require('./erb');
const sassLoaders = environment.loaders.get('sass').use

module.exports = {
  test: /\.(scss|sass)(\.erb)$/i,
  enforce: 'pre',
  exclude: /node_modules/,
  use: [
    ...sassLoaders,
    erbLoader.use[0]
  ]
}

// environment.js
environment.loaders.prepend('erb', erb)
+ environment.loaders.insert('sass-erb', sassErb, { before: 'erb'} )

This seems to be working, although not extensively tested.
It still looks like some duplication here. Maybe there's a more webpackish/clean way of doing this.

Hope it helps anyone who lands here.
Cheers 鉁岋笍

All 5 comments

@timonbandit Ahh seems like you need to add erb-loader in front of sass loader. From the log it looks like erb loader is compiling it correctly but then it doesn't know which loader to hand off afterwards?

You may need an appropriate loader to handle this file type.
| 
| 
| body {
|   background: blue!important;
| }

You could use sass variables though no?

This is an old thread, but i had to deal with this problem recently, and it's still number one google result for webpacker scss.erb query.

After struggling for a while, based on @gauravtiwari lead:

// default bundle exec rails webpacker:install:erb

// loaders/erb.js
module.exports = {
  test: /\.erb$/,
  enforce: 'pre',
  exclude: /node_modules/,
  use: [{
    loader: 'rails-erb-loader',
    options: {
      runner: (/^win/.test(process.platform) ? 'ruby ' : '') + 'bin/rails runner'
    }
  }]
}

// environment.js
environment.loaders.prepend('erb', erb)

As stated this works out of the box for .js.erb, not for (scss|sass).erb

My attempt to ship it

// loaders/sass-erb.js
const { environment } = require('@rails/webpacker');
const erbLoader  = require('./erb');
const sassLoaders = environment.loaders.get('sass').use

module.exports = {
  test: /\.(scss|sass)(\.erb)$/i,
  enforce: 'pre',
  exclude: /node_modules/,
  use: [
    ...sassLoaders,
    erbLoader.use[0]
  ]
}

// environment.js
environment.loaders.prepend('erb', erb)
+ environment.loaders.insert('sass-erb', sassErb, { before: 'erb'} )

This seems to be working, although not extensively tested.
It still looks like some duplication here. Maybe there's a more webpackish/clean way of doing this.

Hope it helps anyone who lands here.
Cheers 鉁岋笍

@renatodeleao I'm trying to implement your solution, but I'm getting sass-loader error when attempting to parse the erb syntax in my scss file. It seems that sass-loader is trying to run before erb has a chance to convert it. Any ideas?

I see now that this solution doesn't work if the scss.erb file is imported from another .scss file.

Hey @sspread , as mentioned i didn't test this extensively, but i'm glad you find the cause :)

Since you can import .scss files in .js another workaround is just to rename manifesto.scss.js. Actually if you have big manifesto files, as in, sass files that import a lot of other sass modules, it's actually better for webpack compile performance: In sass every import is just injected text at the top of a file, so a save in a "manifesto's module" will trigger all the other files compilation; on the other hand at a .js file each sass import is treated as separate module, and a change in one module doesn't affect the other modules in the manifesto.

Hope it had help you someway. 鉁岋笍

Was this page helpful?
0 / 5 - 0 ratings