Skip to content

How to find the path of a compiled pack by name? #231

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

Closed
rmosolgo opened this issue Apr 4, 2017 · 13 comments
Closed

How to find the path of a compiled pack by name? #231

rmosolgo opened this issue Apr 4, 2017 · 13 comments

Comments

@rmosolgo
Copy link

rmosolgo commented Apr 4, 2017

Hi! Thanks for your work on this project. I'm working on adding webpacker support to react-rails and it's my first time really digging in. The integration is great! I'm looking forward to migrating my own Rails projects!

In order to support server-rendered React component, I need to read a compiled pack file into memory and feed the JS code to ExecJS. I'm looking for a way to get the pack contents by name, something like:

full_pack_path("hello_react.js")
# => "/Users/rmosolgo/code/webpackertest/public/assets/packs/hello_react.js"

Is there a built-in way to do this?

I tried but I couldn't quite get it. I know I can get the pack path from Webpacker::Manifest:

pack_path = Webpacker::Manifest.lookup("hello_react.js")
# => "/packs/hello_react-42333475ee741b8cba43.js"

And I can get the output path from Webpacker::Configuration:

output_path = Webpacker::Configuration.output_path
# => #<Pathname:/Users/rmosolgo/code/webpackertest/public/packs>

But joining them doesn't quite work, because of the leading /:

output_path.join(pack_path) 
# => #<Pathname:/packs/hello_react-42333475ee741b8cba43.js>

(It thinks that pack_path was absolute.)

Even removing the leading / isn't quite right, it has packs in there twice:

output_path.join(pack_path[1..-1])
# => #<Pathname:/Users/rmosolgo/code/webpackertest/public/packs/packs/hello_react-42333475ee741b8cba43.js>

Of course, I can manually remove one of the packs, but that would break for users with nonstandard configuration:

# Remove the last `packs/`, assuming default setup:
output_path = output_path.parent 
output_path.join(pack_path[1..-1])
# => #<Pathname:/Users/rmosolgo/code/webpackertest/public/packs/hello_react-42333475ee741b8cba43.js>

Is there another way to accomplish this? Or, are you open to adding one here? I'd be happy to take a try at it.

@gauravtiwari
Copy link
Member

@rmosolgo How about using the configuration file directly to join paths? -
https://github.com/rails/webpacker/blob/master/lib/webpacker/configuration.rb (which reads paths from paths.yml configuration file)

irb(main):004:0> Rails.root.join(Webpacker::Configuration.output_path, "hello_react.js")
# entries is entry files folder (default is packs)
=> <Pathname:/Users/gaurav/webpacker-example-app/public/entries/hello_react.js>
=> "/Users/gaurav/webpacker-example-app/public/entries/hello_react.js"
begin 
 if Webpacker::Manifest.lookup("hello_react.js")
   path = Rails.root.join(Webpacker::Configuration.output_path, "hello_react.js")
   @context = ExecJS.compile(GLOBAL_WRAPPER + File.read(path))
 end
rescue Webpacker::FileLoader::NotFoundError
  # some rescue code
end

Would this work?

@gauravtiwari
Copy link
Member

Left a comment here regarding paths - reactjs/react-rails#666 (comment)

@rmosolgo
Copy link
Author

rmosolgo commented Apr 5, 2017

I think that would work well for development, but it seems like in production, the pack filename includes the asset digest:

$ rails webpacker:compile RAILS_ENV=production
Compiled digests for all packs in /Users/rmosolgo/code/webpackertest/public/packs:
{"application.js"=>"/packs/application-3045631e9e78a2b93572.js", "hello_react.js"=>"/packs/hello_react-42333475ee741b8cba43.js"}
$ ls public/packs
application-3045631e9e78a2b93572.js	
application-3045631e9e78a2b93572.js.gz
hello_react-42333475ee741b8cba43.js		
hello_react-42333475ee741b8cba43.js.gz
manifest.json

In that case, I somehow need the digest in order to find the file. I can get the digest from Webpacker::Manifest, but I'm not sure how to go the last mile and join it into an absolute path!

@gauravtiwari
Copy link
Member

gauravtiwari commented Apr 5, 2017

Would this work?

begin 
 pack_path = Webpacker::Manifest.lookup("hello_react.js")
 if pack_path
   path = File.join(Webpacker::Configuration.output_path, File.basename(pack_path))
   @context = ExecJS.compile(GLOBAL_WRAPPER + File.read(path))
 end
rescue Webpacker::FileLoader::NotFoundError
  # some rescue code
end

@gauravtiwari
Copy link
Member

But I guess this might lead to some edge case where a pack is emitted in a sub-directory. In that case .basename might not work as it will ignore the in-between directories.

@gauravtiwari
Copy link
Member

gauravtiwari commented Apr 5, 2017

Or we could do this, a bit hacky 😄

screen shot 2017-04-05 at 13 39 55

begin 
 pack_path = Webpacker::Manifest.lookup("hello_react.js")
 if pack_path
   path = Rails.root.join(Webpacker::Configuration.paths[:output], pack.split('/').reject(&:empty?).join('/'))
   @context = ExecJS.compile(GLOBAL_WRAPPER + File.read(path))
 end
rescue Webpacker::FileLoader::NotFoundError
  # some rescue code
end

@rmosolgo
Copy link
Author

rmosolgo commented Apr 5, 2017

Yep, there are definitely ways to hack it together, as there always are in Ruby 😆

I'm particularly asking:

  • Is there a public API that I overlooked which supports this? (It sounds like there isn't.)
  • Are you open to adding a public API that supports this?

@gauravtiwari
Copy link
Member

Yes, there isn't. Totally, feel free 👍 🍰

@gauravtiwari
Copy link
Member

Fixed by #237

@rmosolgo
Copy link
Author

🙇 thanks!

@naiyt
Copy link

naiyt commented May 31, 2018

If anybody else runs into this down the road, the solution in #237 looks like it was refactored a bit. Now you want to do:

Webpacker.manifest.lookup("packfile.js")

@awongh
Copy link

awongh commented Jun 6, 2021

actually the above comments are asking about an absolute path, lookup_path and that seems to have been merged in #237 but that method seems to have disappeared so we're back to a method for the relative path only....

this example only seems to get the relative path:

Webpacker.manifest.lookup("packfile.js")

@mcmire
Copy link

mcmire commented Jun 7, 2021

Using the manifest doesn't completely work because as the OP alluded to, the manifest only produces "public" paths for entrypoints ("packfiles"). In other words, any value in any hash that manifest.json contains, you're meant to take that value and combine it with the public output path to get a request path. To get a file path, you should be able to say:

Webpacker.configuration.source_entry_path.join("packfile.js")

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

No branches or pull requests

5 participants