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

Depend on a specific version of Node.js #5158

Merged
merged 3 commits into from
Oct 18, 2023
Merged

Depend on a specific version of Node.js #5158

merged 3 commits into from
Oct 18, 2023

Conversation

javierm
Copy link
Member

@javierm javierm commented Jul 22, 2023

References

Objectives

  • Make sure all Consul Democracy installations compile the assets using the same version of Node.js, so we don't get inconsistent errors
  • Make it easier to use Node packages in the future

Documentation

We need to update the technical documentation in order to add instructions about how to install a Node Version Manager and use it to install Node.js and to reflect the fact that, due to this change, Ubuntu 18.04 is no longer supported.

Release Notes

⚠️ We now depend on a specific version on Node.js. If you use Capistrano to deploy, this version is already installed during deployment. If you use a different system to deploy, you might need to take this into account.

@javierm javierm self-assigned this Jul 22, 2023
@javierm javierm marked this pull request as draft July 22, 2023 21:50
@javierm javierm added this to Reviewing in Consul Democracy Jul 22, 2023
@javierm javierm moved this from Reviewing to Doing in Consul Democracy Jul 22, 2023
@javierm javierm force-pushed the node_version branch 6 times, most recently from e560213 to 138d15c Compare July 23, 2023 02:19
@javierm javierm force-pushed the node_version branch 2 times, most recently from 53b511e to 8ba0db0 Compare August 6, 2023 20:57
@javierm javierm force-pushed the ruby3.1 branch 4 times, most recently from 3fad249 to 35884f9 Compare September 6, 2023 11:47
@javierm javierm marked this pull request as ready for review September 7, 2023 20:01
@javierm javierm moved this from Doing to Reviewing in Consul Democracy Sep 7, 2023
@Senen
Copy link
Member

Senen commented Oct 11, 2023

Hi @javierm, I've been testing deployments from this implementation (with bundle within map_node_bins) on servers built with the installer with Consul Democracy 2.0.1 and on servers with Consul Democracy with the new nodejs version:

It worked well in all cases, but I found that on the server with Consul Democracy 2.0.1, the fnm entries were not added to the deploy user .bashrc file, as you can see in the following deployment log:

03:00 install_node
      01 export PATH="$HOME/.fnm:$PATH" && cd /home/deploy/consul/releases/20231011105903 && eval "$(fnm env)" && fnm use --install-if-missing
      01 bash: fnm: command not found
      01
      01 bash: fnm: command not found
      02 export PATH="$HOME/.fnm:$PATH" && cd /home/deploy/consul/releases/20231011105903 && eval "$(fnm env)"
      02 bash: fnm: command not found
      02
    ✔ 02 [email protected] 0.005s
      03 curl -fsSL https://fnm.vercel.app/install | bash -s -- --install-dir "$HOME/.fnm" --skip-shell
      03 Checking dependencies for the installation script...
      03 Checking availability of curl...
      03 OK!
      03 Checking availability of unzip...
      03 OK!
      03 Downloading https://github.com/Schniz/fnm/releases/latest/download/fnm-linux.zip...
      03 #=#=#
      03 ##O#- #
      03 ##O=#  #
      03 #=#=-#  #
      03 -#O#- #   #
                                                                           0.3%
##                                                                         3.6%
#######                                                                   10.1%
############                                                              17.4%
#################                                                         24.6%
#######################                                                   32.7%
#############################                                             40.5%
##################################                                        48.3%
#######################################                                   54.8%
###########################################                               60.0%
##################################################                        70.2%
#######################################################                   76.9%
#############################################################             85.8%
#####################################################################     97.0%
######################################################################## 100.0%
    ✔ 03 [email protected] 2.713s
      01 Installing Node v18.18.0 (x64)
      01 Using Node v18.18.0
      01
    ✔ 01 [email protected] 8.649s

I think adding those entries to the deploy user .bashrc file is important so interactive sessions load the proper nodejs environment through fnm automatically.

@javierm
Copy link
Member Author

javierm commented Oct 11, 2023

I think adding those entries to the deploy user .bashrc file is important so interactive sessions load the proper nodejs environment through fnm automatically.

I agree! No idea what's going on here 🤔. Maybe next week we can share a screen and try to find out.

@Senen
Copy link
Member

Senen commented Oct 13, 2023

Hi @javierm ,

I was wondering exactly which application dependencies need the Execjs runtime and why we need them.

We have five dependencies that use Execjs for asset precompilation purposes (except eslintrb):

  1. autoprefixer-rails
  2. babel-transpiler
  3. coffee-script
  4. eslintrb
  5. uglifier

Quoting ExecJS docs:

ExecJS lets you run JavaScript code from Ruby. It automatically picks the best runtime available to evaluate your JavaScript program, then returns the result to you as a Ruby object.

I verified this behaviour by removing all my local NodeJS versions and checking that the runtime in my development environment changed from NodeJS to Apple JavaScriptCore, which is Included by default with MacOS.

Before migrating to a specific version of NodeJS and allowing the use of npm packages in the Rails Asset Pipeline, we used the Execjs just for assets precompilation purposes. Now, we want to load npm packages in the Rails Assets Pipeline from a particular NodeJS version. Using other NodeJS versions could lead to unexpected results.

I think now we should force the Execjs runtime environment so if developers do not have NodeJS installed, they get a very explicit error. We can do it with an initializer so any environment would fail if they do not find the runtime we want to use:

config/initializers/execjs.rb

ExecJS.runtime = ExecJS::Runtimes::Node

With this change the error is more precise:

> rails s                   
=> Booting Puma
=> Rails 6.1.7.4 application starting in development 
=> Run `bin/rails server --help` for more startup options
Exiting
/Users/sendero/.rvm/gems/ruby-3.1.4/gems/execjs-2.8.1/lib/execjs/module.rb:14:in `runtime=': Node.js (V8) is unavailable on this system (ExecJS::RuntimeUnavailable)

Another thing we can do is add the required NodeJS version in the README file and mention the need to install the package.json dependencies to precompile assets.

What do you think?

@javierm
Copy link
Member Author

javierm commented Oct 13, 2023

@Senen I've updated the code:

  • Added > /dev/null to the fnm env command so we don't constantly get its output while deploying
  • Run map_node_bins after git:create_release so we don't use the wrong folder when running the FNM setup command
  • Install node before running bundle, since bundle now depends on Node being installed 😌

Tried every scenario I could think of 🤞.

@javierm
Copy link
Member Author

javierm commented Oct 14, 2023

Another thing we can do is add the required NodeJS version in the README file and mention the need to install the package.json dependencies to precompile assets.

I've updated the README to add the required Node.js version 👍. Not sure about the package.json dependencies, but I guess that one belongs to pull request #5159 🤔.

@javierm
Copy link
Member Author

javierm commented Oct 14, 2023

I think now we should force the Execjs runtime environment so if developers do not have NodeJS installed, they get a very explicit error.

Good question 🤔.

Dockerfile Show resolved Hide resolved
We're choosing version 18 because if offers support for SSL 3, just
like Ruby 3.1 does.

Note we're symlinking a .nvmrc file as well, in order to make it
compatible with NVM. While the .nvmrc and .node-version files use
different formats, they both support the syntax we're using to
define the version.

The code to install Node.js in the Dockerfile is a simplification of the
code in the Rails Dockerfile template [1].

[1] https://github.com/rails/rails/blob/04c97aec8a/railties/lib/rails/generators/rails/app/templates/Dockerfile.tt#L25
We use FNM instead of NVM. Reason: the setup seems easier with just
`eval "$(fnm env)"`.

So now, we try to install Node.js; if the command fails, it could be
because FNM isn't installed (and we need to install it) or because the
version of Node.js cannot be installed with the current version of FNM
(and we need to update FNM). After installing/updating FNM, we try to
install Node.js again.

Note we're using `fnm env` in the middle of the `fnm_setup_command`.
That way, the command will raise a `SSHKit::Command::Failed` exception
if `fnm` isn't installed, and it will give us an indicator that we need
to actually install it.
This code is based on what the rvm1-capistrano and capistrano-nvm gems
do, but simplified a bit to take advantage of the `fnm exec` command.

Since ExecJS will check for a JavaScript runtime every time the
application is started, we need to include commands like `bundle` (used
when running `bin/delayed_job`), `puma` and `rake`, so Node.js is found
when running these commands. I'm not sure whether `pumactl` is also
necessary, but I've added it for consistency.

We're also including the default commands gems like capistrano-nvm use
because we will add the `npm` command in the near future.

Note that, in order to setup FNM, we need to enter the actual release
folder (using `within release_path` isn't enough). So we have to run
this task after the actual release is created; otherwise many commands
would run in the previous release's folder.
Consul Democracy automation moved this from Reviewing to Testing Oct 18, 2023
Copy link
Member

@Senen Senen left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @javierm,

As we talked about, if we finally decide to set the Execjs runtime to NodeJS, we'll do it in a separate PR.

@javierm javierm merged commit 55efcbc into master Oct 18, 2023
13 checks passed
Consul Democracy automation moved this from Testing to Release 2.1.0 Oct 18, 2023
@javierm javierm deleted the node_version branch October 18, 2023 12:52
@javierm
Copy link
Member Author

javierm commented Oct 18, 2023

@Senen We finally made it! 🎉

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants