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
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
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)