This question already has answers here:
How to serve static files in Flask
(24 answers)
Link to Flask static files with url_for
(2 answers)
Closed 5 years ago.
I'm currently creating a project involving flask and webpack. Currently the flask server is able to find the revelant template, but is not able to find the relevant JavaScript.
I have a webpack config for creating the HTML file using the webpack html plugin like so:
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin');
module.exports = {
entry: {app: './src/index.js', print: './src/print.js'},
output: {filename: '[name].bundle.js', path: path.resolve(__dirname, 'dist')},
plugins: [new HtmlWebpackPlugin({template:"./src/index.html"}), new CleanWebpackPlugin(['dist'])],
};
This uses a template called index.html in the src directory which contains the following:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Hellow World</title>
</head>
<body>
<h1>It Works</h1>
</body>
</html>
Which should be bundled by webpack with the following javascript,
index.js:
import _ from 'lodash';
import printMe from './print.js';
function component() {
let element = document.createElement('div');
let btn = document.createElement('button');
// lodash now imported
element.innerHTML = _.join(['Hello', 'webpack'], ' ');
// new button
btn.innerHTML = 'Click me and check the console!';
btn.onclick = printMe;
element.appendChild(btn);
return element;
}
document.body.appendChild(component());
and print.js:
export default function printMe() {
console.log('I get called from print.js!');
}
The app.py looks like the following:
from flask import Flask, render_template
app = Flask(__name__, template_folder="dist/", static_folder="dist/")
#app.route("/")
def index():
"""
renders basic index page
:return: template
"""
return render_template("index.html")
# app entry point
if __name__ == "__main__":
app.run(debug=True)
After running a build, a template is produced in the dist folder with the following content in index.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Hellow World</title>
</head>
<body>
<h1>It Works</h1>
<script type="text/javascript" src="app.bundle.js"></script><script type="text/javascript" src="print.bundle.js"></script></body>
</html>
I can't workout how it is able to find the template but not able to find the relevant JavaScript.
The correct URL for app.bundle.js as per your configuration is /dist/app.bundle.js
If you want to serve static files from a different folder, you have to set the static_url_path parameter, in this case to "":
app = Flask(__name__, template_folder="dist", static_folder="dist", static_url_path="")
Reference: https://vilimpoc.org/blog/2012/11/21/serving-static-files-from-root-and-not-static-using-flask/
Related
I'm trying to display an image on a simple website, which I am using Flask for. I already tried to do this using a js script on the website itself, but it didn't work.
However, I do not know how to periodically update/refresh the image.
I'm using html and javascript for the first time right now and I'm too confused to get it to work.
This is the main .py file:
from flask import Flask, render_template
import os
#sorry for the bad code :/
app = Flask(__name__)
#app.route("/")
def running():
return "<p>Website running!</p>"
app.config['UPLOAD_FOLDER'] = os.path.join('static','images')
#app.route("/chart")
def show_img():
full_filename = os.path.join(app.config['UPLOAD_FOLDER'], 'chart.png')
return render_template("chart.html", user_image = full_filename)
if __name__ == "__main__":
app.run(port=3000)
This is chart.html:
<!DOCTYPE html>
<html>
<body>
<img src={{ url_for("static", filename="images/"+"chart.png" ) }}/>
</body>
</html>
What is the easiest way to update/reload the image every 5 seconds?
The filename stays the same, but the image itself changes
Some notes:
When working inside a request, it is better to use current_app
from Flask import current_app
#app.route("/chart")
def show_img():
# current_app.config
full_filename = os.path.join('images', 'chart.png')
return render_template("chart.html", user_image=full_filename)
We removed static as we'll be using static in the template itself.
Since you already have the user_image variable, you can add it to the file directly
<!DOCTYPE html>
<html>
<body>
<img src={{ url_for("static", filename=user_image ) }}/>
</body>
</html>
This will display the image.
Dealing with uploads
If you want to implement uploads etc, use flask-reuploaded, a maintained fork of Flask-uploads.
On the front-end, you need a file upload form. Then you need a route to accept the uploaded file. Then you need to make sure that the uploaded filename is always the same, maybe by deleting existing files beforehand.
A complete demo
Following the official docs, here is a demo.
Folder structure
.
├── app.py
├── static
│ └── images
├── templates
└── chart.html
chart.html
<!DOCTYPE html>
<html>
<body>
<form method="post" enctype=multipart/form-data action="/upload">
<input type="file" name="file">
<input type="submit" value="Upload">
</form>
<br>
<img src={{ url_for("static", filename=user_image ) }}/>
</body>
</html>
app.py
import os
from flask import Flask, flash, request, redirect, url_for, render_template
from werkzeug.utils import secure_filename
UPLOAD_FOLDER = '/path/to/the/uploads'
ALLOWED_EXTENSIONS = {'txt', 'pdf', 'png', 'jpg', 'jpeg', 'gif'}
app = Flask(__name__)
current_file = ''
#app.route("/")
def running():
return "<p>Website running!</p>"
app.config['UPLOAD_FOLDER'] = os.path.join('static','images')
def allowed_file(filename):
return '.' in filename and \
filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS
#app.route('/upload', methods=['GET', 'POST'])
def upload_file():
global current_file
if request.method == 'POST':
# check if the post request has the file part
if 'file' not in request.files:
flash('No file part')
return redirect(request.url)
file = request.files['file']
# If the user does not select a file, the browser submits an
# empty file without a filename.
if file.filename == '':
flash('No selected file')
return redirect(request.url)
if file and allowed_file(file.filename):
filename = secure_filename(file.filename)
current_file = filename
file.save(os.path.join(app.config['UPLOAD_FOLDER'], filename))
return redirect(url_for('show_img', name=filename))
#app.route("/chart")
def show_img():
filename = os.path.join('images', current_file)
return render_template("chart.html", user_image=filename)
if __name__ == "__main__":
app.run(port=3000)
This question is related to
run vue with webpack
I would be grateful for answer why I can't simply initialize Vue & Webpack app by creating:
index.js
import Vue from 'vue';
let app = new Vue({
el: '#app',
data: {
message: 'message'
}
});
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Vue Playground</title>
</head>
<body>
<div id="app">
{{ message }}
</div>
</body>
</html>
Here's my webpack config file:
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: './src/index.js',
output: {
filename: 'main.js',
path: path.join(__dirname, 'dist')
},
plugins: [new HtmlWebpackPlugin({
template: './src/index.html'
})]
};
In this way, root (#app) is simply removed from HTML file by Vue.
I'm new to Vue, and will be glad for explanation. I have a learning manner, that before learning complex solutions like #vue/cli I wish to analyze dependencies of it.
Should I work only with vue-loader? As far as I know, it's used to parse .vue files, but I don't need one here.
Thank You in advance.
By default, when used with Webpack, the runtime only build of Vue is used. If you want to have in-DOM template (your case where Vue template is included directly inside HTML file) or string templates (template component option), those are compiled at runtime (when the page is loaded into browser) and that requires Vue build which includes compiler.
Take a look to the docs on how to configure Webpack to use compiler build of Vue - Runtime + Compiler vs. Runtime-only
I am trying to create a simple node.js app using Webpack for compiling my javascript files. I am totally new to node.js, so I am having a hard time understanding what I am doing wrong and how it should be done.
I am sorry that it's going to be really long-winded, but I am having trouble with the configuration and I'm not sure which specific file is causing the problem, so I am posting a lot of code. Really sorry.
My app architecture so far is the following:
app
└─app.js
└─package.json
└─package-lock.json
└─webpack.config.js
└─views
| └─index.ejs
└─public
└─javascript
└─scripts //where I put functions i am importing into index.js
| └─foo.js
| └─bar.js
└─index.js //file with all js functions create
└─main.js //bundle made by webpacker
in my app.js files:
const path = require("path");
const express = require("express");
const port = process.env.PORT || "8000";
const app = express();
app.set("view engine", "ejs");
app.use(express.static("public"));
in my public/javascript/scripts/foo.js:
const foo = () => {
....
};
module.exports = { foo };
in my public/javascript/index.js:
const foo = require("./scripts/foo");
foo();
in my webpack.config:
const path = require("path");
module.exports = {
context: __dirname,
entry: "./public/javascript/index.js",
output: {
path: path.resolve(__dirname, "public/javascript"),
filename: "main.js"
},
watch: true
};
and in my views/index.ejs:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Objects</title>
<link rel="stylesheet" type="text/css" href="/css/style.css" />
</head>
<body>
...
<script type="text/javascript" src="/javascript/main.js"></script>
</body>
</html>
Then I start the server with:
nodemon ./app.js
And start the client with:
webpack --config ./webpack.config.js
The html loads just fine in the browser, but the javascript doesn't work and the console prints:
Uncaught TypeError: r(...) is not a function
at Object.<anonymous> (main.js:1)
at r (main.js:1)
at main.js:1
at main.js:1
r(...) is something webpack created in main.js when it compiled all js files, but I don't know what could be wrong there.
The problem is your export:
module.exports = { foo };
This is a shorthand notation for writing
module.exports = {
foo: foo,
};
That is, an object with a single key "foo", with the value of your function named foo.
When you later require the module, you're trying to call your module export, which is not the function, but the object around it. If you want to simply export a single function and import a single function, you can instead do:
module.exports = foo;
Using express, I am trying to serve a folder statically which was created using an in memory file system. As of yet this has not been working for me, and I am not sure if this is even possible. Here is what I have tried.
const express = require("express");
const Memory = require("memory-fs");
const mfs = new Memory();
const html = `
<!DOCTYPE html>
<html>
<head>
<title>Title of the document</title>
</head>
<body>
The content of the document......
</body>
</html>
`;
mfs.mkdirpSync("/public");
mfs.writeFileSync("/public/index.html", html, "utf-8");
const app = express();
app.use(express.static("public"));
app.listen(3000, () => console.log("server is running"));
This code just gives me Cannot GET /. Can this be done?
Context
I'm writing an application with Electron and Angular 2+ using Angular CLI. I've set up my electron .js file to point to the URL provided by the ng serve command, that usually is localhost:4200, in order to capture the code changes. Some considerations:
The address localhost:4200 points to index.html;
index.js is my Electron entry point script
Here is my index.js file used as an entry point for the electron module.
const {app, BrowserWindow} = require('electron');
const url = require('url');
const path = require('path');
let win = null;
function createWindow() {
win = new BrowserWindow({width: 1000, height: 600, show: false});
win.loadURL('http://localhost:4200');
win.maximize();
win.on('closed', () => {
win = null;
});
win.on('ready-to-show', () => {
win.show();
});
win.webContents.openDevTools();
}
app.on('ready', () => {
createWindow();
});
app.on('activate', () => {
if (win === null) {
createWindow();
}
});
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') {
app.quit();
}
});
And my index.html file:
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>BRISA Carbon</title>
<base href="/">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon" type="image/x-icon" href="favicon.ico">
<!--Clarity Design Elements-->
<link rel="stylesheet" href="../node_modules/clarity-icons/clarity-icons.min.css">
<script type="text/javascript" src="../node_modules/#webcomponents/custom-elements/custom-elements.min.js"></script>
<script type="text/javascript" src="../node_modules/clarity-icons/clarity-icons.min.js"></script>
</head>
<body>
<app-root></app-root>
</body>
</html>
My Problem
When I run ng serve, the node_modules resources inside the .html file are not being loaded and the Chrome console outputs the following messages
I know that the path to the resources are correct because I'm using WebStorm IDE and I can go to the referenced element through a link like this image below.
Why my resources are not being loaded when I'm running in Angular live mode?
For everyone that is having this same problem, I just found a solution. Instead of loading my resources through the index.html file, I've placed them in the .angular-cli.json. Basically, Angular 2+ has the own way of importing resources and seems that is not correct loading resources from the main .html file.
Well, for scripts (I mean, .js files), I'm placing it in the scripts array and styles inside the styles array. The .angular-cli.json file section that I've changed looks like this:
"styles": [
"styles.css",
"../node_modules/clarity-icons/clarity-icons.min.css",
"../node_modules/clarity-ui/clarity-ui.min.css"
],
"scripts": [
"../node_modules/#webcomponents/custom-elements/custom-elements.min.js",
"../node_modules/clarity-icons/clarity-icons.min.js"
]
Hope that this information will help someone else. For me everything is working just fine.
I assume you're experiencing the same problem when you're visiting localhost:4200 in your browser also?
In your index.html you're referencing to ../node_modules/ ... which works in your IDE because that's how the folder structure looks like.
Let's say your folder structure looks like this:
node_modules/
src/
And src is the folder that your server's using as root. Then the server wont be able to retrieve files from .. (since a root dir has no parent dir).
Instead of referencing to the JS files in your index.html, you should import/require them in your other JS files. Exactly how you do that depnds on your building/bundling tools (eg Webpack and/or Babel).
import '#webcomponents/custom-elements/custom-elements.min.js'
import 'clarity-icons/clarity-icons.min.js'
import 'clarity-icons/clarity-icons.min.css' // Assumes that you use webpack and webpack-css-loader, for example