Optimizing implementation of Dijkstra
Handling vertices multiple times
There are two places where you are doing extra work because you are handling vertices multiple times:

When you find a shorter path to a vertex, you currently push that vertex with the new path length into your priority queue.  While this works, you still have the old vertex in the priority queue as well.  You will eventually pop the vertex off twice (and handle it twice), which is not ideal.  If you kept track of which vertices you've already handled, you could quickly skip duplicate vertices when you come across them.

When you handle a new vertex, you iterate over all of its edges.  But if you see an edge to a vertex that has already been handled, you don't need to deal with it.  Right now, you could be pushing vertices back onto your priority queue that you've already dealt with.