Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

flask does not see change in .js file

I made a change on one of the .js files that I use and no matter what I do, flask insists on picking up, from memory cache, the last version of the file, without the change.

To clarify, I have the following structure. It all starts with foo.html

return render_template foo.html

foo.html has a form inside that calls flask with some data and then returns a second template bar.html:

return render_template bar.html

This second template calls some .js file, placed in the static folder, but it doesn't update when the code changes.

I mention the structure above because if the .js file was placed on foo.html instead of bar.html then Flask would pick up the new changes on the file. But in bar.html Flask completely ignores them.

What is happening?

The only thing that worked was to click on "disable cache" on the browser and reload again.

like image 603
elelias Avatar asked Dec 14 '16 14:12

elelias


People also ask

Why js file changes are not reflected in browser?

js and . css files. That is the reason those new changes will not appear to the user. The user either has to clear the browser cookie & reload the page or else he or she has to do a hard refresh of the page by pressing Ctrl+F5.

Where do I put JavaScript files in Flask?

As the Flask documentation mentions, you should store . css and . js files within your static folder and for organizational purposes, its fine to have each type of file as subdirectories (especially as your app grows).

Is JavaScript better than Flask?

"Lightweight", "Python" and "Minimal" are the key factors why developers consider Flask; whereas "Can be used on frontend/backend", "It's everywhere" and "Lots of great frameworks" are the primary reasons why JavaScript is favored.

Does JavaScript work with Flask?

As I'm sure you know, the reason is that JavaScript is the only language that runs natively in web browsers. In Chapter 14 you saw me add a simple JavaScript enabled link in a Flask template to provide real-time language translations of blog posts.


3 Answers

Ultimately this is a frustrating browser cache issue, which can be solved by forcing the browser to do a "hard refresh", which is going to be a browser/OS dependent keystroke, but generally this works:

  • Windows: Ctrl+F5
  • Mac: Cmd+Shift+R
  • Linux: Ctrl+Shift+R

There are other filename tricks one can use to avoid this issue (mentioned in comments of the OP). These are especially important in production where you have no control over browser behavior.

For non-Static Flask responses you can set the cache_control.max_age property, which should tell the browser when to expire the response if it is cached. For instance if you have a Flask XHR endpoint that returns JSON data you could do this:

@app.route('/_get_ajax_data/') def get_ajax_data():     data = {"hello": "world"}     response = jsonify(data)     response.cache_control.max_age = 60 * 60 * 24  # 1 day (in seconds)     return response 

You typically can also set default values in your production web server configuration for specific resource types (e.g. CSS/JS/HTML/JSON/etc)

Edit 4/1/2019 (unrelated to April Fools day)

  • Mac / Safari keystroke now appears to be: Cmd+Opt+R (via comments, thanks!).
  • See the new answer from @MarredCheese for a very elegant "filename trick" to force the browser to ignore cached copies for updated files.
like image 53
abigperson Avatar answered Sep 22 '22 03:09

abigperson


Caching is normally good, so it's not advisable to eliminate it entirely. And using control + F5 or whatever to do a hard refresh is obviously not a scalable solution since you have to do it in every browser on every computer.

A better idea is to let browsers cache the files most of the time, but not right after they've been updated. You can achieve this by appending the time that the source file was last updated as an argument to its path URL. For simplicity, you can use the most recent modification time for any file in the static folder (or any subfolders), as opposed to looking at each file individually.

Python

def dir_last_updated(folder):     return str(max(os.path.getmtime(os.path.join(root_path, f))                    for root_path, dirs, files in os.walk(folder)                    for f in files))  @app.route('/my-site') def my_site():     return render_template('my-site.html',                            last_updated=dir_last_updated('mydir/static')) 

Jinja Template

<script type="text/javascript" src="/static/my-script.js?u={{ last_updated }}"></script> 

HTML Result

<script type="text/javascript" src="/static/my-script.js?u=1547330602.31"></script> 
like image 20
MarredCheese Avatar answered Sep 21 '22 03:09

MarredCheese


If you are serving your static assets with Flask (this is typically the case in a development environment), then you might need to set the SEND_FILE_MAX_AGE_DEFAULT configuration value:

Default cache control max age to use with send_static_file() (the default static file handler) and send_file(), as datetime.timedelta or as seconds. Override this value on a per-file basis using the get_send_file_max_age() hook on Flask or Blueprint, respectively. Defaults to 43200 (12 hours).

Solving this can be as simple as updating the app.config dictionary, like so:

app = Flask(__name__)
...
app.config['SEND_FILE_MAX_AGE_DEFAULT'] = 0

If you do that, your browser will not cache static assets that are served by Flask.

like image 30
YellowShark Avatar answered Sep 23 '22 03:09

YellowShark