Skip to main content

Django server side rendering, powered by Parcel bundler

Project description

Django Parcel SSR

Zero configuration performant JavaScript server side rendering for Django web framework, powered by Parcel bundler.

Install

pip install django-parcel-ssr
npm install parcel-bundler

React is supported out of the box, but any JavaScript view library with server side rendering support can be used instead (see scripts option and examples). To use React install additional dependencies:

npm install react react-dom react-helmet

Update TEMPLATES and STATICFILES_DIRS entries in settings.py:

TEMPLATES = [
    {
        'BACKEND': 'ssr.backend.Components',
        'DIRS': [],
        'APP_DIRS': True,
        'OPTIONS': {
            # 'extensions': ['js', 'jsx', 'ts', 'tsx'],
            # 'output_dirname': 'dist/',
            # 'json_encoder': 'django.core.serializers.json.DjangoJSONEncoder',
            # 'cache': True,
            # 'env': {
            #     'NODE_ENV': 'development' if DEBUG else 'production',
            #     'NODE_OPTIONS': '--experimental-modules --no-warnings',
            #     'WORKER_TTL': 1000,
            # },
            # 'scripts': {
            #     'server': os.path.join(BASE_DIR, '.ssr', 'scripts', 'react', 'server.js'),
            #     'client': os.path.join(BASE_DIR, '.ssr', 'scripts', 'react', 'client.js'),
            # }
        }
    },
    # ...
]

STATICFILES_DIRS = (
    os.path.join(BASE_DIR, '.ssr', 'static'),
    # ...
)

Initialize server side rendering in wsgi.py:

# ...
import ssr
ssr.setup()

Usage

JavaScript files in bundles directories of installed Django apps serve as Parcel entry points and they have to provide a root component as default export.

Create an example bundles/template.js file in an installed app directory:

import React from 'react'
import { Helmet } from 'react-helmet'

export default props => {
    const [count, setCount] = React.useState(props.count)
    return (
        <div>
            <Helmet>
                <title>{props.title}</title>
            </Helmet>

            <h1>Count: {count}</h1>
            <button onClick={() => setCount(count + 1)}>+</button>
            <button onClick={() => setCount(count - 1)}>-</button>
        </div>
    )
}

Bundles are available to the templating engine for server side rendering, but context has to be JSON serializable (see restrictions below).

Create an example Django view in urls.py:

from django.urls import path
from django.shortcuts import render

def react_view(request):
    return render(request, 'template.js', context={
        'title': 'Django SSR'
        'count': 0
    })

urlpatterns = [
    # ...
    path('', react_view)
]

Run ./manage.py runserver and navigate to http://localhost:8000.

Consult Parcel documentation to learn about supported assets, recipes, and more.

Restrictions

Template context has to be a JSON serializable value because the actual rendering is handled by JavaScript. Django objects have to be serialized; querysets can be rendered as dictionaries instead of model instances using QuerySet.values(). For advanced use cases such as handling model relations, serialize context data manually, e.g. using Django Rest Framework's model serializer.

Options

extensions

Default: ['js', 'jsx', 'ts', 'tsx']

List of valid file extensions for bundles.

output_dirname

Default: 'dist/'

Name of the Parcel bundles output directory. Trailing slash is required.

json_encoder

Default: 'django.core.serializers.json.DjangoJSONEncoder'

JSON encoder class used for serializing view context into props.

cache

Default: True

Enables or disables Parcel bundler caching.

env.NODE_ENV

Default: 'development' if DEBUG else 'production'

Development mode activates bundle watchers with HMR (hot module replacement). Production mode performs a single build and outputs optimized bundles.

env.NODE_OPTIONS

Default: '--experimental-modules --no-warnings'

CLI options for Node workers.

Server side renderer uses experimental ECMAScript modules loader to handle dynamic imports, only available in Node 10+. If you require support for older versions of Node, esm loader can be used instead:

npm install esm

Add it to settings.py:

'OPTIONS': {
    'env': {
        'NODE_OPTIONS': '-r esm'
    }
}

env.WORKER_TTL

Default: 1000

Number of milliseconds Node workers will wait for Django to restart before exiting.

scripts.server

Default: '{BASE_DIR}/.ssr/scripts/react/server.js'

Absolute path to custom createRenderer function, used to create render function which has to return HTML document string. This file is transpiled and executed on the server.

import { createElement, renderToString } from 'some-view-library'

export default Component => ({ script, stylesheet }, props) => {
    const component = createElement(Component, props)
    const html = renderToString(component)
    const serializedProps = encodeURIComponent(JSON.stringify(props))
    return `
        <!DOCTYPE html>
        <head>
            <!-- ... -->
            ${stylesheet && `<link src="${stylesheet}" rel="stylesheet">`}
        </head>
        <body>
            <div id="root" data-props="${serializedProps}">${html}</div>
            <script src="${script}"></script>
        </body>
    `
}

scripts.client

Default: '{BASE_DIR}/.ssr/scripts/react/client.js'

Absolute path to custom hydrate function, used to update the root DOM node when the page loads. This file is transpiled and executed in the browser.

import { createElement, hydrate } from 'some-view-library'

export default Component => {
    const root = document.getElementById('root')
    const props = JSON.parse(decodeURIComponent(root.dataset.props))
    const component = createElement(Component, props)
    hydrate(component, root)
}

Examples

For advanced use cases such as using client side routing, state management libraries, or different JavaScript view libraries altogether, check out the examples:

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

django-parcel-ssr-0.1.4.tar.gz (10.4 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

django_parcel_ssr-0.1.4-py3-none-any.whl (13.8 kB view details)

Uploaded Python 3

File details

Details for the file django-parcel-ssr-0.1.4.tar.gz.

File metadata

  • Download URL: django-parcel-ssr-0.1.4.tar.gz
  • Upload date:
  • Size: 10.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/1.13.0 pkginfo/1.5.0.1 requests/2.21.0 setuptools/40.8.0 requests-toolbelt/0.9.1 tqdm/4.31.1 CPython/3.5.2

File hashes

Hashes for django-parcel-ssr-0.1.4.tar.gz
Algorithm Hash digest
SHA256 b096024a5b42dac141eb3740ebd8b81ec9d5e64e5a3ec501e07dfca749bb505f
MD5 a11ff0009836be7dfeab4be20d438b37
BLAKE2b-256 1d4f7a3da76c027b1b171739d3bf53fd64d249f0e0533285b6bc072c3155e38b

See more details on using hashes here.

File details

Details for the file django_parcel_ssr-0.1.4-py3-none-any.whl.

File metadata

  • Download URL: django_parcel_ssr-0.1.4-py3-none-any.whl
  • Upload date:
  • Size: 13.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/1.13.0 pkginfo/1.5.0.1 requests/2.21.0 setuptools/40.8.0 requests-toolbelt/0.9.1 tqdm/4.31.1 CPython/3.5.2

File hashes

Hashes for django_parcel_ssr-0.1.4-py3-none-any.whl
Algorithm Hash digest
SHA256 cb40db8a863abe911a2c2c4e04cf4769a0c005b9c437be5b45d4622adb55eaba
MD5 188b292b5b0999c61f0a4c02713c772f
BLAKE2b-256 e0cf2fff25a4a1c9dee2bca94b39bfdda351411e5406961464af8b4b2d35f280

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page