I am trying to figure out if there is a way to achieve facet lighting in OpenGL ES 2.0 without extensions. I know it is possible if I don't used indexed vertices but I don't really want to do that because it is a bit wasteful. I have seen people use dFdx and dFdy to achieve this in the shader but unfortunately they are only avaible with extensions here. Are the other options or is there perhaps a way to implement these functions manually?
Unfortunately, when it comes to lighting, some way or another, you'll need some normals.
As you mentioned, for flat shading, you need per triangle normals, which implies vertices duplication, compared to smooth shading.
The most often used techniques to compute normals in an OpenGL shader (using dfx/dfy or geometry shader) are not available in gles 2.0.
Still, there could be another more exotic technique that you could use. This technique consist in storing per triangle normals in CPU memory and construct an array of these to send to the GPU before drawing the mesh.
Let's say you have a 4 triangle tetrahedron (4 vertices). You could the construct an array of 12 normals based on the normals for the 4 triangles repeated 3 times for each vertex involved in the triangle. You can then bind this array to a specific attribute of your shader before each rendering, separately from your non redundant indexed array. In the shader, you'll then get the same normal for the three vertices of a triangle so you'll be able to do flat shading.
Anyway, this technique will eat up some CPU cycles and also some memory bandwidth as you'll have to transfer data between CPU and GPU memory before each mesh rendering.
Indeed, other techniques like dfx/dfy will consume some GPU cycles.
Then, in the end, my advice would be to profile your rendering time in order to find the best solution for you app.
For example, if you are short in GPU cycles, it's better to have pre-computed normals in a vbo even if this leads to vertices duplication. If you are short in the CPU, again, pre-computed normals are a better choice. If you're short in GPU memory, then on the fly GPU normals computation could be a good solution...
Hope this helps.