React-Router enables your ReactJS app to become a SPA through simple routing components. When deploying to IIS, everything works fine when setup using bashHistory. However, when I try to use browserHistory, IIS is trying to return a directory instead of allowing React-Router to grab and resolve the route. How do I setup React-Router to work in an IIS environment?
2 Answers
The key to getting React-Router to work with IIS is to setup URL Rewrite rules. After looking at how some others have setup AngularJS SPA apps with IIS, I have come up with the following solution.
Download and install URL Rewrite on your server (development and production)
Setup rule to catch any url routes that ARE NOT files and ARE NOT directories. Optionally, you can negate any actual directories that you want serve regularly. More info can be found here on Microsoft's Documentation
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<system.webServer>
<rewrite>
<rules>
<rule name="ReactRouter Routes" stopProcessing="true">
<match url=".*" />
<conditions logicalGrouping="MatchAll">
<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
<add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
<add input="{REQUEST_URI}" pattern="^/(docs)" negate="true" />
</conditions>
<action type="Rewrite" url="index.html" />
</rule>
</rules>
</rewrite>
</system.webServer>
</configuration>
- In your base html page (index.html) add a
<base/>tag with ahrefattribute to your app.
<base href='/path/to/my/app'/>
Just building on this answer for anyone interested. If your like me and need to deploy your app via script. Here are the powershell scripts necessary to create the webconfiguration above.
This installs the URL Rewrite on the server.
#Install IIS UrlRewrite
If(Test-Path c:/msi) {
Invoke-WebRequest 'http://download.microsoft.com/download/C/F/F/CFF3A0B8-99D4-41A2-AE1A-496C08BEB904/WebPlatformInstaller_amd64_en-US.msi' -OutFile c:/msi/WebPlatformInstaller_amd64_en-US.msi
Start-Process 'c:/msi/WebPlatformInstaller_amd64_en-US.msi' '/qn' -PassThru | Wait-Process
cd 'C:/Program Files/Microsoft/Web Platform Installer'; .\WebpiCmd.exe /Install /Products:'UrlRewrite2,ARRv3_0' /AcceptEULA /Log:c:/msi/WebpiCmd.log
}
else {
New-Item c:/msi -ItemType Directory
Invoke-WebRequest 'http://download.microsoft.com/download/C/F/F/CFF3A0B8-99D4-41A2-AE1A-496C08BEB904/WebPlatformInstaller_amd64_en-US.msi' -OutFile c:/msi/WebPlatformInstaller_amd64_en-US.msi
Start-Process 'c:/msi/WebPlatformInstaller_amd64_en-US.msi' '/qn' -PassThru | Wait-Process
cd 'C:/Program Files/Microsoft/Web Platform Installer'; .\WebpiCmd.exe /Install /Products:'UrlRewrite2,ARRv3_0' /AcceptEULA /Log:c:/msi/WebpiCmd.log
}
And here is how you add the rules.
Add-WebConfigurationProperty -pspath "$IISPath\MyWebsite" -filter "system.webServer/rewrite/rules" -name "." -value @{name='Home';stopProcessing='True'}
Set-WebConfigurationProperty -pspath "$IISPath\MyWebsite" -filter "system.webServer/rewrite/rules/rule/match" -name "url" -value ".*"
Add-WebConfiguration -pspath "$IISPath\MyWebsite" -filter "system.webServer/rewrite/rules/rule[@name='Home']/conditions" -value @{ input="{REQUEST_FILENAME}"; matchType="IsFile"; negate="true" }
Add-WebConfiguration -pspath "$IISPath\MyWebsite" -filter "system.webServer/rewrite/rules/rule[@name='Home']/conditions" -value @{ input="{REQUEST_FILENAME}"; matchType="IsDirectory"; negate="true" }
Add-WebConfiguration -pspath "$IISPath\MyWebsite" -filter "system.webServer/rewrite/rules/rule[@name='Home']/conditions" -value @{ input="{REQUEST_URI}"; pattern="^/(docs)"; negate="true" }
Set-WebConfigurationProperty -pspath "$IISPath\MyWebsite" -filter "system.webServer/rewrite/rules/rule/action" -name "type" -value "Rewrite"
Set-WebConfigurationProperty -pspath "$IISPath\MyWebsite" -filter "system.webServer/rewrite/rules/rule/action" -name "url" -value "index.html"
These scripts can be executed locally or remotely via Invoke-Command in Powershell.
Also I had some trouble with React Router warnings and with using the base tag in my header on index.html. This link is fairly helpful.
https://github.com/ReactTraining/react-router/issues/4006
I essentially change my React-Router package and History package to version 3.x and set the config in my router to get rid of the deprecation warnings. This is my react router now.
import { useRouterHistory } from 'react-router'
import { createHistory } from 'history'
const history = useRouterHistory(createHistory)({
basename: '/base-path'
})
ReactDOM.render(
<Router history={history}>
....