Flask

Flask

Flask is a micro web framework written in Python. It is classified as a microframework because it does not require particular tools or libraries. It has no database abstraction layer, form validation, or any other components where pre-existing third-party libraries provide common functions.
Maryjane  Olson

Maryjane Olson

1660489500

Latam 5 Project: WebApp Boilerplate with React JS and Flask API

WebApp boilerplate with React JS and Flask API

Styles

You can update the styles/index.scss or create new .scss files inside styles/ and import them into your current scss or js files depending on your needs.

Components

Add more files into your ./src/js/components or styles folder as you need them and import them into your current files as needed.

💡Note: There is an example using the Context API inside views/demo.js;

Views (Components)

Add more files into your ./src/js/views and import them in ./src/js/layout.jsx.

Context

This boilerplate comes with a centralized general Context API. The file ./src/js/store/flux.js has a base structure for the store, we encourage you to change it and adapt it to your needs.

React Context docs BreathCode Lesson view

The Provider is already set. You can consume from any component using the useContext hook to get the store and actions from the Context. Check /views/demo.js to see a demo.

import { Context } from "../store/appContext";
const MyComponentSuper = () => {
    //here you use useContext to get store and actions
    const { store, actions } = useContext(Context);
    return <div>{/* you can use your actions or store inside the html */}</div>;
};

Back-End Manual Installation:

It is recomended to install the backend first, make sure you have Python 3.8, Pipenv and a database engine (Posgress recomended)

  1. Install the python packages: $ pipenv install
  2. Create a .env file based on the .env.example: $ cp .env.example .env
  3. Install your database engine and create your database, depending on your database you have to create a DATABASE_URL variable with one of the possible values, make sure yo replace the valudes with your database information:
EngineDATABASE_URL
SQLitesqlite:////test.db
MySQLmysql://username:password@localhost:port/example
Postgresspostgres://username:password@localhost:5432/example
  1. Migrate the migrations: $ pipenv run migrate (skip if you have not made changes to the models on the ./src/api/models.py)
  2. Run the migrations: $ pipenv run upgrade
  3. Run the application: $ pipenv run start

Backend Populate Table Users

To insert test users in the database execute the following command:

$ flask insert-test-users 5

And you will see the following message:

  Creating test users
  test_user1@test.com created.
  test_user2@test.com created.
  test_user3@test.com created.
  test_user4@test.com created.
  test_user5@test.com created.
  Users created successfully!

To update with all yours tables you can edit the file app.py and go to the line 80 to insert the code to populate others tables

Front-End Manual Installation:

  • Make sure you are using node version 14+ and that you have already successfully installed and runned the backend.
  1. Install the packages: $ npm install
  2. Start coding! start the webpack dev server $ npm run start

Publish your website!

This boilerplate it's 100% integrated with Herkou, just by pushing your changes to the heroku repository it will deploy: $ git push heroku main

    // "prettier-webpack-plugin": "^1.2.0",

"dotenv-webpack": "^1.7.0", "friendly-errors-webpack-plugin": "^1.7.0",


Author: arnaldoperez
Source code: https://github.com/arnaldoperez/latam-5-project

#react  #javascript  #flask #python 

Latam 5 Project: WebApp Boilerplate with React JS and Flask API
Isai  Upton

Isai Upton

1660438740

How Can I Combine Vue.js With Flask?

Combining Flask and Vue

In this article, we'll take a look at three different methods for combining Flask and Vue:

  1. Jinja Template: Importing Vue into a Jinja template
  2. Single-Page Application: Building a Single-Page Application (SPA) to completely separate Flask and Vue
  3. Flask Blueprint: Serving up Vue from a Flask blueprint to partially separate the two

Source: https://testdriven.io

#vue #flask 

How Can I Combine Vue.js With Flask?
Duyen Hoang

Duyen Hoang

1660431480

Làm Cách Nào Để Kết Hợp Vue.js Với Flask?

Kết hợp Flask và Vue

Vì vậy, cuối cùng bạn đã có Flask dưới dây của mình, và bạn không còn xa lạ với JavaScript. Bạn thậm chí đã phát triển một vài ứng dụng web, nhưng bạn bắt đầu nhận ra điều gì đó - bạn có chức năng xuất sắc, nhưng UX của bạn hơi nhạt nhẽo. Luồng ứng dụng và điều hướng liền mạch mà bạn thấy trên nhiều trang web và ứng dụng phổ biến hiện nay đang ở đâu? Làm thế nào có thể đạt được điều đó?

Khi bạn đầu tư nhiều hơn vào các trang web và ứng dụng web của mình, có thể bạn sẽ muốn thêm nhiều chức năng và phản ứng phía máy khách hơn cho chúng. Việc phát triển web hiện đại thường đạt được điều này thông qua việc sử dụng các khung công tác front-end và một khung công tác đang nhanh chóng trở nên phổ biến là Vue (còn được gọi là Vue.js hoặc VueJS).

Tùy thuộc vào yêu cầu của dự án của bạn, có một số cách khác nhau để xây dựng một ứng dụng web với Flask và Vue, và mỗi cách đều liên quan đến các mức phân tách back-end / front-end khác nhau.

Trong bài viết này, chúng ta sẽ xem xét ba phương pháp khác nhau để kết hợp Flask và Vue:

  1. Mẫu Jinja : Nhập Vue vào mẫu Jinja
  2. Ứng dụng một trang : Xây dựng một ứng dụng một trang (SPA) để tách hoàn toàn Flask và Vue
  3. Bản thiết kế Flask : Cung cấp Vue từ bản thiết kế Flask để tách một phần hai

Các cách khác nhau để xây dựng ứng dụng web với Flask và Vue

Chúng tôi sẽ phân tích ưu và nhược điểm của từng phương pháp, xem xét các trường hợp sử dụng tốt nhất của chúng và chi tiết cách thiết lập từng phương pháp.

Mẫu Jinja

Bất kể bạn đang sử dụng React, Vue hay Angular, đây là cách dễ nhất để chuyển sang sử dụng front-end framework.

In many cases, when you're building a front-end for your web app, you design it around the front-end framework itself. With this method, however, the focus is still on your back-end Flask application. You'll still use Jinja and server-side templating along with a bit of reactive functionality with Vue if and when you need it.

You can import the Vue library either through a Content Delivery Network (CDN) or by serving it yourself along with your app, while setting up and routing Flask as you would normally.

Pros

  • You can build your app your way instead of fitting it around Vue's foundation.
  • Search Engine Optimization (SEO) doesn't require any additional configuring.
  • You can take advantage of cookie-based authentication instead of token-based authentication. This tends to be easier, as you're not dealing with asynchronous communication between the front and back end.

Cons

  • You have to import Vue on and set up each page individually, which can be difficult if you start adding Vue to more and more pages. It may require a number of workarounds as well since it's not really the intended way to use either Flask or Vue.

Best For

  • Small web apps literally using a single HTML page or two (as opposed to a SPA with its own dynamic routing -- see the SPA method for more info).
  • Building functionality into an already existing web app.
  • Adding bits of reactivity to an app without fully committing to a front-end framework.
  • Các ứng dụng web không cần giao tiếp thường xuyên với back-end thông qua AJAX.

Phụ thuộc bổ sung

Phương pháp này chỉ yêu cầu thư viện Vue, bạn có thể thêm thư viện này qua CDN:

<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>

Thành lập

Trong số tất cả các phương pháp, thiết lập này là đơn giản nhất.

Tạo một thư mục để chứa tất cả mã ứng dụng của bạn. Bên trong thư mục đó, hãy tạo tệp app.py như bình thường:

from flask import Flask, render_template # These are all we need for our purposes

app = Flask(__name__)

@app.route("/")
def index():
    return render_template("index.html", **{"greeting": "Hello from Flask!"})

Chúng tôi chỉ cần nhập Flaskrender_templatetừ flask.

Biến greetingsẽ xuất hiện lại sau một giây nữa khi chúng ta xem xét cách hiển thị các biến với cả Jinja và Vue trong cùng một tệp.

Tiếp theo, tạo một thư mục "mẫu" để chứa tệp HTML của chúng tôi. Bên trong thư mục đó, hãy tạo tệp index.html . Trong phần nội dung của tệp HTML, hãy tạo một div vùng chứa có id là vm.

Cần lưu ý rằng đó vmchỉ là một tiêu chuẩn đặt tên chung. Nó là viết tắt của ViewModel . Bạn có thể đặt tên cho nó bất cứ điều gì bạn muốn; nó không cần phải được vm.

Trong div, hãy tạo hai pthẻ để làm trình giữ chỗ cho các biến Flask và Vue của chúng tôi:

  1. Một trong các chữ divs phải chứa từ 'lời chào' được bao quanh bởi dấu ngoặc nhọn {{ greeting }}:.
  2. Cái kia phải chứa 'lời chào' được bao quanh bởi dấu ngoặc vuông [[ greeting ]]:.

Nếu bạn không sử dụng các dấu phân cách riêng biệt, với thiết lập mặc định, Flask sẽ thay thế cả hai lời chào bằng bất kỳ biến nào bạn chuyển với nó (ví dụ: "Xin chào từ Flask!").

Đây là những gì chúng tôi có cho đến nay:

<body>
<!-- The id 'vm' is just for consistency - it can be anything you want -->
    <div id="vm">
        <p>{{ greeting }}</p>
        <p>[[ greeting ]]</p>
    </div>
</body>

Trước khi kết thúc thẻ body, hãy nhập Vue từ CDN chính thức cùng với tập lệnh để giữ mã JavaScript của chúng tôi:

<body>
<!-- The id 'vm' is just for consistency - it can be anything you want -->
    <div id="vm">
        <p>{{ greeting }}</p>
        <p>[[ greeting ]]</p>
    </div>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <script src="{{ url_for('static', filename='index.js') }}"></script>
</body>

Điều hướng lên một thư mục, tạo một thư mục "tĩnh". Thêm một tệp JavaScript mới trong thư mục đó có tên là index.js .

Trong tệp này, hãy tạo ngữ cảnh Vue, đặt phiên bản của chúng tôi el'#vm', thay đổi các dấu phân cách mặc định từ '{{', '}}'thành '[[', ']]':

const vm = new Vue({ // Again, vm is our Vue instance's name for consistency.
    el: '#vm',
    delimiters: ['[[', ']]']
})

Trong thực tế, chúng ta có thể sử dụng bất cứ thứ gì chúng ta muốn làm dấu phân cách. Trên thực tế, nếu đó là sở thích của bạn, bạn có thể thay đổi các dấu phân cách cho các mẫu Jinja của mình trong Flask.

Cuối cùng, thêm một phần tử dữ liệu với khóa / giá trị là greeting: 'Hello, Vue!':

const vm = new Vue({ // Again, vm is our Vue instance's name for consistency.
    el: '#vm',
    delimiters: ['[[', ']]'],
    data: {
        greeting: 'Hello, Vue!'
    }
})

Và bây giờ chúng ta đã hoàn thành với tệp đó. Cấu trúc thư mục cuối cùng của bạn sẽ trông giống như sau:

├───app.py
├───static
│   └───index.js
└───templates
    └───index.html

Now you can go back to you root project folder and run the app with flask run. Navigate to the site in your browser. The first and second line should have been replaced by Flask and Vue, respectively:

Hello from Flask!
Hello, Vue!

That's it! You can mix and match JSON endpoints and HTML endpoints as you please, but be aware that this can get really ugly really quickly. For a more manageable alternative, see the Flask Blueprint method.

With each additional HTML page, you'll have to either import the same JavaScript file and account for variables and elements that may not apply to it or create a new Vue object for each page. A true SPA will be difficult, but not impossible -- theoretically you could write a tiny JavaScript library that will asynchronously grab HTML pages/elements served by Flask.

I've actually created my own JavaScript library for this before. It was a big hassle and honestly not worth it, especially considering JavaScript will not run script tags imported this way, unless you build the functionality yourself. You'll also be reinventing the wheel.

If you'd like to check out my implementation of this method, you can find it on GitHub. The library takes a given chunk of HTML and replaces the specified HTML on the page with it. If the given HTML contains no <script> elements (it checks using regex), it simply uses HTMLElement.innerHTML to replace it. If it does contain <script> elements, it recursively adds the nodes, recreating any <script> nodes that come up, allowing your JavaScript to run.

Using something like this in combination with the History API can help you build a small SPA with a very tiny file size. You can even create your own Server-Side Rendering (SSR) functionality by serving full HTML pages on page load and then serve up partial pages through AJAX requests. You can learn more about SSR in the SPA with Nuxt method.

Single-Page Application

If you want to build a fully dynamic web app with a seamless User Experience (UX), you can completely separate your Flask back-end from your Vue front-end. This may take learning a whole new way of thinking when it comes to web app design if you're not familiar with modern front-end frameworks.

Developing your app as a SPA may put a dent in your SEO. In the past, this hit would be much more dramatic, but updates to how Googlebot indexes sites have negated this at least somewhat. It may, however, still have a greater impact on non-Google search engines that don't render JavaScript or those that snapshot your page(s) too early -- the latter shouldn't happen if your website is well-optimized.

For more information on SEO in modern SPAs, this article on Medium shows how Googlebot indexes JavaScript-rendered sites. Additionally, this article talks in-depth about the same thing along with other helpful tips concerning SEO on other search engines.

Với phương pháp này, bạn sẽ muốn tạo một ứng dụng Vue hoàn toàn riêng biệt bằng công cụ Vue CLI . Sau đó, Flask sẽ được sử dụng để cung cấp API JSON RESTful mà Vue SPA của bạn sẽ giao tiếp thông qua AJAX.

Ưu điểm

  • Front-end và back-end của bạn sẽ hoàn toàn độc lập với nhau, vì vậy bạn có thể thực hiện các thay đổi cho một cái mà không ảnh hưởng đến cái kia.
    • Điều này cho phép chúng được triển khai, phát triển và duy trì riêng biệt.
    • Bạn thậm chí có thể thiết lập một số giao diện người dùng khác để tương tác với API Flask của mình nếu bạn muốn.
  • Trải nghiệm giao diện người dùng của bạn sẽ mượt mà và liền mạch hơn nhiều.

Nhược điểm

  • Còn nhiều hơn thế nữa để thiết lập và học hỏi.
  • Khó triển khai.
  • SEO có thể bị ảnh hưởng nếu không có thêm sự can thiệp (xem phương pháp SPA với Nuxt để biết thêm chi tiết).
  • Xác thực có liên quan nhiều hơn, vì bạn sẽ phải tiếp tục chuyển mã thông báo xác thực ( JWT hoặc Paseto ) đến back-end của mình.

Tốt nhất cho

  • Các ứng dụng mà UX quan trọng hơn SEO.
  • Các giao diện người dùng cần có thể truy cập được bởi nhiều giao diện người dùng.

Phụ thuộc bổ sung

  • Node / npm
  • CLI View
  • Flask-CORS

Việc triển khai và lưu trữ nằm ngoài phạm vi của bài viết này, nhưng không quá khó để Dockerize thiết lập này để đơn giản hóa việc triển khai.

Thành lập

Bởi vì chúng tôi hoàn toàn tách Vue khỏi Flask, phương pháp này yêu cầu thiết lập thêm một chút. Chúng tôi sẽ cần bật Chia sẻ tài nguyên đa nguồn gốc (CORS) trong Flask, vì front-end và back-end của chúng tôi sẽ được phân phát trên các cổng riêng biệt. Để thực hiện điều này một cách nhanh chóng và dễ dàng, chúng tôi sẽ sử dụng gói Python Flask-CORS .

Vì lý do bảo mật, các trình duyệt web hiện đại không cho phép JavaScript phía máy khách truy cập tài nguyên (chẳng hạn như dữ liệu JSON) từ nguồn gốc khác với nguồn gốc mà tập lệnh của bạn sử dụng trừ khi chúng bao gồm một tiêu đề phản hồi cụ thể để trình duyệt biết điều đó ổn.

Nếu bạn chưa cài đặt Flask-CORS, hãy làm như vậy với pip.

Hãy bắt đầu với API Flask của chúng tôi.

Đầu tiên, hãy tạo một thư mục để chứa mã cho dự án của bạn. Bên trong, tạo một thư mục có tên "api". Tạo tệp app.py trong thư mục. Mở tệp bằng trình soạn thảo văn bản yêu thích của bạn. Lần này, chúng tôi sẽ cần nhập Flasktừ flaskCORStừ flask_cors. Vì chúng tôi đang sử dụng flask_corsđể bật chia sẻ tài nguyên nguồn gốc chéo, hãy bọc đối tượng ứng dụng (mà không đặt biến mới) bằng CORS:. CORS(app)Đó là tất cả những gì chúng tôi phải làm để kích hoạt CORS trên tất cả các tuyến đường của chúng tôi cho bất kỳ điểm xuất phát nào.

Mặc dù điều này là tốt cho mục đích trình diễn, nhưng có thể bạn sẽ không muốn bất kỳ ứng dụng hoặc trang web nào có thể truy cập API của bạn. Trong trường hợp đó, bạn có thể sử dụng 'nguồn gốc' kwarg với hàm CORS để thêm danh sách các nguồn gốc được chấp nhận - tức làCORS(app, origins=["origin1", "origin2"])

Để biết thêm thông tin về Chia sẻ Tài nguyên Nhiều Nguồn gốc, MDN có một số tài liệu tuyệt vời về nó.

Cuối cùng, hãy tạo một tuyến chào duy nhất tại /greetingđể trả về một đối tượng JSON với một khóa / giá trị duy nhất:

{"greeting": "Hello from Flask!"}

Đây là những gì bạn nên kết thúc với:

from flask import Flask
from flask_cors import CORS

app = Flask(__name__)
CORS(app)

@app.route("/greeting")
def greeting():
    return {"greeting": "Hello from Flask!"}

Đó là tất cả những gì chúng ta cần làm với Python.

Tiếp theo, chúng tôi sẽ thiết lập ứng dụng web Vue của chúng tôi. Từ một thiết bị đầu cuối, mở thư mục gốc của dự án của bạn. Sử dụng Vue CLI, tạo một dự án Vue có tên "webapp" ( vue create webapp). Bạn có thể sử dụng khá nhiều tùy chọn mà bạn thích, nhưng nếu bạn đang sử dụng các thành phần dựa trên lớp trong TypeScript, thì cú pháp sẽ hơi khác một chút.

Khi dự án của bạn được tạo xong, hãy mở App.vue .

Vì mục tiêu của chúng ta chỉ là xem Vue và Flask tương tác với nhau như thế nào, nên ở đầu trang, hãy xóa tất cả các phần tử bên trong divcó id là app. Bạn chỉ nên để lại:

<template>
<div id="app">
</div>
</template>

Trong #app, hãy tạo hai pphần tử:

  1. Nội dung của đầu tiên nên được {{ greeting }}.
  2. Nội dung của thứ hai nên được {{ flaskGreeting }}.

HTML cuối cùng của bạn phải như vậy:

<template>
<div id="app">
    <p>{{ greeting }}</p>
    <p>{{ flaskGreeting }}</p>
</div>
</template>

Trong của chúng tôi script, hãy thêm logic để hiển thị một lời chào thuần túy từ phía máy khách ( greeting) và một lời chào được lấy từ API ( flaskGreeting) của chúng tôi.

Trong đối tượng Vue (nó bắt đầu bằng export default), hãy tạo một datakhóa. Biến nó thành một hàm trả về một đối tượng. Sau đó, trong đối tượng này, tạo thêm hai khóa: greetingflaskGreeting. greetingGiá trị của 's phải là 'Hello, Vue!'while flaskGreeting' s phải là một chuỗi trống.

Đây là những gì chúng tôi có cho đến nay:

export default {
    name: 'App',
    components: {
        HelloWorld
    },
    data: function(){
        return {
            greeting: 'Hello, Vue!',
            flaskGreeting: ''
        }
    }
}

Cuối cùng, hãy cung cấp cho đối tượng Vue của chúng ta một createdmóc vòng đời. Móc này sẽ chỉ được chạy sau khi DOM được tải và đối tượng Vue của chúng ta được tạo. Điều này cho phép chúng tôi sử dụng fetchAPI và tương tác với Vue mà không có bất kỳ điều gì xung đột:

export default {
    components: {
        Logo
    },
    data: function(){
        return {
            greeting: 'Hello, Vue!',
            flaskGreeting: ''
        }
    },
    created: async function(){
        const gResponse = await fetch("http://localhost:5000/greeting");
        const gObject = await gResponse.json();
        this.flaskGreeting = gObject.greeting;
    }
}

Xem xét mã, chúng tôi đang awaitnhập một phản hồi cho điểm cuối 'lời chào' của API ( http://localhost:5000/greeting), nhập awaitphản hồi không đồng bộ của .json()phản hồi đó và đặt biến đối tượng Vue của chúng tôi thành flaskGreetinggiá trị của đối tượng JSON được trả về cho greetingkhóa của nó.

Đối với những người không quen thuộc với API Tìm nạp tương đối mới của JavaScript , về cơ bản nó là một kẻ giết người AXIOS gốc (ít nhất là theo như phía khách hàng có liên quan - nó không được hỗ trợ bởi Node, nhưng nó sẽ được Deno ). Ngoài ra, nếu bạn thích tính nhất quán, bạn cũng có thể kiểm tra gói isomorphic-fetch để sử dụng Tìm nạp ở phía máy chủ.

Và chúng tôi đã hoàn thành. Bây giờ, một lần nữa, front-end và back-end của chúng tôi là riêng biệt, chúng tôi sẽ cần chạy cả hai ứng dụng của mình một cách riêng biệt.

Hãy mở thư mục gốc của dự án trong hai cửa sổ đầu cuối riêng biệt.

Trong lần đầu tiên, thay đổi thành thư mục "api", và sau đó chạy flask run. Nếu mọi việc suôn sẻ, API Flask sẽ chạy. Trong thiết bị đầu cuối thứ hai, thay đổi vào thư mục "ứng dụng web" và chạy npm run serve.

Sau khi ứng dụng Vue hoạt động, bạn sẽ có thể truy cập nó từ localhost:8080. Nếu mọi thứ hoạt động, bạn sẽ được chào đón hai lần - một lần bởi Vue và một lần nữa từ API Flask của bạn:

Hello, Vue!
Hello from Flask!

Cây tệp cuối cùng của bạn sẽ giống như sau:

├───app.py
├───api
│   └───app.py
└───webapp
    ... {{ Vue project }}

Ứng dụng một trang với Nuxt

Nếu SEO quan trọng đối với bạn như UX, bạn có thể muốn triển khai Kết xuất phía máy chủ (SSR) ở một số định dạng.

SSR giúp các công cụ tìm kiếm điều hướng và lập chỉ mục ứng dụng Vue của bạn dễ dàng hơn, vì bạn sẽ có thể cung cấp cho chúng một dạng ứng dụng của bạn mà không yêu cầu JavaScript để tạo. Nó cũng có thể giúp người dùng tương tác với ứng dụng của bạn nhanh hơn, vì phần lớn nội dung ban đầu của bạn sẽ được hiển thị trước khi gửi cho họ. Nói cách khác, người dùng sẽ không phải đợi tất cả nội dung của bạn tải không đồng bộ.

Ứng dụng một trang có Hiển thị phía máy chủ còn được gọi là Ứng dụng toàn cầu.

Mặc dù có thể triển khai SSR theo cách thủ công, chúng tôi sẽ sử dụng Nuxt trong bài viết này; nó đơn giản hóa mọi thứ rất nhiều.

Cũng giống như phương pháp SPA , front-end và back-end của bạn sẽ hoàn toàn tách biệt; bạn sẽ chỉ sử dụng Nuxt thay vì Vue CLI.

Ưu điểm

  • Tất cả các ưu điểm của phương pháp SPA với việc bổ sung Kết xuất phía máy chủ.

Nhược điểm

  • Khó thiết lập như phương pháp SPA .
  • Về mặt khái niệm, thậm chí còn có nhiều điều để tìm hiểu vì Nuxt về cơ bản chỉ là một lớp khác trên đầu Vue.

Tốt nhất cho

  • Các ứng dụng mà SEO cũng quan trọng như UX.

Phụ thuộc bổ sung

  1. Node / npm
  2. Nuxt
  3. Flask-CORS

Thành lập

Điều này sẽ rất giống với phương pháp SPA . Trên thực tế, phần Flask hoàn toàn giống nhau. Hãy làm theo nó cho đến khi bạn tạo xong API Flask của mình.

Khi API của bạn hoàn tất, trong thiết bị đầu cuối của bạn, hãy mở thư mục gốc của dự án và chạy lệnh npx create-nuxt-app webapp. Điều này sẽ cho phép bạn tạo một dự án Nuxt mới một cách tương tác mà không cần cài đặt bất kỳ phụ thuộc chung nào.

Mọi lựa chọn đều ổn ở đây.

Khi dự án của bạn được tạo xong, hãy đi sâu vào thư mục "ứng dụng web" mới của bạn. Trong thư mục "trang", mở index.vue trong trình soạn thảo văn bản của bạn. Tương tự, xóa mọi thứ trong divlớp có lớp đó container. Bên trong div, hãy tạo hai pthẻ có cùng các vars: {{ greeting }}{{ flaskGreeting }}.

Nó sẽ giống như thế này:

<template>
<div class="container">
    <p>{{ greeting }}</p>
    <p>{{ flaskGreeting }}</p>
</div>
</template>

Và bây giờ cho kịch bản của chúng tôi:

  • Thêm một datakhóa trả về một đối tượng với các biến greetingflaskGreeting
  • Thêm createdmóc vòng đời:
    • await fetchđể nhận lời chào JSON từ API của chúng tôi (trên cổng 5000 trừ khi bạn thay đổi nó)
    • awaitphương json()pháp để lấy dữ liệu JSON của chúng tôi một cách không đồng bộ từ phản hồi của API của chúng tôi
    • Đặt đối tượng Vue của chúng tôi flaskGreetingthành greetingkhóa từ đối tượng JSON của phản hồi của chúng tôi

Đối tượng Vue sẽ giống như sau:

export default {
    components: {
        Logo
    },
    data: function(){
        return {
            greeting: 'Hello, Vue!',
            flaskGreeting: ''
        }
    },
    created: async function(){
        const gResponse = await fetch("http://localhost:5000/greeting");
        const gObject = await gResponse.json();
        this.flaskGreeting = gObject.greeting;
    }
}

Chạy ứng dụng Nuxt / Vue và API Flask cũng sẽ trông rất giống với phương pháp SPA .

Mở hai cửa sổ đầu cuối. Trong lần đầu tiên, thay đổi thành "api" và chạy flask runlệnh. Trong vòng thứ hai, thay đổi thành "webapp" và chạy npm run devđể bắt đầu một máy chủ phát triển cho dự án Nuxt của bạn.

Sau khi ứng dụng Nuxt lên, bạn sẽ có thể truy cập nó từ localhost:3000:

Hello, Vue!
Hello from Flask!

Trong sản xuất, bạn có thể chạy npm run buildvà sau đó npm run startkhởi động máy chủ sản xuất.

Cây cuối cùng của chúng tôi:

├───app.py
├───api
│   └───app.py
└───webapp
    ... {{ Nuxt project }}

THƯỞNG: So sánh Vue và Nuxt SEO

Tôi đã đề cập đến những lợi ích của SEO trước đó trong bài viết này, nhưng chỉ để cho bạn thấy ý tôi là, tôi đã chạy cả hai ứng dụng web và giành được điểm số SEO Lighthouse cho cả hai.

Không có thay đổi nào đối với một trong hai ứng dụng, đây là những gì chúng tôi có:

Điểm SEO Lighthouse cho Ứng dụng Vue và Nuxt của chúng tôi

Một lần nữa, có những điều bạn có thể làm để cải thiện điểm SEO Vue thuần túy của mình. Lighthouse trong các công cụ dành cho nhà phát triển của Chrome đề cập đến việc thêm mô tả meta, nhưng không cần can thiệp thêm, Nuxt đã cho chúng tôi điểm SEO hoàn hảo.

Ngoài ra, bạn thực sự có thể thấy sự khác biệt giữa SSR mà Nuxt thực hiện và cách tiếp cận hoàn toàn không đồng bộ của vani Vue. Nếu bạn chạy cả hai ứng dụng cùng một lúc, hãy điều hướng đến nguồn gốc tương ứng của chúng localhost:8080localhost:3000, lời chào ban đầu của ứng dụng Vue xảy ra mili giây sau khi bạn nhận được phản hồi, trong khi Nuxt's được phân phát với lời chào ban đầu đã được hiển thị.

Để biết thêm thông tin về sự khác biệt giữa Nuxt và Vue, bạn có thể xem các bài viết sau:

  1. Nuxt.js thay vì Vue.js: khi nào bạn nên sử dụng nó và tại sao
  2. Cách Nuxt.js giải quyết các vấn đề SEO trong Vue.js.

Bản thiết kế Flask

Có lẽ bạn đã có một ứng dụng Flask nhỏ được phát triển và bạn muốn xây dựng một ứng dụng Vue như một phương tiện để kết thúc hơn là sự kiện chính.

Ví dụ:

  1. Nguyên mẫu để chứng minh chức năng cho người sử dụng lao động hoặc khách hàng của bạn (bạn luôn có thể thay thế cái này hoặc giao nó cho nhà phát triển front-end sau này).
  2. Bạn chỉ không muốn đối phó với sự thất vọng tiềm ẩn có thể xảy ra khi triển khai front-end và back-end hoàn toàn riêng biệt.

Trong trường hợp đó, bạn có thể sắp xếp gặp nhau ở giữa bằng cách giữ ứng dụng Flask của mình, nhưng xây dựng trên giao diện người dùng Vue trong bản thiết kế Flask của chính nó.

Điều này sẽ trông giống như phương pháp Mẫu Jinja , nhưng mã sẽ có tổ chức hơn.

Ưu điểm

  • Không cần phải xây dựng một giao diện người dùng phức tạp nếu nó không cần thiết.
  • Tương tự như phương pháp Mẫu Jinja với lợi ích bổ sung là tổ chức mã tốt hơn.
  • Bạn luôn có thể mở rộng front-end và back-end nếu cần sau này.

Nhược điểm

  • Các giải pháp thay thế có thể là cần thiết để cho phép một SPA đầy đủ.
  • Việc truy cập API có thể hơi khó chịu hơn từ giao diện người dùng riêng biệt (chẳng hạn như ứng dụng dành cho thiết bị di động) vì giao diện người dùng và giao diện người dùng không hoàn toàn tách biệt.

Tốt nhất cho

  • Các dự án mà chức năng quan trọng hơn giao diện người dùng.
  • Bạn đang xây dựng giao diện người dùng trên một ứng dụng Flask đã có sẵn.
  • Các ứng dụng web nhỏ chỉ được tạo thành từ một vài trang HTML.

Phụ thuộc bổ sung

Tương tự với phương pháp Mẫu Jinja , chúng tôi sẽ sử dụng CDN để kéo vào thư viện Vue:

<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>

Thành lập

Giống như các phương pháp khác, hãy tạo một thư mục mới để chứa mã của bạn. Bên trong nó, tạo hai thư mục: "api" và "client". Theo trực quan, chúng sẽ chứa các bản thiết kế cho API và ứng dụng khách (Vue) của chúng tôi, tương ứng.

Hãy đi sâu vào thư mục "api".

Tạo một tệp có tên api.py. Điều này sẽ chứa tất cả mã được liên kết với API của chúng tôi. Ngoài ra, vì chúng tôi sẽ truy cập tệp / thư mục này dưới dạng mô-đun, hãy tạo tệp __init__.py :

from flask import Blueprint

api_bp = Blueprint('api_bp', __name__) # "API Blueprint"

@api_bp.route("/greeting") # Blueprints don't use the Flask "app" context. They use their own blueprint's
def greeting():
    return {'greeting': 'Hello from Flask!'}

Đối số đầu tiên Blueprintlà cho hệ thống định tuyến của Flask. Đối số thứ hai, __name__tương đương với đối số đầu tiên của ứng dụng Flask ( Flask(__name__)).

Và đó là nó với bản thiết kế API của chúng tôi.

Được chứ. Hãy đi sâu vào thư mục "client" mà chúng ta đã tạo trước đó. Điều này sẽ liên quan nhiều hơn một chút so với bản thiết kế API của chúng tôi, nhưng không phức tạp hơn một ứng dụng Flask thông thường.

Một lần nữa, giống như một ứng dụng Flask thông thường, bên trong thư mục này, tạo một thư mục "tĩnh" và một thư mục "mẫu". Tạo một tệp có tên client.py và mở nó trong trình soạn thảo văn bản của bạn.

Lần này, chúng tôi sẽ chuyển thêm một số đối số vào Blueprintđể nó biết nơi tìm các tệp và mẫu tĩnh chính xác:

client_bp = Blueprint('client_bp', __name__, # 'Client Blueprint'
    template_folder='templates', # Required for our purposes
    static_folder='static', # Again, this is required
    static_url_path='/client/static' # Flask will be confused if you don't do this
)

Thêm cả tuyến đường để cung cấp mẫu index.html :

from flask import Blueprint, render_template

client_bp = Blueprint("client_bp", __name__, # 'Client Blueprint'
    template_folder="templates", # Required for our purposes
    static_folder="static", # Again, this is required
    static_url_path="/client/static" # Flask will be confused if you don't do this
)

@client_bp.route("/")
def index():
    return render_template("index.html")

Xuất sắc. Bản thiết kế khách hàng của chúng tôi hiện đã hoàn thành. Thoát khỏi tệp và chuyển đến thư mục "mẫu" của bản thiết kế. Tạo tệp index.html :

<body>
<!-- The id 'vm' is just for consistency - it can be anything you want -->
    <div id="vm" class="container">
        <p>[[ greeting ]]</p>
        <p>[[ flaskGreeting ]]</p>
    </div>
    <script src="https://cdn.jsdelivr.net/npm/vue@2.6.11"></script>
    <script src="{{ url_for('client_bp.static', filename='index.js') }}"></script>
</body>

Bạn có nhận thấy rằng chúng ta đang sử dụng dấu ngoặc nhọn thay vì dấu ngoặc nhọn không? Đó là bởi vì chúng ta cần thay đổi các dấu phân cách để giữ cho Flask không bắt được chúng trước.

greetingsẽ được Vue hiển thị ngay sau khi nó sẵn sàng, trong khi flaskGreetingsẽ được lấy từ một phản hồi Flask mà chúng tôi sẽ yêu cầu không đồng bộ.

Xong. Thêm một tệp mới vào thư mục "tĩnh" được gọi là index.js . Tạo một biến được gọi apiEndpointvà đặt nó thành api_v1. Điều này chỉ làm cho mọi thứ KHÔ hơn một chút nếu chúng tôi quyết định thay đổi điểm cuối của mình sau này:

const apiEndpoint = '/api_v1/';

Chúng tôi chưa tạo ra logic cho điểm cuối của chúng tôi. Điều đó sẽ đến trong bước cuối cùng.

Tiếp theo, hãy bắt đầu bằng cách làm cho ngữ cảnh Vue trông giống với ngữ cảnh trong phương pháp Mẫu Jinja :

const apiEndpoint = '/api_v1/';

const vm = new Vue({ // Again, vm is our Vue instance's name for consistency.
    el: '#vm',
    delimiters: ['[[', ']]'],
    data: {
        greeting: 'Hello, Vue!'
    }
})

Một lần nữa, chúng tôi đã tạo ngữ cảnh Vue, đặt phiên bản của chúng tôi el'#vm', thay đổi các dấu phân cách mặc định từ '{{', '}}'thành '[[', ']]'và thêm một phần tử dữ liệu với khóa / giá trị là greeting:.'Hello, Vue!'

Bởi vì chúng tôi cũng sẽ lấy một lời chào từ API của mình, hãy tạo một trình giữ chỗ dữ liệu được gọi flaskGreetingvới giá trị của một chuỗi trống:

const apiEndpoint = '/api_v1/';

const vm = new Vue({
    el: '#vm',
    delimiters: ['[[', ']]'],
    data: {
        greeting: 'Hello, Vue!',
        flaskGreeting: ''
    }
})

Hãy cung cấp cho đối tượng Vue của chúng ta một createdhook vòng đời không đồng bộ:

const apiEndpoint = '/api_v1/';

const vm = new Vue({
    el: '#vm',
    delimiters: ['[[', ']]'],
    data: {
        greeting: 'Hello, Vue!',
        flaskGreeting: ''
    },
    created: async function(){
        const gResponse = await fetch(apiEndpoint + 'greeting');
        const gObject = await gResponse.json();
        this.flaskGreeting = gObject.greeting;
    }
})

Xem xét mã, chúng tôi đang nhập awaitmột phản hồi từ điểm cuối 'lời chào' của API ( /api_v1/greeting), nhập awaitphản hồi không đồng bộ của .json()phản hồi đó và đặt biến đối tượng Vue của chúng tôi thành flaskGreetinggiá trị của đối tượng JSON được trả về cho greetingkhóa của nó. Về cơ bản, nó là sự kết hợp giữa các đối tượng Vue từ phương pháp 1 và 2.

Xuất sắc. Chỉ còn một việc cần làm: Hãy tập hợp mọi thứ lại với nhau bằng cách thêm một app.py vào thư mục gốc của dự án. Trong tệp, nhập flaskcùng với các bản thiết kế:

from flask import Flask
from api.api import api_bp
from client.client import client_bp

Tạo một ứng dụng Flask như bình thường và đăng ký các bản thiết kế bằng cách sử dụng app.register_blueprint():

from flask import Flask
from api.api import api_bp
from client.client import client_bp

app = Flask(__name__)
app.register_blueprint(api_bp, url_prefix='/api_v1')
app.register_blueprint(client_bp)

Cây tệp cuối cùng:

├───app.py
├───api
│   └───__init__.py
│   └───api.py
└───client
    ├───__init__.py
    ├───static
    │   └───index.js
    └───templates
        └───index.html

Và đó là nó! Nếu bạn chạy ứng dụng mới với flask runbạn, bạn sẽ được chào đón hai lần - một lần bởi chính Vue và một lần nữa bởi phản hồi từ API Flask của bạn.

Bản tóm tắt

Có rất nhiều cách khác nhau để xây dựng một ứng dụng web bằng Vue và Flask. Tất cả phụ thuộc vào tình hình của bạn trong tầm tay.

Một số câu hỏi cần hỏi:

  1. SEO quan trọng như thế nào?
  2. Nhóm phát triển của bạn trông như thế nào? Nếu bạn không có nhóm DevOps, bạn có muốn chịu thêm sự phức tạp khi phải triển khai front-end và back-end riêng biệt không?
  3. Bạn chỉ là tạo mẫu nhanh?

Hy vọng rằng bài viết này hướng bạn đi đúng hướng, giúp bạn có ý tưởng về cách kết hợp các ứng dụng Vue và Flask của mình.

Bạn có thể lấy mã cuối cùng từ kho lưu trữ kết hợp-Flask-với-vue trên GitHub.

Nguồn:  https://testdriven.io

#vue #flask 

Làm Cách Nào Để Kết Hợp Vue.js Với Flask?

Как я могу объединить Vue.js с Flask?

Объединение Flask и Vue

Итак, у вас наконец-то есть Flask, и вы не новичок в JavaScript. Вы даже разработали несколько веб-приложений, но начинаете кое-что понимать — у вас отличная функциональность, но ваш UX какой-то пресный. Где поток приложений и плавная навигация, которые вы видите сегодня на многих популярных веб-сайтах и ​​в приложениях? Как этого можно достичь?

По мере того, как вы будете больше инвестировать в свои веб-сайты и веб-приложения, вы, вероятно, захотите добавить к ним больше клиентских функций и реактивности. Современная веб-разработка обычно достигает этого за счет использования интерфейсных фреймворков, и одним из таких фреймворков, который быстро набирает популярность, является Vue (также известный как Vue.js или VueJS).

В зависимости от требований вашего проекта существует несколько различных способов создания веб-приложения с помощью Flask и Vue, и каждый из них включает различные уровни разделения серверной и внешней части.

В этой статье мы рассмотрим три разных метода объединения Flask и Vue:

  1. Шаблон Jinja : Импорт Vue в шаблон Jinja
  2. Одностраничное приложение : создание одностраничного приложения (SPA) для полного разделения Flask и Vue.
  3. Flask Blueprint : предоставление Vue из схемы Flask для частичного разделения двух

Различные способы создания веб-приложения с помощью Flask и Vue

Мы проанализируем плюсы и минусы каждого метода, рассмотрим их лучшие варианты использования и подробно расскажем, как настроить каждый из них.

Джиндзя Шаблон

Независимо от того, используете ли вы React, Vue или Angular, это самый простой способ перейти к использованию интерфейсного фреймворка.

Во многих случаях, когда вы создаете внешний интерфейс для своего веб-приложения, вы проектируете его на основе самого внешнего интерфейса. Однако при использовании этого метода основное внимание по-прежнему уделяется вашему серверному приложению Flask. Вы по-прежнему будете использовать Jinja и шаблоны на стороне сервера, а также немного реактивной функциональности с Vue, если и когда вам это нужно.

Вы можете импортировать библиотеку Vue либо через сеть доставки контента (CDN), либо обслуживать ее самостоятельно вместе с вашим приложением, настраивая и маршрутизируя Flask, как обычно.

Плюсы

  • Вы можете создать свое приложение по-своему, вместо того, чтобы подгонять его под основу Vue.
  • Поисковая оптимизация (SEO) не требует дополнительной настройки.
  • Вы можете воспользоваться аутентификацией на основе файлов cookie вместо аутентификации на основе токенов. Это, как правило, проще, поскольку вы не имеете дело с асинхронной связью между интерфейсом и сервером.

Минусы

  • Вы должны импортировать Vue и настраивать каждую страницу отдельно, что может быть сложно, если вы начнете добавлять Vue на все больше и больше страниц. Это также может потребовать ряда обходных путей, поскольку на самом деле это не предполагаемый способ использования ни Flask, ни Vue.

Лучшее для

  • Небольшие веб-приложения буквально используют одну или две HTML-страницы (в отличие от SPA с собственной динамической маршрутизацией — см. метод SPA для получения дополнительной информации).
  • Встраивание функциональности в уже существующее веб-приложение.
  • Добавление немного реактивности в приложение без полной приверженности интерфейсной среде.
  • Веб-приложения, которым не нужно так часто связываться с серверной частью через AJAX.

Дополнительные зависимости

Для этого метода просто требуется библиотека Vue, которую вы можете добавить через CDN:

<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>

Настраивать

Из всех способов этот способ самый простой.

Создайте папку для хранения всего кода вашего приложения. Внутри этой папки создайте файл app.py , как обычно:

from flask import Flask, render_template # These are all we need for our purposes

app = Flask(__name__)

@app.route("/")
def index():
    return render_template("index.html", **{"greeting": "Hello from Flask!"})

Нам нужно только импортировать Flaskи render_templateиз flask.

Переменная greetingснова появится через секунду, когда мы посмотрим, как визуализировать переменные с помощью Jinja и Vue в одном файле.

Затем создайте папку «templates» для хранения нашего HTML-файла. Внутри этой папки создайте файл index.html . В теле нашего HTML-файла создайте div-контейнер с идентификатором vm.

Стоит отметить, что vmэто всего лишь общепринятый стандарт именования. Это означает ViewModel . Вы можете назвать его как хотите; это не должно быть vm.

Внутри divсоздайте два pтега, которые будут служить заполнителями для наших переменных Flask и Vue:

  1. Один из divs должен содержать слово «приветствие», заключенное в фигурные скобки: {{ greeting }}.
  2. Другой должен содержать «приветствие», заключенное в скобки: [[ greeting ]].

Если вы не используете отдельные разделители, при настройке по умолчанию Flask заменит оба приветствия любой переменной, которую вы передадите (например, «Привет из Flask!»).

Вот что мы имеем на данный момент:

<body>
<!-- The id 'vm' is just for consistency - it can be anything you want -->
    <div id="vm">
        <p>{{ greeting }}</p>
        <p>[[ greeting ]]</p>
    </div>
</body>

Перед концом тега body импортируйте Vue из официального CDN вместе со скриптом для хранения нашего кода JavaScript:

<body>
<!-- The id 'vm' is just for consistency - it can be anything you want -->
    <div id="vm">
        <p>{{ greeting }}</p>
        <p>[[ greeting ]]</p>
    </div>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <script src="{{ url_for('static', filename='index.js') }}"></script>
</body>

Перейдя вверх по каталогу, создайте «статическую» папку. Добавьте в эту папку новый файл JavaScript с именем index.js .

В этом файле создайте контекст Vue, установите наш экземпляр elкак '#vm', измените разделители по умолчанию с '{{', '}}'на '[[', ']]':

const vm = new Vue({ // Again, vm is our Vue instance's name for consistency.
    el: '#vm',
    delimiters: ['[[', ']]']
})

На самом деле мы можем использовать в качестве разделителей все, что захотим. На самом деле, если вы предпочитаете, вы можете вместо этого изменить разделители для своих шаблонов Jinja во Flask.

Наконец, добавьте элемент данных с ключом/значением greeting: 'Hello, Vue!':

const vm = new Vue({ // Again, vm is our Vue instance's name for consistency.
    el: '#vm',
    delimiters: ['[[', ']]'],
    data: {
        greeting: 'Hello, Vue!'
    }
})

И теперь мы закончили с этим файлом. Ваша окончательная структура папок должна выглядеть примерно так:

├───app.py
├───static
│   └───index.js
└───templates
    └───index.html

Теперь вы можете вернуться в корневую папку проекта и запустить приложение с расширением flask run. Перейдите на сайт в браузере. Первую и вторую строку нужно было заменить на Flask и Vue соответственно:

Hello from Flask!
Hello, Vue!

Вот и все! Вы можете смешивать и сопоставлять конечные точки JSON и конечные точки HTML по своему усмотрению, но имейте в виду, что это может очень быстро стать очень уродливым. Для более удобной альтернативы см. метод Flask Blueprint .

С каждой дополнительной HTML-страницей вам придется либо импортировать один и тот же файл JavaScript и учитывать переменные и элементы, которые могут не применяться к нему, либо создавать новый объект Vue для каждой страницы. Настоящий SPA будет сложным, но не невозможным — теоретически вы можете написать крошечную библиотеку JavaScript, которая будет асинхронно захватывать HTML-страницы/элементы, обслуживаемые Flask.

На самом деле я создал свою собственную библиотеку JavaScript для этого раньше. Это было большой проблемой и, честно говоря, оно того не стоило, особенно если учесть, что JavaScript не будет запускать теги сценариев, импортированные таким образом, если только вы не создадите функциональность самостоятельно. Вы также будете заново изобретать колесо.

Если вы хотите проверить мою реализацию этого метода, вы можете найти ее на GitHub . Библиотека берет заданный фрагмент HTML и заменяет им указанный HTML на странице. Если данный HTML не содержит <script>элементов (он проверяется с помощью регулярных выражений), он просто используется HTMLElement.innerHTMLдля его замены. Если он содержит <script>элементы, он рекурсивно добавляет узлы, воссоздавая любые <script>появляющиеся узлы, позволяя запускать ваш JavaScript.

Использование чего-то подобного в сочетании с History API может помочь вам создать небольшой SPA с очень маленьким размером файла. Вы даже можете создать свою собственную функцию рендеринга на стороне сервера (SSR), обслуживая полные HTML-страницы при загрузке страницы, а затем обслуживая частичные страницы с помощью запросов AJAX. Вы можете узнать больше о SSR в SPA с методом Nuxt .

Одностраничное приложение

Если вы хотите создать полностью динамическое веб-приложение с удобным пользовательским интерфейсом (UX), вы можете полностью отделить серверную часть Flask от внешней части Vue. Это может потребовать изучения совершенно нового способа мышления, когда дело доходит до дизайна веб-приложений, если вы не знакомы с современными интерфейсными фреймворками.

Разработка вашего приложения как SPA может нанести ущерб вашему SEO. В прошлом этот удар был бы гораздо более драматичным, но обновления того, как Googlebot индексирует сайты, по крайней мере, несколько свели на нет это. Однако это может иметь большее влияние на поисковые системы, отличные от Google, которые не отображают JavaScript или слишком рано делают снимки ваших страниц — последнего не должно происходить, если ваш веб-сайт хорошо оптимизирован.

Для получения дополнительной информации о SEO в современных SPA, эта статья на Medium показывает, как робот Googlebot индексирует сайты с JavaScript. Кроме того, в этой статье подробно рассказывается об этом, а также приводятся другие полезные советы, касающиеся SEO в других поисковых системах.

С помощью этого метода вы захотите создать совершенно отдельное приложение Vue с помощью инструмента Vue CLI . Затем Flask будет использоваться для обслуживания JSON RESTful API, с которым ваш Vue SPA будет взаимодействовать через AJAX.

Плюсы

  • Ваш интерфейс и сервер будут полностью независимы друг от друга, поэтому вы можете вносить изменения в один, не влияя на другой.
    • Это позволяет развертывать, разрабатывать и поддерживать их отдельно.
    • Вы даже можете настроить ряд других интерфейсов для взаимодействия с вашим Flask API, если хотите.
  • Ваш внешний интерфейс будет намного более плавным и плавным.

Минусы

  • Еще многое предстоит настроить и изучить.
  • Развертывание затруднено.
  • SEO может пострадать без дальнейшего вмешательства (см. SPA с методом Nuxt для более подробной информации).
  • Authentication is much more involved, as you'll have to keep passing your auth token (JWT or Paseto) to your back-end.

Best For

  • Apps where UX is more important than SEO.
  • Back-ends that need to be accessible by multiple front-ends.

Additional Dependencies

  • Node/npm
  • Vue CLI
  • Flask-CORS

Deployment and containerization are outside of the scope of this article, but it's not terribly difficult to Dockerize this setup to simplify deployment.

Setup

Because we're completely separating Vue from Flask, this method requires a bit more setup. We'll need to enable Cross-Origin Resource Sharing (CORS) in Flask, since our front- and back-end will be served on separate ports. To accomplish this quickly and easily, we'll use the Flask-CORS Python package.

Из соображений безопасности современные веб-браузеры не разрешают клиентскому JavaScript получать доступ к ресурсам (таким как данные JSON) из источника, отличного от источника, в котором находится ваш скрипт, если только они не включают определенный заголовок ответа, сообщающий браузеру, что все в порядке.

Если вы еще не установили Flask-CORS, сделайте это с помощью pip.

Начнем с нашего Flask API.

Сначала создайте папку для хранения кода вашего проекта. Внутри создайте папку с именем «api». Создайте файл app.py в папке. Откройте файл в вашем любимом текстовом редакторе. На этот раз нам нужно импортировать Flaskиз flaskи CORSиз flask_cors. Поскольку мы используем flask_corsдля включения совместного использования ресурсов между источниками, оберните объект приложения (без установки новой переменной) с помощью CORS: CORS(app). Это все, что нам нужно сделать, чтобы включить CORS на всех наших маршрутах для любого источника.

Хотя это подходит для демонстрационных целей, вы, вероятно, не захотите, чтобы любое приложение или веб-сайт могли получить доступ к вашему API. В этом случае вы можете использовать «исходные данные» kwarg с функцией CORS, чтобы добавить список допустимых источников, т. е.CORS(app, origins=["origin1", "origin2"])

Для получения дополнительной информации о совместном использовании ресурсов между источниками в MDN есть отличная документация по этому вопросу.

Наконец, создайте один маршрут приветствия, /greetingчтобы вернуть объект JSON с одним ключом/значением:

{"greeting": "Hello from Flask!"}

Вот что у вас должно было получиться:

from flask import Flask
from flask_cors import CORS

app = Flask(__name__)
CORS(app)

@app.route("/greeting")
def greeting():
    return {"greeting": "Hello from Flask!"}

Это все, что нам нужно сделать с Python.

Далее мы настроим наше веб-приложение Vue. В терминале откройте корневую папку вашего проекта. Используя Vue CLI, создайте проект Vue под названием «webapp» ( vue create webapp). Вы можете использовать практически любые параметры, которые вам нравятся, но если вы используете компоненты на основе классов в TypeScript, синтаксис будет выглядеть немного иначе.

Когда ваш проект будет создан, откройте App.vue .

Since our goal is just to see how Vue and Flask interact with each other, at the top of the page, delete all elements within the div with the id of app. You should just be left with:

<template>
<div id="app">
</div>
</template>

Within #app, create two p elements:

  1. The content of the first should be {{ greeting }}.
  2. The content of the second should be {{ flaskGreeting }}.

Your final HTML should be as such:

<template>
<div id="app">
    <p>{{ greeting }}</p>
    <p>{{ flaskGreeting }}</p>
</div>
</template>

In our script, let's add logic to show a purely client-side greeting (greeting) and a greeting pulled from our API (flaskGreeting).

Within the Vue object (it begins with export default), create a data key. Make it a function that returns an object. Then, within this object, create two more keys: greeting and flaskGreeting. greeting's value should be 'Hello, Vue!' while flaskGreeting's should be an empty string.

Here's what we have thus far:

export default {
    name: 'App',
    components: {
        HelloWorld
    },
    data: function(){
        return {
            greeting: 'Hello, Vue!',
            flaskGreeting: ''
        }
    }
}

Finally, let's give our Vue object a created lifecycle hook. This hook will only be run once the DOM is loaded and our Vue object is created. This allows us to use the fetch API and interact with Vue without anything clashing:

export default {
    components: {
        Logo
    },
    data: function(){
        return {
            greeting: 'Hello, Vue!',
            flaskGreeting: ''
        }
    },
    created: async function(){
        const gResponse = await fetch("http://localhost:5000/greeting");
        const gObject = await gResponse.json();
        this.flaskGreeting = gObject.greeting;
    }
}

Глядя на код, мы получаем awaitответ на конечную точку «приветствия» нашего API ( http://localhost:5000/greeting), awaitпередаем асинхронный .json()ответ этого ответа и устанавливаем для flaskGreetingпеременной нашего объекта Vue значение возвращенного объекта JSON для его greetingключа.

Для тех, кто не знаком с относительно новым API-интерфейсом Fetch в JavaScript , это, по сути, нативный убийца AXIOS (по крайней мере, что касается клиентской стороны — он не поддерживается Node, но будет поддерживаться Deno ). Кроме того, если вам нравится согласованность, вы также можете проверить пакет isomorphic-fetch , чтобы использовать Fetch на стороне сервера.

И мы закончили. Теперь, поскольку, опять же, наш внешний и внутренний интерфейсы разделены, нам нужно будет запускать оба наших приложения по отдельности.

Давайте откроем корневую папку нашего проекта в двух отдельных окнах терминала.

В первом перейдите в каталог «api», а затем запустите flask run. Если все пойдет хорошо, Flask API должен работать. Во втором терминале перейдите в каталог «webapp» и запустите npm run serve.

Как только приложение Vue будет запущено, вы сможете получить к нему доступ из localhost:8080. Если все работает, вас должны приветствовать дважды — один раз от Vue и еще раз от вашего Flask API:

Hello, Vue!
Hello from Flask!

Ваше окончательное дерево файлов должно выглядеть так:

├───app.py
├───api
│   └───app.py
└───webapp
    ... {{ Vue project }}

Одностраничное приложение с Nuxt

Если SEO так же важно для вас, как и UX, вы можете реализовать рендеринг на стороне сервера (SSR) в каком-то формате.

SSR упрощает для поисковых систем навигацию и индексирование вашего приложения Vue, поскольку вы сможете предоставить им форму вашего приложения, для создания которой не требуется JavaScript. Это также может ускорить взаимодействие пользователей с вашим приложением, поскольку большая часть исходного содержимого будет отображаться до того, как оно будет отправлено им. Другими словами, пользователям не придется ждать, пока весь ваш контент загрузится асинхронно.

Одностраничное приложение с рендерингом на стороне сервера также называется универсальным приложением.

Хотя можно реализовать SSR вручную, в этой статье мы будем использовать Nuxt ; это сильно упрощает дело.

Как и в случае с методом SPA , ваш интерфейс и сервер будут полностью разделены; вы просто будете использовать Nuxt вместо Vue CLI.

Плюсы

  • Все плюсы метода SPA с добавлением рендеринга на стороне сервера.

Минусы

  • Примерно так же сложно настроить, как метод SPA .
  • Концептуально есть еще чему поучиться, поскольку Nuxt — это, по сути, просто еще один слой поверх Vue.

Лучшее для

  • Приложения, в которых SEO так же важно, как и UX.

Дополнительные зависимости

  1. Узел/npm
  2. Nuxt
  3. Колба-CORS

Настраивать

Это будет очень похоже на метод СПА . Фактически, часть Flask точно такая же. Следуйте за ним, пока не создадите свой Flask API.

Как только ваш API будет готов, в вашем терминале откройте корневую папку вашего проекта и выполните команду npx create-nuxt-app webapp. Это позволит вам интерактивно создать новый проект Nuxt без установки каких-либо глобальных зависимостей.

Здесь подойдут любые варианты.

Once your project is done being generated, dive into your new "webapp" folder. Within the "pages" folder, open index.vue in your text editor. Similarly, delete everything within the div that has the class container. Inside the div, create two p tags with the same vars: {{ greeting }} and {{ flaskGreeting }}.

It should look like this:

<template>
<div class="container">
    <p>{{ greeting }}</p>
    <p>{{ flaskGreeting }}</p>
</div>
</template>

And now for our script:

  • Add a data key that returns an object with the variables greeting and flaskGreeting
  • Add a created lifecycle hook:
    • await fetch to get the JSON greeting from our API (on port 5000 unless you changed it)
    • await the json() method to asynchronously get our JSON data from our API's response
    • Set our Vue instance's flaskGreeting to the greeting key from our response's JSON object

Объект Vue должен выглядеть так:

export default {
    components: {
        Logo
    },
    data: function(){
        return {
            greeting: 'Hello, Vue!',
            flaskGreeting: ''
        }
    },
    created: async function(){
        const gResponse = await fetch("http://localhost:5000/greeting");
        const gObject = await gResponse.json();
        this.flaskGreeting = gObject.greeting;
    }
}

Запуск приложения Nuxt/Vue и Flask API также будет очень похож на метод SPA .

Откройте два окна терминала. В первом измените на «api» и выполните flask runкоманду. Во втором измените на «webapp» и запустите npm run dev, чтобы запустить сервер разработки для вашего проекта Nuxt.

Как только приложение Nuxt будет запущено, вы сможете получить к нему доступ из localhost:3000:

Hello, Vue!
Hello from Flask!

В производстве вы можете запустить, npm run buildа затем npm run startзапустить рабочий сервер.

Наше финальное дерево:

├───app.py
├───api
│   └───app.py
└───webapp
    ... {{ Nuxt project }}

БОНУС: Сравнение Vue и Nuxt SEO

Я упоминал о преимуществах SEO ранее в этой статье, но просто чтобы показать вам, что я имел в виду, я запустил оба веб-приложения как есть и получил оценки Lighthouse SEO для обоих.

Без изменений ни в одном из приложений, вот что мы имеем:

SEO-оценки Lighthouse для нашего приложения Vue и Nuxt

Опять же, есть вещи, которые вы можете сделать, чтобы улучшить свой чистый рейтинг Vue SEO. В Lighthouse в инструментах разработчика Chrome упоминается добавление метаописания, но без дополнительного вмешательства Nuxt дал нам отличную оценку SEO.

Кроме того, вы действительно можете увидеть разницу между SSR, который делает Nuxt, и полностью асинхронным подходом vanilla Vue. Если вы запустите оба приложения одновременно, перейдете к их соответствующим источникам localhost:8080и localhost:3000, начальное приветствие приложения Vue произойдет через миллисекунды после того, как вы получите ответ, тогда как приложение Nuxt обслуживается с уже отрендеренным начальным приветствием.

Для получения дополнительной информации о различиях между Nuxt и Vue вы можете ознакомиться с этими статьями:

  1. Nuxt.js вместо Vue.js: когда его следует использовать и почему
  2. Как Nuxt.js решает проблемы SEO в Vue.js.

Чертеж фляги

Возможно, у вас уже есть небольшое разработанное приложение Flask, и вы хотите создать приложение Vue скорее как средство для достижения цели, чем как основное событие.

Примеры:

  1. Создайте прототип, чтобы продемонстрировать функциональность вашему работодателю или клиенту (вы всегда можете заменить его или передать разработчику внешнего интерфейса позже).
  2. Вы просто не хотите иметь дело с потенциальными разочарованиями, которые могут возникнуть при развертывании полностью отдельных интерфейсов и серверов.

В этом случае вы могли бы найти компромисс, сохранив свое приложение Flask, но построив интерфейс Vue в рамках собственного проекта Flask.

Это будет очень похоже на метод шаблона Jinja , но код будет более организованным.

Плюсы

  • Нет необходимости создавать сложный интерфейс, если в этом нет необходимости.
  • Аналогичен методу шаблона Jinja с дополнительным преимуществом лучшей организации кода.
  • Вы всегда можете расширить интерфейс и серверную часть по мере необходимости позже.

Минусы

  • Чтобы разрешить полный SPA, могут потребоваться обходные пути.
  • Доступ к API может быть немного более раздражающим из отдельного внешнего интерфейса (например, мобильного приложения), поскольку внешний и внутренний интерфейс не полностью разделены.

Лучшее для

  • Проекты, в которых функциональность важнее пользовательского интерфейса.
  • Вы создаете интерфейс для уже существующего приложения Flask.
  • Небольшие веб-приложения, состоящие всего из нескольких HTML-страниц.

Дополнительные зависимости

Как и в методе шаблона Jinja , мы будем использовать CDN для извлечения библиотеки Vue:

<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>

Настраивать

Как и в других методах, создайте новую папку для размещения кода. Внутри него создайте две папки: «api» и «client». Интуитивно понятно, что они будут содержать чертежи для нашего API и клиента (Vue) соответственно.

Давайте погрузимся в папку «api».

Создайте файл с именем api.py. Он будет содержать весь код, связанный с нашим API. Кроме того, поскольку мы будем обращаться к этому файлу/папке как к модулю, создайте файл __init__.py :

from flask import Blueprint

api_bp = Blueprint('api_bp', __name__) # "API Blueprint"

@api_bp.route("/greeting") # Blueprints don't use the Flask "app" context. They use their own blueprint's
def greeting():
    return {'greeting': 'Hello from Flask!'}

Первый аргумент Blueprintдля системы маршрутизации Flask. Второй, __name__, эквивалентен первому аргументу приложения Flask ( Flask(__name__)).

И это все с нашим планом API.

Хорошо. Давайте погрузимся в папку «клиент», которую мы создали ранее. Это будет немного сложнее, чем наш план API, но не сложнее, чем обычное приложение Flask.

Опять же, как и в обычном приложении Flask, внутри этой папки создайте «статическую» папку и папку «templates». Создайте файл с именем client.py и откройте его в текстовом редакторе.

На этот раз мы передадим в наш еще несколько аргументов, Blueprintчтобы он знал, где найти правильные статические файлы и шаблоны:

client_bp = Blueprint('client_bp', __name__, # 'Client Blueprint'
    template_folder='templates', # Required for our purposes
    static_folder='static', # Again, this is required
    static_url_path='/client/static' # Flask will be confused if you don't do this
)

Добавьте также маршрут для обслуживания шаблона index.html :

from flask import Blueprint, render_template

client_bp = Blueprint("client_bp", __name__, # 'Client Blueprint'
    template_folder="templates", # Required for our purposes
    static_folder="static", # Again, this is required
    static_url_path="/client/static" # Flask will be confused if you don't do this
)

@client_bp.route("/")
def index():
    return render_template("index.html")

Превосходно. Наш план клиента готов. Выйдите из файла и перейдите в папку «templates» чертежа. Создайте файл index.html :

<body>
<!-- The id 'vm' is just for consistency - it can be anything you want -->
    <div id="vm" class="container">
        <p>[[ greeting ]]</p>
        <p>[[ flaskGreeting ]]</p>
    </div>
    <script src="https://cdn.jsdelivr.net/npm/vue@2.6.11"></script>
    <script src="{{ url_for('client_bp.static', filename='index.js') }}"></script>
</body>

Вы заметили, что мы используем скобки вместо скобок? Это потому, что нам нужно изменить разделители, чтобы Flask не смог их поймать первым.

greetingбудет отображаться Vue, как только он будет готов, а flaskGreetingбудет взят из ответа Flask, который мы запросим асинхронно.

Сделанный. Добавьте новый файл в «статическую» папку с именем index.js . Создайте переменную с именем apiEndpointи установите для нее значение api_v1. Это просто делает все немного более СУХИМ, если мы решим изменить нашу конечную точку позже:

const apiEndpoint = '/api_v1/';

Мы еще не создали логику для нашей конечной точки. Это придет на последнем шаге.

Затем начните с того, что контекст Vue будет выглядеть идентично контексту в методе шаблона Jinja :

const apiEndpoint = '/api_v1/';

const vm = new Vue({ // Again, vm is our Vue instance's name for consistency.
    el: '#vm',
    delimiters: ['[[', ']]'],
    data: {
        greeting: 'Hello, Vue!'
    }
})

Опять же, мы создали контекст Vue, установили наш экземпляр elкак '#vm', изменили разделители по умолчанию с '{{', '}}'на '[[', ']]'и добавили элемент данных с ключом/значением greeting: 'Hello, Vue!'.

Поскольку мы также собираемся извлекать приветствие из нашего API, создайте заполнитель данных, вызываемый flaskGreetingсо значением пустой строки:

const apiEndpoint = '/api_v1/';

const vm = new Vue({
    el: '#vm',
    delimiters: ['[[', ']]'],
    data: {
        greeting: 'Hello, Vue!',
        flaskGreeting: ''
    }
})

Давайте добавим нашему объекту Vue createdхук асинхронного жизненного цикла:

const apiEndpoint = '/api_v1/';

const vm = new Vue({
    el: '#vm',
    delimiters: ['[[', ']]'],
    data: {
        greeting: 'Hello, Vue!',
        flaskGreeting: ''
    },
    created: async function(){
        const gResponse = await fetch(apiEndpoint + 'greeting');
        const gObject = await gResponse.json();
        this.flaskGreeting = gObject.greeting;
    }
})

Глядя на код, мы получаем awaitответ от конечной точки «приветствия» нашего API ( /api_v1/greeting), получаем awaitасинхронный .json()ответ этого ответа и устанавливаем для flaskGreetingпеременной нашего объекта Vue значение возвращаемого объекта JSON для его greetingключа. По сути, это мэшап между объектами Vue из методов 1 и 2.

Превосходно. Осталось сделать только одно: давайте соберем все вместе, добавив app.py в корень проекта. В файл импортируйте flaskвместе с чертежами:

from flask import Flask
from api.api import api_bp
from client.client import client_bp

Создайте приложение Flask, как обычно, и зарегистрируйте чертежи, используя app.register_blueprint():

from flask import Flask
from api.api import api_bp
from client.client import client_bp

app = Flask(__name__)
app.register_blueprint(api_bp, url_prefix='/api_v1')
app.register_blueprint(client_bp)

Окончательное дерево файлов:

├───app.py
├───api
│   └───__init__.py
│   └───api.py
└───client
    ├───__init__.py
    ├───static
    │   └───index.js
    └───templates
        └───index.html

Вот и все! Если вы запустите свое новое приложение flask run, вас должны приветствовать дважды — один раз от самого Vue и еще раз от вашего API Flask.

Резюме

Существует множество различных способов создания веб-приложения с использованием Vue и Flask. Все зависит от вашей конкретной ситуации.

Некоторые вопросы, чтобы задать:

  1. Насколько важно SEO?
  2. Как выглядит ваша команда разработчиков? Если у вас нет команды DevOps, хотите ли вы взять на себя дополнительную сложность, связанную с необходимостью раздельного развертывания клиентской и серверной частей?
  3. Вы просто быстро прототипируете?

Надеюсь, эта статья направит вас в правильном направлении и даст вам представление о том, как объединить ваши приложения Vue и Flask.

Вы можете получить окончательный код из репозитория Combined-flask-with-vue на GitHub.

Источник:  https://testdriven.io

#vue #flask 

Как я могу объединить Vue.js с Flask?
笹田  洋介

笹田 洋介

1660416600

如何將 Vue.js 與 Flask 結合使用?

結合 Flask 和 Vue

所以你終於掌握了 Flask,而且你對 JavaScript 並不陌生。您甚至開發了一些 Web 應用程序,但您開始意識到一些事情——您擁有出色的功能,但您的 UX 有點乏味。您在當今許多流行的網站和應用程序上看到的應用程序流程和無縫導航在哪裡?怎樣才能做到這一點?

隨著您對網站和 Web 應用程序的投入越來越多,您可能希望為它們添加更多的客戶端功能和反應性。現代 Web 開發通常通過使用前端框架來實現這一點,其中一個迅速流行的框架是Vue(也稱為 Vue.js 或 VueJS)。

根據您項目的要求,有幾種不同的方法可以使用 Flask 和 Vue 構建 Web 應用程序,並且每種方法都涉及不同級別的後端/前端分離。

在本文中,我們將了解 Flask 和 Vue 結合的三種不同方法:

  1. Jinja 模板:將 Vue 導入 Jinja 模板
  2. 單頁應用程序:構建單頁應用程序(SPA)以完全分離 Flask 和 Vue
  3. Flask 藍圖:從 Flask 藍圖中提供 Vue 以將兩者部分分離

使用 Flask 和 Vue 構建 Web 應用程序的不同方法

我們將分析每種方法的優缺點,查看它們的最佳用例,並詳細說明如何設置它們。

神社模板

無論您使用的是 React、Vue 還是 Angular,這是過渡到使用前端框架的最簡單方法。

在許多情況下,當您為 Web 應用程序構建前端時,您會圍繞前端框架本身進行設計。但是,使用這種方法,重點仍然是您的後端 Flask 應用程序。如果需要,您仍將使用 Jinja 和服務器端模板以及 Vue 的一些反應性功能。

您可以通過內容交付網絡(CDN) 導入 Vue 庫,也可以將其與您的應用程序一起提供,同時像往常一樣設置和路由 Flask。

優點

  • 您可以按照自己的方式構建應用程序,而不是在 Vue 的基礎上安裝它。
  • 搜索引擎優化 (SEO) 不需要任何額外的配置。
  • 您可以利用基於 cookie 的身份驗證而不是基於令牌的身份驗證。這往往更容易,因為您不需要處理前端和後端之間的異步通信。

缺點

  • 您必須導入 Vue 並單獨設置每個頁面,如果您開始將 Vue 添加到越來越多的頁面,這可能會很困難。它可能還需要一些變通方法,因為它並不是使用 Flask 或 Vue 的真正預期方式。

最適合

  • 小型 Web 應用程序實際上使用一個或兩個 HTML 頁面(與具有自己的動態路由的 SPA 不同——有關更多信息,請參閱SPA方法)。
  • 將功能構建到現有的 Web 應用程序中。
  • 在不完全致力於前端框架的情況下向應用程序添加一些反應性。
  • 不需要通過 AJAX 頻繁與後端通信的 Web 應用程序。

附加依賴項

此方法只需要 Vue 庫,您可以通過 CDN 添加:

<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>

設置

在所有方法中,此設置是最簡單的。

創建一個文件夾來保存您的所有應用程序代碼。在該文件夾中,像往常一樣創建一個app.py文件:

from flask import Flask, render_template # These are all we need for our purposes

app = Flask(__name__)

@app.route("/")
def index():
    return render_template("index.html", **{"greeting": "Hello from Flask!"})

我們只需要 importFlaskrender_templatefrom flask

greeting當我們查看如何在同一個文件中使用 Jinja 和 Vue 渲染變量時,該變量將在一秒鐘內再次出現。

接下來,創建一個“模板”文件夾來保存我們的 HTML 文件。在該文件夾中,創建一個index.html文件。在我們的 HTML 文件的主體中,創建一個 id 為 的容器 div vm

It's worth noting that vm is just a common naming standard. It stands for ViewModel. You can name it whatever you want; it does not need to be vm.

Within the div, create two p tags to serve as placeholders for our Flask and Vue variables:

  1. One of the divs should contain the word 'greeting' surrounded by braces: {{ greeting }}.
  2. The other should contain 'greeting' surrounded by brackets: [[ greeting ]].

If you don't use separate delimiters, with the default setup, Flask will replace both greetings with whatever variable you pass with it (i.e., "Hello from Flask!").

Here's what we have thus far:

<body>
<!-- The id 'vm' is just for consistency - it can be anything you want -->
    <div id="vm">
        <p>{{ greeting }}</p>
        <p>[[ greeting ]]</p>
    </div>
</body>

Before the end of the body tag, import Vue from the official CDN along with a script to hold our JavaScript code:

<body>
<!-- The id 'vm' is just for consistency - it can be anything you want -->
    <div id="vm">
        <p>{{ greeting }}</p>
        <p>[[ greeting ]]</p>
    </div>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <script src="{{ url_for('static', filename='index.js') }}"></script>
</body>

Navigating up a directory, create a "static" folder. Add a new JavaScript file in that folder called index.js.

In this file, create the Vue context, set our instance's el as '#vm', change the default delimiters from '{{', '}}' to '[[', ']]':

const vm = new Vue({ // Again, vm is our Vue instance's name for consistency.
    el: '#vm',
    delimiters: ['[[', ']]']
})

In reality, we can use anything we want as our delimiters. In fact, if it's your preference, you can change the delimiters for your Jinja templates in Flask instead.

Finally, add a data element with the key/value of greeting: 'Hello, Vue!':

const vm = new Vue({ // Again, vm is our Vue instance's name for consistency.
    el: '#vm',
    delimiters: ['[[', ']]'],
    data: {
        greeting: 'Hello, Vue!'
    }
})

And now we're done with that file. Your final folder structure should look something like:

├───app.py
├───static
│   └───index.js
└───templates
    └───index.html

Now you can go back to you root project folder and run the app with flask run. Navigate to the site in your browser. The first and second line should have been replaced by Flask and Vue, respectively:

Hello from Flask!
Hello, Vue!

That's it! You can mix and match JSON endpoints and HTML endpoints as you please, but be aware that this can get really ugly really quickly. For a more manageable alternative, see the Flask Blueprint method.

With each additional HTML page, you'll have to either import the same JavaScript file and account for variables and elements that may not apply to it or create a new Vue object for each page. A true SPA will be difficult, but not impossible -- theoretically you could write a tiny JavaScript library that will asynchronously grab HTML pages/elements served by Flask.

I've actually created my own JavaScript library for this before. It was a big hassle and honestly not worth it, especially considering JavaScript will not run script tags imported this way, unless you build the functionality yourself. You'll also be reinventing the wheel.

If you'd like to check out my implementation of this method, you can find it on GitHub. The library takes a given chunk of HTML and replaces the specified HTML on the page with it. If the given HTML contains no <script> elements (it checks using regex), it simply uses HTMLElement.innerHTML to replace it. If it does contain <script> elements, it recursively adds the nodes, recreating any <script> nodes that come up, allowing your JavaScript to run.

Using something like this in combination with the History API can help you build a small SPA with a very tiny file size. You can even create your own Server-Side Rendering (SSR) functionality by serving full HTML pages on page load and then serve up partial pages through AJAX requests. You can learn more about SSR in the SPA with Nuxt method.

Single-Page Application

If you want to build a fully dynamic web app with a seamless User Experience (UX), you can completely separate your Flask back-end from your Vue front-end. This may take learning a whole new way of thinking when it comes to web app design if you're not familiar with modern front-end frameworks.

Developing your app as a SPA may put a dent in your SEO. In the past, this hit would be much more dramatic, but updates to how Googlebot indexes sites have negated this at least somewhat. It may, however, still have a greater impact on non-Google search engines that don't render JavaScript or those that snapshot your page(s) too early -- the latter shouldn't happen if your website is well-optimized.

For more information on SEO in modern SPAs, this article on Medium shows how Googlebot indexes JavaScript-rendered sites. Additionally, this article talks in-depth about the same thing along with other helpful tips concerning SEO on other search engines.

With this method, you'll want to generate a completely separate Vue app using the Vue CLI tool. Flask will then be used to serve up a JSON RESTful API that your Vue SPA will communicate with via AJAX.

Pros

  • Your front- and back-end will be completely independent of each other, so you can make changes to one without it impacting the other.
    • This allows them to be deployed, developed, and maintained separately.
    • You can even set up a number of other front-ends to interact with your Flask API if you'd like.
  • Your front-end experience will be much smoother and more seamless.

Cons

  • There is much more to set up and learn.
  • Deployment is difficult.
  • SEO might suffer without further intervention (see the SPA with Nuxt method for more details).
  • Authentication is much more involved, as you'll have to keep passing your auth token (JWT or Paseto) to your back-end.

Best For

  • Apps where UX is more important than SEO.
  • Back-ends that need to be accessible by multiple front-ends.

Additional Dependencies

  • Node/npm
  • Vue CLI
  • Flask-CORS

Deployment and containerization are outside of the scope of this article, but it's not terribly difficult to Dockerize this setup to simplify deployment.

Setup

Because we're completely separating Vue from Flask, this method requires a bit more setup. We'll need to enable Cross-Origin Resource Sharing (CORS) in Flask, since our front- and back-end will be served on separate ports. To accomplish this quickly and easily, we'll use the Flask-CORS Python package.

For security reasons, modern web browsers do not allow client-side JavaScript to access resources (such as JSON data) from an origin differing from the origin your script is on unless they include a specific response header letting the browser know it's okay.

If you haven't yet installed Flask-CORS, do so with pip.

Let's start with our Flask API.

首先,創建一個文件夾來保存項目的代碼。在裡面,創建一個名為“api”的文件夾。在文件夾中創建一個app.py文件。使用您喜歡的文本編輯器打開文件。這次我們需要FlaskflaskCORS從導入flask_cors。因為我們flask_cors用於啟用跨域資源共享,所以用CORS:包裝 app 對象(不設置新變量) CORS(app)。這就是我們在所有路線上為任何來源啟用 CORS 所要做的一切。

儘管這對於演示目的來說很好,但您可能不希望任何應用程序或網站都能夠訪問您的 API。在這種情況下,您可以使用帶有 CORS 函數的 kwarg 'origins' 來添加可接受的來源列表——即CORS(app, origins=["origin1", "origin2"])

有關跨域資源共享的更多信息,MDN 有一些很棒的文檔

最後,創建一個單一的問候路由/greeting以返回一個帶有單一鍵/值的 JSON 對象:

{"greeting": "Hello from Flask!"}

以下是你應該得到的結果:

from flask import Flask
from flask_cors import CORS

app = Flask(__name__)
CORS(app)

@app.route("/greeting")
def greeting():
    return {"greeting": "Hello from Flask!"}

這就是我們需要用 Python 做的所有事情。

接下來,我們將設置我們的 Vue webapp。從終端打開項目的根文件夾。使用 Vue CLI,創建一個名為“webapp”的 Vue 項目 ( vue create webapp)。你幾乎可以使用任何你喜歡的選項,但是如果你在 TypeScript 中使用基於類的組件,語法看起來會有點不同。

項目創建完成後,打開App.vue

由於我們的目標只是查看 Vue 和 Flask 是如何相互交互的,因此在頁面頂部,刪除divid 為 的所有元素app。你應該只剩下:

<template>
<div id="app">
</div>
</template>

#app中,創建兩個p元素:

  1. 第一個的內容應該是{{ greeting }}
  2. 第二個的內容應該是{{ flaskGreeting }}

您的最終 HTML 應該是這樣的:

<template>
<div id="app">
    <p>{{ greeting }}</p>
    <p>{{ flaskGreeting }}</p>
</div>
</template>

在我們的script中,讓我們添加邏輯以顯示純粹的客戶端問候語 ( greeting) 和從我們的 API 中提取的問候語 ( flaskGreeting)。

Within the Vue object (it begins with export default), create a data key. Make it a function that returns an object. Then, within this object, create two more keys: greeting and flaskGreeting. greeting's value should be 'Hello, Vue!' while flaskGreeting's should be an empty string.

Here's what we have thus far:

export default {
    name: 'App',
    components: {
        HelloWorld
    },
    data: function(){
        return {
            greeting: 'Hello, Vue!',
            flaskGreeting: ''
        }
    }
}

Finally, let's give our Vue object a created lifecycle hook. This hook will only be run once the DOM is loaded and our Vue object is created. This allows us to use the fetch API and interact with Vue without anything clashing:

export default {
    components: {
        Logo
    },
    data: function(){
        return {
            greeting: 'Hello, Vue!',
            flaskGreeting: ''
        }
    },
    created: async function(){
        const gResponse = await fetch("http://localhost:5000/greeting");
        const gObject = await gResponse.json();
        this.flaskGreeting = gObject.greeting;
    }
}

Looking at the code, we're awaiting a response to our API's 'greeting' endpoint (http://localhost:5000/greeting), awaiting that response's asynchronous .json() response, and setting our Vue object's flaskGreeting variable to the returned JSON object's value for its greeting key.

For those unfamiliar with JavaScript's relatively new Fetch API, it's basically a native AXIOS killer (at least as far as the client-side is concerned -- it's not supported by Node, but it will be by Deno). Additionally, if you like consistency, you can also check out the isomorphic-fetch package in order to use Fetch on the server-side.

我們已經完成了。現在,因為我們的前端和後端是分開的,所以我們需要分別運行我們的兩個應用程序。

讓我們在兩個單獨的終端窗口中打開項目的根文件夾。

首先,切換到“api”目錄,然後運行flask run. 如果一切順利,Flask API 應該正在運行。在第二個終端中,切換到“webapp”目錄並運行npm run serve.

Vue 應用程序啟動後,您應該可以從localhost:8080. 如果一切正常,你應該會收到兩次問候——一次是 Vue,一次是你的 Flask API:

Hello, Vue!
Hello from Flask!

您的最終文件樹應如下所示:

├───app.py
├───api
│   └───app.py
└───webapp
    ... {{ Vue project }}

使用 Nuxt 的單頁應用程序

如果 SEO 對您和 UX 一樣重要,您可能希望以某種格式實現服務器端渲染 (SSR)。

SSR 使搜索引擎更容易導航和索引您的 Vue 應用程序,因為您將能夠為他們提供一種不需要 JavaScript 生成的應用程序形式。它還可以讓用戶更快地與您的應用交互,因為您的大部分初始內容將在發送給他們之前呈現。換句話說,用戶不必等待您的所有內容異步加載。

具有服務器端渲染的單頁應用程序也稱為通用應用程序。

雖然可以手動實現 SSR,但我們將在本文中使用Nuxt ;它大大簡化了事情。

就像使用SPA方法一樣,您的前端和後端將完全分開;您將只使用 Nuxt 而不是 Vue CLI。

優點

  • SPA方法的所有優點加上服務器端渲染。

缺點

  • 與SPA方法一樣難以設置。
  • 從概念上講,還有更多需要學習的內容,因為 Nuxt 本質上只是 Vue 之上的另一層。

最適合

  • SEO 與 UX 一樣重要的應用程序。

附加依賴項

  1. 節點/npm
  2. 紐斯特
  3. 燒瓶CORS

設置

這將與SPA方法非常相似。事實上,Flask 部分是完全相同的。跟隨它,直到你創建了你的 Flask API。

完成 API 後,在終端中打開項目的根文件夾並運行命令npx create-nuxt-app webapp。這將讓您以交互方式生成一個新的 Nuxt 項目,而無需安裝任何全局依賴項。

任何選項在這裡都應該沒問題。

生成項目後,進入新的“webapp”文件夾。在“pages”文件夾中,在文本編輯器中打開index.vue 。同樣,刪除div中具有 class的所有內容container。在 內部div,創建兩個p具有相同 vars:{{ greeting }}{{ flaskGreeting }}.

它應該如下所示:

<template>
<div class="container">
    <p>{{ greeting }}</p>
    <p>{{ flaskGreeting }}</p>
</div>
</template>

現在對於我們的腳本:

  • 添加一個data返回帶有變量的對象的鍵greetingflaskGreeting
  • 添加created生命週期鉤子:
    • await fetch從我們的 API 獲取 JSON 問候語(在端口 5000 上,除非您更改它)
    • awaitjson()從 API 響應中異步獲取 JSON 數據的方法
    • 將我們的 Vue 實例設置flaskGreetinggreeting來自我們響應的 JSON 對象的鍵

Vue 對象應如下所示:

export default {
    components: {
        Logo
    },
    data: function(){
        return {
            greeting: 'Hello, Vue!',
            flaskGreeting: ''
        }
    },
    created: async function(){
        const gResponse = await fetch("http://localhost:5000/greeting");
        const gObject = await gResponse.json();
        this.flaskGreeting = gObject.greeting;
    }
}

運行 Nuxt/Vue 應用程序和 Flask API 看起來也與SPA方法非常相似。

打開兩個終端窗口。首先,更改為“api”並運行flask run命令。在第二個中,更改為“webapp”並運行npm run dev以啟動 Nuxt 項目的開發服務器。

Nuxt 應用程序啟動後,您應該可以從以下位置訪問它localhost:3000

Hello, Vue!
Hello from Flask!

在生產中,您可以運行npm run build然後npm run start啟動生產服務器。

我們的最後一棵樹:

├───app.py
├───api
│   └───app.py
└───webapp
    ... {{ Nuxt project }}

獎金:Vue 與 Nuxt SEO 比較

我在本文前面提到了 SEO 的好處,但只是為了向您展示我的意思,我按原樣運行了兩個 Web 應用程序並獲取了兩者的Lighthouse SEO 分數。

沒有對任何一個應用程序進行任何更改,這就是我們所擁有的:

我們的 Vue 和 Nuxt 應用程序的 Lighthouse SEO 得分

同樣,您可以採取一些措施來提高您的純 Vue SEO 分數。Chrome 的開發工具中的 Lighthouse 提到添加元描述,但沒有額外的干預,Nuxt 給了我們一個完美的 SEO 分數。

此外,您實際上可以看到 Nuxt 所做的 SSR 與 vanilla Vue 的完全異步方法之間的區別。如果您同時運行這兩個應用程序,導航到它們各自的來源,localhost:8080並且localhost:3000Vue 應用程序的初始問候語會在您收到響應後的幾毫秒內發生,而 Nuxt 的初始問候語已經呈現。

有關 Nuxt 和 Vue 之間差異的更多信息,您可以查看這些文章:

  1. Nuxt.js 優於 Vue.js:何時應該使用它以及為什麼
  2. Nuxt.js 如何解決 Vue.js 中的 SEO 問題

燒瓶藍圖

也許您已經開發了一個小型 Flask 應用程序,並且您希望構建一個 Vue 應用程序作為達到目的的手段而不是主要事件。

例子:

  1. 向您的雇主或客戶展示功能的原型(您可以隨時替換它或稍後將其交給前端開發人員)。
  2. 您只是不想處理部署完全獨立的前端和後端時可能導致的潛在挫敗感。

在這種情況下,您可以通過保留您的 Flask 應用程序,但在其自己的 Flask 藍圖中構建一個 Vue 前端,從而在中間相遇。

這看起來很像Jinja Template方法,但代碼會更有條理。

優點

  • 如果沒有必要,無需構建複雜的前端。
  • 類似於Jinja 模板方法,具有更好的代碼組織的額外好處。
  • 您以後可以隨時根據需要擴展前端和後端。

缺點

  • 可能需要解決方法來允許完整的 SPA。
  • 從單獨的前端(例如移動應用程序)訪問 API 可能會稍微煩人,因為前端和後端並不是完全分開的。

最適合

  • 功能比 UI 更重要的項目。
  • 您正在構建一個已經存在的 Flask 應用程序的前端。
  • 僅由幾個 HTML 頁面組成的小型 Web 應用程序。

附加依賴項

與Jinja 模板方法類似,我們將使用 CDN 來拉入 Vue 庫:

<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>

設置

與其他方法一樣,創建一個新文件夾來存放您的代碼。在其中,創建兩個文件夾:“api”和“client”。直觀地說,這些將分別包含我們的 API 和客戶端 (Vue) 的藍圖。

讓我們深入“api”文件夾。

創建一個名為api.py的文件。這將包含與我們的 API 相關的所有代碼。此外,因為我們將作為模塊訪問此文件/文件夾,所以創建一個__init__.py文件:

from flask import Blueprint

api_bp = Blueprint('api_bp', __name__) # "API Blueprint"

@api_bp.route("/greeting") # Blueprints don't use the Flask "app" context. They use their own blueprint's
def greeting():
    return {'greeting': 'Hello from Flask!'}

第一個參數Blueprint是 Flask 的路由系統。第二個 ,__name__等價於 Flask 應用程序的第一個參數 ( Flask(__name__))。

我們的 API 藍圖就是這樣。

好的。讓我們深入了解我們之前創建的“客戶端”文件夾。這個會比我們的 API 藍圖更複雜一些,但不會比普通的 Flask 應用程序複雜。

同樣,像普通的 Flask 應用程序一樣,在這個文件夾中,創建一個“靜態”文件夾和一個“模板”文件夾。創建一個名為client.py的文件並在文本編輯器中打開它。

這一次,我們將向我們傳遞更多參數,Blueprint以便它知道在哪裡可以找到正確的靜態文件和模板:

client_bp = Blueprint('client_bp', __name__, # 'Client Blueprint'
    template_folder='templates', # Required for our purposes
    static_folder='static', # Again, this is required
    static_url_path='/client/static' # Flask will be confused if you don't do this
)

添加路由以提供index.html模板:

from flask import Blueprint, render_template

client_bp = Blueprint("client_bp", __name__, # 'Client Blueprint'
    template_folder="templates", # Required for our purposes
    static_folder="static", # Again, this is required
    static_url_path="/client/static" # Flask will be confused if you don't do this
)

@client_bp.route("/")
def index():
    return render_template("index.html")

出色的。我們的客戶藍圖現已完成。退出文件並轉到藍圖的“模板”文件夾。創建一個index.html文件:

<body>
<!-- The id 'vm' is just for consistency - it can be anything you want -->
    <div id="vm" class="container">
        <p>[[ greeting ]]</p>
        <p>[[ flaskGreeting ]]</p>
    </div>
    <script src="https://cdn.jsdelivr.net/npm/vue@2.6.11"></script>
    <script src="{{ url_for('client_bp.static', filename='index.js') }}"></script>
</body>

您是否注意到我們使用的是方括號而不是大括號?這是因為我們需要更改分隔符以防止 Flask 先捕獲它們。

greeting將在 Vue 準備好後立即呈現,而flaskGreeting將從我們將異步請求的 Flask 響應中獲取。

完畢。在名為index.js的“靜態”文件夾中添加一個新文件。創建一個名為的變量apiEndpoint並將其設置為api_v1. 如果我們決定稍後更改端點,這只會讓一切變得更加干燥:

const apiEndpoint = '/api_v1/';

我們還沒有為我們的端點創建邏輯。這將在最後一步出現。

接下來,首先讓 Vue 上下文看起來與Jinja 模板方法中的上下文相同:

const apiEndpoint = '/api_v1/';

const vm = new Vue({ // Again, vm is our Vue instance's name for consistency.
    el: '#vm',
    delimiters: ['[[', ']]'],
    data: {
        greeting: 'Hello, Vue!'
    }
})

同樣,我們創建了 Vue 上下文,將我們的實例設置el'#vm',將默認分隔符從 更改'{{', '}}''[[', ']]',並添加了一個鍵/值為greeting:的數據元素'Hello, Vue!'

因為我們還要從 API 中提取問候語,所以創建一個flaskGreeting使用空字符串值調用的數據佔位符:

const apiEndpoint = '/api_v1/';

const vm = new Vue({
    el: '#vm',
    delimiters: ['[[', ']]'],
    data: {
        greeting: 'Hello, Vue!',
        flaskGreeting: ''
    }
})

讓我們給我們的 Vue 對像一個異步created生命週期鉤子:

const apiEndpoint = '/api_v1/';

const vm = new Vue({
    el: '#vm',
    delimiters: ['[[', ']]'],
    data: {
        greeting: 'Hello, Vue!',
        flaskGreeting: ''
    },
    created: async function(){
        const gResponse = await fetch(apiEndpoint + 'greeting');
        const gObject = await gResponse.json();
        this.flaskGreeting = gObject.greeting;
    }
})

查看代碼,我們await從 API 的“問候”端點 ( /api_v1/greeting)中獲取響應,await將該響應作為異步.json()響應,並將 Vue 對象的flaskGreeting變量設置為返回的 JSON 對象的greeting鍵值。它基本上是方法 1 和 2 中的 Vue 對象之間的混搭。

出色的。只剩下一件事要做:讓我們通過將app.py添加到項目根目錄來將所有內容放在一起。在文件中,flask連同藍圖一起導入:

from flask import Flask
from api.api import api_bp
from client.client import client_bp

像往常一樣創建一個 Flask 應用程序並使用以下方法註冊藍圖app.register_blueprint()

from flask import Flask
from api.api import api_bp
from client.client import client_bp

app = Flask(__name__)
app.register_blueprint(api_bp, url_prefix='/api_v1')
app.register_blueprint(client_bp)

最終文件樹:

├───app.py
├───api
│   └───__init__.py
│   └───api.py
└───client
    ├───__init__.py
    ├───static
    │   └───index.js
    └───templates
        └───index.html

就是這樣!如果你運行你的新應用程序,flask run你應該會受到兩次問候——一次是 Vue 本身,另一次是來自 Flask API 的響應。

概括

使用 Vue 和 Flask 構建 Web 應用程序的方式有很多種。這一切都取決於你手頭的情況。

一些問題要問:

  1. 搜索引擎優化有多重要?
  2. 你的開發團隊是什麼樣的?如果您沒有 DevOps 團隊,您是否想承擔必須單獨部署前端和後端的額外複雜性?
  3. 你只是快速原型設計嗎?

希望這篇文章能引導您朝著正確的方向前進,讓您了解如何組合 Vue 和 Flask 應用程序。

您可以從GitHub 上的 combine-flask-with-vue 存儲庫中獲取最終代碼。

來源:  https ://testdriven.io

#vue #flask 

如何將 Vue.js 與 Flask 結合使用?

Comment Puis-je Combiner Vue.js Avec Flask?

Combiner Flask et Vue

Donc, vous avez enfin Flask à votre actif et vous n'êtes pas étranger à JavaScript. Vous avez même développé quelques applications Web, mais vous commencez à réaliser quelque chose : vous avez d'excellentes fonctionnalités, mais votre UX est un peu fade. Où en sont le flux d'applications et la navigation transparente que vous voyez sur de nombreux sites Web et applications populaires aujourd'hui ? Comment cela peut-il être réalisé ?

Au fur et à mesure que vous vous investissez dans vos sites Web et vos applications Web, vous souhaiterez probablement leur ajouter davantage de fonctionnalités et de réactivité côté client. Le développement Web moderne y parvient généralement grâce à l'utilisation de frameworks frontaux, et l'un de ces frameworks qui gagne rapidement en popularité est Vue (également connu sous le nom de Vue.js ou VueJS).

Selon les exigences de votre projet, il existe plusieurs façons de créer une application Web avec Flask et Vue, et elles impliquent chacune différents niveaux de séparation back-end/front-end.

Dans cet article, nous examinerons trois méthodes différentes pour combiner Flask et Vue :

  1. Modèle Jinja : Importation de Vue dans un modèle Jinja
  2. Application monopage : création d'une application monopage (SPA) pour séparer complètement Flask et Vue
  3. Flask Blueprint : servir Vue à partir d'un Flask blueprint pour séparer partiellement les deux

Différentes façons de créer une application Web avec Flask et Vue

Nous analyserons les avantages et les inconvénients de chaque méthode, examinerons leurs meilleurs cas d'utilisation et détaillerons comment configurer chacune d'entre elles.

Modèle Jinja

Que vous utilisiez React, Vue ou Angular, c'est le moyen le plus simple de passer à l'utilisation d'un framework frontal.

Dans de nombreux cas, lorsque vous créez un frontal pour votre application Web, vous le concevez autour du framework frontal lui-même. Avec cette méthode, cependant, l'accent est toujours mis sur votre application Flask principale. Vous utiliserez toujours Jinja et les modèles côté serveur avec un peu de fonctionnalité réactive avec Vue si et quand vous en avez besoin.

Vous pouvez importer la bibliothèque Vue soit via un réseau de diffusion de contenu (CDN), soit en la servant vous-même avec votre application, tout en configurant et en acheminant Flask comme vous le feriez normalement.

Avantages

  • Vous pouvez créer votre application à votre façon au lieu de l'adapter à la fondation de Vue.
  • L'optimisation pour les moteurs de recherche (SEO) ne nécessite aucune configuration supplémentaire.
  • Vous pouvez tirer parti de l'authentification basée sur les cookies au lieu de l'authentification basée sur les jetons. Cela a tendance à être plus facile, car vous n'avez pas affaire à une communication asynchrone entre le front et le back-end.

Les inconvénients

  • Vous devez importer Vue et configurer chaque page individuellement, ce qui peut être difficile si vous commencez à ajouter Vue à de plus en plus de pages. Cela peut également nécessiter un certain nombre de solutions de contournement, car ce n'est pas vraiment la manière prévue d'utiliser Flask ou Vue.

Meilleur pour

  • Petites applications Web utilisant littéralement une ou deux pages HTML (par opposition à un SPA avec son propre routage dynamique - voir la méthode SPA pour plus d'informations).
  • Création de fonctionnalités dans une application Web déjà existante.
  • Ajouter des éléments de réactivité à une application sans s'engager pleinement dans un framework frontal.
  • Les applications Web qui n'ont pas besoin de communiquer aussi fréquemment avec un back-end via AJAX.

Dépendances supplémentaires

Cette méthode nécessite juste la librairie Vue, que vous pouvez ajouter via un CDN :

<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>

Installer

De toutes les méthodes, cette configuration est la plus simple.

Créez un dossier pour contenir tout le code de votre application. Dans ce dossier, créez un fichier app.py comme vous le feriez normalement :

from flask import Flask, render_template # These are all we need for our purposes

app = Flask(__name__)

@app.route("/")
def index():
    return render_template("index.html", **{"greeting": "Hello from Flask!"})

Nous avons seulement besoin d'importer Flasket render_templatede flask.

La greetingvariable réapparaîtra dans une seconde lorsque nous verrons comment rendre les variables avec Jinja et Vue dans le même fichier.

Ensuite, créez un dossier "templates" pour contenir notre fichier HTML. Dans ce dossier, créez un fichier index.html . Dans le corps de notre fichier HTML, créez un conteneur div avec un identifiant vm.

Il convient de noter qu'il vmne s'agit que d'une norme de dénomination commune. Il signifie ViewModel . Vous pouvez lui donner le nom que vous voulez ; ce n'est pas nécessaire vm.

Dans le div, créez deux pbalises pour servir d'espaces réservés pour nos variables Flask et Vue :

  1. L'un des divs doit contenir le mot "salutation" entouré d'accolades : {{ greeting }}.
  2. L'autre doit contenir "salut" entouré de crochets : [[ greeting ]].

Si vous n'utilisez pas de délimiteurs séparés, avec la configuration par défaut, Flask remplacera les deux salutations par la variable que vous lui passerez (c'est-à-dire "Bonjour de Flask!").

Voici ce que nous avons jusqu'à présent :

<body>
<!-- The id 'vm' is just for consistency - it can be anything you want -->
    <div id="vm">
        <p>{{ greeting }}</p>
        <p>[[ greeting ]]</p>
    </div>
</body>

Avant la fin de la balise body, importez Vue depuis le CDN officiel avec un script pour contenir notre code JavaScript :

<body>
<!-- The id 'vm' is just for consistency - it can be anything you want -->
    <div id="vm">
        <p>{{ greeting }}</p>
        <p>[[ greeting ]]</p>
    </div>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <script src="{{ url_for('static', filename='index.js') }}"></script>
</body>

En remontant un répertoire, créez un dossier "statique". Ajoutez un nouveau fichier JavaScript dans ce dossier appelé index.js .

Dans ce fichier, créez le contexte Vue, définissez notre instance sur el, '#vm'changez les délimiteurs par défaut de '{{', '}}'à '[[', ']]':

const vm = new Vue({ // Again, vm is our Vue instance's name for consistency.
    el: '#vm',
    delimiters: ['[[', ']]']
})

En réalité, nous pouvons utiliser tout ce que nous voulons comme délimiteurs. En fait, si c'est votre préférence, vous pouvez à la place modifier les délimiteurs de vos modèles Jinja dans Flask.

Enfin, ajoutez un élément de données avec la clé/valeur degreeting: 'Hello, Vue!' :

const vm = new Vue({ // Again, vm is our Vue instance's name for consistency.
    el: '#vm',
    delimiters: ['[[', ']]'],
    data: {
        greeting: 'Hello, Vue!'
    }
})

Et maintenant nous en avons fini avec ce fichier. Votre structure de dossier finale devrait ressembler à :

├───app.py
├───static
│   └───index.js
└───templates
    └───index.html

Vous pouvez maintenant revenir à votre dossier de projet racine et exécuter l'application avec flask run. Accédez au site dans votre navigateur. La première et la deuxième ligne auraient dû être remplacées par Flask et Vue, respectivement :

Hello from Flask!
Hello, Vue!

C'est ça! Vous pouvez mélanger et faire correspondre les points de terminaison JSON et les points de terminaison HTML à votre guise, mais sachez que cela peut devenir très moche très rapidement. Pour une alternative plus gérable, voir la méthode Flask Blueprint .

Avec chaque page HTML supplémentaire, vous devrez soit importer le même fichier JavaScript et tenir compte des variables et des éléments qui peuvent ne pas s'y appliquer, soit créer un nouvel objet Vue pour chaque page. Un véritable SPA sera difficile, mais pas impossible - théoriquement, vous pourriez écrire une petite bibliothèque JavaScript qui saisira de manière asynchrone les pages/éléments HTML servis par Flask.

J'ai en fait créé ma propre bibliothèque JavaScript pour cela auparavant. C'était un gros problème et honnêtement, cela n'en valait pas la peine, d'autant plus que JavaScript n'exécutera pas les balises de script importées de cette manière, à moins que vous ne construisiez vous-même la fonctionnalité. Vous réinventerez également la roue.

Si vous souhaitez consulter mon implémentation de cette méthode, vous pouvez la trouver sur GitHub . La bibliothèque prend un morceau de code HTML donné et remplace le code HTML spécifié sur la page par celui-ci. Si le code HTML donné ne contient aucun <script>élément (il vérifie à l'aide de regex), il l'utilise simplement HTMLElement.innerHTMLpour le remplacer. S'il contient des <script>éléments, il ajoute récursivement les nœuds, recréant tous les <script>nœuds qui apparaissent, permettant à votre JavaScript de s'exécuter.

L'utilisation de quelque chose comme ça en combinaison avec l'API History peut vous aider à créer un petit SPA avec une très petite taille de fichier. Vous pouvez même créer votre propre fonctionnalité de rendu côté serveur (SSR) en servant des pages HTML complètes lors du chargement de la page, puis en servant des pages partielles via des requêtes AJAX. Vous pouvez en savoir plus sur la SSR dans la méthode SPA avec Nuxt .

Demande d'une seule page

Si vous souhaitez créer une application Web entièrement dynamique avec une expérience utilisateur (UX) transparente, vous pouvez complètement séparer votre back-end Flask de votre front-end Vue. Cela peut nécessiter d'apprendre une toute nouvelle façon de penser en matière de conception d'applications Web si vous n'êtes pas familier avec les frameworks frontaux modernes.

Développer votre application en tant que SPA peut nuire à votre référencement. Dans le passé, ce coup serait beaucoup plus dramatique, mais les mises à jour de la façon dont Googlebot indexe les sites ont au moins quelque peu annulé cela. Cependant, cela peut avoir un impact plus important sur les moteurs de recherche autres que Google qui n'affichent pas JavaScript ou ceux qui capturent votre ou vos pages trop tôt - ce dernier ne devrait pas se produire si votre site Web est bien optimisé.

Pour plus d'informations sur le référencement dans les SPA modernes, cet article sur Medium montre comment Googlebot indexe les sites rendus en JavaScript. De plus, cet article traite en profondeur de la même chose ainsi que d'autres conseils utiles concernant le référencement sur d'autres moteurs de recherche.

Avec cette méthode, vous souhaiterez générer une application Vue complètement distincte à l'aide de l' outil Vue CLI . Flask sera ensuite utilisé pour servir une API JSON RESTful avec laquelle votre Vue SPA communiquera via AJAX.

Avantages

  • Votre front-end et votre back-end seront complètement indépendants l'un de l'autre, vous pouvez donc apporter des modifications à l'un sans que cela n'affecte l'autre.
    • Cela leur permet d'être déployés, développés et maintenus séparément.
    • Vous pouvez même configurer un certain nombre d'autres frontaux pour interagir avec votre API Flask si vous le souhaitez.
  • Votre expérience frontale sera beaucoup plus fluide et transparente.

Les inconvénients

  • Il y a beaucoup plus à configurer et à apprendre.
  • Le déploiement est difficile.
  • Le SEO pourrait souffrir sans autre intervention (voir la méthode SPA avec Nuxt pour plus de détails).
  • L'authentification est beaucoup plus complexe, car vous devrez continuer à transmettre votre jeton d'authentification ( JWT ou Paseto ) à votre back-end.

Meilleur pour

  • Applications où l'UX est plus important que le SEO.
  • Les back-ends qui doivent être accessibles par plusieurs front-ends.

Dépendances supplémentaires

  • Nœud/npm
  • Vue CLI
  • Flacon-CORS

Le déploiement et la conteneurisation sortent du cadre de cet article, mais il n'est pas très difficile de Dockeriser cette configuration pour simplifier le déploiement.

Installer

Parce que nous séparons complètement Vue de Flask, cette méthode nécessite un peu plus de configuration. Nous devrons activer le partage de ressources cross-origin (CORS) dans Flask, car notre front-end et notre back-end seront servis sur des ports séparés. Pour accomplir cela rapidement et facilement, nous utiliserons le package Flask-CORS Python.

For security reasons, modern web browsers do not allow client-side JavaScript to access resources (such as JSON data) from an origin differing from the origin your script is on unless they include a specific response header letting the browser know it's okay.

If you haven't yet installed Flask-CORS, do so with pip.

Let's start with our Flask API.

First, create a folder to hold the code for your project. Inside, create a folder called "api". Create an app.py file in the folder. Open the file with your favorite text editor. This time we'll need to import Flask from flask and CORS from flask_cors. Because we're using flask_cors to enable cross-origin resource sharing, wrap the app object (without setting a new variable) with CORS: CORS(app). That's all we have to do to enable CORS on all of our routes for any origin.

Although this is fine for demonstration purposes, you probably aren't going to want just any app or website to be able to access your API. In that case, you can use the kwarg 'origins' with the CORS function to add a list of acceptable origins -- i.e., CORS(app, origins=["origin1", "origin2"])

Pour plus d'informations sur le partage de ressources cross-origin, MDN a une excellente documentation à ce sujet.

Enfin, créez une route de salutation unique à /greetingpour renvoyer un objet JSON avec une seule clé/valeur :

{"greeting": "Hello from Flask!"}

Voici ce à quoi vous auriez dû vous retrouver :

from flask import Flask
from flask_cors import CORS

app = Flask(__name__)
CORS(app)

@app.route("/greeting")
def greeting():
    return {"greeting": "Hello from Flask!"}

C'est tout ce que nous devons faire avec Python.

Ensuite, nous allons configurer notre application Web Vue. Depuis un terminal, ouvrez le dossier racine de votre projet. À l'aide de Vue CLI, créez un projet Vue appelé "webapp" ( vue create webapp). Vous pouvez utiliser à peu près toutes les options que vous aimez, mais si vous utilisez des composants basés sur des classes dans TypeScript, la syntaxe sera un peu différente.

Lorsque votre projet est terminé, ouvrez App.vue .

Étant donné que notre objectif est simplement de voir comment Vue et Flask interagissent les uns avec les autres, en haut de la page, supprimez tous les éléments dans le divavec l'id de app. Il ne devrait vous rester que :

<template>
<div id="app">
</div>
</template>

Dans #app, créez deux péléments :

  1. Le contenu du premier devrait être {{ greeting }}.
  2. Le contenu de la seconde devrait être {{ flaskGreeting }}.

Votre HTML final devrait être comme tel :

<template>
<div id="app">
    <p>{{ greeting }}</p>
    <p>{{ flaskGreeting }}</p>
</div>
</template>

Dans notre script, ajoutons une logique pour afficher un message d'accueil purement côté client ( greeting) et un message d'accueil tiré de notre API ( flaskGreeting).

Dans l'objet Vue (il commence par export default), créez une dataclé. Faites-en une fonction qui renvoie un objet. Ensuite, dans cet objet, créez deux autres clés : greetinget flaskGreeting. greetingLa valeur de doit être 'Hello, Vue!'tandis que flaskGreeting's doit être une chaîne vide.

Voici ce que nous avons jusqu'à présent :

export default {
    name: 'App',
    components: {
        HelloWorld
    },
    data: function(){
        return {
            greeting: 'Hello, Vue!',
            flaskGreeting: ''
        }
    }
}

Enfin, donnons à notre objet Vue un createdhook de cycle de vie. Ce crochet ne sera exécuté qu'une fois le DOM chargé et notre objet Vue créé. Cela nous permet d'utiliser l' fetchAPI et d'interagir avec Vue sans que rien ne se heurte :

export default {
    components: {
        Logo
    },
    data: function(){
        return {
            greeting: 'Hello, Vue!',
            flaskGreeting: ''
        }
    },
    created: async function(){
        const gResponse = await fetch("http://localhost:5000/greeting");
        const gObject = await gResponse.json();
        this.flaskGreeting = gObject.greeting;
    }
}

En regardant le code, nous awaitrenvoyons une réponse au point de terminaison "salutation" de notre API ( http://localhost:5000/greeting), awaitrenvoyons la réponse asynchrone de cette .json()réponse et définissons la variable de notre objet Vue flaskGreetingsur la valeur de l'objet JSON renvoyé pour sa greetingclé.

Pour ceux qui ne connaissent pas l' API Fetch relativement nouvelle de JavaScript , il s'agit essentiellement d'un tueur AXIOS natif (du moins en ce qui concerne le côté client - il n'est pas pris en charge par Node, mais ce sera par Deno ). De plus, si vous aimez la cohérence, vous pouvez également consulter le package isomorphic-fetch afin d'utiliser Fetch côté serveur.

Et nous avons terminé. Maintenant, parce que, encore une fois, notre front-end et notre back-end sont séparés, nous devrons exécuter nos deux applications séparément.

Ouvrons le dossier racine de notre projet dans deux fenêtres de terminal distinctes.

Dans le premier, accédez au répertoire "api", puis exécutez flask run. Si tout se passe bien, l'API Flask devrait être en cours d'exécution. Dans le deuxième terminal, accédez au répertoire "webapp" et exécutez npm run serve.

Une fois l'application Vue lancée, vous devriez pouvoir y accéder à partir de localhost:8080. Si tout fonctionne, vous devriez être accueilli deux fois -- une fois par Vue, et encore une fois depuis votre API Flask :

Hello, Vue!
Hello from Flask!

Votre arborescence de fichiers finale devrait ressembler à :

├───app.py
├───api
│   └───app.py
└───webapp
    ... {{ Vue project }}

Application monopage avec Nuxt

Si le SEO est aussi important pour vous que l'UX, vous voudrez peut-être implémenter le rendu côté serveur (SSR) dans un certain format.

SSR permet aux moteurs de recherche de naviguer et d'indexer plus facilement votre application Vue, car vous pourrez leur donner une forme de votre application qui ne nécessite pas de JavaScript pour être générée. Cela peut également permettre aux utilisateurs d'interagir plus rapidement avec votre application, car une grande partie de votre contenu initial sera rendue avant de leur être envoyée. En d'autres termes, les utilisateurs n'auront pas à attendre que tout votre contenu se charge de manière asynchrone.

Une application monopage avec rendu côté serveur est également appelée application universelle.

Bien qu'il soit possible d'implémenter SSR manuellement, nous utiliserons Nuxt dans cet article ; cela simplifie grandement les choses.

Tout comme avec la méthode SPA , votre front-end et votre back-end seront complètement séparés ; vous utiliserez simplement Nuxt au lieu de Vue CLI.

Avantages

  • Tous les avantages de la méthode SPA avec l'ajout du rendu côté serveur.

Les inconvénients

  • À peu près aussi difficile à mettre en place que la méthode SPA .
  • Conceptuellement, il y a encore plus à apprendre car Nuxt n'est essentiellement qu'une autre couche au-dessus de Vue.

Meilleur pour

  • Des applications où le SEO est aussi important que l'UX.

Dépendances supplémentaires

  1. Nœud/npm
  2. Nuxt
  3. Flacon-CORS

Installer

Cela va être très similaire à la méthode SPA . En fait, la partie Flask est exactement la même. Suivez-le jusqu'à ce que vous ayez créé votre API Flask.

Une fois votre API terminée, dans votre terminal, ouvrez le dossier racine de votre projet et exécutez la commande npx create-nuxt-app webapp. Cela vous permettra de générer de manière interactive un nouveau projet Nuxt sans installer de dépendances globales.

Toutes les options devraient convenir ici.

Une fois votre projet généré, plongez dans votre nouveau dossier "webapp". Dans le dossier "pages", ouvrez index.vue dans votre éditeur de texte. De même, supprimez tout ce divqui a la classe container. À l'intérieur du div, créez deux pbalises avec les mêmes vars : {{ greeting }}et {{ flaskGreeting }}.

Ça devrait ressembler à ça:

<template>
<div class="container">
    <p>{{ greeting }}</p>
    <p>{{ flaskGreeting }}</p>
</div>
</template>

Et maintenant pour notre script :

  • Ajoutez une dataclé qui renvoie un objet avec les variables greetingetflaskGreeting
  • Ajoutez un createdhook de cycle de vie :
    • await fetchpour obtenir le message d'accueil JSON de notre API (sur le port 5000 sauf si vous l'avez modifié)
    • awaitla json()méthode pour obtenir de manière asynchrone nos données JSON à partir de la réponse de notre API
    • Définissez notre instance Vue flaskGreetingsur la greetingclé de l'objet JSON de notre réponse

The Vue object should look like:

export default {
    components: {
        Logo
    },
    data: function(){
        return {
            greeting: 'Hello, Vue!',
            flaskGreeting: ''
        }
    },
    created: async function(){
        const gResponse = await fetch("http://localhost:5000/greeting");
        const gObject = await gResponse.json();
        this.flaskGreeting = gObject.greeting;
    }
}

Running the Nuxt/Vue app and Flask API will look very similar to the the SPA method as well.

Open two terminal windows. Within the first, change into "api" and run the flask run command. Within the second, change into "webapp" and run npm run dev to start a development server for your Nuxt project.

Once the Nuxt app is up, you should be able to access it from localhost:3000:

Hello, Vue!
Hello from Flask!

In production you can run npm run build and then npm run start to start a production server.

Our final tree:

├───app.py
├───api
│   └───app.py
└───webapp
    ... {{ Nuxt project }}

BONUS: Vue vs Nuxt SEO Comparison

I mentioned the benefits of SEO earlier in this article, but just to show you what I meant, I ran both web apps as-is and grabbed the Lighthouse SEO scores for both.

En l'absence de modifications apportées à l'une ou l'autre des applications, voici ce que nous avons :

Lighthouse SEO Scores pour nos applications Vue et Nuxt

Encore une fois, il y a des choses que vous pouvez faire pour améliorer votre score SEO pur Vue. Les outils de développement de Lighthouse dans Chrome mentionnent l'ajout d'une méta description, mais sans intervention supplémentaire, Nuxt nous a donné un score SEO parfait.

De plus, vous pouvez réellement voir la différence entre le SSR que Nuxt fait et l'approche complètement asynchrone de Vanilla Vue. Si vous exécutez les deux applications en même temps, accédez à leurs origines respectives localhost:8080et localhost:3000, le message d'accueil initial de l'application Vue se produit quelques millisecondes après avoir reçu la réponse, tandis que celui de Nuxt est servi avec son message d'accueil initial déjà rendu.

Pour plus d'informations sur les différences entre Nuxt et Vue, vous pouvez consulter ces articles :

  1. Nuxt.js sur Vue.js : quand l'utiliser et pourquoi
  2. Comment Nuxt.js résout les problèmes de référencement dans Vue.js .

Plan du flacon

Peut-être avez-vous déjà développé une petite application Flask et souhaitez-vous créer une application Vue davantage comme un moyen d'atteindre une fin que comme l'événement principal.

Exemples:

  1. Prototype pour démontrer la fonctionnalité à votre employeur ou client (vous pouvez toujours le remplacer ou le remettre ultérieurement à un développeur front-end).
  2. Vous ne voulez tout simplement pas faire face à la frustration potentielle qui pourrait résulter du déploiement d'un front-end et d'un back-end complètement séparés.

Dans ce cas, vous pourriez en quelque sorte vous rencontrer au milieu en conservant votre application Flask, mais en vous appuyant sur une interface Vue dans son propre plan Flask.

Cela ressemblera beaucoup à la méthode Jinja Template , mais le code sera plus organisé.

Avantages

  • Pas besoin de construire un front-end complexe si ce n'est pas nécessaire.
  • Semblable à la méthode Jinja Template avec l'avantage supplémentaire d'une meilleure organisation du code.
  • Vous pouvez toujours étendre le front-end et le back-end si nécessaire ultérieurement.

Les inconvénients

  • Des solutions de contournement peuvent être nécessaires pour autoriser un SPA complet.
  • L'accès à l'API peut être légèrement plus ennuyeux à partir d'un front-end séparé (comme une application mobile) car le front-end et le back-end ne sont pas complètement séparés.

Meilleur pour

  • Projets où la fonctionnalité est plus importante que l'interface utilisateur.
  • Vous construisez une interface sur une application Flask déjà existante.
  • Petites applications Web composées de seulement quelques pages HTML.

Dépendances supplémentaires

De la même manière que pour la méthode Jinja Template , nous utiliserons un CDN pour extraire la bibliothèque Vue :

<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>

Installer

Comme les autres méthodes, créez un nouveau dossier pour héberger votre code. A l'intérieur de celui-ci, créez deux dossiers : "api" et "client". Intuitivement, ceux-ci contiendront les plans de notre API et de notre client (Vue), respectivement.

Plongeons dans le dossier "api".

Créez un fichier appelé api.py . Celui-ci contiendra tout le code associé à notre API. De plus, comme nous allons accéder à ce fichier/dossier en tant que module, créez un fichier __init__.py :

from flask import Blueprint

api_bp = Blueprint('api_bp', __name__) # "API Blueprint"

@api_bp.route("/greeting") # Blueprints don't use the Flask "app" context. They use their own blueprint's
def greeting():
    return {'greeting': 'Hello from Flask!'}

Le premier argument à Blueprintconcerne le système de routage de Flask. Le second, __name__, équivaut au premier argument d'une application Flask ( Flask(__name__)).

Et c'est tout avec notre modèle d'API.

D'accord. Plongeons dans le dossier "client" que nous avons créé précédemment. Celui-ci sera un peu plus complexe que notre modèle d'API, mais pas plus compliqué qu'une application Flask standard.

Encore une fois, comme une application Flask normale, dans ce dossier, créez un dossier "statique" et un dossier "modèles". Créez un fichier appelé client.py et ouvrez-le dans votre éditeur de texte.

Cette fois, nous allons passer quelques arguments supplémentaires à notre Blueprintafin qu'il sache où trouver les fichiers statiques et modèles corrects :

client_bp = Blueprint('client_bp', __name__, # 'Client Blueprint'
    template_folder='templates', # Required for our purposes
    static_folder='static', # Again, this is required
    static_url_path='/client/static' # Flask will be confused if you don't do this
)

Ajoutez également la route pour servir le modèle index.html :

from flask import Blueprint, render_template

client_bp = Blueprint("client_bp", __name__, # 'Client Blueprint'
    template_folder="templates", # Required for our purposes
    static_folder="static", # Again, this is required
    static_url_path="/client/static" # Flask will be confused if you don't do this
)

@client_bp.route("/")
def index():
    return render_template("index.html")

Excellent. Notre plan client est maintenant terminé. Quittez le fichier et accédez au dossier "modèles" du plan. Créez un fichier index.html :

<body>
<!-- The id 'vm' is just for consistency - it can be anything you want -->
    <div id="vm" class="container">
        <p>[[ greeting ]]</p>
        <p>[[ flaskGreeting ]]</p>
    </div>
    <script src="https://cdn.jsdelivr.net/npm/vue@2.6.11"></script>
    <script src="{{ url_for('client_bp.static', filename='index.js') }}"></script>
</body>

Did you notice that we're using brackets instead of braces? It's because we need to change the delimiters to keep Flask from catching them first.

greeting will be rendered by Vue as soon as it's ready, while flaskGreeting will be taken from a Flask response that we'll request asynchronously.

Done. Add a new file to the "static" folder called index.js. Create a variable called apiEndpoint and set it to api_v1. This just makes everything a little more DRY if we decide to change our endpoint later on:

const apiEndpoint = '/api_v1/';

We haven't created the logic for our endpoint yet. That will come in the last step.

Next, start by making the Vue context look identical to the context in the Jinja Template method:

const apiEndpoint = '/api_v1/';

const vm = new Vue({ // Again, vm is our Vue instance's name for consistency.
    el: '#vm',
    delimiters: ['[[', ']]'],
    data: {
        greeting: 'Hello, Vue!'
    }
})

Encore une fois, nous avons créé le contexte Vue, défini notre instance sur el, '#vm'modifié les délimiteurs par défaut de '{{', '}}'à '[[', ']]', et ajouté un élément de données avec la clé/valeur de greeting: 'Hello, Vue!'.

Étant donné que nous allons également extraire un message d'accueil de notre API, créez un espace réservé de données appelé flaskGreetingavec la valeur d'une chaîne vide :

const apiEndpoint = '/api_v1/';

const vm = new Vue({
    el: '#vm',
    delimiters: ['[[', ']]'],
    data: {
        greeting: 'Hello, Vue!',
        flaskGreeting: ''
    }
})

Donnons à notre objet Vue un createdhook de cycle de vie asynchrone :

const apiEndpoint = '/api_v1/';

const vm = new Vue({
    el: '#vm',
    delimiters: ['[[', ']]'],
    data: {
        greeting: 'Hello, Vue!',
        flaskGreeting: ''
    },
    created: async function(){
        const gResponse = await fetch(apiEndpoint + 'greeting');
        const gObject = await gResponse.json();
        this.flaskGreeting = gObject.greeting;
    }
})

En regardant le code, nous awaitrenvoyons une réponse du point de terminaison "salutation" de notre API ( /api_v1/greeting), awaitrenvoyons la réponse asynchrone de cette .json()réponse et définissons la variable de notre objet Vue flaskGreetingsur la valeur de l'objet JSON renvoyé pour sa greetingclé. Il s'agit essentiellement d'un mashup entre les objets Vue des méthodes 1 et 2.

Excellent. Il ne reste plus qu'une chose à faire : rassemblons tout en ajoutant un app.py à la racine du projet. Dans le fichier, importez flaskavec les plans :

from flask import Flask
from api.api import api_bp
from client.client import client_bp

Créez une application Flask comme vous le feriez normalement et enregistrez les plans en utilisant app.register_blueprint():

from flask import Flask
from api.api import api_bp
from client.client import client_bp

app = Flask(__name__)
app.register_blueprint(api_bp, url_prefix='/api_v1')
app.register_blueprint(client_bp)

Arborescence finale des fichiers :

├───app.py
├───api
│   └───__init__.py
│   └───api.py
└───client
    ├───__init__.py
    ├───static
    │   └───index.js
    └───templates
        └───index.html

Et c'est tout! Si vous exécutez votre nouvelle application avec flask run, vous devriez être accueilli deux fois - une fois par Vue lui-même et une autre fois par une réponse de votre API Flask.

Sommaire

Il existe de très nombreuses façons de créer une application Web à l'aide de Vue et Flask. Tout dépend de votre situation actuelle.

Quelques questions à se poser :

  1. Quelle est l'importance du référencement ?
  2. À quoi ressemble votre équipe de développement ? Si vous n'avez pas d'équipe DevOps, souhaitez-vous assumer la complexité supplémentaire de devoir déployer séparément le front-end et le back-end ?
  3. Faites-vous simplement du prototypage rapide ?

Espérons que cet article vous oriente dans la bonne direction, vous donnant une idée de la façon de combiner vos applications Vue et Flask.

Vous pouvez récupérer le code final du dépôt de combinaison-flask-with-vue sur GitHub.

Source :  https://testdrive.io

#vue #flask 

Comment Puis-je Combiner Vue.js Avec Flask?
Derrick  Ferry

Derrick Ferry

1660402080

¿Cómo Puedo Combinar Vue.js Con Flask?

Combinando Flask y Vue

Así que finalmente tienes Flask bajo tu cinturón, y no eres ajeno a JavaScript. Incluso ha desarrollado algunas aplicaciones web, pero comienza a darse cuenta de algo: tiene una excelente funcionalidad, pero su UX es un poco soso. ¿Dónde está el flujo de aplicaciones y la navegación fluida que ves en muchos sitios web y aplicaciones populares hoy en día? ¿Cómo se puede lograr eso?

A medida que invierta más en sus sitios web y aplicaciones web, probablemente querrá agregarles más funcionalidad y reactividad del lado del cliente. El desarrollo web moderno generalmente logra esto mediante el uso de marcos front-end, y uno de esos marcos que está aumentando rápidamente en popularidad es Vue (también conocido como Vue.js o VueJS).

Dependiendo de los requisitos de su proyecto, hay algunas formas diferentes de crear una aplicación web con Flask y Vue, y cada una implica varios niveles de separación de back-end/front-end.

En este artículo, veremos tres métodos diferentes para combinar Flask y Vue:

  1. Plantilla Jinja : Importación de Vue en una plantilla Jinja
  2. Aplicación de una sola página: creación de una aplicación de una sola página (SPA) para separar completamente Flask y Vue
  3. Flask Blueprint : sirviendo Vue desde un plano de Flask para separar parcialmente los dos

Diferentes formas de crear una aplicación web con Flask y Vue

Analizaremos los pros y los contras de cada método, veremos sus mejores casos de uso y detallaremos cómo configurar cada uno de ellos.

Plantilla Jinja

Independientemente de si está utilizando React, Vue o Angular, esta es la forma más fácil de hacer la transición al uso de un marco de front-end.

En muchos casos, cuando está creando un front-end para su aplicación web, lo diseña en torno al propio marco de front-end. Sin embargo, con este método, el enfoque sigue estando en su aplicación Flask de back-end. Todavía usará Jinja y las plantillas del lado del servidor junto con un poco de funcionalidad reactiva con Vue cuando lo necesite.

Puede importar la biblioteca de Vue a través de una red de entrega de contenido (CDN) o sirviéndola usted mismo junto con su aplicación, mientras configura y enruta Flask como lo haría normalmente.

ventajas

  • Puede crear su aplicación a su manera en lugar de adaptarla a la base de Vue.
  • La optimización de motores de búsqueda (SEO) no requiere ninguna configuración adicional.
  • Puede aprovechar la autenticación basada en cookies en lugar de la autenticación basada en token. Esto tiende a ser más fácil, ya que no se trata de una comunicación asíncrona entre el front-end y el back-end.

Contras

  • Debe importar Vue y configurar cada página individualmente, lo que puede ser difícil si comienza a agregar Vue a más y más páginas. También puede requerir una serie de soluciones alternativas, ya que no es realmente la forma prevista de usar Flask o Vue.

Mejor para

  • Pequeñas aplicaciones web que literalmente usan una sola página HTML o dos (a diferencia de un SPA con su propio enrutamiento dinámico; consulte el método SPA para obtener más información).
  • Construir funcionalidad en una aplicación web ya existente.
  • Agregar bits de reactividad a una aplicación sin comprometerse completamente con un marco de front-end.
  • Aplicaciones web que no necesitan comunicarse con tanta frecuencia con un back-end a través de AJAX.

dependencias adicionales

Este método solo requiere la biblioteca Vue, que puede agregar a través de un CDN:

<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>

Configuración

De todos los métodos, esta configuración es la más simple.

Cree una carpeta para guardar todo el código de su aplicación. Dentro de esa carpeta, crea un archivo app.py como lo harías normalmente:

from flask import Flask, render_template # These are all we need for our purposes

app = Flask(__name__)

@app.route("/")
def index():
    return render_template("index.html", **{"greeting": "Hello from Flask!"})

Solo necesitamos importar Flasky render_templatedesde flask.

La greetingvariable volverá a aparecer en un segundo cuando veamos cómo representar variables con Jinja y Vue en el mismo archivo.

A continuación, cree una carpeta de "plantillas" para guardar nuestro archivo HTML. Dentro de esa carpeta, cree un archivo index.html . En el cuerpo de nuestro archivo HTML, cree un contenedor div con una identificación de vm.

Vale la pena señalar que vmes solo un estándar de nomenclatura común. Significa ViewModel . Puedes nombrarlo como quieras; no necesita serlo vm.

Dentro de div, cree dos petiquetas para que sirvan como marcadores de posición para nuestras variables Flask y Vue:

  1. Una de las divs debe contener la palabra 'saludo' entre llaves: {{ greeting }}.
  2. El otro debe contener 'saludo' entre corchetes: [[ greeting ]].

Si no usa delimitadores separados, con la configuración predeterminada, Flask reemplazará ambos saludos con cualquier variable que le pase (es decir, "¡Hola desde Flask!").

Esto es lo que tenemos hasta ahora:

<body>
<!-- The id 'vm' is just for consistency - it can be anything you want -->
    <div id="vm">
        <p>{{ greeting }}</p>
        <p>[[ greeting ]]</p>
    </div>
</body>

Antes del final de la etiqueta del cuerpo, importe Vue desde la CDN oficial junto con un script para contener nuestro código JavaScript:

<body>
<!-- The id 'vm' is just for consistency - it can be anything you want -->
    <div id="vm">
        <p>{{ greeting }}</p>
        <p>[[ greeting ]]</p>
    </div>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <script src="{{ url_for('static', filename='index.js') }}"></script>
</body>

Navegando hacia arriba en un directorio, cree una carpeta "estática". Agregue un nuevo archivo JavaScript en esa carpeta llamado index.js .

En este archivo, cree el contexto de Vue, establezca nuestra instancia elcomo '#vm', cambie los delimitadores predeterminados de '{{', '}}'a '[[', ']]':

const vm = new Vue({ // Again, vm is our Vue instance's name for consistency.
    el: '#vm',
    delimiters: ['[[', ']]']
})

En realidad, podemos usar lo que queramos como delimitadores. De hecho, si lo prefiere, puede cambiar los delimitadores de sus plantillas Jinja en Flask.

Finalmente, agregue un elemento de datos con la clave/valor de greeting: 'Hello, Vue!':

const vm = new Vue({ // Again, vm is our Vue instance's name for consistency.
    el: '#vm',
    delimiters: ['[[', ']]'],
    data: {
        greeting: 'Hello, Vue!'
    }
})

Y ahora hemos terminado con ese archivo. Su estructura final de carpetas debería verse como:

├───app.py
├───static
│   └───index.js
└───templates
    └───index.html

Ahora puede volver a la carpeta del proyecto raíz y ejecutar la aplicación con flask run. Navegue al sitio en su navegador. La primera y segunda línea deberían haber sido reemplazadas por Flask y Vue, respectivamente:

Hello from Flask!
Hello, Vue!

¡Eso es todo! Puede mezclar y combinar puntos finales JSON y puntos finales HTML como desee, pero tenga en cuenta que esto puede ponerse muy feo muy rápidamente. Para una alternativa más manejable, consulte el método Flask Blueprint .

Con cada página HTML adicional, deberá importar el mismo archivo JavaScript y tener en cuenta las variables y elementos que pueden no aplicarse o crear un nuevo objeto Vue para cada página. Un verdadero SPA será difícil, pero no imposible: en teoría, podría escribir una pequeña biblioteca de JavaScript que capturará de forma asíncrona las páginas/elementos HTML servidos por Flask.

De hecho, he creado mi propia biblioteca de JavaScript para esto antes. Fue una gran molestia y, sinceramente, no valió la pena, especialmente teniendo en cuenta que JavaScript no ejecutará las etiquetas de script importadas de esta manera, a menos que usted mismo cree la funcionalidad. También estarás reinventando la rueda.

Si desea ver mi implementación de este método, puede encontrarlo en GitHub . La biblioteca toma una porción dada de HTML y reemplaza el HTML especificado en la página con él. Si el HTML dado no contiene <script>elementos (se verifica usando expresiones regulares), simplemente lo usa HTMLElement.innerHTMLpara reemplazarlo. Si contiene <script>elementos, agrega recursivamente los nodos, recreando cualquier <script>nodo que surja, permitiendo que su JavaScript se ejecute.

Using something like this in combination with the History API can help you build a small SPA with a very tiny file size. You can even create your own Server-Side Rendering (SSR) functionality by serving full HTML pages on page load and then serve up partial pages through AJAX requests. You can learn more about SSR in the SPA with Nuxt method.

Single-Page Application

If you want to build a fully dynamic web app with a seamless User Experience (UX), you can completely separate your Flask back-end from your Vue front-end. This may take learning a whole new way of thinking when it comes to web app design if you're not familiar with modern front-end frameworks.

Developing your app as a SPA may put a dent in your SEO. In the past, this hit would be much more dramatic, but updates to how Googlebot indexes sites have negated this at least somewhat. It may, however, still have a greater impact on non-Google search engines that don't render JavaScript or those that snapshot your page(s) too early -- the latter shouldn't happen if your website is well-optimized.

For more information on SEO in modern SPAs, this article on Medium shows how Googlebot indexes JavaScript-rendered sites. Additionally, this article talks in-depth about the same thing along with other helpful tips concerning SEO on other search engines.

With this method, you'll want to generate a completely separate Vue app using the Vue CLI tool. Flask will then be used to serve up a JSON RESTful API that your Vue SPA will communicate with via AJAX.

Pros

  • Your front- and back-end will be completely independent of each other, so you can make changes to one without it impacting the other.
    • This allows them to be deployed, developed, and maintained separately.
    • You can even set up a number of other front-ends to interact with your Flask API if you'd like.
  • Your front-end experience will be much smoother and more seamless.

Cons

  • There is much more to set up and learn.
  • Deployment is difficult.
  • SEO might suffer without further intervention (see the SPA with Nuxt method for more details).
  • La autenticación es mucho más complicada, ya que tendrá que seguir pasando su token de autenticación ( JWT o Paseto ) a su back-end.

Mejor para

  • Aplicaciones donde UX es más importante que SEO.
  • Back-ends que necesitan ser accesibles por múltiples front-ends.

dependencias adicionales

  • Nodo/npm
  • Vista CLI
  • Matraz-CORS

La implementación y la creación de contenedores están fuera del alcance de este artículo, pero no es muy difícil dockerizar esta configuración para simplificar la implementación.

Configuración

Debido a que estamos separando completamente Vue de Flask, este método requiere un poco más de configuración. Tendremos que habilitar el intercambio de recursos de origen cruzado (CORS) en Flask, ya que nuestro front-end y back-end se servirán en puertos separados. Para lograr esto rápida y fácilmente, usaremos el paquete Flask-CORS Python.

Por razones de seguridad, los navegadores web modernos no permiten que JavaScript del lado del cliente acceda a recursos (como datos JSON) desde un origen diferente al origen en el que se encuentra su secuencia de comandos, a menos que incluyan un encabezado de respuesta específico que informe al navegador que está bien.

Si aún no ha instalado Flask-CORS, hágalo con pip.

Empecemos con nuestra Flask API.

Primero, cree una carpeta para guardar el código de su proyecto. Dentro, crea una carpeta llamada "api". Cree un archivo app.py en la carpeta. Abre el archivo con tu editor de texto favorito. Esta vez necesitaremos importar Flaskdesde flasky CORSdesde flask_cors. Debido a que estamos usando flask_corspara habilitar el uso compartido de recursos de origen cruzado, envuelva el objeto de la aplicación (sin configurar una nueva variable) con CORS: CORS(app). Eso es todo lo que tenemos que hacer para habilitar CORS en todas nuestras rutas para cualquier origen.

Aunque esto está bien para fines de demostración, probablemente no querrá que cualquier aplicación o sitio web pueda acceder a su API. En ese caso, puede usar los 'orígenes' de kwarg con la función CORS para agregar una lista de orígenes aceptables, es decir,CORS(app, origins=["origin1", "origin2"])

Para obtener más información sobre el uso compartido de recursos de origen cruzado, MDN tiene una excelente documentación al respecto.

Por último, cree una única ruta de saludo /greetingpara devolver un objeto JSON con una sola clave/valor:

{"greeting": "Hello from Flask!"}

Esto es con lo que deberías haber terminado:

from flask import Flask
from flask_cors import CORS

app = Flask(__name__)
CORS(app)

@app.route("/greeting")
def greeting():
    return {"greeting": "Hello from Flask!"}

Eso es todo lo que necesitamos hacer con Python.

A continuación, configuraremos nuestra aplicación web Vue. Desde una terminal, abra la carpeta raíz de su proyecto. Con la CLI de Vue, cree un proyecto de Vue llamado "webapp" ( vue create webapp). Puede usar prácticamente cualquier opción que desee, pero si usa componentes basados ​​en clases en TypeScript, la sintaxis se verá un poco diferente.

Cuando termine de crear su proyecto, abra App.vue .

Dado que nuestro objetivo es solo ver cómo Vue y Flask interactúan entre sí, en la parte superior de la página, elimine todos los elementos dentro del divcon la identificación de app. Solo debes quedarte con:

<template>
<div id="app">
</div>
</template>

Dentro #appde , crea dos pelementos:

  1. El contenido de la primera debe ser {{ greeting }}.
  2. El contenido de la segunda debe ser {{ flaskGreeting }}.

Su HTML final debe ser como tal:

<template>
<div id="app">
    <p>{{ greeting }}</p>
    <p>{{ flaskGreeting }}</p>
</div>
</template>

En nuestro script, agreguemos lógica para mostrar un saludo puramente del lado del cliente ( greeting) y un saludo extraído de nuestra API ( flaskGreeting).

Dentro del objeto Vue (comienza con export default), cree una dataclave. Conviértalo en una función que devuelva un objeto. Luego, dentro de este objeto, cree dos claves más: greetingy flaskGreeting. greetingEl valor de debe ser 'Hello, Vue!'mientras que flaskGreetingel de debe ser una cadena vacía.

Esto es lo que tenemos hasta ahora:

export default {
    name: 'App',
    components: {
        HelloWorld
    },
    data: function(){
        return {
            greeting: 'Hello, Vue!',
            flaskGreeting: ''
        }
    }
}

Finalmente, demos a nuestro objeto Vue un createdgancho de ciclo de vida. Este enlace solo se ejecutará una vez que se cargue el DOM y se cree nuestro objeto Vue. Esto nos permite usar la fetchAPI e interactuar con Vue sin que nada choque:

export default {
    components: {
        Logo
    },
    data: function(){
        return {
            greeting: 'Hello, Vue!',
            flaskGreeting: ''
        }
    },
    created: async function(){
        const gResponse = await fetch("http://localhost:5000/greeting");
        const gObject = await gResponse.json();
        this.flaskGreeting = gObject.greeting;
    }
}

Mirando el código, estamos awaitenviando una respuesta al punto final de 'saludo' de nuestra API ( http://localhost:5000/greeting), awaitenviando la respuesta asíncrona de esa respuesta .json()y configurando la variable de nuestro objeto Vue flaskGreetingal valor del objeto JSON devuelto para su greetingclave.

Para aquellos que no están familiarizados con la API Fetch relativamente nueva de JavaScript , es básicamente un asesino nativo de AXIOS (al menos en lo que respecta al lado del cliente, no es compatible con Node, pero lo será con Deno ). Además, si le gusta la consistencia, también puede consultar el paquete isomorphic-fetch para usar Fetch en el lado del servidor.

Y hemos terminado. Ahora, debido a que, nuevamente, nuestro front-end y back-end están separados, necesitaremos ejecutar ambas aplicaciones por separado.

Abramos la carpeta raíz de nuestro proyecto en dos ventanas de terminal separadas.

En el primero, cambie al directorio "api" y luego ejecute flask run. Si todo va bien, la API de Flask debería estar ejecutándose. En la segunda terminal, cambie al directorio "webapp" y ejecute npm run serve.

Una vez que la aplicación Vue esté activa, debería poder acceder a ella desde localhost:8080. Si todo funciona, debería ser recibido dos veces, una vez por Vue y otra vez por la API de Flask:

Hello, Vue!
Hello from Flask!

Su árbol de archivos final debería verse así:

├───app.py
├───api
│   └───app.py
└───webapp
    ... {{ Vue project }}

Solicitud de una sola página con Nuxt

Si el SEO es tan importante para usted como UX, es posible que desee implementar la representación del lado del servidor (SSR) en algún formato.

SSR facilita que los motores de búsqueda naveguen e indexen su aplicación Vue, ya que podrá darles una forma de su aplicación que no requiere JavaScript para generarse. También puede hacer que sea más rápido para los usuarios interactuar con su aplicación, ya que gran parte de su contenido inicial se procesará antes de que se les envíe. En otras palabras, los usuarios no tendrán que esperar a que todo su contenido se cargue de forma asíncrona.

Una aplicación de una sola página con representación del lado del servidor también se denomina aplicación universal.

Aunque es posible implementar SSR manualmente, usaremos Nuxt en este artículo; simplifica mucho las cosas.

Al igual que con el método SPA , su front-end y back-end estarán completamente separados; simplemente usará Nuxt en lugar de Vue CLI.

ventajas

  • Todas las ventajas del método SPA con la incorporación de la representación del lado del servidor.

Contras

  • Casi tan difícil de configurar como el método SPA .
  • Conceptualmente, hay aún más que aprender, ya que Nuxt es esencialmente solo otra capa sobre Vue.

Mejor para

  • Aplicaciones donde el SEO es tan importante como la UX.

dependencias adicionales

  1. Nodo/npm
  2. Siguiente
  3. Matraz-CORS

Configuración

Esto va a ser muy similar al método SPA . De hecho, la porción de Frasco es exactamente la misma. Síguelo hasta que hayas creado tu Flask API.

Una vez que su API haya terminado, dentro de su terminal, abra la carpeta raíz de su proyecto y ejecute el comando npx create-nuxt-app webapp. Esto le permitirá generar de forma interactiva un nuevo proyecto de Nuxt sin instalar ninguna dependencia global.

Cualquier opción debería estar bien aquí.

Una vez que su proyecto haya terminado de generarse, sumérjase en su nueva carpeta "webapp". Dentro de la carpeta "páginas", abra index.vue en su editor de texto. Del mismo modo, elimine todo lo divque tenga la clase container. Dentro de div, cree dos petiquetas con las mismas variables: {{ greeting }}y {{ flaskGreeting }}.

Debe tener un aspecto como este:

<template>
<div class="container">
    <p>{{ greeting }}</p>
    <p>{{ flaskGreeting }}</p>
</div>
</template>

Y ahora nuestro script:

  • Agregue una dataclave que devuelva un objeto con las variables greetingyflaskGreeting
  • Agregue un createdgancho de ciclo de vida:
    • await fetchpara obtener el saludo JSON de nuestra API (en el puerto 5000 a menos que lo haya cambiado)
    • awaitel json()método para obtener de forma asincrónica nuestros datos JSON a partir de la respuesta de nuestra API
    • Establezca nuestra instancia de Vue flaskGreetingen la greetingclave del objeto JSON de nuestra respuesta

El objeto Vue debería verse así:

export default {
    components: {
        Logo
    },
    data: function(){
        return {
            greeting: 'Hello, Vue!',
            flaskGreeting: ''
        }
    },
    created: async function(){
        const gResponse = await fetch("http://localhost:5000/greeting");
        const gObject = await gResponse.json();
        this.flaskGreeting = gObject.greeting;
    }
}

Ejecutar la aplicación Nuxt/Vue y Flask API también se verá muy similar al método SPA .

Abra dos ventanas de terminal. En el primero, cambie a "api" y ejecute el flask runcomando. En el segundo, cambie a "webapp" y ejecute npm run devpara iniciar un servidor de desarrollo para su proyecto Nuxt.

Una vez que la aplicación Nuxt esté activa, debería poder acceder a ella desde localhost:3000:

Hello, Vue!
Hello from Flask!

En producción, puede ejecutar npm run buildy luego npm run startiniciar un servidor de producción.

Nuestro árbol final:

├───app.py
├───api
│   └───app.py
└───webapp
    ... {{ Nuxt project }}

BONIFICACIÓN: Comparación de SEO entre Vue y Nuxt

Mencioné los beneficios del SEO anteriormente en este artículo, pero solo para mostrarle lo que quise decir, ejecuté ambas aplicaciones web tal cual y obtuve los puntajes de Lighthouse SEO para ambos.

Sin cambios en ninguna de las aplicaciones, esto es lo que tenemos:

Puntuaciones de Lighthouse SEO para nuestra aplicación Vue y Nuxt

Nuevamente, hay cosas que puede hacer para mejorar su puntaje puro de Vue SEO. Lighthouse en las herramientas de desarrollo de Chrome menciona agregar una meta descripción, pero sin intervención adicional, Nuxt nos dio un puntaje de SEO perfecto.

Además, puede ver la diferencia entre el SSR que hace Nuxt y el enfoque completamente asincrónico de Vanilla Vue. Si ejecuta ambas aplicaciones al mismo tiempo, navegue a sus respectivos orígenes localhost:8080y localhost:3000, el saludo inicial de la aplicación Vue ocurre milisegundos después de recibir la respuesta, mientras que Nuxt se sirve con su saludo inicial ya representado.

Para obtener más información sobre las diferencias entre Nuxt y Vue, puede consultar estos artículos:

  1. Nuxt.js sobre Vue.js: cuándo debería usarlo y por qué
  2. Cómo Nuxt.js resuelve los problemas de SEO en Vue.js.

Plano de matraz

Tal vez ya haya desarrollado una pequeña aplicación Flask y desee crear una aplicación Vue más como un medio para lograr un fin que como el evento principal.

Ejemplos:

  1. Prototipo para demostrar la funcionalidad a su empleador o cliente (siempre puede reemplazarlo o entregárselo a un desarrollador front-end más adelante).
  2. Simplemente no quiere lidiar con la frustración potencial que podría resultar al implementar un front-end y un back-end completamente separados.

En ese caso, podría reunirse en el medio manteniendo su aplicación Flask, pero construyendo un front-end Vue dentro de su propio modelo Flask.

Esto se parecerá mucho al método Plantilla Jinja , pero el código estará más organizado.

ventajas

  • No es necesario crear un front-end complejo si no es necesario.
  • Similar al método de plantilla Jinja con el beneficio adicional de una mejor organización del código.
  • Siempre puede expandir el front-end y el back-end según sea necesario más adelante.

Contras

  • Es posible que se necesiten soluciones alternativas para permitir un SPA completo.
  • Acceder a la API puede ser un poco más molesto desde un front-end separado (como una aplicación móvil) ya que el front-end y el back-end no están completamente separados.

Mejor para

  • Proyectos donde la funcionalidad es más importante que la interfaz de usuario.
  • Está creando un front-end en una aplicación Flask ya existente.
  • Pequeñas aplicaciones web que se componen de solo un par de páginas HTML.

dependencias adicionales

De manera similar al método de plantilla Jinja , usaremos un CDN para extraer la biblioteca Vue:

<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>

Configuración

Al igual que los otros métodos, cree una nueva carpeta para alojar su código. Dentro de él, cree dos carpetas: "api" y "cliente". Intuitivamente, estos contendrán los planos para nuestra API y cliente (Vue), respectivamente.

Vamos a sumergirnos en la carpeta "api".

Crea un archivo llamado api.py. Esto contendrá todo el código asociado con nuestra API. Además, debido a que accederemos a este archivo/carpeta como un módulo, cree un archivo __init__.py :

from flask import Blueprint

api_bp = Blueprint('api_bp', __name__) # "API Blueprint"

@api_bp.route("/greeting") # Blueprints don't use the Flask "app" context. They use their own blueprint's
def greeting():
    return {'greeting': 'Hello from Flask!'}

El primer argumento Blueprintes para el sistema de enrutamiento de Flask. El segundo, __name__, es equivalente al primer argumento de una aplicación Flask ( Flask(__name__)).

Y eso es todo con nuestro modelo de API.

Bueno. Sumerjámonos en la carpeta "cliente" que creamos anteriormente. Este va a ser un poco más complicado que nuestro modelo de API, pero no más complicado que una aplicación Flask normal.

Nuevamente, como una aplicación Flask normal, dentro de esta carpeta, cree una carpeta "estática" y una carpeta de "plantillas". Cree un archivo llamado client.py y ábralo en su editor de texto.

Esta vez, le pasaremos algunos argumentos más a nuestro Blueprintpara que sepa dónde encontrar las plantillas y los archivos estáticos correctos:

client_bp = Blueprint('client_bp', __name__, # 'Client Blueprint'
    template_folder='templates', # Required for our purposes
    static_folder='static', # Again, this is required
    static_url_path='/client/static' # Flask will be confused if you don't do this
)

Agregue la ruta también para servir la plantilla index.html :

from flask import Blueprint, render_template

client_bp = Blueprint("client_bp", __name__, # 'Client Blueprint'
    template_folder="templates", # Required for our purposes
    static_folder="static", # Again, this is required
    static_url_path="/client/static" # Flask will be confused if you don't do this
)

@client_bp.route("/")
def index():
    return render_template("index.html")

Excelente. Nuestro modelo de cliente ya está terminado. Salga del archivo y diríjase a la carpeta de "plantillas" del plano. Cree un archivo index.html :

<body>
<!-- The id 'vm' is just for consistency - it can be anything you want -->
    <div id="vm" class="container">
        <p>[[ greeting ]]</p>
        <p>[[ flaskGreeting ]]</p>
    </div>
    <script src="https://cdn.jsdelivr.net/npm/vue@2.6.11"></script>
    <script src="{{ url_for('client_bp.static', filename='index.js') }}"></script>
</body>

¿Te diste cuenta de que estamos usando corchetes en lugar de llaves? Es porque necesitamos cambiar los delimitadores para evitar que Flask los atrape primero.

greetingVue lo procesará tan pronto como esté listo, mientras flaskGreetingque se tomará de una respuesta de Flask que solicitaremos de forma asíncrona.

Hecho. Agregue un nuevo archivo a la carpeta "estática" llamada index.js . Cree una variable llamada apiEndpointy configúrela en api_v1. Esto solo hace que todo esté un poco más SECO si decidimos cambiar nuestro punto final más adelante:

const apiEndpoint = '/api_v1/';

Todavía no hemos creado la lógica para nuestro punto final. Eso vendrá en el último paso.

A continuación, comience haciendo que el contexto de Vue se vea idéntico al contexto en el método de la plantilla de Jinja :

const apiEndpoint = '/api_v1/';

const vm = new Vue({ // Again, vm is our Vue instance's name for consistency.
    el: '#vm',
    delimiters: ['[[', ']]'],
    data: {
        greeting: 'Hello, Vue!'
    }
})

Nuevamente, creamos el contexto de Vue, configuramos nuestra instancia elcomo '#vm', cambiamos los delimitadores predeterminados de '{{', '}}'a '[[', ']]'y agregamos un elemento de datos con la clave/valor de greeting: 'Hello, Vue!'.

Debido a que también vamos a obtener un saludo de nuestra API, cree un marcador de posición de datos llamado flaskGreetingcon el valor de una cadena vacía:

const apiEndpoint = '/api_v1/';

const vm = new Vue({
    el: '#vm',
    delimiters: ['[[', ']]'],
    data: {
        greeting: 'Hello, Vue!',
        flaskGreeting: ''
    }
})

Démosle a nuestro objeto Vue un enlace de ciclo de createdvida asíncrono:

const apiEndpoint = '/api_v1/';

const vm = new Vue({
    el: '#vm',
    delimiters: ['[[', ']]'],
    data: {
        greeting: 'Hello, Vue!',
        flaskGreeting: ''
    },
    created: async function(){
        const gResponse = await fetch(apiEndpoint + 'greeting');
        const gObject = await gResponse.json();
        this.flaskGreeting = gObject.greeting;
    }
})

Mirando el código, estamos awaitenviando una respuesta desde el punto final de 'saludo' de nuestra API ( /api_v1/greeting), awaitenviando la respuesta asincrónica de esa respuesta .json()y configurando la variable de nuestro objeto Vue flaskGreetingal valor del objeto JSON devuelto para su greetingclave. Es básicamente una mezcla entre los objetos Vue de los métodos 1 y 2.

Excelente. Solo queda una cosa por hacer: juntemos todo agregando un app.py a la raíz del proyecto. Dentro del archivo, importe flaskjunto con los planos:

from flask import Flask
from api.api import api_bp
from client.client import client_bp

Cree una aplicación Flask como lo haría normalmente y registre los planos usando app.register_blueprint():

from flask import Flask
from api.api import api_bp
from client.client import client_bp

app = Flask(__name__)
app.register_blueprint(api_bp, url_prefix='/api_v1')
app.register_blueprint(client_bp)

Árbol de archivos final:

├───app.py
├───api
│   └───__init__.py
│   └───api.py
└───client
    ├───__init__.py
    ├───static
    │   └───index.js
    └───templates
        └───index.html

¡Y eso es! Si ejecuta su nueva aplicación con flask runusted, debería ser recibido dos veces: una vez por Vue y otra vez por una respuesta de su Flask API.

Resumen

Hay muchas, muchas formas diferentes de crear una aplicación web con Vue y Flask. Todo depende de su situación actual.

Algunas preguntas para hacer:

  1. ¿Qué tan importante es el SEO?
  2. ¿Cómo es su equipo de desarrollo? Si no tiene un equipo de DevOps, ¿desea asumir la complejidad adicional de tener que implementar el front-end y el back-end por separado?
  3. ¿Estás haciendo prototipos rápidos?

Con suerte, este artículo lo guiará en la dirección correcta, brindándole una idea sobre cómo combinar sus aplicaciones Vue y Flask.

Puede obtener el código final del repositorio combine-flask-with-vue en GitHub.

Fuente:  https://testdriven.io

#vue #flask 

¿Cómo Puedo Combinar Vue.js Con Flask?
Callum  Allen

Callum Allen

1660394460

Como Posso Combinar O Vue.js Com O Flask?

Combinando Flask e Vue

Então você finalmente tem o Flask em seu currículo e não é estranho ao JavaScript. Você até desenvolveu alguns aplicativos da web, mas começa a perceber algo - você tem uma excelente funcionalidade, mas seu UX é meio sem graça. Onde está o fluxo de aplicativos e a navegação perfeita que você vê em muitos sites e aplicativos populares hoje? Como isso pode ser alcançado?

À medida que você investe mais em seus sites e aplicativos da Web, provavelmente desejará adicionar mais funcionalidade e reatividade do lado do cliente a eles. O desenvolvimento web moderno normalmente consegue isso através do uso de frameworks front-end, e um desses frameworks que está crescendo rapidamente em popularidade é o Vue (também conhecido como Vue.js ou VueJS).

Dependendo dos requisitos do seu projeto, existem algumas maneiras diferentes de construir uma aplicação web com Flask e Vue, e cada uma delas envolve vários níveis de separação back-end/front-end.

Neste artigo, veremos três métodos diferentes para combinar o Flask e o Vue:

  1. Modelo Jinja : Importando Vue para um modelo Jinja
  2. Aplicativo de página única : Construindo um aplicativo de página única (SPA) para separar completamente o Flask e o Vue
  3. Flask Blueprint : Servindo o Vue de um blueprint do Flask para separar parcialmente os dois

Diferentes maneiras de construir um aplicativo Web com Flask e Vue

Analisaremos os prós e os contras de cada método, analisaremos seus melhores casos de uso e detalharemos como configurar cada um deles.

Modelo Jinja

Independentemente de você estar usando React, Vue ou Angular, essa é a maneira mais fácil de fazer a transição para um framework front-end.

Em muitos casos, quando você está criando um front-end para seu aplicativo Web, você o projeta em torno da própria estrutura de front-end. Com esse método, no entanto, o foco ainda está no aplicativo Flask de back-end. Você ainda usará Jinja e templates do lado do servidor, juntamente com um pouco de funcionalidade reativa com o Vue, se e quando precisar.

Você pode importar a biblioteca Vue por meio de uma Content Delivery Network (CDN) ou servindo você mesmo junto com seu aplicativo, enquanto configura e roteia o Flask como faria normalmente.

Prós

  • Você pode construir seu aplicativo do seu jeito em vez de encaixá-lo na base do Vue.
  • Search Engine Optimization (SEO) não requer nenhuma configuração adicional.
  • Você pode aproveitar a autenticação baseada em cookie em vez da autenticação baseada em token. Isso tende a ser mais fácil, pois você não está lidando com comunicação assíncrona entre o front-end e o back-end.

Contras

  • Você precisa importar o Vue e configurar cada página individualmente, o que pode ser difícil se você começar a adicionar o Vue a mais e mais páginas. Também pode exigir várias soluções alternativas, pois não é realmente a maneira pretendida de usar o Flask ou o Vue.

Melhor para

  • Pequenos aplicativos da Web usando literalmente uma única página HTML ou duas (em oposição a um SPA com seu próprio roteamento dinâmico - consulte o método SPA para obter mais informações).
  • Construindo funcionalidade em um aplicativo da web já existente.
  • Adicionando bits de reatividade a um aplicativo sem se comprometer totalmente com uma estrutura de front-end.
  • Aplicativos da Web que não precisam se comunicar com tanta frequência com um back-end via AJAX.

Dependências Adicionais

Este método requer apenas a biblioteca Vue, que você pode adicionar por meio de um CDN:

<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>

Configurar

De todos os métodos, esta configuração é a mais simples.

Crie uma pasta para armazenar todo o código do seu aplicativo. Dentro dessa pasta, crie um arquivo app.py como faria normalmente:

from flask import Flask, render_template # These are all we need for our purposes

app = Flask(__name__)

@app.route("/")
def index():
    return render_template("index.html", **{"greeting": "Hello from Flask!"})

Só precisamos importar Flaske render_templatede flask.

A greetingvariável aparecerá novamente em um segundo quando observarmos como renderizar variáveis ​​com Jinja e Vue no mesmo arquivo.

Em seguida, crie uma pasta "templates" para armazenar nosso arquivo HTML. Dentro dessa pasta, crie um arquivo index.html . No corpo do nosso arquivo HTML, crie um container div com um id de vm.

Vale a pena notar que vmé apenas um padrão de nomenclatura comum. Significa ViewModel . Você pode nomeá-lo como quiser; não precisa ser vm.

Dentro do div, crie duas ptags para servir como placeholders para nossas variáveis ​​Flask e Vue:

  1. Um dos divs deve conter a palavra 'saudação' entre chaves: {{ greeting }}.
  2. O outro deve conter 'saudação' entre colchetes: [[ greeting ]].

Se você não usar delimitadores separados, com a configuração padrão, o Flask substituirá ambas as saudações por qualquer variável que você passar com ela (ou seja, "Olá do Flask!").

Aqui está o que temos até agora:

<body>
<!-- The id 'vm' is just for consistency - it can be anything you want -->
    <div id="vm">
        <p>{{ greeting }}</p>
        <p>[[ greeting ]]</p>
    </div>
</body>

Antes do final da tag body, importe o Vue da CDN oficial junto com um script para armazenar nosso código JavaScript:

<body>
<!-- The id 'vm' is just for consistency - it can be anything you want -->
    <div id="vm">
        <p>{{ greeting }}</p>
        <p>[[ greeting ]]</p>
    </div>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <script src="{{ url_for('static', filename='index.js') }}"></script>
</body>

Navegando em um diretório, crie uma pasta "estática". Adicione um novo arquivo JavaScript nessa pasta chamado index.js .

Neste arquivo, crie o contexto Vue, defina nossa instância elcomo '#vm', altere os delimitadores padrão de '{{', '}}'para '[[', ']]':

const vm = new Vue({ // Again, vm is our Vue instance's name for consistency.
    el: '#vm',
    delimiters: ['[[', ']]']
})

Na realidade, podemos usar o que quisermos como nossos delimitadores. Na verdade, se for sua preferência, você pode alterar os delimitadores dos seus modelos Jinja no Flask.

Por fim, adicione um elemento de dados com a chave/valor de greeting: 'Hello, Vue!':

const vm = new Vue({ // Again, vm is our Vue instance's name for consistency.
    el: '#vm',
    delimiters: ['[[', ']]'],
    data: {
        greeting: 'Hello, Vue!'
    }
})

E agora terminamos com esse arquivo. Sua estrutura de pastas final deve ser algo como:

├───app.py
├───static
│   └───index.js
└───templates
    └───index.html

Agora você pode voltar para a pasta raiz do projeto e executar o aplicativo com flask run. Navegue até o site em seu navegador. A primeira e a segunda linha deveriam ter sido substituídas por Flask e Vue, respectivamente:

Hello from Flask!
Hello, Vue!

É isso! Você pode misturar e combinar endpoints JSON e endpoints HTML como quiser, mas esteja ciente de que isso pode ficar muito feio muito rapidamente. Para uma alternativa mais gerenciável, consulte o método Flask Blueprint .

Com cada página HTML adicional, você terá que importar o mesmo arquivo JavaScript e considerar variáveis ​​e elementos que podem não se aplicar a ele ou criar um novo objeto Vue para cada página. Um verdadeiro SPA será difícil, mas não impossível -- teoricamente, você poderia escrever uma pequena biblioteca JavaScript que capturaria de forma assíncrona as páginas/elementos HTML servidos pelo Flask.

Na verdade, criei minha própria biblioteca JavaScript para isso antes. Foi um grande aborrecimento e honestamente não vale a pena, especialmente considerando que o JavaScript não executará tags de script importadas dessa maneira, a menos que você mesmo crie a funcionalidade. Você também estará reinventando a roda.

Se você quiser conferir minha implementação desse método, você pode encontrá-lo no GitHub . A biblioteca pega um determinado pedaço de HTML e substitui o HTML especificado na página por ele. Se o HTML fornecido não contém <script>elementos (ele verifica usando regex), ele simplesmente usa HTMLElement.innerHTMLpara substituí-lo. Se contiver <script>elementos, ele adicionará recursivamente os nós, recriando quaisquer <script>nós que surgirem, permitindo que seu JavaScript seja executado.

Usar algo assim em combinação com a API de histórico pode ajudá-lo a criar um pequeno SPA com um tamanho de arquivo muito pequeno. Você pode até mesmo criar sua própria funcionalidade Server-Side Rendering (SSR) servindo páginas HTML completas no carregamento da página e, em seguida, servindo páginas parciais por meio de solicitações AJAX. Você pode aprender mais sobre SSR no SPA com método Nuxt .

Aplicativo de página única

Se você deseja criar um aplicativo da Web totalmente dinâmico com uma experiência do usuário (UX) perfeita, pode separar completamente o back-end do Flask do front-end do Vue. Isso pode exigir o aprendizado de uma maneira totalmente nova de pensar quando se trata de design de aplicativos da Web, se você não estiver familiarizado com estruturas de front-end modernas.

Desenvolver seu aplicativo como um SPA pode prejudicar seu SEO. No passado, esse impacto seria muito mais dramático, mas as atualizações de como os sites de índices do Googlebot negaram isso pelo menos um pouco. No entanto, ainda pode ter um impacto maior em mecanismos de pesquisa que não são do Google que não renderizam JavaScript ou que capturam suas páginas muito cedo - o último não deve acontecer se seu site estiver bem otimizado.

Para obter mais informações sobre SEO em SPAs modernos, este artigo no Medium mostra como o Googlebot indexa sites renderizados por JavaScript. Além disso, este artigo fala em profundidade sobre a mesma coisa, juntamente com outras dicas úteis sobre SEO em outros mecanismos de pesquisa.

Com este método, você desejará gerar um aplicativo Vue completamente separado usando a ferramenta Vue CLI . O Flask será então usado para servir uma API JSON RESTful com a qual seu Vue SPA se comunicará via AJAX.

Prós

  • Seu front-end e back-end serão completamente independentes um do outro, para que você possa fazer alterações em um sem afetar o outro.
    • Isso permite que eles sejam implantados, desenvolvidos e mantidos separadamente.
    • Você pode até configurar vários outros front-ends para interagir com sua API Flask, se desejar.
  • Sua experiência de front-end será muito mais suave e perfeita.

Contras

  • Há muito mais para configurar e aprender.
  • A implantação é difícil.
  • O SEO pode sofrer sem intervenção adicional (consulte o método SPA com Nuxt para obter mais detalhes).
  • A autenticação é muito mais complexa, pois você terá que continuar passando seu token de autenticação ( JWT ou Paseto ) para seu back-end.

Melhor para

  • Apps onde UX é mais importante que SEO.
  • Back-ends que precisam ser acessíveis por vários front-ends.

Dependências Adicionais

  • Nó/npm
  • Visualização CLI
  • Frasco-CORS

A implantação e a conteinerização estão fora do escopo deste artigo, mas não é muito difícil Dockerizar essa configuração para simplificar a implantação.

Configurar

Como estamos separando completamente o Vue do Flask, esse método requer um pouco mais de configuração. Precisaremos habilitar o Cross-Origin Resource Sharing (CORS) no Flask, pois nosso front-end e back-end serão servidos em portas separadas. Para fazer isso de maneira rápida e fácil, usaremos o pacote Flask-CORS Python.

Por motivos de segurança, os navegadores da Web modernos não permitem que o JavaScript do lado do cliente acesse recursos (como dados JSON) de uma origem diferente da origem em que seu script está, a menos que incluam um cabeçalho de resposta específico informando ao navegador que está tudo bem.

Se você ainda não instalou o Flask-CORS, faça-o com pip.

Vamos começar com nossa API Flask.

Primeiro, crie uma pasta para armazenar o código do seu projeto. Dentro, crie uma pasta chamada "api". Crie um arquivo app.py na pasta. Abra o arquivo com seu editor de texto favorito. Desta vez, precisaremos importar Flaskde flaske CORSde flask_cors. Como estamos usando flask_corspara habilitar o compartilhamento de recursos entre origens, envolva o objeto do aplicativo (sem definir uma nova variável) com CORS: CORS(app). Isso é tudo o que precisamos fazer para habilitar o CORS em todas as nossas rotas para qualquer origem.

Embora isso seja bom para fins de demonstração, você provavelmente não desejará que qualquer aplicativo ou site possa acessar sua API. Nesse caso, você pode usar as 'origens' do kwarg com a função CORS para adicionar uma lista de origens aceitáveis ​​-- ou seja,CORS(app, origins=["origin1", "origin2"])

Para obter mais informações sobre o compartilhamento de recursos entre origens, o MDN tem uma ótima documentação sobre isso.

Por fim, crie uma única rota de saudação em /greetingpara retornar um objeto JSON com uma única chave/valor:

{"greeting": "Hello from Flask!"}

Aqui está o que você deveria ter acabado com:

from flask import Flask
from flask_cors import CORS

app = Flask(__name__)
CORS(app)

@app.route("/greeting")
def greeting():
    return {"greeting": "Hello from Flask!"}

Isso é tudo o que precisamos fazer com o Python.

Em seguida, vamos configurar nosso webapp Vue. A partir de um terminal, abra a pasta raiz do seu projeto. Usando a CLI do Vue, crie um projeto Vue chamado "webapp" ( vue create webapp). Você pode usar praticamente qualquer opção que desejar, mas se estiver usando componentes baseados em classe no TypeScript, a sintaxe parecerá um pouco diferente.

Quando seu projeto terminar de ser criado, abra App.vue .

Como nosso objetivo é apenas ver como o Vue e o Flask interagem entre si, na parte superior da página, exclua todos os elementos dentro do divcom o id de app. Você deve ficar apenas com:

<template>
<div id="app">
</div>
</template>

Dentro #appde , crie dois pelementos:

  1. O conteúdo do primeiro deve ser {{ greeting }}.
  2. O conteúdo do segundo deve ser {{ flaskGreeting }}.

Seu HTML final deve ser assim:

<template>
<div id="app">
    <p>{{ greeting }}</p>
    <p>{{ flaskGreeting }}</p>
</div>
</template>

Em nosso script, vamos adicionar lógica para mostrar uma saudação puramente do lado do cliente ( greeting) e uma saudação extraída de nossa API ( flaskGreeting).

Dentro do objeto Vue (começa com export default), crie uma datachave. Torná-lo uma função que retorna um objeto. Então, dentro desse objeto, crie mais duas chaves: greetinge flaskGreeting. greetingO valor de 's deve ser 'Hello, Vue!'enquanto flaskGreeting's deve ser uma string vazia.

Aqui está o que temos até agora:

export default {
    name: 'App',
    components: {
        HelloWorld
    },
    data: function(){
        return {
            greeting: 'Hello, Vue!',
            flaskGreeting: ''
        }
    }
}

Finalmente, vamos dar ao nosso objeto Vue um createdgancho de ciclo de vida. Este hook só será executado quando o DOM for carregado e nosso objeto Vue for criado. Isso nos permite usar a fetchAPI e interagir com o Vue sem nenhum conflito:

export default {
    components: {
        Logo
    },
    data: function(){
        return {
            greeting: 'Hello, Vue!',
            flaskGreeting: ''
        }
    },
    created: async function(){
        const gResponse = await fetch("http://localhost:5000/greeting");
        const gObject = await gResponse.json();
        this.flaskGreeting = gObject.greeting;
    }
}

Observando o código, estamos awaitenviando uma resposta para o endpoint 'greeting' da nossa API ( http://localhost:5000/greeting), awaitrespondendo a resposta assíncrona dessa resposta .json()e definindo a flaskGreetingvariável do nosso objeto Vue para o valor do objeto JSON retornado para sua greetingchave.

Para aqueles que não estão familiarizados com a API Fetch relativamente nova do JavaScript , é basicamente um assassino AXIOS nativo (pelo menos no que diz respeito ao lado do cliente - não é suportado pelo Node, mas será pelo Deno ). Além disso, se você gosta de consistência, também pode verificar o pacote isomorphic-fetch para usar o Fetch no lado do servidor.

E nós terminamos. Agora, como, novamente, nosso front-end e back-end são separados, precisaremos executar os dois aplicativos separadamente.

Vamos abrir a pasta raiz do nosso projeto em duas janelas de terminal separadas.

No primeiro, mude para o diretório "api" e execute o flask run. Se tudo correr bem, a API do Flask deve estar em execução. No segundo terminal, mude para o diretório "webapp" e execute npm run serve.

Quando o aplicativo Vue estiver ativo, você poderá acessá-lo de localhost:8080. Se tudo funcionar, você deve ser saudado duas vezes -- uma vez pelo Vue, e novamente pela sua API Flask:

Hello, Vue!
Hello from Flask!

Sua árvore de arquivos final deve se parecer com:

├───app.py
├───api
│   └───app.py
└───webapp
    ... {{ Vue project }}

Aplicativo de página única com Nuxt

Se SEO é tão importante para você quanto UX, você pode querer implementar Server-Side Rendering (SSR) em algum formato.

O SSR torna mais fácil para os mecanismos de pesquisa navegar e indexar seu aplicativo Vue, pois você poderá fornecer a eles uma forma de seu aplicativo que não requer JavaScript para gerar. Também pode agilizar a interação dos usuários com seu aplicativo, pois grande parte do seu conteúdo inicial será renderizado antes de ser enviado a eles. Em outras palavras, os usuários não precisarão esperar que todo o seu conteúdo seja carregado de forma assíncrona.

Um aplicativo de página única com renderização no lado do servidor também é chamado de aplicativo universal.

Embora seja possível implementar o SSR manualmente, usaremos o Nuxt neste artigo; simplifica muito as coisas.

Assim como no método SPA , seu front-end e back-end serão completamente separados; você usará apenas o Nuxt em vez do Vue CLI.

Prós

  • Todos os prós do método SPA com a adição do Server-Side Rendering.

Contras

  • Tão difícil de configurar quanto o método SPA .
  • Conceitualmente, há ainda mais a aprender, pois o Nuxt é essencialmente apenas mais uma camada no topo do Vue.

Melhor para

  • Apps onde SEO é tão importante quanto UX.

Dependências Adicionais

  1. Nó/npm
  2. Nuxt
  3. Frasco-CORS

Configurar

Isso será muito semelhante ao método SPA . Na verdade, a parte do Flask é exatamente a mesma. Acompanhe-o até criar sua API do Flask.

Quando sua API estiver concluída, dentro do seu terminal, abra a pasta raiz do seu projeto e execute o comando npx create-nuxt-app webapp. Isso permitirá que você gere interativamente um novo projeto Nuxt sem instalar nenhuma dependência global.

Qualquer opção deve estar bem aqui.

Depois que seu projeto terminar de ser gerado, mergulhe em sua nova pasta "webapp". Dentro da pasta "pages", abra index.vue em seu editor de texto. Da mesma forma, exclua tudo dentro do divque tem a classe container. Dentro do div, crie duas ptags com as mesmas vars: {{ greeting }}e {{ flaskGreeting }}.

Deve ficar assim:

<template>
<div class="container">
    <p>{{ greeting }}</p>
    <p>{{ flaskGreeting }}</p>
</div>
</template>

E agora para o nosso script:

  • Adicione uma datachave que retorne um objeto com as variáveis greeting​​eflaskGreeting
  • Adicione um createdgancho de ciclo de vida:
    • await fetchpara obter a saudação JSON da nossa API (na porta 5000, a menos que você a tenha alterado)
    • awaito json()método para obter nossos dados JSON de forma assíncrona da resposta da nossa API
    • Defina nossas instâncias Vue flaskGreetingpara a greetingchave do objeto JSON de nossa resposta

O objeto Vue deve se parecer com:

export default {
    components: {
        Logo
    },
    data: function(){
        return {
            greeting: 'Hello, Vue!',
            flaskGreeting: ''
        }
    },
    created: async function(){
        const gResponse = await fetch("http://localhost:5000/greeting");
        const gObject = await gResponse.json();
        this.flaskGreeting = gObject.greeting;
    }
}

A execução do aplicativo Nuxt/Vue e da API Flask também será muito semelhante ao método SPA .

Abra duas janelas de terminal. Dentro do primeiro, mude para "api" e execute o flask runcomando. Dentro do segundo, mude para "webapp" e execute npm run devpara iniciar um servidor de desenvolvimento para seu projeto Nuxt.

Quando o aplicativo Nuxt estiver ativo, você poderá acessá-lo em localhost:3000:

Hello, Vue!
Hello from Flask!

Na produção, você pode executar npm run builde, em seguida, npm run startiniciar um servidor de produção.

Nossa árvore final:

├───app.py
├───api
│   └───app.py
└───webapp
    ... {{ Nuxt project }}

BÔNUS: Comparação de SEO Vue vs Nuxt

Mencionei os benefícios do SEO anteriormente neste artigo, mas apenas para mostrar o que eu quis dizer, executei os dois aplicativos da Web como estão e obtive as pontuações do Lighthouse SEO para ambos.

Sem alterações em nenhum dos aplicativos, aqui está o que temos:

Pontuações de SEO do Lighthouse para nosso aplicativo Vue e Nuxt

Novamente, há coisas que você pode fazer para melhorar sua pontuação de SEO Vue pura. O Lighthouse nas ferramentas de desenvolvimento do Chrome menciona a adição de uma meta descrição, mas sem intervenção adicional, o Nuxt nos deu uma pontuação de SEO perfeita.

Além disso, você pode realmente ver a diferença entre o SSR que o Nuxt faz e a abordagem completamente assíncrona do vanilla Vue. Se você executar os dois aplicativos ao mesmo tempo, navegue até suas respectivas origens localhost:8080e localhost:3000, a saudação inicial do aplicativo Vue acontece milissegundos após você obter a resposta, enquanto o Nuxt é servido com sua saudação inicial já renderizada.

Para mais informações sobre as diferenças entre Nuxt e Vue, você pode conferir estes artigos:

  1. Nuxt.js sobre Vue.js: quando você deve usá-lo e por que
  2. Como o Nuxt.js resolve os problemas de SEO no Vue.js .

Planta do Frasco

Talvez você já tenha um pequeno aplicativo Flask desenvolvido e queira construir um aplicativo Vue como mais um meio para um fim e não como o evento principal.

Exemplos:

  1. Protótipo para demonstrar a funcionalidade ao seu empregador ou cliente (você sempre pode substituir isso ou entregá-lo a um desenvolvedor front-end mais tarde).
  2. Você simplesmente não quer lidar com a frustração potencial que pode resultar ao implantar front-end e back-end completamente separados.

Nesse caso, você poderia se encontrar no meio mantendo seu aplicativo Flask, mas construindo um front-end Vue dentro de seu próprio blueprint Flask.

Isso se parecerá muito com o método Jinja Template , mas o código será mais organizado.

Prós

  • Não há necessidade de construir um front-end complexo se não for necessário.
  • Semelhante ao método Jinja Template com o benefício adicional de uma melhor organização de código.
  • Você sempre pode expandir o front-end e o back-end conforme necessário posteriormente.

Contras

  • Soluções alternativas podem ser necessárias para permitir um SPA completo.
  • Acessar a API pode ser um pouco mais irritante de um front-end separado (como um aplicativo móvel), pois o front-end e o back-end não são completamente separados.

Melhor para

  • Projetos em que a funcionalidade é mais importante que a interface do usuário.
  • Você está construindo um front-end em um aplicativo Flask já existente.
  • Pequenos aplicativos da web que são compostos de apenas algumas páginas HTML.

Dependências Adicionais

Da mesma forma que o método Jinja Template , usaremos um CDN para extrair a biblioteca Vue:

<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>

Configurar

Assim como os outros métodos, crie uma nova pasta para hospedar seu código. Dentro dele, crie duas pastas: "api" e "client". Intuitivamente, eles conterão os blueprints para nossa API e cliente (Vue), respectivamente.

Vamos mergulhar na pasta "api".

Crie um arquivo chamado api.py . Isso conterá todo o código associado à nossa API. Além disso, como acessaremos este arquivo/pasta como um módulo, crie um arquivo __init__.py :

from flask import Blueprint

api_bp = Blueprint('api_bp', __name__) # "API Blueprint"

@api_bp.route("/greeting") # Blueprints don't use the Flask "app" context. They use their own blueprint's
def greeting():
    return {'greeting': 'Hello from Flask!'}

O primeiro argumento Blueprinté para o sistema de roteamento do Flask. O segundo, __name__, é equivalente ao primeiro argumento de um aplicativo Flask ( Flask(__name__)).

E é isso com nosso blueprint de API.

OK. Vamos mergulhar na pasta "cliente" que criamos anteriormente. Este será um pouco mais complicado do que o nosso modelo de API, mas não mais complicado do que um aplicativo Flask comum.

Novamente, como um aplicativo Flask comum, dentro dessa pasta, crie uma pasta "static" e uma pasta "templates". Crie um arquivo chamado client.py e abra-o em seu editor de texto.

Desta vez, passaremos mais alguns argumentos para o nosso Blueprintpara que ele saiba onde encontrar os arquivos e modelos estáticos corretos:

client_bp = Blueprint('client_bp', __name__, # 'Client Blueprint'
    template_folder='templates', # Required for our purposes
    static_folder='static', # Again, this is required
    static_url_path='/client/static' # Flask will be confused if you don't do this
)

Adicione a rota também para servir o modelo index.html :

from flask import Blueprint, render_template

client_bp = Blueprint("client_bp", __name__, # 'Client Blueprint'
    template_folder="templates", # Required for our purposes
    static_folder="static", # Again, this is required
    static_url_path="/client/static" # Flask will be confused if you don't do this
)

@client_bp.route("/")
def index():
    return render_template("index.html")

Excelente. Nosso projeto de cliente está concluído. Saia do arquivo e vá para a pasta "templates" do blueprint. Crie um arquivo index.html :

<body>
<!-- The id 'vm' is just for consistency - it can be anything you want -->
    <div id="vm" class="container">
        <p>[[ greeting ]]</p>
        <p>[[ flaskGreeting ]]</p>
    </div>
    <script src="https://cdn.jsdelivr.net/npm/vue@2.6.11"></script>
    <script src="{{ url_for('client_bp.static', filename='index.js') }}"></script>
</body>

Você notou que estamos usando colchetes em vez de colchetes? É porque precisamos alterar os delimitadores para evitar que o Flask os capture primeiro.

greetingserá renderizado pelo Vue assim que estiver pronto, enquanto flaskGreetingserá obtido de uma resposta do Flask que solicitaremos de forma assíncrona.

Feito. Adicione um novo arquivo à pasta "static" chamada index.js . Crie uma variável chamada apiEndpointe defina-a como api_v1. Isso apenas torna tudo um pouco mais DRY se decidirmos alterar nosso endpoint mais tarde:

const apiEndpoint = '/api_v1/';

Ainda não criamos a lógica para nosso endpoint. Isso virá na última etapa.

Em seguida, comece fazendo com que o contexto Vue pareça idêntico ao contexto no método Jinja Template :

const apiEndpoint = '/api_v1/';

const vm = new Vue({ // Again, vm is our Vue instance's name for consistency.
    el: '#vm',
    delimiters: ['[[', ']]'],
    data: {
        greeting: 'Hello, Vue!'
    }
})

Novamente, criamos o contexto Vue, configuramos nossa instância elcomo '#vm', alteramos os delimitadores padrão de '{{', '}}'para '[[', ']]'e adicionamos um elemento de dados com a chave/valor de greeting: 'Hello, Vue!'.

Como também vamos extrair uma saudação da nossa API, crie um espaço reservado para dados chamado flaskGreetingcom o valor de uma string vazia:

const apiEndpoint = '/api_v1/';

const vm = new Vue({
    el: '#vm',
    delimiters: ['[[', ']]'],
    data: {
        greeting: 'Hello, Vue!',
        flaskGreeting: ''
    }
})

Vamos dar ao nosso objeto Vue um createdgancho de ciclo de vida assíncrono:

const apiEndpoint = '/api_v1/';

const vm = new Vue({
    el: '#vm',
    delimiters: ['[[', ']]'],
    data: {
        greeting: 'Hello, Vue!',
        flaskGreeting: ''
    },
    created: async function(){
        const gResponse = await fetch(apiEndpoint + 'greeting');
        const gObject = await gResponse.json();
        this.flaskGreeting = gObject.greeting;
    }
})

Observando o código, estamos awaitrecebendo uma resposta do endpoint 'greeting' da nossa API ( /api_v1/greeting), definindo a resposta awaitassíncrona dessa resposta .json()e definindo a flaskGreetingvariável do nosso objeto Vue para o valor do objeto JSON retornado para sua greetingchave. É basicamente um mashup entre os objetos Vue dos métodos 1 e 2.

Excelente. Apenas uma coisa a fazer: vamos juntar tudo adicionando um app.py à raiz do projeto. Dentro do arquivo, importe flaskjunto com os blueprints:

from flask import Flask
from api.api import api_bp
from client.client import client_bp

Crie um aplicativo Flask como faria normalmente e registre os blueprints usando app.register_blueprint():

from flask import Flask
from api.api import api_bp
from client.client import client_bp

app = Flask(__name__)
app.register_blueprint(api_bp, url_prefix='/api_v1')
app.register_blueprint(client_bp)

Árvore de arquivos final:

├───app.py
├───api
│   └───__init__.py
│   └───api.py
└───client
    ├───__init__.py
    ├───static
    │   └───index.js
    └───templates
        └───index.html

E é isso! Se você executar seu novo aplicativo flask run, você deve ser saudado duas vezes - uma vez pelo próprio Vue e novamente por uma resposta da sua API do Flask.

Resumo

Existem muitas, muitas maneiras diferentes de construir um aplicativo da web usando Vue e Flask. Tudo depende da sua situação em mãos.

Algumas perguntas a fazer:

  1. Quão importante é o SEO?
  2. Como é sua equipe de desenvolvimento? Se você não tem uma equipe de DevOps, deseja assumir a complexidade adicional de ter que implantar o front-end e o back-end separadamente?
  3. Você está apenas prototipando rápido?

Espero que este artigo guie você na direção certa, dando a você uma ideia sobre como combinar seus aplicativos Vue e Flask.

Você pode pegar o código final do repositório de combinação-flask-with-vue no GitHub.

Fonte:  https://testdrive.io

#vue #flask 

Como Posso Combinar O Vue.js Com O Flask?
Vicenta  Hauck

Vicenta Hauck

1660390620

How to Use Vault To Create Postgres Credentials for A Flask App

In this tutorial, we'll look at a quick, real-world example of using Hashicorp's Vault and Consul to create dynamic Postgres credentials for a Flask web app.

Source: https://testdriven.io

#vault #flask #postgres 

How to Use Vault To Create Postgres Credentials for A Flask App
Duyen Hoang

Duyen Hoang

1660383360

Sử Dụng Vault Để Tạo Thông Tin Đăng Nhập Cho Ứng Dụng Flask

Trong hướng dẫn này, chúng ta sẽ xem xét một ví dụ nhanh, trong thế giới thực về việc sử dụng Vault and Consul của Hashicorp để tạo thông tin đăng nhập Postgres động cho ứng dụng web Flask.

Điều kiện tiên quyết

Trước khi bắt đầu, bạn nên có:

  1. Kiến thức cơ bản về quản lý bí mật với Vault và Consul.
  2. Một phiên bản của Vault được triển khai với phần phụ trợ lưu trữ .
  3. Đã triển khai một máy chủ Postgres.
  4. Đã làm việc với Flask và Docker trước đây.

Bắt đầu

Hãy bắt đầu với một ứng dụng web Flask cơ bản.

Nếu bạn muốn làm theo, hãy sao chép repo vault-consul-flask , sau đó kiểm tra nhánh v1 :

$ git clone https://github.com/testdrivenio/vault-consul-flask --branch v1 --single-branch
$ cd vault-consul-flask

Hãy xem nhanh mã:

├── .gitignore
├── Dockerfile
├── README.md
├── docker-compose.yml
├── manage.py
├── project
│   ├── __init__.py
│   ├── api
│   │   ├── __init__.py
│   │   ├── main.py
│   │   ├── models.py
│   │   └── users.py
│   └── config.py
└── requirements.txt

Về cơ bản, để ứng dụng này hoạt động, chúng tôi cần thêm các biến môi trường sau vào tệp .env (chúng tôi sẽ thực hiện ngay):

  1. DB_USER
  2. DB_PASSWORD
  3. DB_SERVER

project / config.py :

import os

USER = os.environ.get('DB_USER')
PASSWORD = os.environ.get('DB_PASSWORD')
SERVER = os.environ.get('DB_SERVER')


class ProductionConfig():
    """Production configuration"""
    SQLALCHEMY_TRACK_MODIFICATIONS = False
    SQLALCHEMY_DATABASE_URI = f'postgresql://{USER}:{PASSWORD}@{SERVER}:5432/users_db'

Định cấu hình Vault

Một lần nữa, nếu bạn muốn làm theo, bạn nên có một phiên bản của Vault được triển khai với phần phụ trợ lưu trữ . Phiên bản này cũng nên được khởi tạo và không được niêm phong. Bạn muốn thiết lập và chạy một cụm một cách nhanh chóng? Chạy tập lệnh deploy.sh từ vault-consul-swarm để triển khai cụm Vault và Consul thành ba giọt DigitalOcean. Sẽ mất chưa đầy năm phút để cung cấp và triển khai!

Trước tiên, hãy đăng nhập vào Vault (nếu cần) và sau đó bật chương trình phụ trợ bí mật cơ sở dữ liệu từ Vault CLI :

$ vault secrets enable database

Success! Enabled the database secrets engine at: database/

Thêm kết nối Postgres cùng với thông tin plugin công cụ cơ sở dữ liệu :

$ vault write database/config/users_db \
    plugin_name="postgresql-database-plugin" \
    connection_url="postgresql://{{username}}:{{password}}@<ENDPOINT>:5432/users_db" \
    allowed_roles="mynewrole" \
    username="<USERNAME>" \
    password="<PASSWORD>"

Bạn có nhận thấy rằng URL có các mẫu cho usernamepasswordtrong đó không? Điều này được sử dụng để ngăn truy cập đọc trực tiếp vào mật khẩu và cho phép xoay vòng thông tin xác thực.

Đảm bảo cập nhật điểm cuối cơ sở dữ liệu cũng như tên người dùng và mật khẩu. Ví dụ:

$ vault write database/config/users_db \
    plugin_name="postgresql-database-plugin" \
    connection_url="postgresql://{{username}}:{{password}}@users-db.c7vzuyfvhlgz.us-east-1.rds.amazonaws.com:5432/users_db" \
    allowed_roles="mynewrole" \
    username="vault" \
    password="lOfon7BA3uzZzxGGv36j"

Điều này đã tạo ra một đường dẫn bí mật mới tại "database / config / users_db":

$ vault list database/config

Keys
----
users_db

Tiếp theo, tạo một vai trò mới có tên mynewrole:

$ vault write database/roles/mynewrole \
    db_name=users_db \
    creation_statements="CREATE ROLE \"{{name}}\" \
        WITH LOGIN PASSWORD '{{password}}' VALID UNTIL '{{expiration}}'; \
        GRANT SELECT ON ALL TABLES IN SCHEMA public TO \"{{name}}\";" \
    default_ttl="1h" \
    max_ttl="24h"

Success! Data written to: database/roles/mynewrole

Ở đây, chúng tôi đã ánh xạ mynewroletên trong Vault với một câu lệnh SQL, khi chạy, sẽ tạo một người dùng mới với tất cả các quyền trong cơ sở dữ liệu. Hãy nhớ rằng điều này chưa thực sự tạo ra một người dùng mới. Hãy lưu ý cả TTL mặc định và tối đa.

Bây giờ chúng tôi đã sẵn sàng để tạo người dùng mới.

Tạo thông tin đăng nhập

Hãy xem nhanh những người dùng mà bạn có sẵn từ psql:

$ \du

Tạo một tệp mới có tên run.sh trong thư mục gốc của dự án:

#!/bin/sh

rm -f .env

echo DB_SERVER=<DB_ENDPOINT> >> .env

user=$(curl  -H "X-Vault-Token: $VAULT_TOKEN" \
        -X GET http://<VAULT_ENDPOINT>:8200/v1/database/creds/mynewrole)
echo DB_USER=$(echo $user | jq -r .data.username) >> .env
echo DB_PASSWORD=$(echo $user | jq -r .data.password) >> .env

docker-compose up -d --build

Vì vậy, thao tác này sẽ thực hiện lệnh gọi tới API Vault để tạo một tập hợp thông tin xác thực mới từ /credsđiểm cuối. Phản hồi tiếp theo được phân tích cú pháp qua JQ và thông tin đăng nhập được thêm vào tệp .env . Đảm bảo cập nhật điểm cuối cơ sở dữ liệu ( DB_ENDPOINT) và Vault ( VAULT_ENDPOINT).

Thêm VAULT_TOKENbiến môi trường:

$ export VAULT_TOKEN=<YOUR_VAULT_TOKEN>

Xây dựng hình ảnh và quay lên vùng chứa:

$ sh run.sh

Xác minh rằng các biến môi trường đã được thêm thành công:

$ docker-compose exec web env

Bạn cũng sẽ thấy người dùng đó trong cơ sở dữ liệu:

Role name                                   | Attributes                                  | Member of
--------------------------------------------+---------------------------------------------+----------
 v-root-mynewrol-jC8Imdx2sMTZj03-1533704364 | Password valid until 2018-08-08 05:59:29+00 | {}

Tạo và khởi tạo bảng cơ sở dữ liệu users:

$ docker-compose run web python manage.py recreate-db
$ docker-compose run web python manage.py seed-db

Kiểm tra nó trong trình duyệt tại http: // localhost: 5000 / users :

{
  "status": "success",
  "users": [{
    "active": true,
    "admin": false,
    "email": "michael@notreal.com",
    "id": 1,
    "username": "michael"
  }]
}

Mang xuống các vùng chứa sau khi hoàn thành:

$ docker-compose down

Sự kết luận

Đó là nó!

Hãy nhớ rằng trong ví dụ này, thông tin xác thực chỉ có giá trị trong một giờ. Điều này là hoàn hảo cho các nhiệm vụ ngắn, năng động, một lần. Nếu bạn có các nhiệm vụ dài hơn, bạn có thể thiết lập một công việc cron để kích hoạt tập lệnh run.sh mỗi giờ để có được thông tin đăng nhập mới. Chỉ cần lưu ý rằng TTL tối đa được đặt thành 24 giờ.

Bạn cũng có thể muốn xem việc sử dụng envconsul để đặt thông tin đăng nhập vào môi trường cho Flask. Nó thậm chí có thể khởi động lại Flask khi thông tin đăng nhập được cập nhật.

Bạn có thể tìm thấy mã cuối cùng trong repo vault-consul-flask .

Nguồn:  https://testdriven.io

#vault #flask #postgres 

Sử Dụng Vault Để Tạo Thông Tin Đăng Nhập Cho Ứng Dụng Flask
曾 俊

曾 俊

1660377320

使用 Flask 部署 Next.js

Flask 和 Next.js 是两个独特的开源 Web 框架,分别构建在 Python 和 JavaScript 编程语言之上。

您可以在没有 Next.js 的情况下构建 Flask 应用程序,也可以在没有 Flask 的情况下构建 Next.js 应用程序。但是,您可能会发现自己使用 Flask 构建了一个应用程序,然后决定使用 Next.js 进行服务器端渲染。

那么,此时你会怎么做?

您可以尝试的一件事是逐步采用 Next.js 或 Flask。在本文中,我将向您展示如何使用 Next.js 增量采用设计使 Next.js 与 Flask API 无缝协作,以及如何在 Ubuntu 服务器上使用 Nginx 部署它。

在 Next.js 和 Flask 中构建应用程序

需求_

  • 节点.js v12
  • Python

让我们从构建示例 Next.js 应用程序开始。按照官方Next.js 文档,运行以下命令在您的计算机上安装 Next.js npx create-next-app@latest:. 按照说明设置基本应用程序。

基本应用设置

这个装置会给我们一个“Hello, World!” 应用程序,准备部署。如果一切顺利,您可以yarn run dev在终端上运行并访问localhost:3000您的浏览器以确认它可以正常工作。您应该看到如下内容:

Next.js 应用程序

这就是现在的全部内容。接下来,让我们构建一个基本的 Flask API。我假设您已经安装了 Python,但如果您没有安装,您可以按照操作系统官方文档中的说明进行安装。

首先,让我们创建并激活一个虚拟环境来包含 Python 应用程序。

python3 -m venv env &amp;amp; source ./env/bin/activate

接下来,通过在终端中运行以下命令来安装 Flask 。我们将使用 Flask-RESTful 创建一个 RESTful API:

pip install Flask flask-restful

然后,创建一个名为的文件hello.py并将以下代码添加到其中:

from flask import Flask
from flask_restful import reqparse, Api, Resource
app = Flask(__name__)
api = Api(app)

parser = reqparse.RequestParser()
parser.add_argument('task')
class Message(Resource):
    def get(self):
        return {"message": 'Hello World'}
api.add_resource(Message, '/api/hello')

if __name__ == '__main__':
    app.run(debug=True)

现在,我们已经设置了 Flask 和 Next.js 应用程序。让我们继续让它们一起工作。

使用重写将 Flask API 集成到 Next.js

Next.js 重写允许您将传入请求路径映射到不同的目标路径。

进入我们刚刚创建的 Next.js 应用的目录,打开next.config.js文件,将内容替换为以下代码:

module.exports = () =&amp;gt; {
  const rewrites = () =&amp;gt; {
    return [
      {
        source: "/hello/:path*",
        destination: "http://localhost:5000/hello/:path*",
      },
    ];
  };
  return {
    rewrites,
  };
};

通过这种集成,我们可以直接从 Next.js 访问我们所有的 API 路由,就好像 API 与 Next.js 客户端在同一个域和端口中一样。这意味着我们只需要调用http://localhost:3000/api/,就可以在端口5000间接访问 API。

让我们看一个例子。

打开/pages/index.js文件并将其组件替换为“Hello, World!” 下面的组件:

import styles from '../styles/Home.module.css'
import { useEffect, useState } from 'react'

export default function Home() {
    const [message, setMessage] = useState("");
    const [loading, setLoading] = useState(true);

    useEffect(() =&amp;gt; {
        fetch('/hello/')
            .then(res =&amp;gt; res.json())
            .then(data =&amp;gt; {
                setMessage(data.message);
                setLoading(false);
            })
    }, [])

    return (
        &amp;lt;div className={styles.container}&amp;gt;
            &amp;lt;p&amp;gt; {!loading ? message : "Loading.."}&amp;lt;/p&amp;gt;
        &amp;lt;/div&amp;gt;
    )
}

上面的代码是一个简单的 Next.js 组件,它使用 Fetch 与 Flask API 对话。如您所见,我们不必将确切的 URL 放入 API 调用中。Next.js 根据我们最初设置的设置来理解它。

当然,你也可以选择直接调用 Flask API。

设置 Nginx

现在我们有了一个有效的集成,让我们继续在 Nginx 中进行部署。在你的服务器(在我们的例子中是一个 Ubuntu 服务器)上安装 Nginx,为你的 Nginx 配置创建一个配置文件,我们将调用它nextflask,并将以下代码添加到文件中:

/** 
/etc/nginx/sites-available/nextflask
**/
server {
    server_name        yourdomainname.com www.yourdomainname.com;
    listen 80;

  location /hello/ {
    proxy_pass http://127.0.0.1:5000/hello/;
    proxy_http_version 1.1;
    proxy_set_header Connection "upgrade";
    proxy_set_header Host $host;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
  }
  location / {
    proxy_pass http://0.0.0.0:3000;
    proxy_http_version 1.1;
    proxy_set_header Connection "upgrade";
    proxy_set_header Host $host;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
  }
}

上面的 Nginx 配置将在根域上为您的 Next.js 应用程序提供yourdomainname.com服务,并在yourdomainname.com/api/hello.

添加此配置后,通过运行以下命令启动 Nginx:

sudo systemctl start nginx.service

这就是设置 Nginx 来为我们的 Flask API 和 Next.js 服务器提供服务。将 Flask 和 Next.js 代码推送到服务器,安装依赖项,然后分别运行它们。哦,等等,我们需要对它们进行守护

您可以使用SupervisorGunicorn来守护 Flask 应用程序,这两种流行的 Python 应用程序部署工具。

我们将在 Flask 中使用 Gunicorn,在 Next.js 中使用 PM2。

将 Flask API 和 Next.js API 作为服务运行

让我们从使用 Gunicorn 运行 Flask API 开始。确保您的服务器上安装了正常工作的 Python,然后创建一个虚拟环境来安装 Gunicorn。

创建虚拟环境:

python3 -m venv env

然后,安装 Gunicorn 和 Flask:

pip install gunicorn flask

设置 Gunicorn 以服务于 Flask 应用程序

wsgi.py首先,在根目录下创建一个文件。这将作为应用程序的入口点。将以下代码添加到文件中:

// wsgi.py
from hello import app

if __name__ == "__main__":
    app.run()

接下来,sudo vim /etc/systemd/system/hello.service为 Gunicorn 创建配置文件并将以下配置添加到其中:

[Unit]
Description=Gunicorn instance to serve hello
After=network.target

[Service]
User=eze
Group=www-data
WorkingDirectory=/path/to/your/app/directory
ExecStart=/path/to/gunicorn/bin/gunicorn --workers 3 --bind unix:hello.sock -m 007 wsgi:app

[Install]
WantedBy=multi-user.target

注意参考路径。最后,通过在终端中运行以下命令来启动并启用 Gunicorn:

sudo systemctl start hello &amp;amp; sudo systemctl enable hello

要检查操作是否成功,请运行以下命令查看状态:

sudo systemctl status

如果一切顺利,我们的 Flask 应用程序应该在端口500和根域中启动并运行,yourdomainname.com.

使用 PM2 运行 Next.js 应用程序

PM2是 Node.js 应用程序的进程管理工具。要使用它,请使用以下命令全局安装 PM2:

pm2 install -g pm2

接下来,在包含 Next.js 代码的目录中运行此命令:

pm2 start "npm run start" --name nextapp

您的 Next.js 应用程序将开始在端口3000和根域中工作,yourdomainname.com.

恭喜!您已经使用 Flask API 成功部署了 Next.js 前端。起初它可能看起来很复杂,但您不必在以后的部署中重复此过程,因为这为您的应用程序正常工作设置了基本环境。您可能只需要推送您的代码并重新启动您的服务器,这可以通过您的CI/CD 管道进行管理。

结论

新技术总是来来去去,现在可能是您选择使用 Flask 部署 Next.js 以改进应用程序的一般工程的时候了。我希望你觉得这篇文章有帮助。

就个人而言,我有一个旧的 Flask API,但我想继续使用 Next.js 进行开发,同时保留一些 Python 后端实现。我发现它很容易切换而不会中断或破坏我现有的 API。

查看此示例 Next.js 项目,您可以克隆该项目以复制本文中的流程。干杯!

来源:https ://blog.logrocket.com/deploying-next-js-flask/

#nextjs #flask 

使用 Flask 部署 Next.js

Как использовать Vault для создания учетных данных Postgres для Flask

В этом руководстве мы рассмотрим быстрый реальный пример использования хранилища Hashicorp и Consul для создания динамических учетных данных Postgres для веб-приложения Flask.

Предпосылки

Перед началом у вас должно быть:

  1. Базовые навыки работы с секретами в Vault и Consul.
  2. Экземпляр Vault, развернутый с серверной частью хранилища .
  3. Развернут сервер Postgres.
  4. Раньше работал с Flask и Docker.

Начиная

Начнем с простого веб-приложения Flask.

Если вы хотите продолжить, скопируйте репозиторий vault-consul-flask , а затем проверьте ветку v1 :

$ git clone https://github.com/testdrivenio/vault-consul-flask --branch v1 --single-branch
$ cd vault-consul-flask

Взгляните на код:

├── .gitignore
├── Dockerfile
├── README.md
├── docker-compose.yml
├── manage.py
├── project
│   ├── __init__.py
│   ├── api
│   │   ├── __init__.py
│   │   ├── main.py
│   │   ├── models.py
│   │   └── users.py
│   └── config.py
└── requirements.txt

По сути, чтобы это приложение работало, нам нужно добавить следующие переменные среды в файл .env (что мы вскоре и сделаем):

  1. DB_USER
  2. DB_PASSWORD
  3. DB_SERVER

проект/config.py :

import os

USER = os.environ.get('DB_USER')
PASSWORD = os.environ.get('DB_PASSWORD')
SERVER = os.environ.get('DB_SERVER')


class ProductionConfig():
    """Production configuration"""
    SQLALCHEMY_TRACK_MODIFICATIONS = False
    SQLALCHEMY_DATABASE_URI = f'postgresql://{USER}:{PASSWORD}@{SERVER}:5432/users_db'

Настройка хранилища

Опять же, если вы хотите продолжить, у вас должен быть развернут экземпляр Vault с серверной частью хранилища . Этот экземпляр также должен быть инициализирован и распечатан. Хотите быстро запустить кластер? Запустите скрипт deploy.sh из vault-consul-swarm , чтобы развернуть кластер Vault и Consul в трех дроплетах DigitalOcean. Подготовка и развертывание займет менее пяти минут!

Сначала войдите в Vault (при необходимости), а затем включите серверную часть секретов базы данных из интерфейса командной строки Vault :

$ vault secrets enable database

Success! Enabled the database secrets engine at: database/

Добавьте соединение Postgres вместе с информацией о подключаемом модуле базы данных :

$ vault write database/config/users_db \
    plugin_name="postgresql-database-plugin" \
    connection_url="postgresql://{{username}}:{{password}}@<ENDPOINT>:5432/users_db" \
    allowed_roles="mynewrole" \
    username="<USERNAME>" \
    password="<PASSWORD>"

Вы заметили, что в URL есть шаблоны для usernameи passwordв нем? Это используется для предотвращения прямого доступа для чтения к паролю и включения ротации учетных данных.

Обязательно обновите конечную точку базы данных, а также имя пользователя и пароль. Например:

$ vault write database/config/users_db \
    plugin_name="postgresql-database-plugin" \
    connection_url="postgresql://{{username}}:{{password}}@users-db.c7vzuyfvhlgz.us-east-1.rds.amazonaws.com:5432/users_db" \
    allowed_roles="mynewrole" \
    username="vault" \
    password="lOfon7BA3uzZzxGGv36j"

Это создало новый путь секретов в «database/config/users_db»:

$ vault list database/config

Keys
----
users_db

Затем создайте новую роль с именем mynewrole:

$ vault write database/roles/mynewrole \
    db_name=users_db \
    creation_statements="CREATE ROLE \"{{name}}\" \
        WITH LOGIN PASSWORD '{{password}}' VALID UNTIL '{{expiration}}'; \
        GRANT SELECT ON ALL TABLES IN SCHEMA public TO \"{{name}}\";" \
    default_ttl="1h" \
    max_ttl="24h"

Success! Data written to: database/roles/mynewrole

Здесь мы сопоставили mynewroleимя в Vault с оператором SQL, который при запуске создаст нового пользователя со всеми разрешениями в базе данных. Имейте в виду, что это еще не создало нового пользователя. Обратите внимание на значение по умолчанию и максимальное значение TTL.

Теперь мы готовы создавать новых пользователей.

Создание учетных данных

Взгляните на то, какие пользователи у вас есть psql:

$ \du

Создайте новый файл с именем run.sh в корне проекта:

#!/bin/sh

rm -f .env

echo DB_SERVER=<DB_ENDPOINT> >> .env

user=$(curl  -H "X-Vault-Token: $VAULT_TOKEN" \
        -X GET http://<VAULT_ENDPOINT>:8200/v1/database/creds/mynewrole)
echo DB_USER=$(echo $user | jq -r .data.username) >> .env
echo DB_PASSWORD=$(echo $user | jq -r .data.password) >> .env

docker-compose up -d --build

Таким образом, это вызовет Vault API для создания нового набора учетных данных из /credsконечной точки. Последующий ответ анализируется с помощью JQ, и учетные данные добавляются в файл .env . Обязательно обновите конечные точки базы данных ( DB_ENDPOINT) и Vault ( VAULT_ENDPOINT).

Добавьте VAULT_TOKENпеременную среды:

$ export VAULT_TOKEN=<YOUR_VAULT_TOKEN>

Создайте образ и запустите контейнер:

$ sh run.sh

Убедитесь, что переменные среды были успешно добавлены:

$ docker-compose exec web env

Вы также должны увидеть этого пользователя в базе данных:

Role name                                   | Attributes                                  | Member of
--------------------------------------------+---------------------------------------------+----------
 v-root-mynewrol-jC8Imdx2sMTZj03-1533704364 | Password valid until 2018-08-08 05:59:29+00 | {}

usersСоздайте и заполните таблицу базы данных :

$ docker-compose run web python manage.py recreate-db
$ docker-compose run web python manage.py seed-db

Проверьте это в браузере по адресу http://localhost:5000/users :

{
  "status": "success",
  "users": [{
    "active": true,
    "admin": false,
    "email": "michael@notreal.com",
    "id": 1,
    "username": "michael"
  }]
}

Снесите контейнеры, как только закончите:

$ docker-compose down

Вывод

Вот и все!

Помните, что в этом примере учетные данные действительны только в течение часа. Это идеально подходит для коротких, динамичных, разовых задач. Если у вас есть более длинные задачи, вы можете настроить задание cron для запуска сценария run.sh каждый час для получения новых учетных данных. Просто имейте в виду, что максимальный TTL установлен на 24 часа.

Вы также можете рассмотреть возможность использования envconsul для размещения учетных данных в среде для Flask. Он может даже перезапустить Flask при обновлении учетных данных.

Вы можете найти окончательный код в репозитории vault-consul-flask .

Источник:  https://testdriven.io

#flask #vault #postgre 

Как использовать Vault для создания учетных данных Postgres для Flask
伊藤  直子

伊藤 直子

1660375800

Flask を使用した Next.js のデプロイ

Flask と Next.js は、それぞれ Python と JavaScript プログラミング言語の上に構築された 2 つのユニークなオープンソース Web フレームワークです。

Next.js なしで Flask アプリケーションを構築できます。また、Flask なしで Next.js アプリを構築することもできます。ただし、Flask を使用してアプリケーションを構築し、後でサーバー側のレンダリングに Next.js を使用することにした場合があります。

それで、あなたはこの時点で何をしますか?

試してみることができることの 1 つは、Next.js または Flask を段階的に採用することです。この記事では、Next.js の増分採用設計を使用して、Next.js を Flask API とシームレスに連携させる方法と、Nginx を使用して Ubuntu サーバーにデプロイする方法を紹介します。

Next.js と Flask でアプリをビルドする

要件_

  • Node.js v12
  • パイソン

サンプルの Next.js アプリケーションを作成することから始めましょう。公式のNext.js ドキュメントに従って、次のコマンドを実行して Next.js をコンピューターにインストールしますnpx create-next-app@latest。指示に従って、基本的なアプリをセットアップします。

アプリの基本設定

このインストールにより、「Hello, World!」が表示されます。アプリ、展開の準備ができました。すべてがうまくいけばyarn run dev、ターミナルで実行し、localhost:3000ブラウザにアクセスして、動作することを確認できます。次のように表示されます。

Next.js アプリ

今のところはこれだけです。次に、基本的な Flask API を作成しましょう。Python がインストールされていることを前提としていますが、インストールされていない場合は、OSの公式ドキュメントの手順に従ってインストールできます。

まず、仮想環境を作成してアクティブ化し、Python アプリケーションを含めます。

python3 -m venv env &amp;amp; source ./env/bin/activate

次に、ターミナルで次のコマンドを実行してFlask をインストールします。Flask-RESTful を使用して安静な API を作成します。

pip install Flask flask-restful

次に、というファイルを作成しhello.py、次のコードを追加します。

from flask import Flask
from flask_restful import reqparse, Api, Resource
app = Flask(__name__)
api = Api(app)

parser = reqparse.RequestParser()
parser.add_argument('task')
class Message(Resource):
    def get(self):
        return {"message": 'Hello World'}
api.add_resource(Message, '/api/hello')

if __name__ == '__main__':
    app.run(debug=True)

これで、Flask と Next.js アプリの両方がセットアップされました。それらを連携させながら進めていきましょう。

書き換えを使用して Flask API を Next.js に統合する

Next.js の書き換えにより、着信要求パスを別の宛先パスにマップできます。

作成したばかりの Next.js アプリのディレクトリに移動し、next.config.jsファイルを開き、内容を以下のコードに置き換えます。

module.exports = () =&amp;gt; {
  const rewrites = () =&amp;gt; {
    return [
      {
        source: "/hello/:path*",
        destination: "http://localhost:5000/hello/:path*",
      },
    ];
  };
  return {
    rewrites,
  };
};

この統合により、API が Next.js クライアントと同じドメインおよびポートにあるかのように、Next.js からすべての API ルートに直接アクセスできます。これは、呼び出すだけでよく、ポートで間接的http://localhost:3000/api/に API にアクセスできることを意味します。5000

例を見てみましょう。

ファイルを開き、/pages/index.jsそのコンポーネントを「Hello, World!」に置き換えます。以下のコンポーネント:

import styles from '../styles/Home.module.css'
import { useEffect, useState } from 'react'

export default function Home() {
    const [message, setMessage] = useState("");
    const [loading, setLoading] = useState(true);

    useEffect(() =&amp;gt; {
        fetch('/hello/')
            .then(res =&amp;gt; res.json())
            .then(data =&amp;gt; {
                setMessage(data.message);
                setLoading(false);
            })
    }, [])

    return (
        &amp;lt;div className={styles.container}&amp;gt;
            &amp;lt;p&amp;gt; {!loading ? message : "Loading.."}&amp;lt;/p&amp;gt;
        &amp;lt;/div&amp;gt;
    )
}

上記のコードは、Fetch を使用して Flask API と通信する単純な Next.js コンポーネントです。ご覧のとおり、API の呼び出しに正確な URL を入れる必要はありませんでした。Next.js は、最初に設定した設定に基づいてそれを理解しました。

もちろん、Flask API を直接呼び出すこともできます。

Nginxをセットアップする

統合が機能するようになったので、Nginx での展開に進みましょう。サーバー (この場合は Ubuntu サーバー) にNginx をインストールnextflaskし、Nginx 構成用の構成ファイルを作成します。これを と呼び、次のコードをファイルに追加します。

/** 
/etc/nginx/sites-available/nextflask
**/
server {
    server_name        yourdomainname.com www.yourdomainname.com;
    listen 80;

  location /hello/ {
    proxy_pass http://127.0.0.1:5000/hello/;
    proxy_http_version 1.1;
    proxy_set_header Connection "upgrade";
    proxy_set_header Host $host;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
  }
  location / {
    proxy_pass http://0.0.0.0:3000;
    proxy_http_version 1.1;
    proxy_set_header Connection "upgrade";
    proxy_set_header Host $host;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
  }
}

上記の Nginx 構成は、ルート ドメインyourdomainname.comで Next.js アプリを提供し、で API を提供しますyourdomainname.com/api/hello

この構成を追加したら、次のコマンドを実行して Nginx を起動します。

sudo systemctl start nginx.service

これで、Flask API と Next.js サーバーにサービスを提供するように Nginx をセットアップしました。Flask と Next.js コードをサーバーにプッシュし、依存関係をインストールして、個別に実行します。ああ、待って、デーモン化する必要があります

Python アプリケーションをデプロイするための 2 つの一般的なツールであるSupervisorまたはGunicornを使用して、Flask アプリをデーモン化できます。

Flask には Gunicorn を使用し、Next.js には PM2 を使用します。

Flask API と Next.js API をサービスとして実行する

Gunicorn で Flask API を実行することから始めましょう。サーバーに Python がインストールされていることを確認してから、仮想環境を作成して Gunicorn をインストールします。

仮想環境を作成します。

python3 -m venv env

次に、Gunicorn と Flask をインストールします。

pip install gunicorn flask

Flask アプリケーションを提供するように Gunicorn をセットアップする

まず、wsgi.pyルート ディレクトリにファイルを作成します。これは、アプリケーションのエントリ ポイントとして機能します。次のコードをファイルに追加します。

// wsgi.py
from hello import app

if __name__ == "__main__":
    app.run()

次に、sudo vim /etc/systemd/system/hello.serviceGunicorn の構成ファイルを作成し、次の構成を追加します。

[Unit]
Description=Gunicorn instance to serve hello
After=network.target

[Service]
User=eze
Group=www-data
WorkingDirectory=/path/to/your/app/directory
ExecStart=/path/to/gunicorn/bin/gunicorn --workers 3 --bind unix:hello.sock -m 007 wsgi:app

[Install]
WantedBy=multi-user.target

参照パスに注意してください。最後に、ターミナルで次のコマンドを実行して、Gunicorn を起動して有効にします。

sudo systemctl start hello &amp;amp; sudo systemctl enable hello

操作が成功したかどうかを確認するには、次のコマンドを実行してステータスを確認します。

sudo systemctl status

すべてがうまくいけば、Flask アプリが起動し、ポート500とルート ドメインで実行されるはずyourdomainname.comです。

PM2 で Next.js アプリを実行する

PM2は、Node.js アプリケーション用のプロセス管理ツールです。これを使用するには、次のコマンドで PM2 をグローバルにインストールします。

pm2 install -g pm2

次に、Next.js コードがあるディレクトリで次のコマンドを実行します。

pm2 start "npm run start" --name nextapp

Next.js アプリケーションは、ポート3000とルート ドメインで動作を開始しますyourdomainname.com

おめでとう!Flask API を使用して Next.js フロントエンドを正常にデプロイしました。最初は複雑に思えるかもしれませんが、アプリケーションが適切に動作するための基本的な環境が設定されるため、将来の展開でこのプロセスを繰り返す必要はありません。コードをプッシュしてサーバーを再起動するだけでよく、 CI/CD パイプラインで管理できます。

結論

新しいテクノロジーは常に生まれては消えていきます。アプリケーションの一般的なエンジニアリングを改善するために、Flask を使用して Next.js をデプロイすることを選択するのは今かもしれません。この記事がお役に立てば幸いです。

個人的には、古い Flask API を使用していましたが、Python バックエンドの実装の一部を保持しながら、Next.js で開発を続けたいと考えていました。既存の API を中断したり壊したりすることなく、非常に簡単に切り替えることができました。

このサンプルの Next.js プロジェクトを確認してください。クローンを作成して、この記事のプロセスを複製できます。乾杯!

ソース: https://blog.logrocket.com/deploying-next-js-flask/

#nextjs #flask 

Flask を使用した Next.js のデプロイ
Duong Tran

Duong Tran

1660370700

Triển Khai Next.js Với Flask

Flask và Next.js là hai khung công tác web mã nguồn mở duy nhất được xây dựng dựa trên ngôn ngữ lập trình Python và JavaScript tương ứng.

Bạn có thể tạo ứng dụng Flask mà không có Next.js và bạn cũng có thể tạo ứng dụng Next.js mà không cần Flask. Tuy nhiên, bạn có thể gặp phải tình huống mà bạn đã tạo một ứng dụng với Flask và sau đó quyết định sử dụng Next.js để hiển thị phía máy chủ.

Vì vậy, bạn làm gì vào thời điểm này?

Một điều bạn có thể thử là áp dụng dần Next.js hoặc Flask. Trong bài viết này, tôi sẽ chỉ cho bạn cách làm cho Next.js hoạt động liền mạch với API Flask bằng cách sử dụng thiết kế áp dụng gia tăng Next.js và cách bạn có thể triển khai nó với Nginx trên máy chủ Ubuntu.

Xây dựng ứng dụng trong Next.js và Flask

Yêu cầu s

  • Node.js v12
  • Python

Hãy bắt đầu bằng cách xây dựng một ứng dụng Next.js mẫu. Làm theo tài liệu Next.js chính thức , hãy chạy lệnh sau để cài đặt Next.js trên máy tính của bạn npx create-next-app@latest:. Làm theo hướng dẫn để thiết lập một ứng dụng cơ bản.

Thiết lập ứng dụng cơ bản

Cài đặt này sẽ cung cấp cho chúng tôi một "Xin chào, Thế giới!" ứng dụng, sẵn sàng để triển khai. Nếu mọi việc suôn sẻ, bạn có thể chạy yarn run devtrên thiết bị đầu cuối và truy cập localhost:3000trên trình duyệt của mình để xác nhận rằng nó hoạt động. Bạn sẽ thấy một cái gì đó như thế này:

Ứng dụng Next.js

Đó là tất cả những gì cần làm cho nó bây giờ. Tiếp theo, hãy xây dựng một API Flask cơ bản. Tôi giả sử bạn đã cài đặt Python, nhưng nếu chưa cài đặt, bạn có thể cài đặt nó bằng cách làm theo hướng dẫn trong tài liệu chính thức dành cho hệ điều hành của bạn.

Đầu tiên, hãy tạo và kích hoạt một môi trường ảo để chứa ứng dụng Python.

python3 -m venv env &amp;amp; source ./env/bin/activate

Tiếp theo, cài đặt Flask bằng cách chạy lệnh sau trong thiết bị đầu cuối của bạn. Chúng tôi sẽ sử dụng Flask-RESTful để tạo một API hoàn chỉnh:

pip install Flask flask-restful

Sau đó, tạo một tệp có tên hello.pyvà thêm mã sau vào tệp đó:

from flask import Flask
from flask_restful import reqparse, Api, Resource
app = Flask(__name__)
api = Api(app)

parser = reqparse.RequestParser()
parser.add_argument('task')
class Message(Resource):
    def get(self):
        return {"message": 'Hello World'}
api.add_resource(Message, '/api/hello')

if __name__ == '__main__':
    app.run(debug=True)

Bây giờ, chúng tôi đã thiết lập cả Flask và ứng dụng Next.js. Hãy tiến hành làm cho chúng hoạt động cùng nhau.

Tích hợp API Flask vào Next.js bằng cách sử dụng ghi lại

Next.js viết lại cho phép bạn ánh xạ một đường dẫn yêu cầu đến một đường dẫn đích khác.

Di chuyển vào thư mục của ứng dụng Next.js mà chúng tôi vừa tạo, mở next.config.jstệp và thay thế nội dung bằng mã bên dưới:

module.exports = () =&amp;gt; {
  const rewrites = () =&amp;gt; {
    return [
      {
        source: "/hello/:path*",
        destination: "http://localhost:5000/hello/:path*",
      },
    ];
  };
  return {
    rewrites,
  };
};

Với sự tích hợp này, chúng tôi có thể truy cập tất cả các tuyến API của mình trực tiếp từ Next.js như thể API nằm trong cùng một miền và cổng với ứng dụng Next.js. Điều này có nghĩa là chúng tôi chỉ cần gọi http://localhost:3000/api/và chúng tôi sẽ có thể truy cập API tại cổng 5000một cách gián tiếp.

Hãy xem một ví dụ.

Mở /pages/index.jstệp và thay thế thành phần của nó bằng "Hello, World!" thành phần bên dưới:

import styles from '../styles/Home.module.css'
import { useEffect, useState } from 'react'

export default function Home() {
    const [message, setMessage] = useState("");
    const [loading, setLoading] = useState(true);

    useEffect(() =&amp;gt; {
        fetch('/hello/')
            .then(res =&amp;gt; res.json())
            .then(data =&amp;gt; {
                setMessage(data.message);
                setLoading(false);
            })
    }, [])

    return (
        &amp;lt;div className={styles.container}&amp;gt;
            &amp;lt;p&amp;gt; {!loading ? message : "Loading.."}&amp;lt;/p&amp;gt;
        &amp;lt;/div&amp;gt;
    )
}

Đoạn mã trên là một thành phần Next.js đơn giản nói chuyện với API Flask bằng cách sử dụng Tìm nạp. Như bạn có thể thấy, chúng tôi không phải đặt URL chính xác trong lệnh gọi tới API. Next.js hiểu nó dựa trên các cài đặt mà chúng tôi đã thiết lập ban đầu.

Tất nhiên, bạn cũng có thể chọn gọi trực tiếp API Flask.

Thiết lập Nginx

Bây giờ chúng ta đã có tích hợp hoạt động, hãy tiến hành triển khai trong Nginx. Cài đặt Nginx trên máy chủ của bạn (trong trường hợp của chúng tôi là máy chủ Ubuntu), tạo tệp cấu hình cho cấu hình Nginx của bạn, tệp này chúng tôi sẽ gọi nextflaskvà thêm mã sau vào tệp:

/** 
/etc/nginx/sites-available/nextflask
**/
server {
    server_name        yourdomainname.com www.yourdomainname.com;
    listen 80;

  location /hello/ {
    proxy_pass http://127.0.0.1:5000/hello/;
    proxy_http_version 1.1;
    proxy_set_header Connection "upgrade";
    proxy_set_header Host $host;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
  }
  location / {
    proxy_pass http://0.0.0.0:3000;
    proxy_http_version 1.1;
    proxy_set_header Connection "upgrade";
    proxy_set_header Host $host;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
  }
}

Cấu hình Nginx ở trên sẽ phân phát ứng dụng Next.js của bạn trên miền gốc yourdomainname.comvà cung cấp API của bạn trên yourdomainname.com/api/hello.

Sau khi thêm cấu hình này, hãy khởi động Nginx bằng cách chạy lệnh bên dưới:

sudo systemctl start nginx.service

Đó là nó để thiết lập Nginx để phục vụ API Flask và máy chủ Next.js của chúng tôi. Đẩy mã Flask và Next.js của bạn vào máy chủ của bạn, cài đặt các phần phụ thuộc và chạy chúng một cách riêng biệt. Ồ, chờ đã, chúng ta sẽ cần phải làm cho chúng bị nhiễm trùng .

Bạn có thể daemonize một ứng dụng Flask bằng Supervisor hoặc Gunicorn , đây là hai công cụ phổ biến để triển khai các ứng dụng Python.

Chúng tôi sẽ sử dụng Gunicorn cho Flask và PM2 cho Next.js.

Chạy API Flask và API Next.js dưới dạng dịch vụ

Hãy bắt đầu với việc chạy API Flask với Gunicorn. Đảm bảo rằng bạn có cài đặt Python đang hoạt động trên máy chủ của mình, sau đó tạo môi trường ảo để cài đặt Gunicorn.

Tạo môi trường ảo:

python3 -m venv env

Sau đó, cài đặt Gunicorn và Flask:

pip install gunicorn flask

Thiết lập Gunicorn để phục vụ ứng dụng Flask

Đầu tiên, tạo một wsgi.pytệp trong thư mục gốc. Đây sẽ là điểm nhập của ứng dụng. Thêm mã sau vào tệp:

// wsgi.py
from hello import app

if __name__ == "__main__":
    app.run()

Tiếp theo, tạo tệp cấu hình sudo vim /etc/systemd/system/hello.servicecho Gunicorn và thêm cấu hình sau vào đó:

[Unit]
Description=Gunicorn instance to serve hello
After=network.target

[Service]
User=eze
Group=www-data
WorkingDirectory=/path/to/your/app/directory
ExecStart=/path/to/gunicorn/bin/gunicorn --workers 3 --bind unix:hello.sock -m 007 wsgi:app

[Install]
WantedBy=multi-user.target

Chú ý đến các đường dẫn tham chiếu. Cuối cùng, khởi động và kích hoạt Gunicorn bằng cách chạy lệnh sau trong thiết bị đầu cuối của bạn:

sudo systemctl start hello &amp;amp; sudo systemctl enable hello

Để kiểm tra xem thao tác có thành công hay không, hãy xem lại trạng thái bằng cách chạy lệnh dưới đây:

sudo systemctl status

Nếu mọi việc suôn sẻ, ứng dụng Flask của chúng tôi sẽ được thiết lập và chạy trên cổng 500và trong miền gốc yourdomainname.com,.

Chạy ứng dụng Next.js với PM2

PM2 là một công cụ quản lý quy trình cho các ứng dụng Node.js. Để sử dụng nó, hãy cài đặt PM2 trên toàn cầu bằng lệnh sau:

pm2 install -g pm2

Tiếp theo, chạy lệnh này trong thư mục có mã Next.js của bạn:

pm2 start "npm run start" --name nextapp

Ứng dụng Next.js của bạn sẽ bắt đầu hoạt động trên cổng 3000và trong miền gốc yourdomainname.com,.

Xin chúc mừng! Bạn đã triển khai thành công giao diện người dùng Next.js với API Flask của mình. Thoạt đầu có vẻ phức tạp, nhưng bạn sẽ không phải lặp lại quá trình này trong các lần triển khai sau này, bởi vì điều này thiết lập môi trường cơ bản để ứng dụng của bạn hoạt động bình thường. Bạn có thể chỉ cần đẩy mã của mình và khởi động lại máy chủ, máy chủ này có thể được quản lý bằng đường dẫn CI / CD của bạn .

Sự kết luận

Các công nghệ mới đến và đi liên tục và bây giờ có thể là lúc bạn chọn triển khai Next.js với Flask để cải thiện kỹ thuật chung của ứng dụng của bạn. Tôi hy vọng bạn thấy bài viết này hữu ích.

Cá nhân tôi đã có một API Flask cũ, nhưng tôi muốn tiếp tục phát triển với Next.js trong khi vẫn giữ lại một số triển khai chương trình phụ trợ Python. Tôi thấy việc chuyển đổi rất dễ dàng mà không làm gián đoạn hoặc phá vỡ API hiện có của mình.

Hãy xem dự án Next.js mẫu này , bạn có thể sao chép dự án này để tái tạo quy trình từ bài viết này. Chúc mừng!

Nguồn: https://blog.logrocket.com/deploy-next-js-flask/

#nextjs #flask 

Triển Khai Next.js Với Flask
Léon  Peltier

Léon Peltier

1660370400

Déployer Next.js avec Flask

Flask et Next.js sont deux frameworks Web open source uniques construits respectivement sur les langages de programmation Python et JavaScript.

Vous pouvez créer une application Flask sans Next.js, et vous pouvez également créer une application Next.js sans Flask. Cependant, vous pourriez vous retrouver dans une situation où vous avez créé une application avec Flask et décidez plus tard d'utiliser Next.js pour le rendu côté serveur.

Alors, que faites-vous à ce stade ?

Une chose que vous pouvez essayer est d'adopter progressivement Next.js ou Flask. Dans cet article, je vais vous montrer comment faire fonctionner Next.js de manière transparente avec une API Flask à l'aide de la conception d'adoption incrémentielle Next.js, et comment vous pouvez le déployer avec Nginx sur un serveur Ubuntu.

Créer une application dans Next.js et Flask

Exigences _

  • Node.js v12
  • Python

Commençons par créer un exemple d'application Next.js. En suivant la documentation officielle de Next.js , exécutez la commande suivante pour installer Next.js sur votre ordinateur : npx create-next-app@latest. Suivez les instructions pour configurer une application de base.

Configuration de base de l'application

Cette installation nous donnera un "Hello, World!" app, prête à être déployée. Si tout se passe bien, vous pouvez exécuter yarn run devsur le terminal et visiter localhost:3000sur votre navigateur pour confirmer que cela fonctionne. Vous devriez voir quelque chose comme ceci :

Application Next.js

C'est tout ce qu'il y a à faire pour l'instant. Ensuite, construisons une API Flask de base. Je suppose que Python est installé, mais si ce n'est pas le cas, vous pouvez l'installer en suivant les instructions de la documentation officielle de votre système d'exploitation.

Commençons par créer et activer un environnement virtuel pour contenir l'application Python.

python3 -m venv env &amp;amp; source ./env/bin/activate

Ensuite, installez Flask en exécutant la commande suivante dans votre terminal. Nous utiliserons Flask-RESTful pour créer une API reposante :

pip install Flask flask-restful

Ensuite, créez un fichier appelé hello.pyet ajoutez-y le code suivant :

from flask import Flask
from flask_restful import reqparse, Api, Resource
app = Flask(__name__)
api = Api(app)

parser = reqparse.RequestParser()
parser.add_argument('task')
class Message(Resource):
    def get(self):
        return {"message": 'Hello World'}
api.add_resource(Message, '/api/hello')

if __name__ == '__main__':
    app.run(debug=True)

Maintenant, nous avons à la fois l'application Flask et l'application Next.js configurées. Continuons à les faire travailler ensemble.

Intégration de l'API Flask dans Next.js à l'aide de réécritures

Les réécritures Next.js vous permettent de mapper un chemin de requête entrant vers un chemin de destination différent.

Déplacez-vous dans le répertoire de l'application Next.js que nous venons de créer, ouvrez le next.config.jsfichier et remplacez le contenu par le code ci-dessous :

module.exports = () =&amp;gt; {
  const rewrites = () =&amp;gt; {
    return [
      {
        source: "/hello/:path*",
        destination: "http://localhost:5000/hello/:path*",
      },
    ];
  };
  return {
    rewrites,
  };
};

Grâce à cette intégration, nous pouvons accéder à toutes nos routes d'API directement à partir de Next.js comme si l'API se trouvait dans le même domaine et port que le client Next.js. Cela signifie que nous n'aurons qu'à appeler http://localhost:3000/api/et que nous pourrons atteindre l'API au port 5000indirectement.

Prenons un exemple.

Ouvrez le /pages/index.jsfichier et remplacez son composant par "Hello, World!" composant ci-dessous :

import styles from '../styles/Home.module.css'
import { useEffect, useState } from 'react'

export default function Home() {
    const [message, setMessage] = useState("");
    const [loading, setLoading] = useState(true);

    useEffect(() =&amp;gt; {
        fetch('/hello/')
            .then(res =&amp;gt; res.json())
            .then(data =&amp;gt; {
                setMessage(data.message);
                setLoading(false);
            })
    }, [])

    return (
        &amp;lt;div className={styles.container}&amp;gt;
            &amp;lt;p&amp;gt; {!loading ? message : "Loading.."}&amp;lt;/p&amp;gt;
        &amp;lt;/div&amp;gt;
    )
}

Le code ci-dessus est un simple composant Next.js qui communique avec l'API Flask à l'aide de Fetch. Comme vous pouvez le voir, nous n'avons pas eu à mettre l'URL exacte dans l'appel à l'API. Next.js l'a compris en fonction des paramètres que nous avons initialement définis.

Bien sûr, vous pouvez également choisir d'appeler directement l'API Flask.

Configurer Nginx

Maintenant que nous avons une intégration fonctionnelle, passons au déploiement dans Nginx. Installez Nginx sur votre serveur (un serveur Ubuntu, dans notre cas), créez un fichier de configuration pour votre configuration Nginx, que nous appellerons nextflask, et ajoutez le code suivant au fichier :

/** 
/etc/nginx/sites-available/nextflask
**/
server {
    server_name        yourdomainname.com www.yourdomainname.com;
    listen 80;

  location /hello/ {
    proxy_pass http://127.0.0.1:5000/hello/;
    proxy_http_version 1.1;
    proxy_set_header Connection "upgrade";
    proxy_set_header Host $host;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
  }
  location / {
    proxy_pass http://0.0.0.0:3000;
    proxy_http_version 1.1;
    proxy_set_header Connection "upgrade";
    proxy_set_header Host $host;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
  }
}

La configuration Nginx ci-dessus servira votre application Next.js sur le domaine racine yourdomainname.comet servira votre API sur yourdomainname.com/api/hello.

Après avoir ajouté cette configuration, démarrez Nginx en exécutant la commande ci-dessous :

sudo systemctl start nginx.service

C'est tout pour configurer Nginx pour servir notre API Flask et notre serveur Next.js. Poussez votre code Flask et Next.js sur votre serveur, installez les dépendances et exécutez-les séparément. Oh, attendez, nous devrons les démoniser .

Vous pouvez démoniser une application Flask avec Supervisor ou Gunicorn , qui sont deux outils populaires pour déployer des applications Python.

Nous utiliserons Gunicorn pour Flask et PM2 pour Next.js.

Exécutez l'API Flask et l'API Next.js en tant que service

Commençons par exécuter l'API Flask avec Gunicorn. Assurez-vous que vous disposez d'une installation Python fonctionnelle sur votre serveur, puis créez un environnement virtuel pour installer Gunicorn.

Créez un environnement virtuel :

python3 -m venv env

Ensuite, installez Gunicorn et Flask :

pip install gunicorn flask

Configurer Gunicorn pour servir l'application Flask

Commencez par créer un wsgi.pyfichier dans le répertoire racine. Cela servira de point d'entrée de l'application. Ajoutez le code suivant au fichier :

// wsgi.py
from hello import app

if __name__ == "__main__":
    app.run()

Ensuite, créez un fichier de configuration sudo vim /etc/systemd/system/hello.servicepour Gunicorn et ajoutez-y la configuration suivante :

[Unit]
Description=Gunicorn instance to serve hello
After=network.target

[Service]
User=eze
Group=www-data
WorkingDirectory=/path/to/your/app/directory
ExecStart=/path/to/gunicorn/bin/gunicorn --workers 3 --bind unix:hello.sock -m 007 wsgi:app

[Install]
WantedBy=multi-user.target

Faites attention aux chemins de référence. Enfin, démarrez et activez Gunicorn en exécutant la commande suivante dans votre terminal :

sudo systemctl start hello &amp;amp; sudo systemctl enable hello

Pour vérifier si l'opération a réussi, vérifiez l'état en exécutant la commande ci-dessous :

sudo systemctl status

Si tout se passe bien, notre application Flask devrait être opérationnelle sur le port 500et dans le domaine racine, yourdomainname.com.

Exécutez l'application Next.js avec PM2

PM2 est un outil de gestion de processus pour les applications Node.js. Pour l'utiliser, installez PM2 globalement avec la commande suivante :

pm2 install -g pm2

Ensuite, exécutez cette commande dans le répertoire contenant votre code Next.js :

pm2 start "npm run start" --name nextapp

Votre application Next.js commencera à fonctionner sur le port 3000et dans le domaine racine, yourdomainname.com.

Toutes nos félicitations! Vous avez déployé avec succès votre frontend Next.js avec votre API Flask. Cela peut sembler compliqué au début, mais vous n'aurez pas à répéter ce processus dans vos futurs déploiements, car cela définit l'environnement de base pour que votre application fonctionne correctement. Il vous suffira peut-être de pousser votre code et de redémarrer votre serveur, qui peut être géré par votre pipeline CI/CD .

Conclusion

Les nouvelles technologies vont et viennent tout le temps, et c'est peut-être le moment pour vous de choisir de déployer Next.js avec Flask pour améliorer l'ingénierie générale de votre application. J'espère que vous trouverez cet article utile.

Personnellement, j'avais une ancienne API Flask, mais je voulais continuer le développement avec Next.js tout en conservant certaines des implémentations du backend Python. J'ai trouvé très facile de changer sans interrompre ou casser mon API existante.

Découvrez cet exemple de projet Next.js , que vous pouvez cloner pour répliquer le processus à partir de cet article. Acclamations!

Source : https://blog.logrocket.com/deploying-next-js-flask/

#nextjs #flask 

Déployer Next.js avec Flask