Pages

Monday, July 16, 2018

Building daycare website [Part 12]: Setup WebPack to use file polling when running application inside Docker container.

On my previous post I described how to use Docker to create an image that can be used for development. However, if you run this container you will find that modifying typescript files will not auto-reload the browser with your changes. The reason is that the WebPack's development server has problems with file notifications when running in a Docker container with volumes.

To work around this, additional steps need to be taken, first in the Docker.dev file:

FROM microsoft/aspnetcore-build:2.0.3

# Required inside Docker, otherwise file-change events may not trigger
ENV DOTNET_USE_POLLING_FILE_WATCHER 1
ENV ASPNETCORE_ENVIRONMENT Development
ENV DOCKER_ENVIRONMENT Development

...

Notice the DOCKER_ENVIRONMENT variable. This is a custom variable that will be used in Startup.cs to configure WebPack's deveopment server to use polling to detect changes instead of the native OS file notifications. Here is the relevant section of Startup.cs:

public class Startup
{
    public void Configure(IApplicationBuilder app)
    {
        if (env.IsDevelopment())
        {
            var webpackOptions = new WebpackDevMiddlewareOptions();
           
            var dockerEnvironment = Environment.GetEnvironmentVariable("DOCKER_ENVIRONMENT");
            if (!String.IsNullOrEmpty(dockerEnvironment))
            {
                webpackOptions.EnvironmentVariables = new Dictionary<string, string>() { { "DOCKER_ENVIRONMENT", dockerEnvironment } };
            }

            app.UseWebpackDevMiddleware(webpackOptions);
        }
    }
}

All that is happening here is that the environment variable is being read and added to the webPackOptions that the JavascriptServices will use when running the webpack development server (all this only if Development mode, of course).

The last piece of the puzzle is in webpack.config.js, where the environment variable is being read, and if the application in running inside a Docker container will configure webpack to use polling to trigger a recompilation of the client side source.

module.exports = (env) => {
    const isDevBuild = !(env && env.prod);
    const isDockerContainer = !isDevBuild && env && env.DOCKER_ENVIRONMENT;

    return [{
        resolve: {
            extensions: ['.ts', '.js'],
            modules: ['ClientApp', 'node_modules'],
        },
        output: {
            path: path.resolve(bundleOutputDir),
            publicPath: '/dist/',
            filename: '[name].js'
        },
        watch: !!isDockerContainer,
        watchOptions: {
            ignored: /node_modules/,
            aggregateTimeout: 300,
            poll: 1000
        },
    }];
}

Notice in line #15 that the 'watch' property is set depending on the DOCKER_ENVIRONMENT variable. Additionally, the 'watchOptions' property configures the file watcher to poll every second.

With these changes in place, when you run the application inside the container and a typescript file is touched, after one second webpack will recompile the sources and you can reload the browser to see the changes.

1 comment:

  1. Wouldn't it be a lot cleaner to use the dotnet.exe tool docker-watch instead of some fragile environment variable that doesn't actually detect whether you are in a container or outside the container?

    ReplyDelete

Note: Only a member of this blog may post a comment.