First thing first you should put your files in WordPress theme. Which has index.php file so your angular manifest code (index.html) goes there, but with proper links to assets.
For example here's how it might look like after ng build --prod:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>Title</title>
<base href="/" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="icon" type="image/x-icon" href="favicon.ico" />
<link rel="stylesheet" href="styles.b9ab77151b21dce46d94.css" />
</head>
<body>
<app-root></app-root>
<script src="runtime.e227d1a0e31cbccbf8ec.js" defer></script>
<script src="polyfills.a5e98176150f229fcd04.js" defer></script>
<script src="scripts.c5648532e9a6a23906a1.js" defer></script>
<script src="main.2965e15bb04f185e6e09.js" defer></script>
</body>
</html>
The problem with the code above is that files have random hashes after the file name and since we're going to put files in a WordPress theme they are going to be placed at /wp-content/themes/%ThemeName%/dist/.
We need to remove hashing in angular.json:
...
"outputHashing": "none",
...
And add proper paths to assets manually or by adding it to the build command ng build --prod --deploy-url /wp-content/themes/%ThemeName%/dist/.
So our index.html looks like:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>Title</title>
<base href="/" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="icon" type="image/x-icon" href="favicon.ico" />
<link rel="stylesheet" href="/wp-content/themes/%ThemeName%/dist/styles.css" />
</head>
<body>
<app-root></app-root>
<script src="/wp-content/themes/%ThemeName%/dist/runtime.js" defer></script>
<script src="/wp-content/themes/%ThemeName%/dist/polyfills.js" defer></script>
<script src="/wp-content/themes/%ThemeName%/dist/scripts.js" defer></script>
<script src="/wp-content/themes/%ThemeName%/dist/main.js" defer></script>
</body>
</html>
Perfect! Now we need to move that to the WordPress theme index.php:
<!DOCTYPE html>
<html <?php language_attributes(); ?>>
<head>
<meta charset="<?php bloginfo('charset'); ?>" />
<title>Title</title>
<base href="/" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="icon" type="image/x-icon" href="favicon.ico" />
<link rel="stylesheet" href="/wp-content/themes/%ThemeName%/dist/styles.css" />
</head>
<body <?php body_class(); ?>>
<app-root></app-root>
<script src="/wp-content/themes/%ThemeName%/dist/runtime.js" defer></script>
<script src="/wp-content/themes/%ThemeName%/dist/polyfills.js" defer></script>
<script src="/wp-content/themes/%ThemeName%/dist/scripts.js" defer></script>
<script src="/wp-content/themes/%ThemeName%/dist/main.js" defer></script>
</body>
</html>
As you can see we replaced some parts with WordPress functions, like language_attributes, bloginfo('charset'), body_class.
Ok. The only problem, is that WordPress is not always loading index.php, sometimes it will load front-page.php, 404.php etc. So we need to force the WordPress to always load index.php. We can do that by adding this to function.php file of the WordPress theme:
add_filter('template_include', function ($template) {
$template = get_query_template('index');
return $template;
});
Now all we need to do is put /dist folder right along with index.php file in the theme. And it works!
If you want to compile angular on the server
Let's create angular folder in our theme and put in there all our angular files. If we run ng build --prod it would compile all files and put/dist inside the angular folder, but we need to put it outside so it's accessible with path /wp-content/themes/%ThemeName%/dist/. For that we need to add one more setting to angular.json:
...
"outputPath": "../dist",
...
Brilliant! Our compiled /dist folder will be placed outside of current (angular) folder and will be accessible for our index.php file!
I just described how I got this whole thing to work, hope it helps somebody else.