Pro Q
Pro Q

Reputation: 5048

Webpack and React Image Not Found

I have looked at so many different resources (some not linked, and this one being the closest to my problem). None of them seem to solve my issue.

I'm brand new to both React and Webpack. I found this tutorial and followed it to create a basic website.

However, I'm having issues displaying images. Instead of displaying the image, I get a "broken file" image and the console says GET http://127.0.0.1:5000/public/images/smiley.png 404 (NOT FOUND)

I have installed the Webpack image loader and I am using require in my React code. It looks like webpack is finding the image because if I change the name of the image I get an error like Uncaught Error: Cannot find module '../images/smiley.png' which crashes the whole website instead of the 404 error.

This is my folder structure:

folder structure

When I run the project with npm run watch and python server.py (from static folder and server folders respectively), a public folder with smiley.png inside of it appears inside of the dist folder.

I have a hunch that the issue is that my Flask is configured in such a way that it does not respond the request because it thinks the public folder is off limits. But that's just a hunch, and I don't know how to fix it if that's the case.

My code can be found here. Any help would be appreciated.

EDIT:

Following my hunch, I added the following to my server.py:

@app.route("/public/<path:path>")
def get_public_file(path):
    print("getting something from public: {}".format(path))
    return send_from_directory("public", path)

But that also did not work - I am still getting a 404.

EDIT 2:

Thanks to @Joost, we found out that using app = Flask(__name__, static_folder="../static", template_folder="../static") puts the image correctly at http://127.0.0.1:5000/static/images/smiley.png.

However, this then causes Flask to not be able to figure out where bundle.js is, since it's located inside the dist folder.

Adding in

@app.route("/dist/<path:path>")
def get_dist_file(path):
    print("getting something from dist: {}".format(path)) # this ran
    return send_from_directory("dist", path)

to server.py did not help - I still get GET http://127.0.0.1:5000/dist/bundle.js net::ERR_ABORTED 404 (NOT FOUND) in the inspector.

So now the trick is to figure out how to keep the smiley face served, and have flask serve the bundle.js file as well.

EDIT 3:

I just discovered a really sketchy way of getting it to work, so sketchy that I'm not even going to post it as an answer because I want something that's less sketchy.

Using @Joost's app = Flask(__name__, static_folder="../static", template_folder="../static") and adding the following to server.py worked.

@app.route('/<path:path>')
def static_file(path):
    print("getting static file {}".format(path))
    if path.startswith("public/"):
        path = "dist/" + path
        print("in public folder; path changed to: {}".format(path))
    return app.send_static_file(path)

The issue with this solution is that I really shouldn't be using send_static_file since it's extremely insecure, and that including an if statement like that seems prone to many errors. A different solution would be appreciated.

Upvotes: 1

Views: 1185

Answers (1)

Joost
Joost

Reputation: 3729

I kept overlooking where the app was running from, sorry about that.

By far the easiest solution is to set you static folder to a different folder:

app = Flask(__name__, static_folder='../static')

I just tried it, and this should work without a problem.

You can find your file here:

http://127.0.0.1:5000/static/images/smiley.png

Your bundle file will be here:

http://127.0.0.1:5000/static/dist/bundle.js

You're getting a template error because you don't have a template folder, which is normally called tempates. So make a subfolder called templates in your server folder. Then, don't specify the template_folder argument in the app = Flask(..) line, but keep it app = Flask(__name__, static_folder='../static').

If, for some reason, you want to seperate your static from your public files and have a /public route as well, you might want to try the following approach:

@app.route("/public/<path:path>")
def get_public_file(path):
    full_path = os.path.join('../static/dist/public/', path)
    head, tail = os.path.split(full_path)
    return send_from_directory(head, tail)

You can then access the smiley in the fullstack_template/static/dist/public/images/smiley.png by going to http://127.0.0.1:5000/public/images/smiley.png.

Upvotes: 2

Related Questions