1

I'm currently in the process of deploying (read: struggling) my: Django (backend) ReactJS/Redux (frontend) django-ninja (api) whitenoise (backend - staticfiles) app to Heroku. However, I keep getting this error message whenever I launch the app and go live:

"Refused to execute script from 'https://off-world-v0.herokuapp.com/static/js/main.6b71531f.js' because its MIME type ('text/html') is not executable, and strict MIME type checking is enabled."

"Manifest: Line: 1, column: 1, Syntax error."

This error does NOT appear when I'm in development, so after doing some research with Stack Overflow, Reddit, YouTube, etc. - a number of other individuals seem to be running into the same problem, yet no reliable answer (to my knowledge) has been postulated at this time. The strange part is the app did work on one try after I removed this line from the build/static "index.html" file:

<link rel="manifest" href="./manifest.json"/>

However, after updating and launching the app again the same errors came back, this time with a different staticfile asset as the source of the error.

Attached below are some snippets of my code.

Django settings.py

import os
from pathlib import Path
from dotenv import load_dotenv, find_dotenv
import django_heroku
import dj_database_url
import mimetypes

mimetypes.add_type("text/javascript", ".js", True)


# Build paths inside the project like this: BASE_DIR / 'subdir'.
BASE_DIR = Path(__file__).resolve().parent.parent


# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/3.2/howto/deployment/checklist/

# SECURITY WARNING: keep the secret key used in production secret!
load_dotenv(find_dotenv())
SECRET_KEY = os.environ['SECRET_KEY']

# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = False

if DEBUG:
    ALLOWED_HOSTS = ["localhost", "127.0.0.1"]
else:
    ALLOWED_HOSTS = ['https://off-world-v0.herokuapp.com/']

CORS_ORIGIN_ALLOW_ALL = True
#ALLOWED_HOSTS = ['*']
#ALLOWED_HOSTS = ['off-world-v0.herokuapp.com', '127.0.0.1:8000', 'localhost']

ROOT_URLCONF = 'offworld_v0.urls'


# Application definition

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'corsheaders',
    'Users',
]

MIDDLEWARE = [
    'corsheaders.middleware.CorsMiddleware',
    'django.middleware.security.SecurityMiddleware',
    'whitenoise.middleware.WhiteNoiseMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]


TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [os.path.join(BASE_DIR, 'build')],
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]

WSGI_APPLICATION = 'offworld_v0.wsgi.application'


# Database
# https://docs.djangoproject.com/en/3.2/ref/settings/#databases

'''
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': BASE_DIR / 'db.sqlite3',
    }
}'''

DATABASES = {}
DATABASES['default'] = dj_database_url.config(conn_max_age=600)

# Password validation
# https://docs.djangoproject.com/en/3.2/ref/settings/#auth-password-validators

AUTH_PASSWORD_VALIDATORS = [
    {
        'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
    },
]


# Internationalization
# https://docs.djangoproject.com/en/3.2/topics/i18n/

LANGUAGE_CODE = 'en-us'

TIME_ZONE = 'UTC'

USE_I18N = True

USE_L10N = True

USE_TZ = True

# Default primary key field type
# https://docs.djangoproject.com/en/3.2/ref/settings/#default-auto-field

DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'

AUTH_USER_MODEL = 'Users.User'


# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/3.2/howto/static-files/

STATIC_URL = '/static/'
STATICFILES_DIRS = [
    os.path.join(BASE_DIR, 'build/static')
]
STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles')
STATICFILES_STORAGE = 'whitenoise.storage.CompressedManifestStaticFilesStorage'
MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
X_FRAME_OPTIONS = 'SAMEORIGIN'

try:
    from .local_settings import *
except ImportError:
    pass

django_heroku.settings(locals())
options = DATABASES['default'].get('OPTIONS', {})
options.pop('sslmode', None)

Django urls.py

from django.contrib import admin
from django.urls import path, include, re_path
from django.conf.urls.static import static
from django.conf import settings
from django.views.generic import TemplateView
from . api import api

urlpatterns = [
    path('admin/', admin.site.urls),
    path('api/', api.urls),
]

urlpatterns += static(settings.STATIC_URL,
                          document_root=settings.STATIC_ROOT)
urlpatterns += static(settings.MEDIA_URL,
                          document_root=settings.MEDIA_ROOT)

# This is will catch the routes in the frontend and 404 errors
urlpatterns += [re_path(r'^.*', TemplateView.as_view(template_name='index.html'))]

django-ninja api

router = Router()

class Assets(View):

    def get(self, _request, filename):
        path = os.path.join(os.path.dirname(__file__), 'static', filename)

        if os.path.isfile(path):
            with open(path, 'rb') as file:
                return HttpResponse(file.read(), content_type='application/javascript')
        else:
            return HttpResponseNotFound()

@router.post("/register")
def register(request, reg: RegistrationSchema):
    try:
        user = User.objects.create_user(reg.username, reg.email, reg.password)
    except IntegrityError:
        raise HttpError(409, "User already registered.")
    except Exception as error:
        print('\n')
        print(traceback.format_exc())
        print('\n')
        raise HttpError(422, f"{error}")
    else:
        if user and user.is_authenticated:
            user.firstname = reg.firstname.capitalize()
            user.lastname = reg.lastname.capitalize()
            user.phone = reg.phone
            user.dob = reg.dob
            user.gender = reg.gender
            user.passcode = reg.passcode
            user.save()
            _, token = AuthToken.objects.create(user)
            #return {'user': user.username, 'token': token}
            return 200, UserAuthSchema(user=user, token_key=token)
        raise HttpError(405, "User registration not permitted or failed.")



@router.post("/login", response=AuthSchema)
def login(request, login: LoginSchema):
    user = authenticate(request, username=login.username, password=login.password)
    if user and user.is_authenticated:
        _, token = AuthToken.objects.create(user)
        #return {'user': user, 'token': token}
        return 200, UserAuthSchema(user=user, token_key=token)
    raise HttpError(401, "Incorrect login credentials.")

                

@router.get("/auth")
def auth(request):
    if 'Authorization' in request.headers:
        auth_header = request.headers.get('Authorization')
        token = auth_header.split()[1]
        try:
            user, token = TokenAuth().authenticate(token=token)
            return 200, UserAuthSchema(user=user, token_key=token)
        except Exception as error:
            raise HttpError(403, "User is not authenticated.")
    else:
        print("Authorization not in headers.")
        raise HttpError(401, "User is not authenticated.")



@router.get("/logout")
def logout(request):
    if 'Authorization' in request.headers:
        auth_header = request.headers.get('Authorization')
        token = auth_header.split()[1]
        try:
            AuthToken.objects.filter(token_key=token[:CONSTANTS.TOKEN_KEY_LENGTH]).delete()
        except Exception as error:
            raise HttpError(405, f"{error}")
        else:
            return Response("User has been logged out.", status=205)
    else:
        print("Authorization not in headers.")
        raise HttpError(412, "Authorization token not in headers.")

ReactJS frontend build/static index.html

<!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="Web site created using create-react-app"/>
<link rel="apple-touch-icon" href="./logo192.png"/>
<link rel="manifest" href="./manifest.json"/>
<title>React App</title>
<script defer="defer" src="./static/js/main.7f6621dd.js"></script>
<link href="./static/css/main.864aa364.css" rel="stylesheet">
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
</body>
</html>

ReactJS frontend build/static manifest.json

{
  "short_name": "React App",
  "name": "Create React App Sample",
  "icons": [
    {
      "src": "favicon.ico",
      "sizes": "64x64 32x32 24x24 16x16",
      "type": "image/x-icon"
    },
    {
      "src": "logo192.png",
      "type": "image/png",
      "sizes": "192x192"
    },
    {
      "src": "logo512.png",
      "type": "image/png",
      "sizes": "512x512"
    }
  ],
  "start_url": "./",
  "display": "standalone",
  "theme_color": "#000000",
  "background_color": "#ffffff"
}

ReactJS frontend package.json

{
  "name": "frontend",
  "version": "0.1.0",
  "homepage": ".",
  "private": true,
  "proxy": "http://localhost:8000",
  "dependencies": {
    "@emotion/react": "^11.10.4",
    "@emotion/styled": "^11.10.4",
    "@fontsource/vt323": "^4.5.10",
    "@mui/material": "^5.10.6",
    "@testing-library/jest-dom": "^5.16.5",
    "@testing-library/react": "^13.4.0",
    "@testing-library/user-event": "^13.5.0",
    "axios": "^0.27.2",
    "formik": "^2.2.9",
    "notistack": "^2.0.5",
    "react": "^18.2.0",
    "react-dom": "^18.2.0",
    "react-error-boundary": "^3.1.4",
    "react-redux": "^8.0.2",
    "react-router-dom": "^6.4.0",
    "react-scripts": "5.0.1",
    "redux": "^4.2.0",
    "redux-devtools-extension": "^2.13.9",
    "redux-form": "^8.3.8",
    "redux-thunk": "^2.4.1",
    "styled-components": "^5.3.5",
    "web-vitals": "^2.1.4",
    "yup": "^0.32.11"
  },
  "scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test",
    "eject": "react-scripts eject"
  },
  "eslintConfig": {
    "extends": [
      "react-app",
      "react-app/jest"
    ]
  },
  "browserslist": {
    "production": [
      ">0.2%",
      "not dead",
      "not op_mini all"
    ],
    "development": [
      "last 1 chrome version",
      "last 1 firefox version",
      "last 1 safari version"
    ]
  },
  "engines": {
    "node": "16.14.1",
    "npm": "8.5.0"
  }
}

ReactJS frontend public index.html

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <meta name="theme-color" content="#000000" />
    <meta
      name="description"
      content="Web site created using create-react-app"
    />
    <link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
    <!--
      manifest.json provides metadata used when your web app is installed on a
      user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
    -->
    <link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
    <!--
      Notice the use of %PUBLIC_URL% in the tags above.
      It will be replaced with the URL of the `public` folder during the build.
      Only files inside the `public` folder can be referenced from the HTML.

      Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
      work correctly both with client-side routing and a non-root public URL.
      Learn how to configure a non-root public URL by running `npm run build`.
    -->
    <title>React App</title>
  </head>
  <body>
    <noscript>You need to enable JavaScript to run this app.</noscript>
    <div id="root"></div>
    <!--
      This HTML file is a template.
      If you open it directly in the browser, you will see an empty page.

      You can add webfonts, meta tags, or analytics to this file.
      The build step will place the bundled scripts into the <body> tag.

      To begin the development, run `npm start` or `yarn start`.
      To create a production bundle, use `npm run build` or `yarn build`.
    -->
  </body>
</html>

ReactJS frontend public manifest.json

{
  "short_name": "React App",
  "name": "Create React App Sample",
  "icons": [
    {
      "src": "favicon.ico",
      "sizes": "64x64 32x32 24x24 16x16",
      "type": "image/x-icon"
    },
    {
      "src": "logo192.png",
      "type": "image/png",
      "sizes": "192x192"
    },
    {
      "src": "logo512.png",
      "type": "image/png",
      "sizes": "512x512"
    }
  ],
  "start_url": ".",
  "display": "standalone",
  "theme_color": "#000000",
  "background_color": "#ffffff"
}

App folder directory:

app directory

halfer
  • 19,824
  • 17
  • 99
  • 186
jpwyse
  • 11
  • 2

0 Answers0