Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Do not run yarn install on every assets:precompile #405

Closed
Gargron opened this issue May 21, 2017 · 37 comments
Closed

Do not run yarn install on every assets:precompile #405

Gargron opened this issue May 21, 2017 · 37 comments

Comments

@Gargron
Copy link

Gargron commented May 21, 2017

At least add an option to disable that behaviour. Usually you have a separate step for making sure bundler/yarn dependencies are installed - I'd say in most cases. So this invocation is just wasting a few seconds in the best case, and in the worst case as I'm experiencing right now it's triggering post-install scripts every time.

@himdel
Copy link

himdel commented May 24, 2017

IMHO dealing yarn should never even be webpacker's job. Don't tell me how to download my dependencies, just compile them when they are there. (Since most projects already had to deal with this and have their own solutions anyway.)

@gauravtiwari
Copy link
Member

@Gargron @himdel That makes sense. I guess it should behave like bundler. This needs updating at two places - on Rails side and other on Webpacker - basically need to remove precompile hook enhancement.

@mipearson
Copy link

I tried working around this using the same workaround described at #440, but for some reason the yarn:install dep is added at some point after my own workaround is called.

Rake is confusing :(

@Gargron
Copy link
Author

Gargron commented Jun 2, 2017

Afaik this is the line that does it: https://github.com/rails/webpacker/blob/master/lib/tasks/webpacker/compile.rake#L32 It also checks for something present in Rails 5.1, and I do wonder if Rails 5.1 also commits this mistake or not?

@gauravtiwari
Copy link
Member

@Gargron Yep it's there too - 5.1+

Gargron added a commit to Gargron/rails that referenced this issue Jun 2, 2017
See also: rails/webpacker#405

Yarn just like bundler is usually run explicitly and only when dependencies are updated. Invoking yarn on every asset precompilation is unnecessary, it can also be problematic if you've cleaned yarn cache prior because you have everything you need, yarn install would also run any post-install scripts regardless of whether any new dependencies had to actually be installed or not
@wagoid
Copy link

wagoid commented Sep 7, 2017

Since they check if the yarn:install task is defined before running it (here), I created this same task with an empty body, as a workaround.

namespace :yarn do
  task :install do
    # workaround to stop running yarn install after precompile
  end
end

@noelrappin
Copy link

@wagoid Hmm.. for me that runs both my workaround task and the existing task...

@gutierlf
Copy link

@wagoid, I also tried your workaround, only to find that it still runs the existing task. 🙁 I'm glad you offered an attempt though. 👍

So does anyone have another workaround? I'm stuck.

Thanks!

@wagoid
Copy link

wagoid commented Sep 21, 2017

Yeah, I thought that worked at first but it didn't :(
I also tried clearing the rake task, no success

@gutierlf
Copy link

@wagoid thanks for chiming in about your results too.

@dbalatero
Copy link
Contributor

I'm having weird issues on Heroku with Rails 5.1, webpacker 3.0.1, and the nodejs + ruby buildpacks.

Whenever I deploy, the nodejs buildpack will run yarn install. Afterwards, the ruby buildpack will run rake assets:precompile, which will do a whole new yarn install, which doesn't seem to be picking up the cache from the prior run, and does a full package download again. If I heroku run bash after the fact and run yarn install manually, it downloads all the packages again as well.

I've been banging my head against the wall trying to get this to just download packages a single time and cache them between builds, but no luck. Anyone else have a similar issue or fix?

I wish I could just yarn install once during the nodejs buildpack and then webpacker would pickup that all the modules are there and everything is ok…

@gauravtiwari
Copy link
Member

Is NODE_MODULES_CACHE set to true? See here: https://devcenter.heroku.com/articles/nodejs-support#cache-behavior

@shaicoleman
Copy link

Deleting bin/yarn in the app will disable yarn

@dbalatero
Copy link
Contributor

Is NODE_MODULES_CACHE set to true? See here: https://devcenter.heroku.com/articles/nodejs-support#cache-behavior

@gauravtiwari yeah it's set to true!

Deleting bin/yarn in the app will disable yarn

@shaicoleman Interesting… I will go down this path and see what happens.

@gutierlf
Copy link

I also came to this issue when trying to deploy to Heroku. I just tried setting NODE_MODULES_CACHE to true and deleting bin/yarn, but neither worked for me.

@dbalatero
Copy link
Contributor

@gutierlf I got it to work by deleting bin/yarn. Once I deleted that binary, webpacker's compile step stopped trying to install a second time.

I'm using the nodejs and ruby buildpacks in that order, with these vars:

remote:        NPM_CONFIG_LOGLEVEL=error
remote:        NPM_CONFIG_PRODUCTION=true
remote:        NODE_VERBOSE=false
remote:        NODE_ENV=production
remote:        NODE_MODULES_CACHE=true

When my nodejs buildpack hit, it took care of doing yarn install (and also cached the results for future deploys, which is 👍).

As well, I'm setting explicit versions in my package.json (which I don't think matters, but I'm mentioning for completeness):

{
  "engines": {
    "node": "8.5.0",
    "npm": "5.3.0",
    "yarn": "^1.0.2"
  }
}

I had to move some babel plugins from devDependencies to my dependencies section to get the actual compilation to work. There's a discussion in #117 that says any build tools need to be put into dependencies so they get installed on Heroku. This is likely because NPM_CONFIG_PRODUCTION is set to true, which must run yarn install --production – which would not pull in devDependencies. Without those, rake assets:precompile will barf.

Let me know if this info helps.

@gutierlf
Copy link

@dbalatero thanks for sharing so many details about what worked for you. I'll try later on and hopefully have the same success you did. In any case, I'll report back.

@gutierlf
Copy link

Ok, my Heroku deploy is working now 🎉, but I'm not sure which was the change that really fixed things 🤔. Following @dbalatero's advice, I set the five vars and used the nodejs and ruby buildpacks. I had previously tried using those buildpacks without success, so my attempts just before @dbalatero's comment had been done without specifying the buildpacks (which I assumed meant that Heroku would choose a smart default). I did not remove bin/yarn. And tra-la-la, success!

My current guess is that it has to do with the NODE_MODULES_CACHE=true setting, but I didn't try narrowing things down to see if that guess holds water.

Anyhow, thanks @dbalatero.

@dbalatero
Copy link
Contributor

@gutierlf glad to hear it's working!

What I'd love to be able to do is only use the ruby buildpack on Heroku. I think the only reason that I'm using the nodejs buildpack is so that I can get higher versions of Node and Yarn, as webpacker I believe installs node 6.x and yarn 0.22.x, and I'm using 8.5.0 and 1.1.0 respectively on my dev machine. If there was a way to hint to webpacker which versions we actually want to install when doing a production assets:precompile, I believe that would completely eliminate the dependency on the nodejs buildpack, and Rails to Heroku deploys would just be seamless again.

This might be getting off topic though at this point…

@wickkidd
Copy link

FWIW, I was able to bypass webpacker's compile-related tasks (and underlying hard dependency on yarn) by simply making my own task derived from webpacker's and setting the environment variable WEBPACKER_PRECOMPILE to false.

Rake::Task["assets:precompile"].enhance do
  $stdout.sync = true

  def ensure_log_goes_to_stdout
    old_logger = Webpacker.logger
    Webpacker.logger = ActiveSupport::Logger.new(STDOUT)
    yield
  ensure
    Webpacker.logger = old_logger
  end

  namespace :webpacker do
    desc "Compile JavaScript packs using webpack for production with digests"
    task custom_compile: :environment do
      ensure_log_goes_to_stdout do
        if Webpacker.compile
          # Successful compilation!
        else
          # Failed compilation
          exit!
        end
      end
    end
  end

  Rake::Task["webpacker:custom_compile"].invoke
end

Granted, this (as well as some other approaches I've come across) aren't what I would call ideal, but I believe that the risk is fairly low:

  1. If "Webpacker.compile" changes, I'll have to adjust.
  2. There's no verification of node or the binstubs, however, since I'm handling node and npm installation separately I'm not really concerned with them.
  3. Things I haven't thought of ;)

@wbotelhos
Copy link

Thank you @wagoid and @shaicoleman , it worked! <3

@atz
Copy link

atz commented Sep 26, 2018

Since they check if the yarn:install task is defined before running it (here), I created this same task with an empty body, as a workaround.

namespace :yarn do
  task :install do
    # workaround to stop running yarn install after precompile
  end
end

The way to nullify an existing rake task prior to redefinition (which otherwise appends, as commenters found out) is:

Rake::Task["yarn:install"].clear

@swistak
Copy link

swistak commented Aug 28, 2019

I'm having this problem in Rails 6 pre. Why is yarn:install called at all when precompilng assets?
Why are assets concerned with dependency management?

PS. Working workaround (to be added at the end of a Rakefile):

Rake::Task["yarn:install"].clear
namespace :yarn do
  task :install do
    # Someone decided to install yarn every time asset:precompile is called for some strange reason.
    # It's less then optimal - as it prevents us from doing it in a separate step during deploy with specific options.
    # So we clear the old task and override it with an empty one.
  end
end

@wbotelhos
Copy link

@swistak Did you tried to just remove bin/yarn?

@swistak
Copy link

swistak commented Aug 28, 2019

But I need a yarn to in a project and I'm installing it in a different step with custom flags.

@nitsujri
Copy link

For anyone coming across this today:

rm bin/yarn

# yarn_install.rake
Rake::Task['yarn:install'].clear
namespace :yarn do
  task :install do
    # Redefine as empty
  end
end

This works for our deployment scheme by rm'ing the bin/yarn in a specific step.

@heaven
Copy link

heaven commented May 3, 2020

Was this ever fixed? The workarounds don't work, the precompile task even fails to start because of Yarn requires Node.js 4.0 or higher to be installed. While 12.6.3 is actually installed via NVM.

@andreorvalho
Copy link

setting NODE_ENV='development' fixed the problem when running yarn install and getting all necessary dev dependencies. Not sure this is the solution for your problem. But it helped me solve a similar one and hope it helps somebody else

@badosu
Copy link

badosu commented Dec 23, 2020

I was able to make it work on Rails 5.2.4.4 and webpacker 4.2.2 with:

# Someone decided to install yarn every time asset:precompile is called for some strange reason.
# It's less then optimal - as it prevents us from doing it in a separate step during deploy with specific options.
# So we clear the old task and override it with an empty one.
if ENV['SKIP_YARN_INSTALL_ON_PRECOMPILE']
  Rails.application.config.after_initialize do
    Rake::Task['webpacker:yarn_install'].clear
    namespace :webpacker do
      task :yarn_install do
      end
    end

    Rake::Task['yarn:install'].clear
    namespace :yarn do
      task :install do
      end
    end
  end

  Rake::Task.define_task("assets:precompile" => ["webpacker:compile"])
end

@my-very-own-account
Copy link

Any news on this guys?

@badosu nice work!

@jaredbeck
Copy link
Contributor

jaredbeck commented Apr 3, 2021

Instead of defining various tasks as "empty", we can surgically remove webpacker:yarn_install from the prerequisites of the assets:precompile task.

# Rakefile
t = Rake::Task['assets:precompile']
deps = t.prerequisites.dup # ["webpacker:yarn_install", "webpacker:compile"]
t.clear_prerequisites
t.enhance(deps - ['webpacker:yarn_install'])

It seems worthwhile to be surgical here, in case webpacker adds other prerequisites in the future.

Tested with:

rake 13.0.3
rails 6.1.3.1
webpacker 5.2.1

@jaredcwhite
Copy link
Contributor

task = Rake::Task['assets:precompile']

Uhhh, you shouldn't be redefining task within Rakefile, it'll break any additional Rake tasks. 🙂

@Joaquim-Ferrer
Copy link

After upgrading Webpacker to 5.4 with rails 6.0 I had problems with the workaround of clearing the task yarn:install. It started throwing the error Don't know how to build task 'yarn:install' for any task I tried to run.

Did this task stop being defined?

@MrBananaLord
Copy link

MrBananaLord commented Aug 13, 2021

Seems like it is enough now (rails 6.0.1) to delete the bin/yarn and then the assets:precompile will not run yarn:install so you could remove the workaround and the bin/yarn executable altogether :)

The task looks like it's defined though, but it's loaded after your rake task so you cannot delete it at that point.

kemenaran added a commit to demarches-simplifiees/demarches-simplifiees.fr that referenced this issue Oct 26, 2021
By default `bin/rails assets:precompile` will run `yarn install` again.

The suggested workaround is to remove `bin/yarn` before running the
task.

See rails/webpacker#405
kemenaran added a commit to demarches-simplifiees/demarches-simplifiees.fr that referenced this issue Oct 26, 2021
By default `bin/rails assets:precompile` will run `yarn install` again.

The suggested workaround is to remove `bin/yarn` before running the
task.

See rails/webpacker#405
kemenaran added a commit to demarches-simplifiees/demarches-simplifiees.fr that referenced this issue Nov 2, 2021
By default `bin/rails assets:precompile` will run `yarn install` again.

The suggested workaround is to remove `bin/yarn` before running the
task.

See rails/webpacker#405
kemenaran added a commit to demarches-simplifiees/demarches-simplifiees.fr that referenced this issue Nov 3, 2021
By default `bin/rails assets:precompile` will run `yarn install` again.

The suggested workaround is to remove `bin/yarn` before running the
task.

See rails/webpacker#405
kemenaran added a commit to demarches-simplifiees/demarches-simplifiees.fr that referenced this issue Nov 9, 2021
By default `bin/rails assets:precompile` will run `yarn install` again.

The suggested workaround is to remove `bin/yarn` before running the
task.

See rails/webpacker#405
@holstvoogd
Copy link

Why was this closed?

@jaredbeck
Copy link
Contributor

Why was this closed?

https://github.com/rails/webpacker/#webpacker-has-been-retired-

@adeeb1
Copy link

adeeb1 commented Jul 2, 2022

Adding this here in case others are coming from search engines: there is a WEBPACKER_PRECOMPILE environment variable defined here. When set to false it prevents Webpacker from enhancing the assets:precompile task and therefore using Yarn. None of the other solutions such as removing bin/yarn worked for me, but this did! Here's how to use it:

WEBPACKER_PRECOMPILE=false bundle exec rails assets:precompile

cooperka added a commit to thecartercenter/nemo that referenced this issue Sep 1, 2022
Previously it was run automatically during theme:preprocess (twice) and
also during deploy:assets:precompile.

See rails/webpacker#405 for more details.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests