Search code examples
angulariissingle-spa

IIS Rewrite rule for multiple SPAs


we're creating a new architecture for our microfrontends, and we'd like to avoid the use of another framework to orquestrate it, like single-spa. Our company currently use IIS for other products, and we need to keep it that way.

So, in order to have multiple SPAs responding to the same address, we simply depose our built SPAs in IIS's content directory, like this:

IIS root folder:

  • spa1
  • spa2

I can access myhost/spa1 and myhost/spa2 normally, and navigate thought their own internal routes (we're using Angular).

The problem is, we want to have URLs without #, and than we need to tell IIS to redirect whatever is a sub-route, to it's SPA main route.

We have something in place, it works for myhost/spa1, myhost/spa1/detail, but does not work for myhost/spa1/detail/1. Let's say, the third level.

Could someone help me with this?

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <system.webServer>
        <rewrite>
            <rules>
                <rule name="SPA Rule" stopProcessing="true">
                    <match url="(.+)/.*" />
                    <conditions logicalGrouping="MatchAll">
                        <add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
                        <add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
                    </conditions>
                    <action type="Rewrite" url="{R:1}/" />
                </rule>
            </rules>
        </rewrite>
        <directoryBrowse enabled="true" />
    </system.webServer>
</configuration>

Solution

  • After a few trials, and another requirement (we need to have a selected "company" in the URL), I came up with something that's working pretty well:

    <?xml version="1.0" encoding="UTF-8"?>
    <configuration>
        <system.webServer>
            <rewrite>
                <rules>
                    <rule name="Application Hub Rule" stopProcessing="true">
                        <match url="(hub)(/?.*)" />
                        <conditions logicalGrouping="MatchAll">
                            <add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
                            <add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
                        </conditions>
                        <action type="Rewrite" url="{R:1}/" />
                    </rule>
                    <rule name="CRM Customer Rule" stopProcessing="true">
                        <match url="(crm/customer)(/?.*)" />
                        <conditions logicalGrouping="MatchAll">
                            <add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
                            <add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
                        </conditions>
                        <action type="Rewrite" url="{R:1}/" />
                    </rule>
                </rules>
            </rewrite>
        </system.webServer>
    </configuration>
    

    It's quite unique as requirement, I know. But it turns out the rules are working pretty well. As soon user enters my-host/COMP_CODE/hub, my Angular application handles the URL changes, because everything after my-host/COMP_CODE/hub/**/** is redirected by IIS to the Hub's root folder. Once you enter my-host/COMP_CODE/crm/customer and it's sub-routes, IIS redirects everything to Customer's root folder, and Angular takes care of URL changes.

    Only thing is, in your Angular's RouterModule.forRoot() configuration, you need to make sure Angular's Router understands path: ':db/hub' (among other things).

    Thanks for the guys who tried to help.