Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django/Webpack - How to serve generated webpack bundles with webpack dev server

Django's 'static' tag generates urls using STATIC_URL, which results in something like '/static/myapp/js/bundle.js' Mean while, webpack-dev-server is serving bundles from the url 'localhost:3000'

My question is how do I get Django 'static' template tag to generate a different url ( which points to webpack dev server) for js bundles. Of course I can hardcode it in the template, but that would not be a good solution.

Below is my project configuration

webpack.config.js

const path = require('path')
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const BundleTracker = require('webpack-bundle-tracker')


module.exports = {
    mode: 'development',
    context: path.dirname(path.resolve(__dirname)),
    entry: {
        index: './typescript_src/index.ts',
    },
    output: {
        path: path.resolve('./myproject/assets/myapp/bundles/'),
        filename: "[name]-[hash].js"
    },
    resolve: {
        extensions: ['.ts', '.js' ]
    },
    module: {
        rules: [
            {
                test: /\.css$/,
                use: ['style-loader', 'css-loader']
            },
            {
                test: /\.ts$/,
                use: 'ts-loader',
                exclude: /node_modules/
            }
        ]
    },
    plugins: [
        new CleanWebpackPlugin(),
        new BundleTracker({filename: './myproject/webpack-stats.json'})
    ],
    devServer: {
        port: 3000,
        publicPath: '/myapp/bundles/',
        // hot: true,
        headers: {
            "Access-Control-Allow-Origin": "http://127.0.0.1:8000", /**Django dev server */
        }
    }
}

settings.py

WEBPACK_LOADER = {
    'DEFAULT': {
        'CACHE': not DEBUG,
        'BUNDLE_DIR_NAME': 'myapp/bundles/', # must end with slash
        'STATS_FILE': os.path.join(BASE_DIR, 'webpack-stats.json'),
        'POLL_INTERVAL': 0.1,
        'TIMEOUT': None,
        'IGNORE': [r'.+\.hot-update.js', r'.+\.map']
    }
}

STATIC_URL = '/static/'
STATICFILES_DIRS = (
    os.path.join(BASE_DIR, 'assets'),
)

Initially I decided webpack should serve other static files as well during development

webpack.config.js

devServer: {
        port: 3000,
        publicPath: '/myapp/bundles/',
        contentBase: path.resolve('./myproject/assets')
        // hot: true,
        headers: {
            "Access-Control-Allow-Origin": "http://127.0.0.1:8000", /**Django dev server */
        }

settings.py

# in development mode serve from wepack dev server
if DEBUG:
    STATIC_URL = 'http://localhost:3000/'
else:
    STATIC_URL = '/static/'

But I later realized I have to serve static files of other apps (admin, tinymce, ...), which is impossible for webpack Dev server to reach

The problem here is that the url generated by 'render_bundle' tag of django-webpack-loader (/static/myapp/bundles/bundle-name.js) will result in a Http 404 because webpack-dev-server keeps the generated bundle in memory and not on disk

Also if I set

STATIC_URL = localhost:3000

and configure webpack-dev-server to serve other static files of my app, static files of other apps won't be served

like image 274
myke Avatar asked Aug 07 '19 12:08

myke


People also ask

Where does webpack serve files from?

The webpack-dev-server will serve the files in the current directory, unless you configure a specific content base. Using this config webpack-dev-server will serve the static files in your public folder. It'll watch your source files for changes and when changes are made the bundle will be recompiled.

Does django use webpack?

Use webpack to generate your static bundles without django's staticfiles or opaque wrappers. Django webpack loader consumes the output generated by webpack-bundle-tracker and lets you use the generated bundles in django.

When we run the webpack-dev-server what port will it run on by default?

The Result Either method will start a server instance and begin listening for connections from localhost on port 8080 . webpack-dev-server is configured by default to support live-reload of files as you edit your assets while the server is running.


1 Answers

Let's analyze the issue:

We have 2 servers and we want to route requests to one or the other based on the path requested:

"/static/webpackbundles/** ==> webpack dev server

other paths ==> django dev server

This is exactly the job of a proxy server, it can be achieved with a third server (haproxy, nginx ...), but that might seem like an overkill, especially if we know that webpack dev server can be used as a proxy! (https://webpack.js.org/configuration/dev-server/#devserverproxy)

webpack.config.js

const path = require('path');

module.exports = {
  mode: 'development',
  entry: './src/index.js',
  output: {
    filename: 'main.js',
    path: '/path/to/django_project/django_project/static/webpackbundles',
    publicPath: '/static/webpackbundles/',
  },
  devServer: {
    contentBase: '/path/to/django_project/django_project/static/webpackbundles',
    hot: true,
    proxy: {
      '!/static/webpackbundles/**': {
        target: 'http://localhost:8000', // points to django dev server
        changeOrigin: true,
      },
    },
  },
};

In your django template:

<script type="text/javascript" src="{% static 'webpackbundles/main.js' %}"></script>

Now access your django app/site using webpack dev server address: ex: http://localhost:8081

With this simple config you'll have browser auto refresh and hot module replacement. You will not need to change anything in django, also no need for django-webpack-loader

like image 147
Ejez Avatar answered Oct 22 '22 21:10

Ejez