Giter Club home page Giter Club logo

django-pwa's Introduction

django-pwa

Build Status Maintainability codecov PyPI - Downloads PyPI - Downloads PyPI - Downloads

This Django app turns your project into a progressive web app. Navigating to your site on an Android phone will prompt you to add the app to your home screen.

Prompt for install

Launching the app from your home screen will display your app without browser chrome. As such, it's critical that your application provides all navigation within the HTML (no reliance on the browser back or forward button).

Requirements

Progressive Web Apps require HTTPS unless being served from localhost. If you're not already using HTTPS on your site, check out Let's Encrypt and ZeroSSL.

Installation

Install from PyPI:

pip install django-pwa

Configuration

Add pwa to your list of INSTALLED_APPS in settings.py:

INSTALLED_APPS = [
    ...
    'pwa',
    ...
]

Define STATICFILES_DIRS for your custom PWA_APP_ICONS

STATICFILES_DIRS = [
    os.path.join(BASE_DIR, 'static'),
]

Configure your app name, description, icons, splash screen images, screenshots and shortcuts in settings.py:

PWA_APP_NAME = 'My App'
PWA_APP_DESCRIPTION = "My app description"
PWA_APP_THEME_COLOR = '#0A0302'
PWA_APP_BACKGROUND_COLOR = '#ffffff'
PWA_APP_DISPLAY = 'standalone'
PWA_APP_SCOPE = '/'
PWA_APP_ORIENTATION = 'any'
PWA_APP_START_URL = '/'
PWA_APP_STATUS_BAR_COLOR = 'default'
PWA_APP_ICONS = [
    {
        'src': '/static/images/my_app_icon.png',
        'sizes': '160x160'
    }
]
PWA_APP_ICONS_APPLE = [
    {
        'src': '/static/images/my_apple_icon.png',
        'sizes': '160x160'
    }
]
PWA_APP_SPLASH_SCREEN = [
    {
        'src': '/static/images/icons/splash-640x1136.png',
        'media': '(device-width: 320px) and (device-height: 568px) and (-webkit-device-pixel-ratio: 2)'
    }
]
PWA_APP_DIR = 'ltr'
PWA_APP_LANG = 'en-US'
PWA_APP_SHORTCUTS = [
    {
        'name': 'Shortcut',
        'url': '/target',
        'description': 'Shortcut to a page in my application'
    }
]
PWA_APP_SCREENSHOTS = [
    {
      'src': '/static/images/icons/splash-750x1334.png',
      'sizes': '750x1334',
      "type": "image/png"
    }
]

Show console.log

Set the PWA_APP_DEBUG_MODE = False to disable the the console.log on browser.

All settings are optional, and the app will work fine with its internal defaults. Highly recommend setting at least PWA_APP_NAME, PWA_APP_DESCRIPTION, PWA_APP_ICONS and PWA_APP_SPLASH_SCREEN. In order to not use one of the internal defaults, a setting can be set to an empty string or list, whichever one is applicable.

Add the progressive web app URLs to urls.py:

from django.urls import url, include

urlpatterns = [
    ...
    url('', include('pwa.urls')),  # You MUST use an empty string as the URL prefix
    ...
]

Inject the required meta tags in your base.html (or wherever your HTML <head> is defined):

{% load pwa %}

<head>
    ...
    {% progressive_web_app_meta %}
    ...
</head>

Troubleshooting

While running the Django test server:

  1. Verify that /manifest.json is being served
  2. Verify that /serviceworker.js is being served
  3. Verify that /offline is being served
  4. Use the Application tab in the Chrome Developer Tools to verify the progressive web app is configured correctly.
  5. Use the "Add to homescreen" link on the Application Tab to verify you can add the app successfully.

The Service Worker

By default, the service worker implemented by this app is:

// Base Service Worker implementation.  To use your own Service Worker, set the PWA_SERVICE_WORKER_PATH variable in settings.py

var staticCacheName = "django-pwa-v" + new Date().getTime();
var filesToCache = [
    '/offline',
    '/css/django-pwa-app.css',
    '/images/icons/icon-72x72.png',
    '/images/icons/icon-96x96.png',
    '/images/icons/icon-128x128.png',
    '/images/icons/icon-144x144.png',
    '/images/icons/icon-152x152.png',
    '/images/icons/icon-192x192.png',
    '/images/icons/icon-384x384.png',
    '/images/icons/icon-512x512.png',
    '/static/images/icons/splash-640x1136.png',
    '/static/images/icons/splash-750x1334.png',
    '/static/images/icons/splash-1242x2208.png',
    '/static/images/icons/splash-1125x2436.png',
    '/static/images/icons/splash-828x1792.png',
    '/static/images/icons/splash-1242x2688.png',
    '/static/images/icons/splash-1536x2048.png',
    '/static/images/icons/splash-1668x2224.png',
    '/static/images/icons/splash-1668x2388.png',
    '/static/images/icons/splash-2048x2732.png'
];

// Cache on install
self.addEventListener("install", event => {
    this.skipWaiting();
    event.waitUntil(
        caches.open(staticCacheName)
            .then(cache => {
                return cache.addAll(filesToCache);
            })
    )
});

// Clear cache on activate
self.addEventListener('activate', event => {
    event.waitUntil(
        caches.keys().then(cacheNames => {
            return Promise.all(
                cacheNames
                    .filter(cacheName => (cacheName.startsWith("django-pwa-")))
                    .filter(cacheName => (cacheName !== staticCacheName))
                    .map(cacheName => caches.delete(cacheName))
            );
        })
    );
});

// Serve from Cache
self.addEventListener("fetch", event => {
    event.respondWith(
        caches.match(event.request)
            .then(response => {
                return response || fetch(event.request);
            })
            .catch(() => {
                return caches.match('offline');
            })
    )
});

Adding Your Own Service Worker

To add service worker functionality, you'll want to create a serviceworker.js or similarly named template in a template directory, and then point at it using the PWA_SERVICE_WORKER_PATH variable (PWA_APP_FETCH_URL is passed through).

PWA_SERVICE_WORKER_PATH = os.path.join(BASE_DIR, 'my_app', 'serviceworker.js')

The offline view

By default, the offline view is implemented in templates/offline.html You can overwrite it in a template directory if you continue using the default serviceworker.js.

Feedback

I welcome your feedback and pull requests. Enjoy!

License

All files in this repository are distributed under the MIT license.

django-pwa's People

Contributors

arhanchaudhary avatar dependabot[bot] avatar dineshssdn-867 avatar eeriksp avatar hansegucker avatar hartungstenio avatar jellebootsma avatar joextodd avatar letnaturebe avatar natureshadow avatar philippeoz avatar setti7 avatar silviolleite avatar stacks13 avatar svvitale avatar viviengiraud avatar voronov007 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

django-pwa's Issues

cannot import name 'url' from 'django.urls'

Hi!

Before all: thanks for doing everything! 😄

I'm trying to install the package on my website, and I'm following the readme.md

On THIS part of the readme, you are doing:

from django.urls import url, include

urlpatterns = [
    ...
    url('', include('pwa.urls')),  # You MUST use an empty string as the URL prefix
    ...
]

But I don't know if I'm doing something wrong (I'm don't know python perfectly) but including your snipper (aka the url inside urlpatterns in the main app/urls.py) gave me this error:

ImportError: cannot import name 'url' from 'django.urls'

Because I usually include a "path" and not an "url" inside "urlpatterns" list, and I saw that in your demo you done the same, I've changed it in a more familiar:

urlpatterns = [
    ...
    path('', include('pwa.urls')),  # You MUST use an empty string as the URL prefix
    ...
]

And is working.

Is the readme.md wrong or there's something I didn't get in django, python or django-pwa?

Manifest: property 'scope' ignored, type string expected.

For some reason, my scope entry in manifest.json ends up as a list:
scope: ["/calendar"]
although it starts up as
PWA_APP_SCOPE = '/calendar/',
(I have tried '/calendar' and '/' as well, with them all ending up as only item in a list.)
This does NOT happen with PWA_APP_START_URL, that seems to be very similar...

I have tried to look trough the django-pwa code, without success.

iPhone X support

Does this support iPhone X & Xs? I’ve been trying it with both but can only get it to work on older iPhones like the iphone 7.

Does anyone have any info on this?
Could this be an Apple issue?

sizes not in html

Hello all,
The links to the icons generated my django-pwa do not show the sizes attribute as set in the settings.
It leaves it empty.
This error comes up while validating html-code:

Error: Bad value "" for attribute sizes on element link

Great "app" by the way thanks for making it.

README not in sync with serviceworker.js

Problem (brief): The 'service worker' section of the README includes the content of serviceworker.js, however it's out of sync with the file and is broken.

Problem (detail): The main issue I noticed was when I was trying to get the custom offline page to work. The original JS file includes '/offline/' in 2 instances (note, wrapped in forward slashes), whereas the README has '/offline' in one instance and 'offline' in the other, which doesn't work as these aren't wrapped in forward slashes. It's such a minor bug that people will likely get very confused as to why it doesn't work if they copy the content from the README into their service worker file (as I did).

Proposed fix: Very easy fix - just link to the file instead. It may be tempting to just correct these forward slashes, but based on the DRY principle, we really shouldn't be repeating a whole file of code in the README when linking to it is sufficient, along with an explanation of something like "Here's our default service worker (link to file). To make your own custom service worker, you can copy this file and tweak its contents to cache the objects relevant to your project"

Uncaught (in promise) TypeError: Request failed

I am getting 404 not found after implementing django-pwa app (Static file, offline and the png files defined in the serviceworker.js file). I don't know if the problem is about paths or not. But there is a missing detail in the README.md file that users needs to know. Do you have any idea?

Console log: Uncaught (in promise) TypeError: Request failed serviceworker.js:1

Network:

Request URL: http://127.0.0.1:8000/offline/
Request Method: GET
Status Code: 400 Bad Request
Remote Address: 127.0.0.1:8000
Referrer Policy: no-referrer-when-downgrade
Request URL: http://127.0.0.1:8000/static/css/django-pwa-app.css
Request Method: GET
Status Code: 404 Not Found
Remote Address: 127.0.0.1:8000
Referrer Policy: no-referrer-when-downgrade
Request URL: http://127.0.0.1:8000/static/images/icons/icon-72x72.png
Request Method: GET
Status Code: 404 Not Found
Remote Address: 127.0.0.1:8000
Referrer Policy: no-referrer-when-downgrade

SuspiciousOperation at /offline/: Attempted access to '/css/django-pwa-app.css' denied.

Hello! I have been playing around with my django app and testing it out in my staging server. I just set up an external DigitalOcean Spaces storage to serve up my static files (very similar to Amazon S3). As it turns out, this caused a new problem in my codebase which originated from django-pwa's offline.html file. A screenshot is attached below.

Screenshot from 2019-05-05 06-50-56

My speculation is that this should not be happening since clearly the request is trying to access /css/django-pwa-app.css whereas in reality it should not be requesting files from '/'. I think this is a typo and can be fixed easily, but if it's not and I need a better understanding of how the static file serving works, please let me know!

I do know that I can just use my own offline.html file but posting this here in case other people face the same issue.

Best,
Ahmed

Issue with precaching during sw install

I have {% load pwa %} in my base template and want it to get installed only for logged in users so pages and assets can authenticate and cache properly. My login page does not extend the base template, but the serviceworker still seems to get installed on this page anyway, which causes the precaching to fail due to unauthenticated requests.

Any ideas for how to handle this situation properly? Why is it getting installed on a page that doesn't include the load pwa directive? Anything else I can do to work around this?

Thanks, hoping this plugin will help with my Django pwa project!

No "Add to homescreen" popup on Chrome

I installed django-pwa according to the instructions, adjusted the paths in serviceworker.js to serve my icons, and checked that manifest.json, serviceworker.js, and offline are served.

Still I do not get the "Add to homescreen" popup on Chrome. Any ideas why not?

Error installing in Divio project

Hi there thanks for the awesome project.

I am trying to add this application to a Divio project and am getting a ModuleNotFoundError: No module named 'pypandoc'.

I think this may be because Divio is using docker and the with that particular image pip is trying to build the package and pandoc is not available (It is not available on the repo in the image, I could probably work around this and install it).

My question is what was the initial purpose of catching the RuntimeError below and would you be happy I make a PR that catches both RuntimeError and ModuleNotFoundError?

setup.py

# noinspection PyBroadException
try:
    # noinspection PyPackageRequirements
    import pypandoc

    long_description = pypandoc.convert('README.md', 'rst')
except RuntimeError:
    long_description = short_description

i18n support

Tried djanog-pwa today, and found that the service worker would not register. Investigations suggest that the cause is re-directs generated by i18n (from root to, e.g. /en/).

Package installs tests to "site-packages/tests" directory

Package installs tests to "site-packages/tests" directory, should be moved or removed?

$ venv/bin/pip install django-pwa
$ venv/bin/pip uninstall django-pwa
Found existing installation: django-pwa 1.0.10
Uninstalling django-pwa-1.0.10:
  Would remove:
    .../venv/lib/python3.9/site-packages/django_pwa-1.0.10.dist-info/*
    .../venv/lib/python3.9/site-packages/pwa/*
    .../venv/lib/python3.9/site-packages/tests/*
Proceed (y/n)? n 

Cache got basic response with bad status 404 while trying to add request http://127.0.0.1:8000/offline/'.

Hi Silvio,

First, thank you for this package and your ongoing support.

We're using Django 2.2.1 and I am getting this error:

django-pwa: ServiceWorker registration successful with scope:  http://127.0.0.1:8000/ 45:52:21
Service worker event waitUntil() was passed a promise that rejected with 'TypeError: Cache got basic response with bad status 404 while trying to add request http://127.0.0.1:8000/offline/'.

I can't delete this issue so I am updating here.

Error was caused by having the django-pwa urls too low in the list of application URLS. Moving it up removed this error. Hopefully this can be of some aid to someone else.
AD

Django PWA and AWS Static Files

Hi,
my Django PWA is giving errors and I think it is related to the fact that I am serving all my static files from AWS S3.
How do make PWA to pick static files from AWS and work properly??

I get this error "Uncaught (in promise) TypeError: Request failed"

"Not Found: /serviceworker.js" err after uninstalling

After switching to a branch without the this module included and uninstalling it from pip, I am still getting a "Not Found: /serviceworker.js" error on "GET /serviceworker.js HTTP/1.1 404". Not sure where this is getting called from anymore or how to get past it, seems like it must have been caused by this module somehow though. Still want to use this, just having to switch back an forth before it is fully integrated.

Thanks

Installing from git

Hi there,

After seeing that #10 is closed, I wanted to install it from directly git since it has not been yet released to pypi and realized that I can't, because setup.py tries to catch RuntimeError instead of ModuleNotFoundError,

django-pwa/setup.py

Lines 8 to 14 in 6ba2817

try:
# noinspection PyPackageRequirements
import pypandoc
long_description = pypandoc.convert('README.md', 'rst')
except RuntimeError:
long_description = short_description
which is not a subclass of RuntimeError, when importing pypandoc. I think this is a mistake since descriptions are not all that important(I think) for the actual installation of the library.

Also, I'd love to learn if you are planning a new release.

Thanks!

Not Installing as webapks

Hey guys!
I've been using this on my website https://sidtu.be
My Website is HTTPS!
it only installs my website on home screen...
But I've seen a lot of website installing it as webapk

it also doesn't show add to home screen button, In android I have to go and click add to home screen by clicking those three dots in top right corner...
In Desktop I have no way to install the app!

you can go and see my website and please tell me how can I do it!

dynamic START_URL

Is it possible to allow different START_URL ?

Say I have many blogs and I want to publish a particular blog as a PWA app. So I visit the blog detail page in chrome and click 'add to home screen'. And when I click the app icon, i should go to the blog detail page only, not to the website home page. Is it possible ? Right now 'Add to home screen' is only putting link to home page of the website.

Vue.js inside django

Please tell me.
I have a VUE application inside the django template.
But if update it, it stays rigidly in the cache (once help ctrl+f5).
I think because service worker cache it.
What to specify that the desired vue file is also updated in the cache?

or problem in nginx cache?

The CSS file 'css/django-pwa-app.css' references a file which could not be found

Anyway to get around this without using bootstrap?

more details

Whitenoise.storage.MissingFileError: The file 'fonts/bootstrap/glyphicons-halflings-regular.eot' could not be found with <whitenoise.storage.CompressedManifestStaticFilesStorage object at 0x7fb5b8567790>.

The CSS file 'css/django-pwa-app.css' references a file which could not be found:
fonts/bootstrap/glyphicons-halflings-regular.eot

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

/offline not redirecting when offline on on Chrome

Produces the following warning:
The FetchEvent for "http://localhost:8000/" resulted in a network error response: a redirected response was used for a request whose redirect mode is not "follow".

The issue is that it's caching the redirect url /offline the fix is to instead cache /offline/
I'll attach a PR with the fix for it.

Not Found: /css/django-pwa-app.css

I'm struggling to get django-pwa to work properly. I followed the setup steps and verified that /manifest.json and /serviceworker.js are served.

However, I still think it's not working like a proper PWA, yet. For example, I still don't get the "add to homescreen" popup.

Also, I just noticed that I always get an error: Not Found: /css/django-pwa-app.css - whether I use the default serviceworker.js or a custom one.
Is the configured CSS path wrong? Or do I need to provide my own CSS? I thought this comes with django-pwa? What about the /offline page?

non PWA_* key/values are filtered out for context processing

pwa/templatetags/pwa.py:progressive_web_app_meta(context) filters out everything but keys starting with PWA. This breaks other context values like CSP_NONCE which is necessary when trying to set security headers and adhere to secure coding practices. The script code that registers the serviceworker.js is admittedly tiny, but for it to execute within a CSP domain, it must have a nonce value or similar registered token.

A simple hack to fix this is to merge the CSP_NONCE value from the context into the returned dictionary:

@register.inclusion_tag('pwa.html', takes_context=True)
def progressive_web_app_meta(context):
    # Pass all PWA_* settings into the template
    rv = {
        setting_name: getattr(app_settings, setting_name)
        for setting_name in dir(app_settings)
        if setting_name.startswith('PWA_')
    }
    rv['CSP_NONCE'] = context['CSP_NONCE']
    return rv

Manifest doesn't have a maskable icon

Hello,
Could you include by default the new property maskable ?

{
  …
  "icons": [
    …
    {
      "src": "path/to/maskable_icon.png",
      "sizes": "196x196",
      "type": "image/png",
      "purpose": "any maskable"
    }
  ]
  …
}

add option for add crossorigin=anonymous in url

Hello i'm using django cookie cutter and bucket type for distribue static and media files (aws s3,google storage,etc..), after some reading, i'm using workbox (google workbox) for the easing caching.
for avoid the opaque responses, it's advised add crossorigin=anonymous in all img and link (https://developers.google.com/web/tools/workbox/guides/handle-third-party-requests) and the opaque responses no put always files in cache.
It's possible add option for add crossorigin anonymous (add in link) in head your generate with the tags.

Personal question and good use of the service worker:
When i generate my docker, i use gulps for modify variable CACHE_VERSION in serviceworkers.js ( example : cacheName: 'js-cache-' + CACHE_VERSION) for add new number version. so that i force reload cache in navigator and reload new cache if new docker is build. it is good usage for pwa ?

Thanks in advance

Distinct setting for short_name field

It would be great if you could add a distinct (perhaps optional?) value for the short_name field.

Happy to try putting in a PR for this myself if that's helpful!

Default serviceworker not handling logout?

When I try logging out from a user with this installed (using default serviceworker) it doesn't seem to register the logout and just redirects to the default root page for a user at '/'. This is regardless of my settings value for LOGOUT_REDIRECT_URL or adding a login_url value to logout_then_login(request, '/login/'). The issue goes away if I unregister the serviceworker.

Missing staticfiles manifest entry for '/css/django-pwa-app.css'

Hello everyone, I'm getting this error only production.

Steps to reproduce:

  1. pip install whitenoise
  2. set settings.py to STATICFILES_STORAGE = 'whitenoise.storage.CompressedManifestStaticFilesStorage'
  3. run python manage.py collectstatic
  4. Access the url https://example.com/offline

In my particular case, my staticfiles.json looks something like this:

{
       ...
       "css/django-pwa-app.css": "css/django-pwa-app.bf6b48f24c55.css
       ...
}

When accessing to offline.html django can't find django-pwa-app-css

Custom manifest.json?

I'm trying to use django-pwa with the Web Share API, so I need to add a line to manifest.json:

...
  "share_target":
  {
    "action": "/share",
    "params":
    {
      "title": "title",
      "text": "text",
      "url": "url"
    }
  },

How do I do this?

It allows me to define a custom service worker, but not a custom manifest file.

Django 1.11 support?

Why has the support for django 1.11 been dropped? I was using the now deprecated django-progressive-web-app and thought of updating it, but our entire application is built on 1.11 and not completely 2.0 compliant. So what features are here which would only work on 2.0?

service-worker.js loading is Unconventional

service-worker.js is in the templates directory, which would lead one to believe that they can override it. However, the file is actually loaded in directly as a plain file. Would you be open to a PR to change the behavior to use template based loading? With caching, the performance difference would be non-existent after the first request, and it would allow for some more powerful customization of the logic within that file.

Error on collectstatic - file reference

whitenoise.storage.MissingFileError: The file 'fonts/bootstrap/glyphicons-halflings-regular.eot' could not be found with <whitenoise.storage.CompressedManifestStaticFilesStorage object at 0x7f9e6cb94828>.

The CSS file 'css/django-pwa-app.css' references a file which could not be found:
  fonts/bootstrap/glyphicons-halflings-regular.eot

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

I don't know if raise this exception when run without whitenoise.
To bypass this i put the font file on /font/bootstrap/glyphicons-halflings-regular.eot.

Can i open a PR and an fix it?
And, if i can, what you think? Add a font file or add a url to font file?

Thanks!

Any examples to poke at

Hello,

This is great! I was wondering, are there any example applications (or real ones) you can point me to so I can poke around at it?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.