Taking you to be asking two questions, what does pkce guard against, and how is client_id being random offering any protection to you if people can just lift it out of your source code, this is my understanding:
why does pkce even exist:
the whole reason for pkce is due to the nature that mutliple smartphone apps can register themselves to be "handlers" of specific url patterns, (this is a vulnerability that only exists in smartphones, if you're making a single page app this is not really a vulnerability for you though I think the advice is to use PKCE if you aren't using a client secret regardless, also it's harmless to use PKCE regardless because it won't ruin anything if you use it and the server doesn't support it)
why bad on smartphone:
when the oauth2 service redirects the user back to your app, following your apps pre-registered redirection url, the browser on the smartphone is going to attempt to navigate to that url, at that point the operating system detects this (both android and ios work this way) and notices that it matches with a few apps already registered at installation time to handle such urls, and it could automatically pass it to the wrong app, which could then maliciously act to get an access token with that and start doing bad stuff in the name of the user.
why should client id be random if it can easily be lifted:
from the docs here:
https://www.oauth.com/oauth2-servers/client-registration/client-id-secret/
"If the client ID is guessable, it makes it slightly easier to craft
phishing attacks against arbitrary applications."
So my guess is being random basically just adds another level of effort for a malware author to put in in order to write something that would affect your app. (you won't be protected from a malware author that targets your app, but you would be protected from a malware author that is blanket targeting all apps say on an appstore...)
The other part to the question, whats to stop an attacker from stealing your clientId and making a request to the auth server masquerading as your app. This won't work because of the redirection URL's.
it is critical that the service doesn’t redirect the user to arbitrary locations
https://www.oauth.com/oauth2-servers/redirect-uris/
If a user visits the attackers app, and is redirected to the auth server to authenticate but the redirect made use of your apps clientId, then the auth server would redirect the user back to your app, not the attackers,
see the security considerations of the docs:
https://www.oauth.com/oauth2-servers/single-page-apps/#security-considerations
The only way the authorization code grant with no client secret can be secure is by using the “state” parameter and restricting the redirect URL to trusted clients.
What they mean by using the state parameter is that your app can make use of local persistent storage (like local storage for a webpage) to generate a random string that it would include in the state param of the redirect request, and if the auth server redirects the user back to your app/web app after the user authenticates, it will echo back the state param and your app should verify that the value in that matches a recently previously stored state random string in said local storage or similar to have a confidence that the user being redirected back to your app was the result of an auth flow that was indeed kicked off by your app and not an attackers app, (if the redirection has no state param or a state param that doesn't match anything in the apps local storage then at that point your app should know that it wasn't itself that initiated that auth flow, and so should not consider the user as having completed the flow properly (should not proceed to trade the auth code for a token)