Deploying Sveltekit on IIS !
Tags: svelte, javascript, iis, sveltekit
Published: 2023-07-15 05:34:23

This is will be long article because it a self note for deploying Sveltekit project (as node project) on IIS version 10.
For a while I searching thru the internet and asking in [svelte discord](https://discord.com/invite/svelte) (so good community , if you're svelter don't miss to join in) I found out it have little information about how to deploying Sveltekit on IIS , may be I've so many conditions and requirements to made Sveltekit project working on my IIS server.

---

##Conditions and Requirements
1. running with <u>one</u> port and separate each project by <u>sub-directory.</u>
**<u>ex.</u>**
projectA ==>  `https://my.testsites.com:443/projectA`
projectB ==>  `https://my.testsites.com:443/projectB`

2. Need to be Server side rendering (SSR) which is Sveltekit project [suppose to be](https://kit.svelte.dev/docs/page-options#ssr).

3. Any form actions are not blocked by Cross-site Request Forgery (CSRF) [protection of Sveltekit project](https://kit.svelte.dev/docs/configuration#csrf).

---

##Prerequisites
- express.js on sveltekit project
- node.js (recommend [LTS version](https://nodejs.org/en)) on IIS server globally install
- some demo Sveltekit project, Let using [Sveltekit demo project](https://kit.svelte.dev/docs/creating-a-project)
- IIS Services -- [how to install IIS](https://www.itechguides.com/how-to-install-iis-in-windows-11/#:~:text=How%20Do%20I%20Enable%20IIS,Then%20click%20the%20OK%20button.)

_after install IIS_
- [iisnode ](https://github.com/Azure/iisnode)
- [urlrewrite](https://www.iis.net/downloads/microsoft/url-rewrite)

---

##How to step by step
- run `npm i` in your sveltekit project folder
- installing additional dependencies
   - adapter-node for sveltekit `npm i -D @sveltejs/adapter-node`
   - dotenv `npm i dotenv` 
- setup `.env` file in your root folder of your project and put this in your `.env` file
```
ORIGIN=http://localhost:PORT_OF_SITES
```
while `PORT_OF_SITES` will be your port number of IIS site you want to deploy to let say it is 443 then it will be
```
ORIGIN=http://localhost:443
```
this will be using after we have deploy Svletekit project to IIS and prevent CSRF blocked after any form actions

- In root folder of your project find `svelte.config.js` and adding adapter-node and set base path to made it support a sub-directory in Sveltekit, let change all code inside like this
```
import adapter from '@sveltejs/adapter-node';

export default {
	kit: {
		adapter: adapter(),
		paths: {
			relative: false,
			base: '/NAME_OF_SUB-DIRECTORY'
		}
	}
};
```
while `NAME_OF_SUB-DIRECTORY` will specifies where your app is served from and allows the app to live on a non-root path
**<u>ex.</u>** you want your site address like `https://my.sites.com/svelteiis`  then `svelte.config.js` code will be like this
```
import adapter from '@sveltejs/adapter-node';

export default {
	kit: {
		adapter: adapter(),
		paths: {
			relative: false,
			base: '/svelteiis'
		}
	}
};
```
- after we adding adapter-node and adding base path we need to prepend all root-relative links with the `base` value _<u>or they will point to the root of your domain, not your `base` path</u>_ ([this is how the Sveltekit and browser work](https://kit.svelte.dev/docs/configuration#paths))

in `src\routes\Header.svelte`, `src\routes\about\+page.svelte` and  `src\routes\sverdle\+page.svelte` we will adding `import { base } from '$app/paths';` in `<script>` tag and adding every `<a>` tag with `{base}`
**<u>ex.</u>** `<a href="{base}/">Home</a>`, `{base}/about">About</a>`

- next we will build our project as a node project by using `npm run build` and let adapter-node handle it's job . . . . . after some times you will have a `build` folder appear in your root project like image below

![`build` folder](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/m8sx7x2d96bkbxit8yc0.png)

- let change side to config our IIS , firstly open our IIS and on your left pane just opening till you seen `Default Web Site` just right click on it and click `explore` like image below

![explore a Default Web Site in IIS](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gausgmc731f8odytfgyj.png)

-it will open a new window of file explorer with path `C:\inetpub\wwwroot`(let note this as a `wwwroot` folder) after that you can copy a `build` folder that we has created earlier in our Sveltekit project folder and let changing it name form `build` to a name of what your sub-directory you want _<u>that will match with `base` path that we config earlier</u>_ or it cause some issue on navigating to your site!
after this step your `wwwroot` folder will be like image below

![wwwroot folder](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/71fs7rpo0zcsv8ogj4of.png)

**you can deploy your project on new IIS site too by creating a new site in IIS and set physicals path to your deploy folder and bring your `build` folder into there and following the step by changing `build` folder name.

- next we need to copy 2 files form your root project folder, that is `.env` file and `package.json` file and bring it to your deploying folder in `wwwroot` and running just `npm i --omit=dev` in this folder to made node downloading only required dependencies  
   after running npm creating new `web.config` file and adding this code into your `web.config` file 
```
<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <system.webServer>
    <webSocket enabled="false" />
    <handlers>
      <add name="iisnode" path="server.cjs" verb="*" modules="iisnode" />
    </handlers>
	<iisnode node_env="production" nodeProcessCommandLine="C:\Program Files\nodejs\node.exe" />
    <rewrite> 
		<rules>				
            <rule name="NodeInspector" patternSyntax="ECMAScript" stopProcessing="true">
                <match url="^server.cjs\/debug[\/]?" />
                <conditions logicalGrouping="MatchAll" trackAllCaptures="false" />
            </rule>
			
            <rule name="StaticContent">
                <conditions logicalGrouping="MatchAll" trackAllCaptures="false" />
                <action type="Rewrite" url="public{PATH_INFO}" />
            </rule>
			
            <rule name="DynamicContent">
                <conditions logicalGrouping="MatchAll" trackAllCaptures="false">
                    <add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
                </conditions>
                <action type="Rewrite" url="server.cjs" />
            </rule> 
        </rules>
        <outboundRules>
            <rule name="back">
                <match serverVariable="RESPONSE_Location" pattern="(.*)/server.cjs" />
                <action type="Rewrite" value="{R:1}" />
            </rule>
        </outboundRules>
    </rewrite>	
	<defaultDocument>
        <files>
            <add value="server.cjs" />
        </files>
    </defaultDocument>
    <security>
      <requestFiltering>
        <hiddenSegments>
          <remove segment="bin" />
        </hiddenSegments>
        <requestLimits maxAllowedContentLength="4294967295" />
      </requestFiltering>
    </security>
    <httpErrors existingResponse="PassThrough" />
  </system.webServer>
</configuration>
```

after this config your Sveltekit deploy folder will be like a image below 


![in project deploy folder](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/15yjgfv1e6vltlaqnvvz.png)

- last but not least we need to have some JavaScript file that will be running after iisnode calling to our project , that made our project can adjust some environment setting
  let create a new file name `server.cjs` or any other name but if you change the name you need to put that name into a `web.config` file from earlier (try search and replace `server.cjs` with your new file's name in `web.config`)
  after creating a `server.cjs` file add this code below to your file

```
require('dotenv').config();
const express = require('express')

import('./handler.js')
	.then((handler) => {
		const app = express();
		// Custom middleware to make routing case-insensitive
		app.use((req, res, next) => {
			const urlSegments = req.url.split('/');
			urlSegments[1] = urlSegments[1].toLowerCase();
			req.url = urlSegments.join('/');
			next();
		});
		
		// let SvelteKit handle everything else, including serving prerendered pages and static assets
		app.use(handler.handler);

		app.listen(process.env.PORT, () => {
			console.log(
				'app start on port ' + process.env.PORT
			);
		});

	}).catch((err) => console.error(err));
```

  this will made your `.env` file that you copying from earlier working as aspect and will set your origin of project to prevent CSRF protection from a form actions of the project itself and it will made your site can accessing with case insensitive url at a first sub-directory.
by the way you can disabled case insensitive by comment out below code in server.cjs
```
app.use((req, res, next) => {
			const urlSegments = req.url.split('/');
			urlSegments[1] = urlSegments[1].toLowerCase();
			req.url = urlSegments.join('/');
			next();
		}); 
```
  now inside the project folder in `wwwroot` will look like this

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/th11dgdw43ycyke0wb4f.png)

after that you can try going to the site that you have deploy by go to 
`http://localhost/NAME_OF_SUB-DIRECTORY` or `http://localhost:YOUR_IIS_PORT/NAME_OF_SUB-DIRECTORY` 
and finally you has achieved Sveltekit deploying on IIS !

---

If you has any question or suggestion on my walkthrough feel free to giving me a comment below. ;)

Thanks you
Have a nice day and keep coding