In https://github.com/heroku/jruby-getting-started/issues/26 it was reported that the jruby getting started guide did not work "out of the box" with the ruby CNB because it was missing a package.json. However it works with the classic buildpack:
$ ls
Gemfile Procfile.windows app db public
Gemfile.lock README.md config lib test
Procfile Rakefile config.ru log vendor
⛄️ 3.3.1 🚀 /tmp/150ca2015abd0c42ade576ee15691dc6/jruby-getting-started (main)
$ git status
On branch main
Your branch is ahead of 'origin/main' by 1 commit.
(use "git push" to publish your local commits)
nothing to commit, working tree clean
⛄️ 3.3.1 🚀 /tmp/150ca2015abd0c42ade576ee15691dc6/jruby-getting-started (main)
$ heroku create
Creating app... done, ⬢ serene-badlands-65663
https://serene-badlands-65663-2a3a8da4d325.herokuapp.com/ | https://git.heroku.com/serene-badlands-65663.git
⛄️ 3.3.1 🚀 /tmp/150ca2015abd0c42ade576ee15691dc6/jruby-getting-started (main)
$ git push heroku main
Enumerating objects: 316, done.
Counting objects: 100% (316/316), done.
Delta compression using up to 12 threads
Compressing objects: 100% (193/193), done.
Writing objects: 100% (316/316), 71.12 KiB | 35.56 MiB/s, done.
Total 316 (delta 99), reused 315 (delta 99), pack-reused 0
remote: Resolving deltas: 100% (99/99), done.
remote: Updated 89 paths from 5cbf940
remote: Compressing source files... done.
remote: Building source:
remote:
remote: -----> Building on the Heroku-22 stack
remote: -----> Determining which buildpack to use for this app
remote: -----> Ruby app detected
remote:
remote: ## Warning: Your app needs java
remote:
remote: The Ruby buildpack determined your app needs java installed
remote: we recommend you add the jvm buildpack to your application:
remote:
remote: $ heroku buildpacks:add heroku/jvm --index=1
remote:
remote: -----> Installing Java
remote:
remote: -----> Downloading Buildpack: heroku/jvm
remote: -----> Detected Framework: JVM Common
remote:
remote: ! WARNING: No OpenJDK version specified
remote: Your application does not explicitly specify an OpenJDK
remote: version. OpenJDK 1.8 will be installed.
remote:
remote: This default version will change at some point. Your
remote: application might fail to build with the new version. We
remote: recommend explicitly setting the required OpenJDK version for
remote: your application.
remote:
remote: To set the OpenJDK version, add or edit the system.properties
remote: file in the root directory of your application to contain:
remote:
remote: java.runtime.version = 1.8
remote:
remote:
remote: -----> Installing OpenJDK 1.8... done
remote: -----> Installing bundler 2.4.22
remote: -----> Removing BUNDLED WITH version in the Gemfile.lock
remote: -----> Compiling Ruby/Rails
remote: -----> Using Ruby version: ruby-3.1.0-jruby-9.4.1.0
remote: -----> Installing dependencies using bundler 2.4.22
remote: Running: BUNDLE_WITHOUT='development:test' BUNDLE_PATH=vendor/bundle BUNDLE_BIN=vendor/bundle/bin BUNDLE_DEPLOYMENT=1 bundle install -j4
remote: Fetching gem metadata from https://rubygems.org/.........
remote: Fetching rake 13.0.6
remote: Installing rake 13.0.6
remote: Fetching minitest 5.18.0
remote: Fetching builder 3.2.4
# ...
remote: Installing sass-rails 6.0.0
remote: Bundle complete! 13 Gemfile dependencies, 74 gems now installed.
remote: Gems in the groups 'development' and 'test' were not installed.
remote: Bundled gems are installed into `./vendor/bundle`
remote: Bundle completed (87.92s)
remote: Cleaning up the bundler cache.
remote:
remote: ###### WARNING:
remote:
remote: Installing a default version (20.9.0) of Node.js.
remote: This version is not pinned and can change over time, causing unexpected failures.
remote:
remote: Heroku recommends placing the `heroku/nodejs` buildpack in front of
remote: `heroku/ruby` to install a specific version of node:
remote:
remote: https://devcenter.heroku.com/articles/ruby-support#node-js-support
remote:
remote: -----> Installing node-v20.9.0-linux-x64
remote: -----> Detecting rake tasks
remote: -----> Preparing app for Rails asset pipeline
remote: Running: rake assets:precompile
[builder] ExecJS::RuntimeUnavailable: Could not find a JavaScript runtime. See https://github.com/rails/execjs for a list of available runtimes.
However it was unclear what the user should do to install a node runtime. The buildpack should "just work" ™️ .
We should replicate the logic in the detect phase and re-play what we're not doing. I.e. something like "Skipping nodejs install (no package.json found)`. So if the user searches the logs for "node" they'll find that breadcrumb.
In https://github.com/heroku/jruby-getting-started/issues/26 it was reported that the jruby getting started guide did not work "out of the box" with the ruby CNB because it was missing a
package.json
. However it works with the classic buildpack:The reason for this is that the two buildpacks have different behavior. And when there's a difference in behavior it should be called out in https://github.com/heroku/buildpacks-ruby/blob/main/docs/upgrading.md which it isn't.
Difference
The CNB ONLY looks for a
package.json
to install a node version and then relies on the node buildpack to install it.When node support was added to the classic buildpack, a
heroku/nodejs
buildpack didn't exist. The asset pipeline (aka sprockets) needed A version of node so the ruby buildpack detected whenexecjs
gem is present and installs node https://github.com/heroku/heroku-buildpack-ruby/blob/168cb5d556f154e4eba57c797d04b18a4d8b354c/lib/language_pack/ruby.rb#L944-L946. So the reason this works on classic is that it detects that jruby has execjs and it installs a version of node.Besides documenting this difference we could try to bring the classic behavior closer to the CNB. by using the
compile_buildpack_v2
bash function to install the nodejs buildpack when apackage.json
is present similar to how java is installed https://github.com/heroku/heroku-buildpack-ruby/blob/168cb5d556f154e4eba57c797d04b18a4d8b354c/bin/compile#L18-L33. This is a riskier change.Improve the experience
In https://github.com/heroku/jruby-getting-started/issues/26 the error was confusing. The message said
However it was unclear what the user should do to install a node runtime. The buildpack should "just work" ™️ .
We should replicate the logic in the
detect
phase and re-play what we're not doing. I.e. something like "Skipping nodejs install (nopackage.json
found)`. So if the user searches the logs for "node" they'll find that breadcrumb.