rails/propshaft

SyntaxError: Unexpected string literal "@hotwired/turbo-rails". import call expects one or two arguments.

Closed this issue · 7 comments

I initially added this as Rails issue (still open). But, as I dug deeper I was able to narrow this down specifically to Propshaft (or so it seems for now...I will continue digging). I can't see that much has changed from 1.0.0 to 1.0.1, but I can reliably and repeatedly resolve and introduce this error by switching back-n-forth from those versions or Propshaft.

Here's the issue I submit in rails/rails.

Upgrading a Rails 7.2 app to Rails 8. Everything went smooth except something is happening with javascript--it's not loading.

My existing app/javascript/application.js file includes:

import "@hotwired/turbo-rails"
import "./controllers"
import * as bootstrap from "bootstrap"
Upon upgrading to Rails 8.0.0.beta1, I get the following error in the browser console:

SyntaxError: Unexpected string literal "@hotwired/turbo-rails". import call expects one or two arguments.

Just for grins I uninstalled Hotwire and reinstalled. The installer moved import "@hotwired/turbo-rails" to the bottom of application.js. Upon reloading the browser I now get this error:

SyntaxError: Unexpected string literal "./controllers". import call expects one or two arguments.

Expected behavior

Nothing in this regard has change in Rails 8, so not sure why the new errors. The reason I am submitting this as a bug, and not simply to SO is because "./bin/rails turbo:install" puts "import '@hotwired/turbo-rails'" into the application.js file---resulting in this error.

System configuration

Rails version: 8.0.0.beta1

Ruby version: 3.3.5

I am experiencing a similar issue with Ruby 3.3.5, Rails 8.0.0.beta1, JSBundling (esbuild), CSSBundling (tailwind), and Propshaft 1.0.1. It seems like Propshaft 1.0.0 works fine, but when upgrading to 1.0.1, it also seems fine until I deploy. The Dev Console on the browser states:

Uncaught TypeError: Failed to resolve module specifier "@hotwired/turbo-rails". Relative references must start with either "/", "./", or "../".

and looking into the Javascript file in the production instance, it looks like it didn't precompile anything, but just doing the "no build".

// Entry point for the build script in your package.json
import "@hotwired/turbo-rails"
import "./controllers"
import "./tailwindui.js";

import "trix"
import "@rails/actiontext"
import * as ActiveStorage from "@rails/activestorage"
ActiveStorage.start()

CleanShot 2024-09-30 at 15 51 32

Reverting back to Propshaft 1.0.0 and redeploying, it does compile the JS and looks like this

CleanShot 2024-09-30 at 15 56 39

Thanks David. I should have also specified that I'm using esbuild.

I suspect this issue could be related to #209 - if you have app/javascript in your load path, but I'm unable to reproduce it in a clean Rails 8 application with esbuild.

Could you run the following command and post the output to confirm Propshaft isn't prioritizing the uncompiled version from the one in builds?

bin/rails runner "puts Rails.application.config.assets.paths"

And please confirm that app/assets/builds is populated by esbuild with an application.js file.

I updated and deployed with Propshaft 1.0.1 to get this information. From kamal, I shelled into the running docker container to execute these scripts. It looks like theapplication.js file in app/assets/builds is the correct one (i cat'd it out and it did have the compiled JS). But, it is definitely not the one being served.

bin/rails runner "puts Rails.application.config.assets.paths"
/rails/vendor/javascript
/rails/app/javascript
/rails/app/assets/stylesheets
/rails/app/assets/images
/rails/app/assets/builds
/usr/local/bundle/ruby/3.3.0/gems/mission_control-jobs-0.3.1/app/assets/config
/usr/local/bundle/ruby/3.3.0/gems/mission_control-jobs-0.3.1/app/assets/stylesheets
/usr/local/bundle/ruby/3.3.0/gems/action_auth-1.6.0/app/assets/config
/usr/local/bundle/ruby/3.3.0/gems/action_auth-1.6.0/app/assets/javascripts
/usr/local/bundle/ruby/3.3.0/gems/action_auth-1.6.0/app/assets/stylesheets
/usr/local/bundle/ruby/3.3.0/gems/stimulus-rails-1.3.4/app/assets/javascripts
/usr/local/bundle/ruby/3.3.0/gems/turbo-rails-2.0.10/app/assets/javascripts
/usr/local/bundle/ruby/3.3.0/gems/actiontext-8.0.0.beta1/app/assets/javascripts
/usr/local/bundle/ruby/3.3.0/gems/actiontext-8.0.0.beta1/app/assets/stylesheets
/usr/local/bundle/ruby/3.3.0/gems/actioncable-8.0.0.beta1/app/assets/javascripts
/usr/local/bundle/ruby/3.3.0/gems/activestorage-8.0.0.beta1/app/assets/javascripts
/usr/local/bundle/ruby/3.3.0/gems/actionview-8.0.0.beta1/app/assets/javascripts
/usr/local/bundle/ruby/3.3.0/gems/mission_control-jobs-0.3.1/app/javascript
ls -lh app/assets/builds
total 2.2M
-rw-r--r-- 1 root root  73K Sep 30 19:49 application.css
-rw-r--r-- 1 root root 690K Sep 30 19:48 application.js
-rw-r--r-- 1 root root 1.4M Sep 30 19:48 application.js.map

Right - you have /rails/app/javascript before /rails/app/assets/builds in your load path, and that causes Propshaft to serve the original application.js file, and not the one from esbuild.

It'll be resolved in the next release. Until then you can stick to v1.0.0 or pull the gem from main:

gem 'propshaft', github: 'rails/propshaft'

You should also check if you have both jsbundling-rails and importmap-rails installed, as the latter will make modifications to your load path and could cause some unexpected behaviour if you attempt to load javascript files that aren't covered by esbuild. I don't think they're conflicting, but typically you would choose to use one of them.

gem 'propshaft', github: 'rails/propshaft' fixed it for me. Thanks!