I want to use Vue.js and Flask together: Vue.js for a dynamic front-end, and Flask for the back-end. How can I do that?
I recently had this problem (combining Vue.js and Flask).
There are at least two ways to combine them, depending on whether you're creating 1) a simple Vue.js app or 2) a more-complicated Vue.js app that needs to use a module bundler like Webpack to combine Single-File Components or npm packages.
Simple Vue.js app:
This is actually fairly easy and very powerful on its own:
.html
file. Otherwise just open whatever .html
template file you want the app to be in.
If you're OK with having your Vue.js JavaScript code in the same file as your HTML, below is a simple "Hello World" example template you can use to get a sense of what needs to be in the Flask template file:
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.13/vue.js"></script>
</head>
<body>
<div id="app">
<p>{{ message }}</p>
</div>
<script>
new Vue({
el: '#app',
data: {
message: 'Hello Vue.js!'
}
})
</script>
</body>
static
folder, name it after this app you want to create.
.html
template file include a script tag to include Vue.js.
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.3.4/vue.js"></script>
<script src="%% url_for('static', filename='js/YOUR_APP_NAME.js') %%"></script>
div
in the .html
template file that has an id
of app
.
<div id="app"></div>
If you are using Jinja2 to render your templates, you will need to add a few lines of code to tell Jinja2 to not use the {{ }}
syntax to render variables, because we need those double-curly-brace symbols for Vue.js. Below is the code you need to add to your app.py
to do this:
class CustomFlask(Flask):
jinja_options = Flask.jinja_options.copy()
jinja_options.update(dict(
variable_start_string='%%', # Default is '{{', I'm changing this because Vue.js uses '{{' / '}}'
variable_end_string='%%',
))
app = CustomFlask(__name__) # This replaces your existing "app = Flask(__name__)"
.html
and .js
files.
Easy!
More-complicated Vue.js app using Webpack:
npm install -g @vue/cli
vue create my-project
server
folder and a client
folder, where the server
folder contains the Flask server code, and the client
folder contains the Vue.js project code.app.html
file is created in your Flask server/templates
folder, and the static JavaScript and CSS needed by app.html
is created in a server/static/app/
folder, isolated from the static assets used by the non-Vue portions of you Flask app.npm run build
from within the folder containing your Vue.js project, which will generate an .html
file and several static files (JavaScript and CSS).The exact changes I made to my Webpack config (via my git commit):
client/build/webpack.dev.conf.js
:
new HtmlWebpackPlugin({
- filename: 'index.html',
- template: 'index.html',
+ filename: 'app.html',
+ template: 'app.html',
Here (above) I'm changing the name of the Vue.js 'launch' file to app.html so that it doesn't conflict with my Flask app's 'index.html'.
client/config/index.js
:
module.exports = {
build: {
env: require('./prod.env'),
- index: path.resolve(__dirname, '../dist/index.html'),
- assetsRoot: path.resolve(__dirname, '../dist'),
- assetsSubDirectory: 'static',
- assetsPublicPath: '/',
+ index: path.resolve(__dirname, '../../server/templates/app.html'),
+ assetsRoot: path.resolve(__dirname, '../../server/static/app'),
+ assetsSubDirectory: '',
+ assetsPublicPath: '/static/app',
Here (above) I'm setting where the app.html file and static assets should be created.
Because we're directing Webpack to generate the static assets within Flask's "static" folder (/static/app/
)...
html
file will automatically be set up correctly by Webpack.
src=/static/app/js/app.f5b53b475d0a8ec9499e.js
static/
folder, which Flask assumes has a /static/etc.
URL.
app.html
file.client/build/webpack.prod.conf.js
:
new HtmlWebpackPlugin({
filename: process.env.NODE_ENV === 'testing'
- ? 'index.html'
+ ? 'app.html'
: config.build.index,
- template: 'index.html',
+ template: 'app.html',
Here (above) I'm just renaming the 'launch' page, same as in webpack.dev.conf.js
.
routes.py
:
@web_routes.route('/app')
@login_required
def app():
if current_user.datetime_subscription_valid_until < datetime.datetime.utcnow():
return redirect(url_for('web_routes.pay'))
return render_template('app.html')
Here (above) is my render function. I'm using Flask's Blueprints feature (<blueprint_name>.route
) but you don't have to.
When using vue-cli or Webpack, process can be simplified. Simply create
vue.config.js
in your Vue project, see: Vue config
module.exports = {
outputDir: "../dist",
// relative to outputDir
assetsDir: "static"
};
then config your flask app:
app.py
from flask import Flask, render_template
app = Flask(__name__,
static_folder = "./dist/static",
template_folder = "./dist")
@app.route('/')
def index():
return render_template("index.html")
Note, that in flask static_folder
and template_folder
can't be the same.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With