0

I was following this tutorial to set up Django to serve templates with webpack-generated bundles. I have set it up just like in the tutorial. However the problem is when i go to localhost:8000 I get Uncaught SyntaxError: Unexpected token < exception when I open the console in chrome devtools. Other html I put in the template file gets rendered except the reactjs bundle. My folder structure is as follows:

.
├── djangoapp
│   ├── db.sqlite3
│   ├── djangoapp
│   │   ├── __init__.py
│   │   ├── settings.py
│   │   ├── urls.py
│   │   └── wsgi.py
│   ├── manage.py
│   ├── reactapp
│   │   └── static
│   │       ├── bundles
│   │       │   └── main-fdf4c969af981093661f.js
│   │       └── js
│   │           └── index.jsx
│   ├── requirements.txt
│   ├── templates
│   │   └── index.html
│   └── webpack-stats.json
├── package.json
├── package-lock.json
└── webpack.config.js

settings.py

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'webpack_loader'
]

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [os.path.join(BASE_DIR, "templates"), ],
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]

WEBPACK_LOADER = {
    'DEFAULT': {
        'BUNDLE_DIR_NAME': 'bundles/',
        'STATS_FILE': os.path.join(BASE_DIR, 'webpack-stats.json'),
    }
}

STATIC_URL = 'static/'

webpack.config.js

var path = require("path");
var webpack = require('webpack');
var BundleTracker = require('webpack-bundle-tracker');

module.exports = {
  context: __dirname,

  entry: './djangoapp/reactapp/static/js/index.jsx', 

  output: {
      path: path.resolve('./djangoapp/reactapp/static/bundles/'),
      filename: "[name]-[hash].js",
  },

  plugins: [
    new BundleTracker({filename: './djangoapp/webpack-stats.json'}),
  ],

  module: {
    rules: [
      { test: /\.js$/, use: ['babel-loader'], exclude: /node_modules/},
      { test: /\.jsx$/, use: ['babel-loader'], exclude: /node_modules/}
    ]
  },

  resolve: {
    modules: ['node_modules', 'bower_components'],
    extensions: ['.js', '.jsx']
  },


};

templates/index.html

{% load render_bundle from webpack_loader %}
<!DOCTYPE html>
<html>
 <head>
 <meta charset="UTF-8">
 <title>Example</title>
 </head>
 <body>
 <div id="react"></div>
 {% render_bundle 'main' %}
 </body>
</html>

.babelrc

{
  "presets": ["babel-preset-env", "react"]
}

The exception is thrown at the start of line 1 of the main-fdf4c969af981093661f.js file, on the opening tag of <!DOCTYPE html> element. My guess is that the browser expects javascript code, but instead it is given html. Also, I don't understand how does Django know where to look for the bundles since I didn't specify the root (the reactapp directory) of the static/bundles anywhere.

2
  • 1
    Not sure if thats the problem but you should write "env" and not "babel-preset-env" as the preset in .babelrc Commented Mar 6, 2018 at 11:04
  • @MatanBobi You're right, but this doesn't solve the problem. Commented Mar 6, 2018 at 11:11

2 Answers 2

1

I solved the problem after a while by adding the following code to settings.py.

STATICFILES_DIRS = [
   ('bundles', os.path.join(BASE_DIR, 'reactapp/bundles'))
]

STATIC_ROOT = os.path.join(BASE_DIR, 'static')

I also had to change STATIC_URL to /static/.

This is how it is supposed to work:

  • Webpack generates bundles to the reactapp/bundles folder.
  • When Django server is running it scans changes inside reactapp/bundles and after each new change copies the contents of the folder to the root djangoapp/static/ folder as defined by STATIC_ROOT setting.
  • After that the files inside STATIC_ROOT can be accessed by browser through the STATIC_URL like this: localhost:8000/static/bundles/<bundle>. It would normally default to localhost:8000/static/<bundle> but the first element of the tuple inside STATICFILES_DIRS explicitly tells Django to copy the contents inside static/bundles directory.
  • Django then automatically generates links to static files when serving a page.

NOTE: STATIC_URL should be prepended with a / otherwise the static path would be appended to the current page link instead of the root. E.g on the /index page the link to the static file would be localhost:8000/index/static/... instead of localhost:8000/static, which would be wrong and would result in 404 not found.

Sign up to request clarification or add additional context in comments.

Comments

0

This is a tricky one! Everything seems to followed perfectly. First, please ensure django-webpack-loader is installed as expected. Second, your concern seems to be valid, we would have to tell django where exactly to look for bundles as by default it uses STATIC_URL + bundle_name (as suggested in documentation at http://owaislone.org/blog/webpack-plus-reactjs-and-django/). Try adding publicPath to webpack.config.js as:

output: {
  path: path.resolve('./djangoapp/reactapp/static/bundles/'),
  filename: "[name]-[hash].js",
  publicPath: "http://localhost:8080/<path to bundles>"
},

I am not sure if it would work, but let me know if it helps!

1 Comment

Doesn't work. Webpack documentation says publicPath is only useful when you host the bundles on a different domain. Anyway I tried replacing {% render_bundle 'name' %} with <script type="text/javascript" src="/reactapp/static/bundles/main-fdf4c969af981093661f.js"></script> but still no success. Same error.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.