That’s because broadcast is special cased for tuples to call map: @inline broadcast(f, t::NTuple{N,Any}, ts::Vararg{NTuple{N,Any}}) where {N} = map(f, t, ts...). In the general case, it really is just broadcast(f::Tf, As...) where {Tf} = materialize(broadcasted(f, As...)), which I suppose dot syntax always lowers to.
I don’t think the accepted comment about collect being the source of worse performance would apply to tuples, it appears that collect occurs in the fallback broadcastable(x) = collect(x), but tuples are one of the many types where broadcastable returns the input. Not sure exactly where in the broadcast machinery is the source of worse performance than map.