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
Advertisement
Answer
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