Integrar Webpack 4 en un proyecto Django 3

1oLDVI S85Zs 59MJvcg6wA
webpack.base.config.js

En este post explicaré los pasos a seguir para integrar Webpack 4 en cualquier proyecto Django 3 con la ayuda de django-webpack-loader y webpack-bundle-tracker

¿Qué es y por qué necesitas Webpack?

Webpack es básicamente un empaquetador de módulos o module bundler que se encarga de generar gráficos de dependencias con todos ellos y crear assets estáticos a partir de los distintos módulos JavaScript o CSS.

En lugar de tener un montón librerías JavaScript (Bootstrap, jQuery, Colorpicker,…) y llamar los ficheros desde el código HTML, podemos obtener un único fichero bundle.js que los incluye todos. Lo mismo ocurre con los CSS.

No solo eso, Webpack es más que una simple utilidad. También tiene loaders y plugins que extienden sus funcionalidades, y permite automatizar tareas con una configuración bastante fácil y ordenada.

Webpack te será útil si desarrollas una aplicación mayormente JavaScript y con unos cuantos módulos. Si estás preparando una página o aplicación muy pequeña y que apenas tenga 2 o 3 componentes, quizá sea demasiado grande para ti. No hay que fliparse y utilizar todo tipo de tecnología moderna para estar a la última. Tenemos que ser ágiles y realistas.

Los módulos que ayudan a integrar Webpack en Django

Webpack se puede utilizar en prácticamente cualquier tipo de proyecto. En el fondo no necesitamos nada especial para que funcione con Django, pero sí existen dos componentes que ayudan en algunas cosas.

En primer lugar, podemos usar webpack-bundle-tracker, que se encarga de “emitir” información sobre el estado de la compilación de Webpack a un fichero JSON que será interpretado por django-webpack-loader, y este utilizará la información generada para integrarlo con Django.

Paso 1: Instalar webpack

El primer paso es generar un package.json y instalar los paquetes necesarios:

npm init

En el fichero package.json podemos añadir los siguientes scripts. Al final me decanté por crear dos webpack.config.js distintos, uno para desarrollo y otro para producción, así que quedaría de esta forma:

...
"main": "webpack.config.js",
"scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "watch": "webpack --watch --mode development",
    "start": "webpack-dev-server --open",
    "build": "webpack --config webpack.base.config.js --progress --colors",
    "build-production": "webpack --config webpack.production.config.js --progress --colors"
  }
...

Esto nos abre la posibilidad de ejecutar los siguientes comandos:

npm run test
npm run watch
npm run start
npm run build
npm run build-production

Paso 2: Crear el fichero webpack.config.js

Como comentaba, en mi caso creé uno para cada entorno.

webpack.base.config.js
webpack.production.config.js

Os voy a compartir el que creé para uno de mis proyectos. He eliminado algunas partes porque tiene varios ficheros css y js añadidos y he dejado dos o tres en cada bundle.

Añadí algunos extras como por ejemplo:

  • IgnorePlugin: Para ignorar ciertos ficheros.
  • ProvidePlugin: Para cargar módulos en lugar de importarlos.
  • ContextReplacementPlugin: Para reemplazar con expresiones regulares. Lo utilicé porque tenía problemas con los .js de la carpeta /locales de uno de los módulos, y con este plugin puedo substituirla con un módulo vacío.
  • En el output: path le indicamos la carpeta donde debe generar los bundles. En este caso: /assets/bundles/

Paso 3: server.js

Necesitamos un servidor node para que Webpack genere los bundles. Para ello necesitamos el fichero server.js, este es el mio:

Paso 4: Instalar django-webpack-loader

Basta con instalar el módulo de Django con pip

pip install django-webpack-loader

Y añadirlo en el fichero requirements.txt

django-webpack-loader==0.7.0

En mi caso he configurado el settings.py para añadir lo siguiente. Primero la carpeta /assets/, que es donde se generan los bundles, en la variable STATICFILES_DIRS

STATICFILES_DIRS = [
...
os.path.join(BASE_DIR, 'assets')
]

Luego la variable WEBPACK_LOADER indicando la carpeta “bundles/” donde se generan (recordamos que es: /assets/bundles), y en el STATS_FILE debemos indicarle el fichero generado por webpack-bundle-tracker, que en mi caso es el de desarrollo.

# Webpack
WEBPACK_LOADER = {
"DEFAULT": {
"CACHE": not DEBUG,
"BUNDLE_DIR_NAME": "bundles/",
"STATS_FILE": os.path.join(BASE_DIR, "webpack-stats.base.json"),
"POLL_INTERVAL": 0.1,
"TIMEOUT": None,
"IGNORE": [".*\.hot-update.js", ".+\.map"],
'LOADER_CLASS': 'webpack_loader.loader.WebpackLoader',
}
}

Paso 5: Indicar los bundles en las plantillas de Django

Nos queda indicarle a Django cómo cargar los bundles generados. En mi caso decidí crear los bundles vendor y main tanto para los ficheros CSS como los JS.

En primer lugar necesitamos cargar el render_bundle del módulo webpack_loader (línea 19)

Ahora ya podemos utilizarlos en la plantilla de Django de la siguiente forma:

<!-- Webpack bundles -->
{% render_bundle "vendor" "css" %}
{% render_bundle "main" "css" %}
....
<!-- Webpack bundles -->
{% render_bundle "vendor" "js" %}
{% render_bundle "main" "js" %}

Y de esta forma, podemos cargar los CSS dentro del <head> y los JS antes de cerrar el <body>

Ahora ya podemos utilizar collectstatic para copiar los ficheros generados en nuestra carpeta de estáticos en producción.

python manage.py collectstatic

Con esto debería ser suficiente para tener todo en funcionamiento. Si se os ocurre alguna forma mejor, será bienvenida.