Search code examples
ruby-on-railsrubyherokuwebpack

Heroku rails 6 Precompiling assets failed


Where i am going wrong? I am unable to deploy my app to heroku even after running $ npm install --save-dev webpack

When i try to deploy my app to heroku i get the below:

remote:        Compiling...
remote:        Compilation failed:
remote:        
remote:        webpack not installed
remote:        
remote:        Install webpack to start bundling: 
remote:          $ npm install --save-dev webpack
remote:        
remote:        
remote: 
remote:  !
remote:  !     Precompiling assets failed.
remote:  !
remote:  !     Push rejected, failed to compile Ruby app.
remote: 
remote:  !     Push failed
remote: Verifying deploy...

i have run npm install --save-dev webpack , i have also run bundle exec rails webpacker:install but when i deploy to heroku i get the same above message

This my application.js file in which i have defined webpack:

// This file is automatically compiled by Webpack, along with any other files
// present in this directory. You're encouraged to place your actual application logic in
// a relevant structure within app/javascript and only use these pack files to reference
// that code so it'll be compiled.

require("@rails/ujs").start()
require("turbolinks").start()
require("@rails/activestorage").start()
require("channels")

require("custom/alert")
var jQuery = require('jquery')

console.log("--- ALL JS FILES LOADED ---")

// Uncomment to copy all static images under ../images to the output folder and reference
// them with the image_pack_tag helper in views (e.g <%= image_pack_tag 'rails.png' %>)
// or the `imagePath` JavaScript helper below.
//
// const images = require.context('../images', true)
// const imagePath = (name) => images(name, true)


//include jQuery in global and window scope (so it can be accessed globally)
global.$ = global.jQuery = jQuery;
window.$ = global.jQuery = jQuery;

//include moment in global and window scope (so it can be accessed globally)
global.moment = moment;
window.moment = moment;

this is my environment.js file

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

const webpack = require('webpack')
environment.plugins.append(
  'Provide',
  new webpack.ProvidePlugin({
    $: 'jquery',
    jQuery: 'jquery'
  })
)

module.exports = environment

this is my production.js file

process.env.NODE_ENV = process.env.NODE_ENV || 'production'

const environment = require('./environment')

module.exports = environment.toWebpackConfig()

and this is my package.json

{
  "name": "sample_app",
  "private": true,
  "dependencies": {
    "@rails/actioncable": "^6.0.0",
    "@rails/activestorage": "^6.0.0",
    "@rails/ujs": "^6.0.0",
    "@rails/webpacker": "4.3.0",
    "jquery": "^3.6.0",
    "turbolinks": "^5.2.0"
  },
  "version": "0.1.0",
  "devDependencies": {
    "webpack": "^5.53.0",
    "webpack-dev-server": "^3.11.2"
  }
}

Solution

  • If you need nodejs (which is the runtime wepacks runs on), you have to tell Heroku about it, otherwise it will only have the ruby runtime.

    In Heroku, these runtimes are called buildpacks and they are usually detected by default as long as there is one clear winner. For instance, whenever Heroku finds a Gemfile, it will use the ruby buildpack.

    You need to add the nodejs buildpack, which is achieved by running

    heroku buildpacks:add --index 1 heroku/nodejs
    

    Once this is set up, you will be able to push, and each buildpack will do its work, first nodejs will install everything that is declared in package.json, and then ruby will install its own dependencies and finaly compile and start the app.