Next.js การรวมโครงการ Django
ดังนั้นคุณต้องการใช้ทั้ง django และ next.js ในโครงการของคุณ มีสองสถานการณ์:
คุณกำลังเริ่มโครงการใหม่และคุณต้องการใช้ Django เป็น back-end และ next.js เป็น front-end Django ให้บริการเฉพาะ API รหัสส่วนหน้าทั้งหมดอาศัยอยู่ใน next.js และคุณไม่ได้เขียนเทมเพลต django ใด ๆ
ในสถานการณ์นี้คุณ ไม่ต้องการ แพ็คเกจนี้ (แม้ว่าคุณจะสามารถใช้งานได้) คุณเพียงแค่เริ่มทั้ง Django และเซิร์ฟเวอร์ next.js และชี้เว็บเซิร์ฟเวอร์สาธารณะของคุณไปที่ Next.js
คุณต้องการทั้งเทมเพลต django และ next.js ในเวลาเดียวกันและหน้าเหล่านั้นควรเชื่อมโยงกันได้อย่างง่ายดาย บางทีคุณอาจมีโครงการ Django ที่มีอยู่ซึ่งมีหน้าเว็บที่แสดงโดยเทมเพลต Django และต้องการหน้าใหม่ใน Next.Js. หรือคุณต้องการโยกย้ายส่วนหน้าของคุณไปยัง next.js แต่เนื่องจากโครงการมีขนาดใหญ่คุณต้องทำมันค่อยๆ
ในสถานการณ์นี้ แพ็คเกจนี้เหมาะสำหรับคุณ!
จากความคิดเห็นเกี่ยวกับ stackoverflow:
เรียกใช้ 2 พอร์ตบนเซิร์ฟเวอร์เดียวกัน หนึ่งสำหรับ Django (หันหน้าไปทางสาธารณะ) และหนึ่งสำหรับ next.js (ภายใน) ให้ Django จัดการคำขอเว็บทั้งหมด สำหรับแต่ละคำขอ Query Next.js จาก Django View เพื่อรับการตอบกลับ HTML ส่งคืนการตอบสนอง HTML ที่แน่นอนจากมุมมอง Django
ติดตั้งเวอร์ชันล่าสุดจาก PYPI
pip install django-nextjs เพิ่ม django_nextjs.apps.DjangoNextJSConfig เพื่อ INSTALLED_APPS
ตั้งค่า url next.js ขึ้นอยู่กับสภาพแวดล้อมของคุณ
หากคุณให้บริการเว็บไซต์ของคุณภายใต้ ASGI ในระหว่างการพัฒนาให้ใช้ช่อง Django และเพิ่ม NextJSProxyHttpConsumer , NextJSProxyWebsocketConsumer ถึง asgi.py เช่นตัวอย่างต่อไปนี้
หมายเหตุ: เราขอแนะนำให้ใช้ช่อง ASGI และ Django เนื่องจากจำเป็นสำหรับการรีเฟรชอย่างรวดเร็ว (การเปลี่ยนโมดูลร้อน) เพื่อทำงานอย่างถูกต้องใน NextJS 12+
import os
from django . core . asgi import get_asgi_application
from django . urls import re_path , path
os . environ . setdefault ( "DJANGO_SETTINGS_MODULE" , "myproject.settings" )
django_asgi_app = get_asgi_application ()
from channels . auth import AuthMiddlewareStack
from channels . routing import ProtocolTypeRouter , URLRouter
from django_nextjs . proxy import NextJSProxyHttpConsumer , NextJSProxyWebsocketConsumer
from django . conf import settings
# put your custom routes here if you need
http_routes = [ re_path ( r"" , django_asgi_app )]
websocket_routers = []
if settings . DEBUG :
http_routes . insert ( 0 , re_path ( r"^(?:_next|__next|next).*" , NextJSProxyHttpConsumer . as_asgi ()))
websocket_routers . insert ( 0 , path ( "_next/webpack-hmr" , NextJSProxyWebsocketConsumer . as_asgi ()))
application = ProtocolTypeRouter (
{
# Django's ASGI application to handle traditional HTTP and websocket requests.
"http" : URLRouter ( http_routes ),
"websocket" : AuthMiddlewareStack ( URLRouter ( websocket_routers )),
# ...
}
) มิฉะนั้น (ถ้าให้บริการภายใต้ WSGI ในระหว่างการพัฒนา) ให้เพิ่มสิ่งต่อไปนี้ไปยังจุดเริ่มต้นของ urls.py :
path ( "" , include ( "django_nextjs.urls" )) คำเตือน: หากคุณให้บริการภายใต้ ASGI อย่าเพิ่มสิ่งนี้ลงใน urls.py ของคุณ มันอาจทำให้เกิดการหยุดชะงัก
ในการผลิตให้ใช้พร็อกซีย้อนกลับเช่น Nginx หรือ Caddy:
| url | การกระทำ |
|---|---|
/_next/static/... | เสิร์ฟ NEXTJS_PATH/.next/static |
/_next/... | พร็อกซีถึง http://localhost:3000 |
/next/... | เสิร์ฟ NEXTJS_PATH/public/next directory |
ตัวอย่างการกำหนดค่าสำหรับ nginx:
location /_next/static/ {
alias NEXTJS_PATH/.next/static/;
expires max;
add_header Cache-Control "public";
}
location /_next/ {
proxy_pass http://127.0.0.1:3000;
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
location /next/ {
alias NEXTJS_PATH/public/next/;
expires max;
add_header Cache-Control "public";
}
เริ่มต้น Next.js Server:
# Development:
$ npm run dev
# Production:
$ npm run build
$ npm run startเริ่มต้นด้วยการพัฒนาหน้าเว็บของคุณใน next.js จากนั้นกำหนด URL django สำหรับแต่ละหน้า next.js นี่คือตัวอย่างของวิธีที่คุณสามารถทำได้:
from django_nextjs . views import nextjs_page
urlpatterns = [
path ( "/nextjs/page" , nextjs_page (), name = "nextjs_page" ),
]แม้ว่าจะไม่แนะนำ แต่บางครั้งคุณอาจต้องเพิ่มขั้นตอนที่กำหนดเองก่อนที่จะแสดงหน้าถัดไป JS ใน Django อย่างไรก็ตาม เราแนะนำให้ย้ายตรรกะนี้ไปยัง next.js เพื่อให้แน่ใจว่ามันถูกนำไปใช้แม้ในระหว่างการเปลี่ยนเส้นทางฝั่งไคลเอ็นต์ หากคุณพบว่าตัวเองอยู่ในสถานการณ์นี้คุณสามารถสร้างมุมมองแบบอะซิงโครนัสสำหรับแต่ละหน้าดังแสดงด้านล่าง:
from django_nextjs . render import render_nextjs_page
async def jobs ( request ):
# Your custom logic
return await render_nextjs_page ( request )คุณสามารถแก้ไขรหัส HTML ที่ Next.js ส่งคืนในรหัส Django ของคุณ
การหลีกเลี่ยงรหัสที่ซ้ำกันสำหรับ Navbar และ Footer เป็นกรณีการใช้งานทั่วไปสำหรับสิ่งนี้หากคุณใช้ทั้งเทมเพลต Next.js และ Django หากไม่มีมันคุณจะต้องเขียนและบำรุงรักษา Navbar และส่วนท้ายของคุณสองเวอร์ชันแยกต่างหาก (เวอร์ชันเทมเพลต Django และรุ่นถัดไป JS) อย่างไรก็ตามคุณสามารถสร้างเทมเพลต Django สำหรับ Navbar ของคุณและแทรกรหัสที่จุดเริ่มต้นของแท็ก <body> ที่ส่งคืนจาก Next.js.
ในการเปิดใช้งานคุณสมบัตินี้คุณต้องปรับแต่งเอกสารและเค้าโครงรูทใน next.js และทำการปรับต่อไปนี้:
id="__django_nextjs_body" เป็นแอตทริบิวต์แรกขององค์ประกอบ <body><div id="__django_nextjs_body_begin" /> เป็นองค์ประกอบแรกภายใน <body><div id="__django_nextjs_body_end" /> เป็นองค์ประกอบสุดท้ายภายใน <body>หมายเหตุ: การปรับแต่ง HTML ในปัจจุบันไม่ทำงานกับเราเตอร์แอพ (next.js 13+)
อ่านเอกสารนี้และปรับแต่งเอกสาร next.js ของคุณ:
// pages/_document.jsx (or .tsx)
...
< body id = "__django_nextjs_body" >
< div id = "__django_nextjs_body_begin" />
< Main />
< NextScript />
< div id = "__django_nextjs_body_end" />
</ body >
. . . เขียนเทมเพลต django ที่ขยาย django_nextjs/document_base.html :
{% extends "django_nextjs/document_base.html" %}
{% block head %}
<!-- ... the content you want to place at the beginning of "head" tag ... -->
{{ block.super }}
<!-- ... the content you want to place at the end of "head" tag ... -->
{% endblock %}
{% block body %}
... the content you want to place at the beginning of "body" tag ...
... e.g. include the navbar template ...
{{ block.super }}
... the content you want to place at the end of "body" tag ...
... e.g. include the footer template ...
{% endblock %} ส่งชื่อเทมเพลตไปยัง nextjs_page หรือ render_nextjs_page :
from django_nextjs . render import render_nextjs_page
from django_nextjs . views import nextjs_page
async def jobs ( request ):
return await render_nextjs_page ( request , template_name = "path/to/template.html" )
urlpatterns = [
path ( "/nextjs/page" , nextjs_page ( template_name = "path/to/template.html" ), name = "nextjs_page" ),
path ( "/jobs" , jobs , name = "jobs_page" )
]public ของ next.js ไฟล์นั้นควรอยู่ในไดเรกทอรี public/next เพื่อทำงานอย่างถูกต้องAPPEND_SLASH = False ใน settings.py โครงการ Django ของคุณ นอกจากนี้อย่าเพิ่ม / ในตอนท้ายของเส้นทาง nextjs ใน urls.pyการตั้งค่าเริ่มต้น:
NEXTJS_SETTINGS = {
"nextjs_server_url" : "http://127.0.0.1:3000" ,
"ensure_csrf_token" : True ,
}nextjs_server_url URL ของเซิร์ฟเวอร์ Next.js (เริ่มต้นโดย npm run dev หรือ npm run start )
ensure_csrf_token หากผู้ใช้ไม่มีโทเค็น CSRF ตรวจสอบให้แน่ใจว่ามีการสร้างและรวมอยู่ในคำขอเริ่มต้นไปยังเซิร์ฟเวอร์ถัดไป JS โดยเรียก django.middleware.csrf.get_token ของ Django หาก django.middleware.csrf.CsrfViewMiddleware ได้รับการติดตั้งการตอบกลับเริ่มต้นจะรวมส่วนหัว Set-Cookie เพื่อคงค่าโทเค็น CSRF บนไคลเอนต์ พฤติกรรมนี้เปิดใช้งานโดยค่าเริ่มต้น
ensure_csrf_token ? คุณอาจต้องออกคำขอ post graphql เพื่อดึงข้อมูลใน next.js getServerSideProps หากนี่เป็นคำขอแรกของผู้ใช้จะไม่มีคุกกี้ CSRF ทำให้คำขอล้มเหลวเนื่องจาก GraphQL ใช้โพสต์แม้กระทั่งการดึงข้อมูล อย่างไรก็ตามตราบใดที่ฟังก์ชั่น getServerSideProps นั้นฟรีเอฟเฟกต์ฟรี (เช่นพวกเขาจะไม่ใช้วิธี HTTP unsafe หรือการกลายพันธุ์ GraphQL) สิ่งนี้ควรจะดีจากมุมมองด้านความปลอดภัย อ่านเพิ่มเติมที่นี่
pip install -e '.[dev]'pre-commit install มิกซ์