Search code examples
pythonangularflasksingle-page-applicationangular-router

Angular router not engaging with Flask server using ng build


When using Angular 5 with Flask and ng build --aot --watch, I am having major issues getting Angular's routing and refreshing the page to work.

I have come across many attempts to fix this, but none of them when applied to my project work (and the example projects provided when I try it there also do not seem to work).

What happens (depending on the thing I try) are these:

  1. It can't find the path at all and I get a Jinja2 error
  2. It can't find the document for localhost:5015/ (the port I'm using) and I get a 404 and a white screen
  3. It loads index.html, but upon refresh it gets a 404 (implying that the browser is attempting to fetch the page from the server, not using the Angular routing system)
  4. I get the same issue as this one: Syntax Error in Angular App: Unexpected token <

I am under the impression this is a normal issue with all SPAs and that the solution is to always redirect the server to index.html. We have done this (AFAIK), and attempted multiple ways to do this: Our structure is roughly the following:

- ProjectDir
  - reverseProxy_Calls
  - scripts
  - swagger_yaml_definitions
  - templates
    - e2e
    - dist
    - src
      - app

And our server.py contains this (among other stuff)

Swagger(app)

app.template_folder = "./templates/dist/"
app.static_folder = "./templates/dist/"
app.static_path = "./templates/dist/"
app.static_url_path = "./templates/dist/"
app.instance_path = "./templates/dist/"
config = settings.config()
config.read("settings.cfg")


@app.route('/', defaults={'path': ''}, methods=['GET', 'POST'])
@app.route('/<path:path>', methods=['GET', 'POST'])
def get_resource(path):  # pragma: no cover
    # If we are devmode, proxy through flask.
    if config.getKey("devmode") == True:
        url = "http://localhost:%s/%s" % (config.getKey('ng_port'), path)
        j = requests.get(url, stream=True, params=request.args)
        return make_response(j.text)
    # return the results
    # return render_template('dist/index.html')
    # return app.send_static_file("index.html")
    return send_from_directory('dist/', path)

if __name__ == '__main__':
    app.run(debug=True, port=int(config.getKey("port")))  # , host='0.0.0.0')

^ A variety of ways here show various attempts to handle this.

I have also looked at and tried projects that use variations of the following:

  • Flask Cli
  • Flask-Script
  • Flask-Bootstrap

None of them have solved this problem when I have tried them.

I have been told that using the hashRoute location strategy in Angular rather than the History PushState strategy will also work, however when I attempted to do that it had the same behavior of losing the page upon refresh (additionally we wish to use server side rendering in the future, and hashRoute location strategy prevents this possibility, among many other downsides).

Possibly related is that Flask seems to reload or re-render the page when it does find the index.html and routes initially, wiping anything printed to the browser dev console. I have seen this in some of the flask examples, but not all, and I'm uncertain what causes this.

When running via ng serve --aot --prod, things work exactly correctly and as expected. It's only when serving via Flask that things break down.

Apologies for the long question and thank you for your time in advance.


Solution

  • I am under the impression this is a normal issue with all SPAs and that the solution is to always redirect the server to index.html. We have done this (AFAIK), and attempted multiple ways to do this

    You also need to redirect all HTTP errors to index.html.