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
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
Share Improve this question edited Sep 25, 2019 at 22:43 myke asked Aug 7, 2019 at 12:11 mykemyke 3063 silver badges11 bronze badges3 Answers
Reset to default 11Let'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/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
Building on @Ejez answer, i was able to configure webpack-dev-server to serve all static files (including, media files)
webpack.config.js
module.exports = {
// project root (usually package.json dir)
context: path.dirname(path.resolve(__dirname)),
output: {
path: path.resolve('./path/to/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: '/path/to/webpack-stats.json'})
],
optimization: {
splitChunks: {
chunks: 'all',
name: 'lib' // bundle all their party libraries in lib.js
}
},
devServer: {
// if you do not mind webpack serving static files of other apps
// collect them (with django collectstatic) into /static_root/static/
// this way webpack-dev-server can serve from your own app's /static/
// directory and also /static_root/static/ directory (which contains
// static files of other apps
contentBase: [path.resolve('./project'), path.resolve('./project/static_root')],
// webpack bundles will be served from http://locahost:3000/static/project/bundles/
publicPath: '/static/project/bundles/',
port: 3000,
// proxy all request except (static and media files) to django dev server
proxy: [{
context: ['**', '!/static/**', '!/media/**'],
target: 'http://localhost:8000',
changeOrigin: true,
}]
}
}
Now you can access your project from webpack-dev-server url localhost:3000
. Do not forget to start both dev servers (webpack and django)
Is generally not justified using STATICFILES_DIRS, instead use STATIC_ROOT. If You have permission to copy static files to the project folder then use STATIC_ROOT.