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). 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(PACKAGE_DIR, 'ssr', 'scripts', 'react', 'server.js'),
# 'client': os.path.join(PACKAGE_DIR, 'ssr', 'scripts', 'react', 'client.js'),
# }
}
},
# ...
]
STATICFILES_DIRS = (
os.path.join(BASE_DIR, '.ssr', 'static'),
# ...
)
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: '{PACKAGE_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)
return `
<!DOCTYPE html>
<head>
<!-- ... -->
${stylesheet && `<link src="${stylesheet}" rel="stylesheet">`}
</head>
<body>
<div id="root">${html}</div>
<script>
window.props = "${encodeURIComponent(JSON.stringify(props))}"
</script>
<script src="${script}"></script>
</body>
`
}
scripts.client
Default: '{PACKAGE_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 component = createElement(Component, JSON.parse(decodeURIComponent(window.props)))
const root = document.getElementById('root')
hydrate(component, root)
}
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Hashes for django_parcel_ssr-0.0.1-py3-none-any.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | efc06d3f488a7d2ab94b9f0f42142e197a246ee423ccbf2d64d3264e2a74b5a3 |
|
MD5 | 51870e98a31e7b022a7b4acb69cb1212 |
|
BLAKE2b-256 | 56a271f3275d5240ae49ddced409e1d24c00dd1ed42a7d2e7c83246d3650220c |