ElMassimo / vite_ruby

⚡️ Vite.js in Ruby, bringing joy to your JavaScript experience

Home Page:https://vite-ruby.netlify.app/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Support new default manifest location in Vite v5

mattbrictson opened this issue · comments

Is your feature request related to a problem? Please describe.

Vite changed the default manifest location from ${outDir}/manifest.json to ${outDir}/.vite/manifest.json in Vite v5.

https://vitejs.dev/guide/migration#manifest-files-are-now-generated-in-vite-directory-by-default

After upgrading to Vite v5, ViteRuby fails to find the manifest, leading to errors like:

ActionView::Template::Error: Vite Ruby can't find entrypoints/application.css in public/vite-test/manifest.json or public/vite-test/manifest-assets.json.

Describe the solution you'd like

One option would be to change the definition of ViteRuby::Config#manifest_path to reference the new v5 location:

def manifest_path
  build_output_dir.join('.vite/manifest.json')
end

This would not be backwards compatible with v4, however.

Describe alternatives you've considered

Alternatively, vite-ruby-plugin could explicitly configure the desired manifest location to match the v4 convention:

manifest: ssrBuild ? false : 'manifest.json',

Additional context

There are likely other changes needed for full Vite v5 compatibility, but this was the first major one I encountered in my testing.

Good timing, I have something in the vite-5 branch, testing before releasing the gems.

Closed in #421. Releasing a new version of vite_ruby soon.

After update to latest vite_rails manifest.json location has been changed and Rails fails to pickup new manifest. Is there is a workaround for this? I'm using Capistrano to deploy the app.

I have to do assets:clobber, assets:precompile and the restart server in order for Rails to pick up the latest build.

You can configure assets_manifests to backup the new location, or configure Vite to output the manifest in the old location.

Thanks! I was able to fix this issue by cleaning shared/public directory in Capistrano and adding public/vite to linked_dirs.

@ElMassimo We just run into an issue while upgrading from Vite 4 to Vite 5. After upgrade and deploy, we ended up with this file structure:

public/
  vite/
    manifest-assets.json
    manifest.json
    .vite/
      manifest-assets.json
      manifest.json

After the application rebooted, it was still loading the old JS assets from public/vite/manifest*. I had to SSH in, remove those old manifest files, restart the application server, then things came right. Is this expected? From what I can see of the commit, it should default to V5 manifest but doesn't appear to be working.

Hi Kieran! In that case, it would load all four manifest files, unfortunately merging the old ones last since the new location is read first.

This problem would only happen when preserving assets from previous deployments (as opposed to when using containers).

Flipping the order would potentially avoid this problem during upgrades, but since it's a one-time thing I'm leaning towards documenting it in Troubleshooting instead.

@ElMassimo You are right that the assets are preserved between deployments, a common practice with Capistrano in order to speed up deployment times. However, I feel that documentation may not be enough in this case. We didn't encounter any issues in development before we rolled out the change, so I imagine most people would not check Troubleshooting until it is already too late.

I think merging the old and the new should be considered incorrect behaviour. Perhaps a better approach may be to check the for presence of the manifests under .vite and use only those, otherwise fall back to the old manifests.

def known_manifest_paths
  manifest_files = [
    # NOTE: Generated by Vite when `manifest: true`, which vite-plugin-ruby enables.
    'manifest.json',
    # NOTE: Path where vite-plugin-ruby outputs the assets manifest file.
    'manifest-assets.json',
  ]

  vite5_manifest_paths = manifest_files.map { |path|
    build_output_dir.join(".vite/#{path}")
  }

  vite4_manifest_paths = manifest_files.map { |path|
    build_output_dir.join(path)
  }

  if vite5_manifest_paths.any? { |path| File.exists?(path) }
    vite5_manifest_paths
  else
    vite4_manifest_paths
  end
end

@ElMassimo Here is a PR for the above suggested change. It seems to be working well on our deployments.

https://github.com/ElMassimo/vite_ruby/pull/432/files