I don't use ECS but I do have to handle mesh data. How you do it partially depends on your underlying API and where you want to draw the line between your engine and low-level interface. For instance, in DirectX12 and I think Vulkan also, you have to make sure your meshes aren't deleted while they are still in use. This is because you can have “in-flight” frames and so even if you are rending one frame, the previous frame may not be completed yet. You don't have this issue with DirectX 11 or OpenGL.
In my case a mesh has mesh-data and a material. The material further has a shader-set, which is just the shaders it uses, and a property-set which includes any constant data, such as constant buffers, textures and so forth. The mesh-data is the actual vertexes and indexes (if needed). Meshes can share mesh-data and materials. And materials can share shader-sets and property-sets. There is a reference countering system to keep track of when things are no longer being used.
Everything I've talked about above GPU meshes, although they can be referenced on the CPU. I also have CPU side meshes that get converted to the GPU mesh via a set of template classes.
How you would set this up in ECS I'm not sure, although I can imagine a few ways. Probably how you do this is going to vary a lot depending on your exact needs. My mesh system is set up primarily for LOD, where things change constantly. That might be overkill for you.