3

So I have a Django - React application. All the static files are served by s3

I ran

npm run build

and then i coped the build folder into my django project folder. and then i setup the template dirs and staticfiles dirs in my settings.py file.

when i try to load the django-admin page. everything works perfectly. the static files are served by aws s3. But when i try to load the react page. it tries to look for static files locally which obviously does not exist.

so how do i tell my react app to look for the staticfiles in s3? this is how my index.html looks

<!doctype html>
<html lang="en">
<head>
    <meta charset="utf-8"/>
    <link rel="icon" href="/favicon.ico"/>
    <meta name="viewport" content="width=device-width,initial-scale=1"/>
    <meta name="theme-color" content="#000000"/>
    <meta name="description" content="jgprth."/>
    <link rel="apple-touch-icon" href="/logo192.png"/>
    <link rel="manifest" href="/manifest.json"/>
    <title>test</title></head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
<script>!function (e) {
    function t(t) {
        for (var n, a, l = t[0], f = t[1], i = t[2], p = 0, s = []; p < l.length; p++) a = l[p], Object.prototype.hasOwnProperty.call(o, a) && o[a] && s.push(o[a][0]), o[a] = 0;
        for (n in f) Object.prototype.hasOwnProperty.call(f, n) && (e[n] = f[n]);
        for (c && c(t); s.length;) s.shift()();
        return u.push.apply(u, i || []), r()
    }

    function r() {
        for (var e, t = 0; t < u.length; t++) {
            for (var r = u[t], n = !0, l = 1; l < r.length; l++) {
                var f = r[l];
                0 !== o[f] && (n = !1)
            }
            n && (u.splice(t--, 1), e = a(a.s = r[0]))
        }
        return e
    }

    var n = {}, o = {1: 0}, u = [];

    function a(t) {
        if (n[t]) return n[t].exports;
        var r = n[t] = {i: t, l: !1, exports: {}};
        return e[t].call(r.exports, r, r.exports, a), r.l = !0, r.exports
    }

    a.m = e, a.c = n, a.d = function (e, t, r) {
        a.o(e, t) || Object.defineProperty(e, t, {enumerable: !0, get: r})
    }, a.r = function (e) {
        "undefined" != typeof Symbol && Symbol.toStringTag && Object.defineProperty(e, Symbol.toStringTag, {value: "Module"}), Object.defineProperty(e, "__esModule", {value: !0})
    }, a.t = function (e, t) {
        if (1 & t && (e = a(e)), 8 & t) return e;
        if (4 & t && "object" == typeof e && e && e.__esModule) return e;
        var r = Object.create(null);
        if (a.r(r), Object.defineProperty(r, "default", {
            enumerable: !0,
            value: e
        }), 2 & t && "string" != typeof e) for (var n in e) a.d(r, n, function (t) {
            return e[t]
        }.bind(null, n));
        return r
    }, a.n = function (e) {
        var t = e && e.__esModule ? function () {
            return e.default
        } : function () {
            return e
        };
        return a.d(t, "a", t), t
    }, a.o = function (e, t) {
        return Object.prototype.hasOwnProperty.call(e, t)
    }, a.p = "/";
    var l = this.webpackJsonpdatacertus = this.webpackJsonpdatacertus || [], f = l.push.bind(l);
    l.push = t, l = l.slice();
    for (var i = 0; i < l.length; i++) t(l[i]);
    var c = f;
    r()
}([])</script>
<script src="/static/js/2.f0a4d193.chunk.js"></script>
<script src="/static/js/main.c64debc0.chunk.js"></script>
</body>
</html>

Shrinidhi Hegde
  • 454
  • 3
  • 14

1 Answers1

1

Set the PUBLIC_URL configuration in the .env file (read by the ReactJS compiler). The string you set there will be used to prefix all static file addresses, so it could be the address of the static files in local development (like http://localhost:8000/static) or a S3 bucket address (like https://foobar.s3.amazonaws.com).

Hints found here, react docs for PUBLIC_URL here.

EDIT: The only solution that I found, and that actually worked, was to serve the static files from Nginx (instead of S3) when running on AWS.

The React.JS app is compiled with an absolute path within the same domain:

PUBLIC_URL=/rjsstatic/foo/bar/

The Django site is handles the route rjsstatic/foo/bar/(?<path>.+)$ to a view that serves static files (just for development setups). I used this method:

from django.contrib.staticfiles.views import serve

REACT_JS_APP_PATH = 'my_reactjs_app'

def serve_react_app_files(request, path):
    return serve(request, os.path.join(REACT_JS_APP_PATH, path))

In this example, the files are stored in static/my_reactjs_app/.

And on production Nginx is configured to capture this same route and serve the static files. A simple alias configuration is used:

location /rjsstatic/foo/bar/ { 
    alias /path/to/reactjs/static/files/;
}
ekinoshita
  • 55
  • 6
  • yes this would work if my bucket was public. but my bucket is private and i am serving the staticfiles using cloudfront cdn. so the url changes everytime. – Shrinidhi Hegde Aug 31 '21 at 12:30
  • @ShrinidhiHegde I updated my answer with my latest findings. When I used the S3 bucket to store the static files, the js files tried to load more files but on the wrong domain (the new requests URLs were pointing directly to S3, instead of the URL of the website). I updated the answer with the solution that actually worked. – ekinoshita Sep 30 '21 at 23:45