Skip to content

Instantly share code, notes, and snippets.

@zefanjajobse
Last active April 30, 2025 15:29
Show Gist options
  • Select an option

  • Save zefanjajobse/95976043292a3380080651102d9caeab to your computer and use it in GitHub Desktop.

Select an option

Save zefanjajobse/95976043292a3380080651102d9caeab to your computer and use it in GitHub Desktop.
Use IISnode for webpack, nextjs or vite dev server

IIS is a way to setup web servers on windows. mostly used when you want to run asp.net with a a domain name instead of a random port. IISNode can be used to run node.js within IIS, so the frontend can have a domain name as well while testing. which can also be frameworks like webpack, vite and next-js. with on-filechange re-rendering. For other languages, like go and python, the httpplatformhandler is recommended. Which can be downloaded here.

For iisnode to work you need to enable the Application Development Features within IIS: Pasted image 20250407204729

The IIS-site can automatically be created or updated via PowerShell, this example creates a IIS-site on the current location:

# https://learn.microsoft.com/en-us/powershell/module/webadministration/new-website?view=windowsserver2025-ps

$name = "gametools-website-v1" # update version number on changes
$loc = Get-Location # current location
# Check if a site exist with the current path
$has_site = Get-Website | Select-Object PhysicalPath, Name | Where-Object PhysicalPath -eq $loc.path

# Check if the name of the site has a specific name
if ($has_site -and $has_site.Name -ne $name) {
	Write-Output "Removed old site"
	Remove-Website -Name $has_site.Name
}

# Check if the site still exists
$has_site = Get-Website | Select-Object PhysicalPath, Name | Where-Object PhysicalPath -eq $loc.path
# Otherwise recreate
if ( !$has_site )
{
	New-WebSite -Name $name -Port "80" -HostHeader "gametools.localhost" -PhysicalPath $loc.path
}

The settings for the created IIS-site can be changed with a web.config file, where you can setup IISNode. This file has to be placed at the entry point of the site:

<configuration>
  <system.webServer>
    <handlers>
      <add name="iisnode" path="server.js" verb="*" modules="iisnode" />
    </handlers>
    
    <rewrite>
      <rules>
        <rule name="myapp">
          <match url=".*" />
          <!-- optional, allow access to the iisnode folder -->
          <conditions logicalGrouping="MatchAll">
            <add input="{REQUEST_URI}" matchType="Pattern" pattern="iisnode/(.*)" negate="true" />
          </conditions>
          <!-- optional -->
          <action type="Rewrite" url="server.js" />
        </rule>
      </rules>
    </rewrite>
    <iisnode
      nodeProcessCommandLine="&quot;C:\Program Files\nodejs\node.exe&quot;" 
      interceptor="&quot;%programfiles%\iisnode\interceptor.js&quot;"
       loggingEnabled="true"
                 debuggingEnabled="true" 
      logDirectory="iisnode" />
  </system.webServer>
</configuration>

After that a server.js can be used as the entry point of the nodejs instance, attached to iisnode. The entrypoint has to use a named pipe as port, which both http and express support. Here are a few versions for different frameworks, with the change to http or express to meet that requirement:

Vite

server.js: https://vite.dev/guide/api-javascript.html#createserver

import express from 'express'
import { createServer as createViteServer } from 'vite'

async function createServer() {
  const app = express()

  // Create Vite server in middleware mode
  const vite = await createViteServer({
    server: { middlewareMode: true },
  })
  // Use vite's connect instance as middleware
  app.use(vite.middlewares)

  app.listen(process.env.PORT, () => console.log(`Example app listening on port ${process.env.PORT}!`))
}

createServer()

nextjs

server.js: https://nextjs.org/docs/pages/building-your-application/configuring/custom-server

import { createServer } from "http";
import { parse } from "url";
import next from "next";

const port = process.env.PORT;
const dev = process.env.NODE_ENV !== "production";
const app = next({ dev });
const handle = app.getRequestHandler();

app.prepare().then(() => {
  createServer((req, res) => {
    const parsedUrl = parse(req.url, true);
    handle(req, res, parsedUrl);
  }).listen(port);

  console.log(
    `> Server listening at ${port} as ${
      dev ? "development" : process.env.NODE_ENV
    }`,
  );
});

Webpack

server.js: https://webpack.js.org/api/webpack-dev-server/

const express = require('express'); //your original BE server
const app = express();

const webpack = require('webpack');
const webpackConfig = require('./configs/webpack/dev.js');
const middleware = require('webpack-dev-middleware'); //webpack hot reloading middleware
const compiler = webpack(webpackConfig); //move your `devServer` config from `webpack.config.js`


app.use(middleware(compiler, {
  // webpack-dev-middleware options
}));

app.listen(process.env.PORT, () => console.log(`Example app listening on port ${process.env.PORT}!`))

End result

Pasted image 20250404231936

Debugging

The iisnode can also be attached to the debugger of vscode according to link. after appending --inspect behind the nodeProcessCommandLine within the iisnode.yml, mentioned below. .vscode\launch.json:

{
    // Use IntelliSense to learn about possible attributes.
    // Hover to view descriptions of existing attributes.
    // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
    "version": "0.2.0",
    "configurations": [
        {
            "type": "node",
            "request": "attach",
            "name": "Debug IISNode",
            "address": "127.0.0.1",
            "port": 9229,
            "localRoot": "${workspaceFolder}",
            "remoteRoot": "${workspaceFolder}"
        }
    ]
}

Further IIS-Node changes can be made by creationg a iisnode.yml config file, it will override all iisnode settings set within web.config:

iisnode.yml

# # The optional iisnode.yml file will override all iisnode configuration settings specified in web.config.

# # node_env - determines the environment (production, development, staging, ...) in which
# # child node processes run; if nonempty, is propagated to the child node processes as their NODE_ENV
# # environment variable; the default is the value of the IIS worker process'es NODE_ENV
# # environment variable

# node_env:

# # nodeProcessCommandLine - command line starting the node executable; in shared
# # hosting environments this setting would typically be locked at the machine scope.

nodeProcessCommandLine: "C:\Users\zjobse\AppData\Local\nvm\v23.11.0\node.exe" --inspect
>iisnode nodeProcessCommandLine=”C:\Program Files\nodejs\node.exe –inspect”<
# # interceptor - fully qualified file name of a node.js application that will run instead of an actual application
# # the request targets; the fully qualified file name of the actual application file is provided as the first parameter
# # to the interceptor application; default interceptor supports iisnode logging

interceptor: "%programfiles%\iisnode\interceptor.js"

# # nodeProcessCountPerApplication - number of node.exe processes that IIS will start per application;
# # setting this value to 0 results in creating one node.exe process per each processor on the machine

nodeProcessCountPerApplication: 1

# # maxConcurrentRequestsPerProcess - maximum number of reqeusts one node process can
# # handle at a time

maxConcurrentRequestsPerProcess: 1024

# # maxNamedPipeConnectionRetry - number of times IIS will retry to establish a named pipe connection with a
# # node process in order to send a new HTTP request

maxNamedPipeConnectionRetry: 100

# # namedPipeConnectionRetryDelay - delay in milliseconds between connection retries

namedPipeConnectionRetryDelay: 250

# # maxNamedPipeConnectionPoolSize - maximum number of named pipe connections that will be kept in a connection pool;
# # connection pooling helps improve the performance of applications that process a large number of short lived HTTP requests

maxNamedPipeConnectionPoolSize: 512

# # maxNamedPipePooledConnectionAge - age of a pooled connection in milliseconds after which the connection is not reused for
# # subsequent requests

maxNamedPipePooledConnectionAge: 30000

# # asyncCompletionThreadCount - size of the IO thread pool maintained by the IIS module to process asynchronous IO; setting it
# # to 0 (default) results in creating one thread per each processor on the machine

asyncCompletionThreadCount: 0

# # initialRequestBufferSize - initial size in bytes of a memory buffer allocated for a new HTTP request

initialRequestBufferSize: 4096

# # maxRequestBufferSize - maximum size in bytes of a memory buffer allocated per request; this is a hard limit of
# # the serialized form of HTTP request or response headers block

maxRequestBufferSize: 65536

# # watchedFiles - semi-colon separated list of files that will be watched for changes; a change to a file causes the application to recycle;
# # each entry consists of an optional directory name plus required file name which are relative to the directory where the main application entry point
# # is located; wild cards are allowed in the file name portion only; for example: "*.js;node_modules\foo\lib\options.json;app_data\*.config.json"

# watchedFiles: *.js;iisnode.yml

# # uncFileChangesPollingInterval - applications are recycled when the underlying *.js file is modified; if the file resides
# # on a UNC share, the only reliable way to detect such modifications is to periodically poll for them; this setting
# # controls the polling interval

# uncFileChangesPollingInterval: 5000

# # gracefulShutdownTimeout - when a node.js file is modified, all node processes handling running this application are recycled;
# # this setting controls the time (in milliseconds) given for currently active requests to gracefully finish before the
# # process is terminated; during this time, all new requests are already dispatched to a new node process based on the fresh version
# # of the application

# gracefulShutdownTimeout: 60000

# # loggingEnabled - controls whether stdout and stderr streams from node processes are captured and made available over HTTP

# loggingEnabled: true

# # logDirectory - directory name relative to the main application file that will store files with stdout and stderr captures; 
# # individual log file names have unique file names; log files are created lazily (i.e. when the process actually writes something
# # to stdout or stderr); an HTML index of all log files is also maintained as index.html in that directory;
# # by default, if your application is at http://foo.com/bar.js, logs will be accessible at http://foo.com/iisnode;
# # SECURITY NOTE: if log files contain sensitive information, this setting should be modified to contain enough entropy to be considered
# # cryptographically secure; in most situations, a GUID is sufficient

# logDirectory: iisnode

# # debuggingEnabled - controls whether the built-in debugger is available

debuggingEnabled: true

# # debuggerPortRange - range of TCP ports that can be used for communication between the node-inspector debugger and the debugee; iisnode
# # will round robin through this port range for subsequent debugging sessions and pick the next available (free) port to use from the range

debuggerPortRange: 5058-6058

# # debuggerPathSegment - URL path segment used to access the built-in node-inspector debugger; given a node.js application at
# # http://foo.com/bar/baz.js, the debugger can be accessed at http://foo.com/bar/baz.js/{debuggerPathSegment}, by default
# # http://foo.com/bar/baz.js/debug

# debuggerPathSegment: debug

# # debugHeaderEnabled - boolean indicating whether iisnode should attach the iisnode-debug HTTP response header with 
# # diagnostics information to all responses

# debugHeaderEnabled: false

# # maxLogFileSizeInKB - maximum size of a single log file in KB; once a log file exceeds this limit a new log file is created

# maxLogFileSizeInKB: 128

# # maxTotalLogFileSizeInKB - maximum total size of all log files in the logDirectory; once exceeded, old log files are removed

# maxTotalLogFileSizeInKB: 1024
    
# # maxLogFiles - maximum number of log files in the logDirectory; once exceeded, old log files are removed

# maxLogFiles: 20

# devErrorsEnabled: true

# # flushResponse - controls whether each HTTP response body chunk is immediately flushed by iisnode; flushing each body chunk incurs
# # CPU cost but may improve latency in streaming scenarios

# flushResponse: false

# # enableXFF - controls whether iisnode adds or modifies the X-Forwarded-For request HTTP header with the IP address of the remote host

# enableXFF: false

# # promoteServerVars - comma delimited list of IIS server variables that will be propagated to the node.exe process in the form of
# # x-iisnode-<server_variable_name>
# # HTTP request headers; for a list of IIS server variables available see
# # http://msdn.microsoft.com/en-us/library/ms524602(v=vs.90).aspx; for example "AUTH_USER,AUTH_TYPE"

# promoteServerVars:     
Pasted image 20250405000209

When using NVM, add the IUSR, IIS_IUSRS to the symbolicly linked folder as mentioned here

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment