From shaderLABS

How chunkloading works:

Chunkloading can be triggered for a lot of different reasons, but for this explanation I am going to assume that chunkloading was triggered because the player crossed a chunk boundary. I am also assuming this is in singleplayer. I will get back to both of these assumptions later.

Step 1: The server thread tries to load that chunk from disk. If that fails, it will generate the chunk based on the world seed. After this is done, the chunk is "loaded server-side", and server-side processes can query what blocks exist in this chunk.

Step 2: The server will send the data of that chunk to the client. This happens in singleplayer too since even singleplayer worlds have their own "integrated" server. After the client receives and processes this information, the chunk is now "loaded client-side", and client-side processes can query what blocks exist in this chunk. But the story isn't over yet.

Step 3: After that, the chunk is queued to have its "meshes built". This basically means converting all the blocks in that chunk into a list of vertexes that the GPU can actually draw. This process is actually done for every "chunk section" (a chunk section is a 16x16x16 volume), not the entire chunk all at once. Also, this will only happen for sections which are within the player's view frustum, and have line of sight to the player. Any sections which do not meet these criteria are only built after that section becomes visible again.

Step 4: Once a chunk section has its mesh built, the final step is to upload that mesh to the GPU. Once this is done, the chunk section is now "uploaded", and it will appear on your screen.

So... why is all of this important to know?

I actually wrote this page as an explanation for why "shadow leaking" happens. This is a common issue with shader packs which use a shadow map, in which sunlight will appear on some blocks underground. The reason why this happens is that shaders only know about chunks which are uploaded. If the player is underground, the chunk sections on the surface may be loaded client-side, but they might not be visible, and therefore might not have their meshes built or uploaded. In this case, the shader thinks there's nothing but air between the wall you're looking at and the sun. And the thing is, sunlight can travel through air. So you get issues like this, this, or this.

The only real way to fix this issue is to make sure the chunk sections on the surface are uploaded, and this usually means going to the surface and looking around to make sure everything has line of sight for a little while. Remember, if you go underground again after this, the surface sections are still uploaded until they exit your view distance.

This is not a guaranteed fix, and things can still break at sunset because the only sections which could block the sun are so far away that they're outside your view distance, and are therefore guaranteed to not be uploaded. There's not really anything you can do in this case unfortunately. But at least now you know what's going wrong.

If you're still curious about some of the other details of chunkloading though, there's actually a few more topics to cover, including:

Chunk unloading:

If the player turns around or moves in such a way that existing uploaded chunk sections are no longer visible, the meshes of those sections remain in VRAM, and will be re-used if the player looks at the section again. The chunk sections do not need to have their meshes re-built in this case. The chunk is not unloaded on the client or the server either, and both the client and the server can still query what blocks are in this chunk.

If the player crosses another chunk boundary and suddenly some chunks are outside the player's view distance, all of the chunkloading processes will be undone. The meshes are erased from VRAM, and the chunk is forgotten on both the client and the server. Nothing can query what blocks are in this chunk anymore unless chunkloading is triggered again.

If a block or light level changes while a chunk is still loaded:

First, the server knows about this change immediately, and server-side processes can query the block to see that it did in fact change.

Then the server tells the client that the block changed. Once the client processes this message, client-side processes can query that change too.

Then the chunk sections are re-added to the queue to have their meshes built again. This uses the same logic as chunkloading, so if the sections aren't visible, then they will only be re-built once they become visible again.

After the new meshes are built, they are re-uploaded to the GPU, and the old meshes are forgotten. The chunk section now looks different on your screen to reflect the block or light level that changed.

The chunk does not unload on the client or the server at any point during this process, and the blocks inside the chunk can still be queried on both the client and the server while its meshes are being re-built on the client.

If chunkloading was triggered for a different reason (for example, redstone):

Step 1 will be performed, but steps 2-4 might not be. This simply depends on whether or not the chunk is within the player's view distance. Or, on a multiplayer server, whether or not the chunk is in any player's view distance.

If the player crosses a chunk border and "loads" a chunk which is already loaded on the server for any reason:

Only step 1 will be skipped in this case. The chunk will not be read from disk, nor will it be generated from the world seed. It will still get sent to the client, and it will still have its meshes built and uploaded.