rails/sprockets

sprockets does not respect the filename extension I specified in link_directory (manifest.js) in ambiguous cases

mildred opened this issue · 0 comments

Actual behavior

Given that I configure in an initializer Sprockets.register_mime_type 'application/javascript, extensions: ['.mjs'] and that I have a directory where two files share the same basename but with different extensions (one .js and one .mjs)

Currently, it is as if when I put in the manifest a directive like //= link_directory path/to file.mjs, sprockets would strip the .mjs extension and register that I want to link the directory path/to and inside the file with the basename file and an extension that match application/javascript. But this is ambiguous and not what I specified.

Currently, in that circumstance, when I ask sprockets for the file path/to/file.mjs it will instead serve me the file public/assets/path/to/file-HASH.js, but the file content differs.

Expected behavior

When in app/assets/config/manifest.js I reference a file, its file extension should be preserved even when there are multiple files with different extensions but the same content-type

System configuration

  • Sprockets version 4.2.1
  • Rails 7.1.2
  • Ruby version 3.2.2

Example App (Reproduction)

I wish I could but I tried to create a new app wuith rails new and sprockets fails out of the box with a "\xE2" to UTF-8 in conversion from ASCII-8BIT to UTF-8 to UTF-32LE (Encoding::UndefinedConversionError)

Reproducing the example should be easy from any app that is working:

  • yarn add use-bootstrap-select (it contains the files that causes the issue

  • add in app/assets/config/manifest.js the directive //= link_directory ../../../node_modules/use-bootstrap-select/dist use-bootstrap-select.mjs

  • optional: make use of it in the importmap (add in config/importmap.rb the line pin 'use-bootstrap-select', to: 'use-bootstrap-select/dist/use-bootstrap-select.mjs', preload: true ). This is to get the asset path easily.

  • start the rails server

  • use bin/importmap json to get the asset oath for the use-bootstrap-select.mjs file, open it up in the browser served by rails and you'll get the file but with a content-type of text/plain. That's not ok, so let's try to fix this.

  • in an initializer in config/initialisers/assets.rb add:

    {
      '.mjs' => 'application/javascript'
    }.each do |ext, content_type|
      Sprockets.register_mime_type content_type, extensions: [ext]
      Rack::Mime::MIME_TYPES[ext] = content_type
    end
  • Restart rails, run bin/importmap json to get the asset path for use-bootstrap-select.mjs

  • Open up the asset path in the browser, this time the content-type is correct but the file content is not node_modules/use-bootstrap-select/dist/use-bootstrap-select.mjs but is node_modules/use-bootstrap-select/dist/use-bootstrap-select.js. The incorrect file is served

edit: by the way it would be great if there was a working example app we could fork to demonstrate the issues.