django 模板调用js
I’ve been building a site that uses a React frontend and Django backend, and I’ve finally gotten around to thinking about how to improve the marketing pages (i.e. landing page, etc.). However, some of the well-known problems with using React for a landing page are (1) worse SEO and (2) likely slower page loading times (which also impacts google ranking).
我一直在建立一个使用React前端和Django后端的网站,最后我终于开始思考如何改善营销页面(即目标页面等)。 但是,使用React登陆页面的一些众所周知的问题是(1)SEO较差;(2)页面加载时间可能会变慢(这也会影响Google排名)。
So I wanted to instead pre-render the marketing pages. Two major solutions that are compatible with my React code are Gatsby and Next.js. And after some googling around, it seemed Next.js could do everything Gatsby could do and would be easier to setup. So I chose Next.js.
因此,我想预渲染营销页面。 与我的React代码兼容的两个主要解决方案是Gatsby和Next.js。 经过一番探索之后,Next.js似乎可以完成Gatsby可以做的所有事情,并且设置起来也更加容易。 所以我选择了Next.js。
But the real challenge I had was figuring out the relationship between Next.js and my Django backend. In short, I decided to use Next.js to pre-render my marketing pages and serve them as Django templates. Below I’ll show you how I did it.
但是我真正面临的挑战是弄清楚Next.js和Django后端之间的关系。 简而言之,我决定使用Next.js预先渲染我的营销页面并将其用作Django模板。 下面,我将向您展示如何做到这一点。
Caveat: I am definitely not a seasoned software engineer (I am a computational biologist by training), but what I came up with works just fine for me. However, some alternative solutions some people might suggest are: (1) just use wordpress for marketing pages, or (2) decouple the marketing pages from django and instead serve it with Next.js on a subdomain or something. Nonetheless, if you still have any thoughts/criticism, I am more than happy to hear them.
警告:我绝对不是经验丰富的软件工程师(我是受过培训的计算机生物学家),但是我的想法对我来说很好。 但是,某些人可能会建议一些替代解决方案:(1)仅将wordpress用于营销页面,或(2)将营销页面与django分离,然后在子域或其他内容上与Next.js一起使用。 但是,如果您仍然有任何想法/批评,我很乐意听到。
Next.js兼容性 (Next.js compatibility)
The first big hassle was to bring all the React code for my marketing pages into its own Django app and make it compatible with Next.js. While Next.js has some pretty good documentation on how to do this, it was still quite annoying (especially since I did not spend much time learning Next.js in-depth :P).
第一个大麻烦是将我的营销页面的所有React代码都带到自己的Django应用中,并使其与Next.js兼容。 尽管Next.js上有一些很好的文档,但是仍然很烦人(特别是因为我没有花很多时间来深入学习Next.js:P)。
Once I was able to successfully build the pages (via npx next build
), Next.js has a command to export the pages to static HTML (via npx next export -o output_folder
).
一旦我能够成功构建页面(通过npx npx next build
),Next.js就会有一个命令将页面导出到静态HTML(通过npx next export -o output_folder
)。
与Django集成 (Integrating with Django)
Next.js pre-rendered HTML files are small and bare-bones, but they still need some accompanying js and css bundles to render correctly (listed within the <head>
section). Here is one example:
Next.js预先渲染HTML文件虽然很小而且很简陋,但是它们仍然需要一些随附的js和css捆绑包才能正确渲染(在<head>
部分中列出)。 这是一个例子:
<link as="script" href="/_next/static/chunks/main-5f4f60561676956d0ca5.js"rel="preload"/>
However, when I serve the HTML page as a Django template, it will not be able to find the js/css bundles. Since Django normally looks for static files in the static directory, I needed to add the static template tags so Django knows where to find the js/css files. Like so:
但是,当我将HTML页面用作Django模板时,它将无法找到js / css包。 由于Django通常在静态目录中查找静态文件,因此我需要添加静态模板标签,以便Django知道在哪里可以找到js / css文件。 像这样:
<link as="script" href='{% static "/_next/static/chunks/main-5f4f60561676956d0ca5.js" %}' rel="preload"/>
But since I don’t want to manually make those edits, I wrote a python script to do it for me using BeautifulSoup (which is an HTML parsing library):
但是由于我不想手动进行这些编辑,因此我编写了一个Python脚本来使用BeautifulSoup(这是一个HTML解析库)为我完成此操作:
import argparse
import glob
import osfrom bs4 import BeautifulSoupdef parse_args():
parser = argparse.ArgumentParser()
parser.add_argument(
'-d',
'--dir',
type=str,
required=True) args = parser.parse_args() return args
def search_and_parse(soup, tag): for x in soup.find_all(tag): if x.get('src') and x['src'].startswith('/_next/'):
x['src'] = "{% static \"" + x['src'] + "\" %}" if x.get('href') and x['href'].startswith('/_next/'):
x['href'] = "{% static \"" + x['href'] + "\" %}"
def main(): args = parse_args() for html_file in glob.glob(os.path.join(args.dir, '*html')): soup = BeautifulSoup(open(html_file), 'html.parser')
soup.insert(0, '{% load static %}') # add script to store user info into window on page load
# is a workaround so i don't need redux django_script = BeautifulSoup("<script>window.django = {is_authenticated: \"{{ request.user.is_authenticated }}\" === \"True\" ? true : false, user_plan: \"{{user_plan}}\"};</script>", 'html.parser')
head = soup.find('head')
head.append(django_script) search_and_parse(soup, 'link')
search_and_parse(soup, 'script') fout = open(html_file, 'wb')
fout.write(soup.prettify('utf-8'))
fout.close()
main()
You’ll notice a couple extra things:
您会注意到一些额外的事情:
I added
{% load static %}
at the top of the HTML file, which Django needs in order for the static files to work correctly.我在HTML文件的顶部添加了
{% load static %}
,Django需要该文件才能使静态文件正常工作。I use the template context variables to store some information into the browser’s
window
object. I need this so I know if the user is logged in and what their payment plan is while they view the marketing pages.我使用模板上下文变量将一些信息存储到浏览器的
window
对象中。 我需要这个,所以我知道用户是否登录以及在查看营销页面时他们的付款计划是什么。
Another important step is actually placing all the js/css bundles within the static
folder. Oddly, running npx next export -o static
does not work and causes some strange bug. So I instead did this npx next export -o output && mv output static
.
另一个重要步骤实际上是将所有js / css捆绑包放在static
文件夹中。 奇怪的是,运行npx next export -o static
无法正常工作,并且会导致一些奇怪的错误。 所以我代替了npx next export -o output && mv output static
。
The final step is to actually place the HTML pages within Django’s required template
directory. However, instead of directly moving the HTML files from the static
folder to the template
folder, I created soft links to them. For example, while I am within the template
directory, I ran the following ln -s ../static/index.html index.html
. The advantage is that I don’t need to commit the pre-rendered HTML files to my git repo, I only need to commit the soft links. In fact, none of the output files from running npx next export
are in my git repo, only the React files that produce them are in my git repo.
最后一步是将HTML页面实际放置在Django所需的template
目录中。 但是,我没有将HTML文件从static
文件夹直接移动到template
文件夹,而是创建了指向它们的软链接。 例如,当我在template
目录中时,我运行了以下ln -s ../static/index.html index.html
。 好处是我不需要将预渲染HTML文件提交到git repo,而只需提交软链接。 实际上,从运行npx next export
的输出文件都不在我的git仓库中,只有生成它们的React文件在我的git仓库中。
Edit: For the above paragraph, I later found that while using links works fine for the local dev environment, I had to actually copy over the HTML files into the template directory to get it to work on AWS-Elastic Beanstalk.
编辑:对于上面的段落,我后来发现,尽管使用链接在本地开发环境中可以正常工作,但我实际上必须将HTML文件复制到模板目录中才能使其在AWS-Elastic Beanstalk上工作。
最后结果 (Final result)
I then combined all the above commands and scripts into one simple build command. Here is what my packages.json
scripts section looks like:
然后,我将上述所有命令和脚本组合成一个简单的构建命令。 这是我的packages.json
脚本部分的样子:
"scripts": {
"dev": "next dev",
"build": "next build",
"deploy": "rm -rf output static && next export -o output && mv output static && python ../bin/finalize_marketing_build.py -d static",
"start": "next start"
},
django 模板调用js