Django con vue.js frontend - Ruta de archivos estáticos

Aug 19 2020

Estoy intentando servir una aplicación django con una interfaz vue y necesito ayuda para configurar los archivos estáticos.

La pregunta TLDR:

¿Cómo consigo que Django reconozca esta ruta construida como un intento de llegar a un archivo estático, o alternativamente, cómo modifico la ruta de inyección posterior a la compilación en el lado de Vue para que coincida con la configuración actual del archivo estático de Django?

Django sirve el index.html construido desde vue, sin embargo, no puede encontrar los archivos estáticos (scripts / css) que se autoinyectan desde el proceso de compilación debido a que la ruta es "absoluta". He modificado vue.config.js para no autoinyectar los scripts (ya que necesitarán {% static %}durante la compilación, y la plantilla index.html para agregarlos adecuadamente.

Mi estructura de directorio es la siguiente:

- Root
  - app
  - migrations
  - templates
    - app (outputDir)
      - index.html (Built from vue)
      - base.html
      - templateFolder1
      - templateFolder2
  - various .py files
  - assets (assetsDir)
    - css
      - static files
    - js
      - static files
  - frontend
    - public
      - index.html (Template for build for vue)
    - src
    - assets
    - components
    - App.vue
    - main.js

La compilación se ejecuta desde el directorio frontend, con --no-clean para no eliminar mi carpeta de plantillas de django en la compilación.

Aquí está mi solución para agregar {% static %}etiquetas al index.html construido. Me doy cuenta de que estoy rompiendo la convención que tiene vue de que assetsDir es un subdirectorio de outputDir, y no me opongo a agregar otro directorio de archivos estáticos a settings.py para que coincida con la convención (aunque mi problema sigue siendo el mismo).

vue.config.js

publicPath: isProd ? '/app/' : '/',
outputDir: __dirname + '/../app/templates/app',
assetsDir: "../../../assets",
indexPath: './index.html',
configureWebpack: {
        ...
        plugins: [
            new HtmlWebpackPlugin({
                template: __dirname + '/public/index.html',
                favicon: __dirname + '/../assets/img/favicon/favicon.ico',
                inject: false,
                minify: false
            })
        ],
    },

public / index.html

{% load static %}
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width,initial-scale=1.0">
    <title>MAPP Remote</title>
      <link rel="shortcut icon" href="{% static '<%= htmlWebpackPlugin.files.favicon %>' %}">
      <% for (key in htmlWebpackPlugin.files.css) { %> <link rel="stylesheet" href="{% static '<%= htmlWebpackPlugin.files.css[key] %>' %}"> <% } %>
  </head>
    <body>
    ...
    <div id="app"></div>

    <!-- built files will be auto injected -->
  <% for (key in htmlWebpackPlugin.files.js) { %> <script type="text/javascript" src="{% static '<%= htmlWebpackPlugin.files.js[key] %>' %}"></script> <% } %>
  </body>
</html>

El index.html construido:

app / templates / app / index.html

{% load static %}
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width,initial-scale=1.0">
    <title>MAPP Remote</title>
      <link rel="shortcut icon" href="{% static '/app/favicon.ico' %}">
       <link rel="stylesheet" href="{% static '/app/../../../assets/css/chunk-vendors.0ba3e87d.css' %}">  <link rel="stylesheet" href="{% static '/app/../../../assets/css/app.fb012fc8.css' %}"> 
  </head>
  <body>
    ...
    <div id="app"></div>

    <!-- built files will be auto injected -->
   <script type="text/javascript" src="{% static '/app/../../../assets/js/chunk-vendors.6a3b11f1.js' %}"></script>  <script type="text/javascript" src="{% static '/app/../../../assets/js/app.45295baa.js' %}"></script> 
  </body>
</html>

Mi configuración de django settings.py para archivos estáticos:

Settings.py

...
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
STATIC_URL = "/static/"
STATICFILES_DIRS = [os.path.join(BASE_DIR, "assets")]
STATIC_ROOT = os.path.join(BASE_DIR, "staticfiles")
STATICFILES_STORAGE = "whitenoise.storage.CompressedManifestStaticFilesStorage"
...

La forma en que mis buscadores de archivos estáticos se configuran a través de Django requiere una modificación en las rutas de script / css integradas dentro de app / templates / app / index.html.

En vez de <script src="{% static '/app/../../../assets/js/chunk-vendors.6a3b11f1.js' %}">

El camino actualmente debe ser <script src="{% static 'js/chunk-vendors.6a3b11f1.js' %}">

Cambiar la ruta assetsDir en vue.config.js para que coincida con la convención de Vue de que los assets sean un subdirectorio de outputDir da como resultado un problema similar en el que la ruta es en 'app/assets/js/...'lugar de'js/...'

Respuestas

1 plum0 Aug 19 2020 at 03:16

Decidí ajustar la ruta que se carga en la plantilla durante la compilación de Vue modificando el archivo public / index.html y las opciones vue.config.js. const asset_dir = '/asset/dirDeclaré un in vue.config.js y luego agregué esto como una opción adicional al HtmlWebpackPlugin para incorporarlo a la plantilla. Por último, hago una subcadena de la ruta de los archivos estáticos por la longitud de la parte innecesaria de la ruta.

vue.config.js

const asset_dir = "../../../assets"

module.exports = {
    publicPath: isProd ? '/app/' : '/',
    outputDir: __dirname + '/../app/templates/app',
    assetsDir: asset_dir,
    indexPath: './index.html',
    configureWebpack: {
        ...
        plugins: [
            new HtmlWebpackPlugin({
                template: __dirname + '/public/index.html',
                inject: false,
                minify: false,
                assetsDir: asset_dir
            })
        ],
    }
}

public / index.html

{% load static %}
<% if (htmlWebpackPlugin.options['assetsDir'] !== undefined) { %> <% var assetDirLength = htmlWebpackPlugin.options['assetsDir'].length + htmlWebpackPlugin.files.publicPath.length + "/".length%> <% } %>
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width,initial-scale=1.0">
    <title>MAPP Remote</title>
      <link rel="shortcut icon" href="{% static 'img/favicon/favicon.ico' %}">
      <% for (key in htmlWebpackPlugin.files.css) { %> <link rel="stylesheet" href="{% static '<%= htmlWebpackPlugin.files.css[key].substr(assetDirLength) %>' %}"> <% } %>
  </head>
  <body>
    <div id="app"></div>
    <!-- built files will be auto injected -->
    <!-- Pulled from htmlWebpackPlugin Docs -->
    <!-- https://github.com/jaketrent/html-webpack-template/blob/86f285d5c790a6c15263f5cc50fd666d51f974fd/index.html -->
    <% for (var chunk in htmlWebpackPlugin.files.chunks) { %>
      <script src="{% static '<%= htmlWebpackPlugin.files.chunks[chunk].entry.substr(assetDirLength) %>' %}"></script>
    <% } %>

  </body>
</html>