Search code examples
ruby-on-railssprocketsyarnpkgwebpackeruglifier

After adding yarn and webpacker several errors in precompilation


I recently added webpacker and yarn to a rails 5 application and executed bundle exec webpacker:install:react.

This installed a plenty of dependency and I getting the several errors while running bundle exec rake assets:precompile RAILS_ENV=production RAILS_SERVE_STATIC_FILES=enable SECRET_KEY_BASE=$(bundle exec rake secret)

uglifier 4.1.5
rails 5.1.4
ruby-2.4.0
yarn 1.3.2
node 9.4.0

My config/initializers/assets.rb

# ...
Rails.application.config.assets.paths << Rails.root.join('node_modules')
Rails.application.config.assets.precompile += %w(*.js *.scss)
Rails.application.config.assets.precompile += %w(*.png *.woff2 *.woff *.ttf *.eot *.jpg *.gif *.svg *.ico)

My config/environments/production.rb includes:

config.assets.js_compressor = Uglifier.new(harmony: true)
config.assets.css_compressor = :sass

As a temporary workaround I added at the end of my .yarnclean the files raising the exceptions:

# misc
*.md
*.jst
*.def

# specific files
jquery/src

# Uglifier::Error: Unexpected token: punc ({)}
ajv/dot
# .jst files
fbjs/flow
# Uglifier::Error: return outside of function
mkdirp/bin/cmd.js
node-gyp/bin/node-gyp.js
strip-indent/cli.js
webpack/bin/webpack.js
webpack-dev-server/bin/webpack-dev-server.js

However cleaning the bin folders was actually a very bad idea, since it broke webpack itself:

/home/kupta/.rvm/gems/ruby-2.4.0@my-project/gems/webpacker-3.2.1/lib/webpacker/webpack_runner.rb:11:in `exec':
No such file or directory - ~/my-project/node_modules/.bin/webpack (Errno::ENOENT)

There is any smart way to handle node modules during the asset precompilation? My assets folder increased by over 60 MB and I would like to prevent some of them to be compiled.

Thank you in advance

Edit 2018-02-09

I currently solved the problem for stylesheets as follows:

yarn add resolve-url-loader

Then I included this resolver which is handling relative imports for fonts, images etc. from assets modules in config/webpacker/environment.js:

const { environment } = require('@rails/webpacker')

// resolve-url-loader must be used before sass-loader
environment.loaders.get('sass').use.splice(-1, 0, {
    loader: 'resolve-url-loader',
    options: {
        attempts: 1
    }
});

module.exports = environment

Then I created an application.sass inside **app/javascripts/packs` where I import node libraries:

@import '~font-awesome/scss/font-awesome'
@import '~bootstrap/dist/css/bootstrap'
# --- and so on

Unfortunately I have not found yet a way to bundle relevant .js files. I would expect to be able to do something similar to //= require used by sprockets


Solution

  • The solution was even too easy (after I figured it out).

    My folder structure:

    app/javascripts/pack
    |
    |_ vendor.js
    |
    |_ styles.js
    

    In vendor.js I just imported the libraries like import 'jquery/dist/jquery.js'; and all of them got bundled to a vendor.js pack.

    In styles.js I just imported the libraries like import 'font-awesome/scss/font-awesome.scss'; and all of them got bundled to a styles.css pack.

    So no need to include node_modules in my assets paths.

    (I documented the all way to get here in this question about yarn)