23 comments

[ 3.6 ms ] story [ 53.3 ms ] thread
Not the OP. Just found this very interesting.
Rails is such a huge community, and Sprockets has to be one of the biggest pain points for many years.

My solution after years of agony has been to just throw it all out, and use a diff asset packager underneath rails.

Really happy that people are taking this issue on. Wish I had the time to help out.

Given how much modern js development depends on node and npm, I think using a different asset packager is the most sensible way to go.
I'm not at all familiar with programming in Rust or Ruby, but what is the significance of the string "muffins" on this line? https://github.com/danielpclark/faster_path/blob/7033f5a5673...

Edit: changed link to blob version which will not change line numbers on me.

I haven't worked with Rust myself, but I read that as a failover/rescue, to provide a string for debugging purposes (hence the silliness).
I don't write Rust either, but I might guess that they are trying to unbox a nullable value that can't be null. They need a default string due to Rusts strong types even if it's not used.
A more idiomatic way to write the line is:

r_str.chars().next() == Some(MAIN_SEPARATOR)

It's a string whose first character is guaranteed not to match MAIN_SEPARATOR, so that the expression always returns false when r_str is empty.

Definitely not the clearest way to do that.

  FasterPath Rust Implementation  Ruby 2.3.1 Implementation  Performance Improvement
  FasterPath.absolute? 	          Pathname#absolute?         1234.6%
Nothing like getting 3 orders of magnitude performance improvement.
Ruby's `Pathname#absolute?` is doing a lot more work[1]. I don't know why, but it is.

If I change it to just check the first character for the file separator, as I understand FasterPath does, then of course it is faster:

    Warming up --------------------------------------
                original     4.109k i/100ms
                  faster   110.202k i/100ms
    Calculating -------------------------------------
                original     42.645k (± 3.7%) i/s -    213.668k in   5.017595s
                  faster      2.643M (± 4.4%) i/s -     13.224M in   5.013294s

    Comparison:
                  faster:  2643274.6 i/s
                original:    42644.5 i/s - 61.98x slower

My implementation:

    class Pathname
      def f_relative?
        @path[0] != File::SEPARATOR
      end
    end

[1] https://github.com/ruby/ruby/blob/68ebbbfebe5b666cf76ab41f1e...
That returns a wrong result on Windows paths, and throws an exception on the empty string.

There are a ton of edge cases in path manipulation code.

I'm pretty sure his implementation works on empty strings because `str[0].nil?`. So the comparison is false, giving the right (?) answer.
How on earth can pathname handling be a performance drag? If I read his stats correctly, then `Pathname#chop_basename` is called 24456 times for one page load. Something is very fishy about that.
Agree, and that's per actual page load. Not at the start of the app. If there's no dynamic searching for paths in the app, I don't understand why there would be even one path operation done after the first request. Templates, extra resources, etc. - you can optimise this down to assembler, but it's always going to take time. What solves this is just caching the results - you don't run the path operations anymore.
Exactly what I was thinking. You look for the last slash and truncate.
This is a naive solution. Try using that on windows.
This actually makes me wonder if it would be worthwhile to look for this and similar issues and remove Windows support from the methods for a custom implementation. It might shave off some more time.
Still, use a pattern to find the last slash or backslash. Should be pretty quick.
(comment deleted)