cookiecutter / cookiecutter-django

Cookiecutter Django is a framework for jumpstarting production-ready Django projects quickly.
https://cookiecutter-django.readthedocs.io
BSD 3-Clause "New" or "Revised" License
12.13k stars 2.9k forks source link

Error with staticfiles collection and missing source map files #4045

Closed pamelafox closed 1 year ago

pamelafox commented 1 year ago

What happened?

When I ran collectstatic on my production server, I get this error:

Traceback (most recent call last):
  File "/tmp/8daedd4f753e458/manage.py", line 31, in <module>
    execute_from_command_line(sys.argv)
  File "/tmp/8daedd4f753e458/antenv/lib/python3.10/site-packages/django/core/management/__init__.py", line 446, in execute_from_command_line
    utility.execute()
  File "/tmp/8daedd4f753e458/antenv/lib/python3.10/site-packages/django/core/management/__init__.py", line 440, in execute
    self.fetch_command(subcommand).run_from_argv(self.argv)
  File "/tmp/8daedd4f753e458/antenv/lib/python3.10/site-packages/django/core/management/base.py", line 414, in run_from_argv
    self.execute(*args, **cmd_options)
  File "/tmp/8daedd4f753e458/antenv/lib/python3.10/site-packages/django/core/management/base.py", line 460, in execute
    output = self.handle(*args, **options)
  File "/tmp/8daedd4f753e458/antenv/lib/python3.10/site-packages/django/contrib/staticfiles/management/commands/collectstatic.py", line 209, in handle
    collected = self.collect()
  File "/tmp/8daedd4f753e458/antenv/lib/python3.10/site-packages/django/contrib/staticfiles/management/commands/collectstatic.py", line 154, in collect
    raise processed
whitenoise.storage.MissingFileError: The file 'js/popper.js.map' could not be found with <whitenoise.storage.CompressedManifestStaticFilesStorage object at 0x7851a54578b0>.

The JS file 'js/vendors.js' references a file which could not be found:

  js/popper.js.map

Please check the URL references in this JS file, particularly any
relative paths which might be pointing to the wrong location.

The error comes because popper.js has this comment:

//# sourceMappingURL=popper.min.js.map

But popper.min.js.map is not copied into the static files directory.

This general issue is reported as an issue in Django 4.1: https://code.djangoproject.com/ticket/33353#comment:15 And there was a fix to django-rest-framework to add source map files: https://github.com/encode/django-rest-framework/pull/8591

I am not sure why I am seeing this in Django 4.0.8, since it's supposedly a 4.1 issue, but perhaps 4.0.8 manifests an earlier version of the issue.

Proposed fix

This is the change I made to my repo: https://github.com/pamelafox/cookiecutter-django-output/commit/c5e8166e40fb8c87f1ce11849ef246f98a52b6f5

I modified the gulpfile to copy over the .map files for the vendor files, and add .map to the gitignore file.

I can submit that as a pull request to this repository if it seems like a helpful change.

Additional details

This is the repository I deployed: https://github.com/pamelafox/cookiecutter-django-output/tree/961a1ebfd226ec1aa0726760e4c2fd46b7bc0840

I deployed using the 'azd up' command to Azure App Service (using infrastructure files I wrote myself), and I found the error in the deployment center logs.

I do not seem to get the error when I run manage.py collectstatic locally.

browniebroke commented 1 year ago

Thanks for the detailed bug report and suggested fix. That's a bit weird, I don't remember seeing an error like this before...

Do you remember which options you have selected when generating? I see frontend_pipeline=Gulp, docker=n, whitenoise=y and Cloud provider=Azure. I think the error is specific to Gulp + Whitenoise?

pamelafox commented 1 year ago

Here's my configuration - it does use Gulp + Whitenoise, yep. I would think it would happen without Gulp too, if Whitenoise tries to server popper.js, but maybe not, still a little fuzzy on static asset compilation.

The strange thing is how it happens in my prod environment and not locally. I'd expect it to always happen in Django 4.1 (based on the django ticket), so if I have time today I'll see if I can upgrade and replicate it locally.

project_name [My Awesome Project]: 
project_slug [my_awesome_project]: 
description [Behold My Awesome Project!]: 
author_name [Daniel Roy Greenfeld]: pamela fox
domain_name [example.com]: pamelafox.org
email [pamela-fox@example.com]: pamela.fox@gmail.com
version [0.1.0]: 
Select open_source_license:
1 - MIT
2 - BSD
3 - GPLv3
4 - Apache Software License 2.0
5 - Not open source
Choose from 1, 2, 3, 4, 5 [1]: 1
timezone [UTC]: 
windows [n]: n
use_pycharm [n]: n
use_docker [n]: n
Select postgresql_version:
1 - 14
2 - 13
3 - 12
4 - 11
5 - 10
Choose from 1, 2, 3, 4, 5 [1]: 2
Select cloud_provider:
1 - AWS
2 - GCP
3 - Azure
4 - None
Choose from 1, 2, 3, 4 [1]: 3
Select mail_service:
1 - Mailgun
2 - Amazon SES
3 - Mailjet
4 - Mandrill
5 - Postmark
6 - Sendgrid
7 - SendinBlue
8 - SparkPost
9 - Other SMTP
Choose from 1, 2, 3, 4, 5, 6, 7, 8, 9 [1]: 9
use_async [n]: n
use_drf [n]: n
Select frontend_pipeline:
1 - None
2 - Django Compressor
3 - Gulp
Choose from 1, 2, 3 [1]: 3
use_celery [n]: n
use_mailhog [n]: n
use_sentry [n]: n
use_whitenoise [n]: y
use_heroku [n]: n
Select ci_tool:
1 - None
2 - Travis
3 - Gitlab
4 - Github
Choose from 1, 2, 3, 4 [1]: 4
keep_local_envs_in_vcs [y]: y
debug [n]: y
 [INFO]: .env(s) are only utilized when Docker Compose and/or Heroku support is enabled so keeping them does not make sense given your current setup.
 [SUCCESS]: Project initialized, keep up the good work!
foarsitter commented 1 year ago

In production, the file popper.js.map isn't needed right? In my case it is referenced from vendors.js and not vendors.min.js.

My workaround was by adding --ignore=js/vendors.js to collectstatic so it isn't processed anyway.

pamelafox commented 1 year ago

I don't believe the default UI uses it, but it would be needed if the website actually utilized one of the Bootstrap JS widgets that rely on popper, so it would become an issue at that point.

pamelafox commented 1 year ago

Update: I was able to replicate this on my local server (keeping Django 4.0.8) by copying the production setting to settings/local:

STATICFILES_STORAGE = "whitenoise.storage.CompressedManifestStaticFilesStorage"