Django dengan vue.js frontend - Jalur Berkas Statis

Aug 19 2020

Saya mencoba untuk melayani aplikasi django dengan frontend vue dan membutuhkan bantuan untuk mengkonfigurasi file statis.

Pertanyaan TLDR:

Bagaimana saya membuat Django mengenali jalur terbangun ini sebagai usaha untuk mencapai berkas statis, atau sebagai alternatif, bagaimana cara saya memodifikasi jalur injeksi pasca-pembuatan pada sisi Vue untuk mencocokkan pengaturan berkas-statis Django saat ini?

Django menyajikan index.html yang dibangun dari vue, namun ia tidak dapat menemukan berkas statis (skrip / css) yang disuntikkan secara otomatis dari proses pembangunan karena jalurnya "mutlak". Saya telah memodifikasi vue.config.js agar tidak menyuntikkan otomatis skrip (karena skrip tersebut akan diperlukan {% static %}selama pembuatan, dan templat index.html untuk menambahkannya dengan benar.

Struktur direktori saya adalah sebagai berikut:

- 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

Build dijalankan dari direktori frontend, dengan --no-clean untuk tidak menghapus folder template django saya pada build.

Berikut adalah solusi saya untuk menambahkan {% static %}tag ke index.html bawaan. Saya menyadari bahwa saya melanggar konvensi vue menyatakan bahwa assetsDir adalah subdirektori dari outputDir, dan saya tidak menentang untuk menambahkan dir staticfile lain ke settings.py agar sesuai dengan konvensi (meskipun masalah saya masih sama).

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>

Index.html yang dibangun:

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>

Konfigurasi django settings.py saya untuk file statis:

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"
...

Cara pencari berkas statis saya dikonfigurasi melalui Django memerlukan modifikasi pada jalur skrip / css yang dibangun di dalam app / templates / app / index.html.

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

Jalannya saat ini perlu <script src="{% static 'js/chunk-vendors.6a3b11f1.js' %}">

Mengubah jalur assetsDir di vue.config.js agar sesuai dengan konvensi Vue yang menjadikan aset menjadi subdirektori dari outputDir menghasilkan masalah serupa di mana jalur tersebut 'app/assets/js/...'bukan'js/...'

Jawaban

1 plum0 Aug 19 2020 at 03:16

Saya memutuskan untuk menyesuaikan jalur yang dimuat ke template selama Vue build dengan memodifikasi file public / index.html serta opsi vue.config.js. Saya mendeklarasikan const asset_dir = '/asset/dirdi vue.config.js dan kemudian menambahkan ini sebagai opsi tambahan ke HtmlWebpackPlugin untuk menariknya ke dalam template. Terakhir, saya substring jalur untuk file statis dengan panjang bagian jalur yang tidak perlu.

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>