I am embedding a react project inside my django app. I am serving the index.html file created by npm run build from django as opposed to just using django as a third party api. I like this approach as it leverages django user authentication/ csrf tokens/ etc.
After npm run build I am extracting the head and the scripts on index.html and putting them in my base.html of django, this way, the react scripts will be available wherever I need them and I can use my django templates for my navbar, footer etc.
The problem I am having is I have to copy and paste the headers and scripts on every build, so my question is if there is a way to make npm run build build the files with the same name every time, or perhaps another solution, so when I rebuild the react project I don't have to recopy and paste to base.html?
Here is a code snippet sample
base.html
<html>
<head>
<!-- Copy and pasted header files from react build-->
</head>
<body>
<navbar></navbar>
{% block content %}
{% endblock %}
<script> //copy and pasted scripts from react build - different script names on every build </script>
</body>
</html>
And then a file served by django
homepage.html
{% extend 'base.html' %}
<div class="other-django-stuff"></div>
{% block content %}
<div id="root"></div> // where my react project is anchored
{% endblock %}
Well, so what is needed in this case is a post build script that allows you to edit the file called base.html to have the right names and scripts produced by the build. I will describe here some conceptual steps on how to achieve this result.
Step n. 1: Change the package.json file to allow the execution of a script after the build
In this case I am using a JavaScript script file that will be run using nodejs, but you can use also other languages or shell scripts
"scripts": {
...
"build": "react-scripts build && node ./postbuild.js",
...
},
Note that, since the && operator is used, the postbuild.js file will executed only if the build will have success.
Step n. 2: Create the post build script that will write your base.html file
With the script you will be able to write the base.html file dynamically.
Note:
Since you can create the script in different languages, the script itself it is not included in the answer.
Thanks to Emanuele's guidance Here is the following solution using python. This assumes the react static build folder is added to STATIC_DIRS in settings.py:
base.html
<html>
<head>
{% include 'react_head.html' %}
</head>
<body>
<navbar></navbar>
{% block content %}
{% endblock %}
{% include 'react_scripts.html' %}
<script src='django-scripts.js'></script>
</body>
</html>
build_base.py
from bs4 import BeautifulSoup
index = open( "build/index.html" )
soup = BeautifulSoup( index, features="html.parser" )
links = soup.findAll( "link" )
scripts = soup.findAll( "script" )
with open( "./../templates/react_head.html", "w" ) as html:
html.write( r"{% load static %}" + "\n" )
for link in links:
url = link["href"]
if "favicon" in url: continue
fname = "/".join( url.split("/static/")[1:] )
link["href"] = '{% static ' + f"'{fname}' " + r"%}"
html.write( link.prettify() )
with open( "./../templates/react_scripts.html", "w" ) as html:
html.write( r"{% load static %}" + "\n" )
for script in scripts:
if 'src' in script:
url = script["src"]
fname = "/".join( url.split("/static/")[1:] )
script["src"] = '{% static ' + f"'{fname}' " + r"%}"
html.write( script.prettify() )
package.json
"scripts": {
...
"build": "react-scripts build && python ./build_base.py",
...
},
Related
I'm trying to embed a small react app into a squarespace site.
Here's the page: https://www.birdiebreak.com/referral-profile?referralCode=WHUOS
I can get the react app to load just fine but various parts of the site disappear! Specifically the header and any images on the page.
I've tried using the Code widget as well as the Embed widget with both have the same result.
I did try a basic Create React App site to see if the minimal code I built was the problem but got the same issues.
Has anyone managed to do this successfully?
I don't know why exactly, but if I add a script tag into the body referencing my react app <script src="path-to-react/main.buildcode.js" /> parts of the squarespace site just stop loading.
However if instead I add a script loader things work just fine.
<script type="text/javascript">
(function (g, r, head, script) {
head = r.getElementsByTagName("head")[0];
script = r.createElement("script");
script.async = 1;
script.src = "https://birdie-break-develop.azurewebsites.net/static/js/main.d2ee648d.js";
head.appendChild(script);
})(window, document);
</script>
I've had success using a modified version of the Add React to a Website guide in the React docs. Assuming you have access to the source code for your React app, the following steps should work:
Add a Code Block with a single empty div containing a unique ID ('custom-react-root', or whatever you'd like). This is where your React app will render.
Configure your index.js to use this block as the root:
function run() {
ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>,
document.getElementById('custom-react-root')
);
}
Run the build command for your build tool to create the minified JS files. (e.g. yarn build)
Wrap the minified JS files in <script> tags, and the CSS file in <style> tags. I wrote a bash script to do this, which includes the following lines:
(
echo "<script>"
cat build/static/js/2.*.chunk.js
echo "</script>"
echo "<script>"
cat build/static/js/main.*.chunk.js
echo "</script>"
echo "<script>"
cat build/static/js/runtime-main.*.js
echo "</script>"
echo "<style>"
cat build/static/css/*.chunk.css
echo "</style>"
) > build/injectable.html
Paste these tags into the Page Header, as described in the SquareSpace docs.
Having the following file in the data folder:
# data/files.json
{
"test/file1.txt": "abcd/1234567890.txt",
"test/file2.txt": "bcde/1234567890.txt"
}
How do I obtain the value of "test/file1.txt" from the map? For example from this file
// layout/index.ace
= doctype html
html lang={{ .Site.Language.Lang }}
body
p {{ .Site.Data.files.????? }}
This is my environment:
$ go version
go version go1.9.2 linux/amd64
$ hugo version
Hugo Static Site Generator v0.35-DEV linux/amd64 BuildDate:
// layout/index.ace
= doctype html
html lang={{ .Site.Language.Lang }}
body
p {{ index .Site.Data.files "test/file1.txt" }}
does the trick.
Jekyll Version: 2.4.0
github pages Version: 35
My Reproduction Steps
Build on locally and the looping of collections site.collections.guides.docs shown, generated the correct .html in _site folder as well.
However, when I deploy to github, it doesn't show the loop content.
The Output I Wanted
shown the loop in github pages, appreciate if someone have a look on my repo.
my codes:
// index.html
{% for doc in site.collections.guides.docs %}
{{ doc.content }}
{% endfor %}
// _config.yml
collections :
guides:
output: true
I would write it like this:
{% for doc in site.guides %}
{{ doc.content }}
{% endfor %}
And the config like this:
collections:
guides:
output: true
From the "getting started" section it seems this should work, but it doesn't.
hugo new site my-site
hugo new privacy.md
hugo server --watch --includeDrafts
curl -L localhost:1313/privacy/index.html
# 404 page not found
curl -L localhost:1313/privacy.html
# 404 page not found
curl -L localhost:1313/privacy/
# 404 page not found
How can I add a new page?
This is the best tutorial how to create static "landing pages" on Hugo: https://discuss.gohugo.io/t/creating-static-content-that-uses-partials/265/19?u=royston
Basically, you create .md in /content/ with type: "page" in front matter, then create custom layout for it, for example layout: "simple-static" in front matter, then create the layout template in themes/<name>/layouts/page/, for example, simple-static.html. Then, use all partials as usual, and call content from original .md file using {{ .Content }}.
All my static (landing) pages are using this method.
By the way, I'm not using hugo new, I just clone .md file or copy a template into /content/ and open it using my iA Writer text editor. But I'm not using Hugo server either, adapted npm-build-boilerplate is running the server and builds.
Just tested OK with this on Hugo 0.13:
hugo new site my-site
cd my-site
hugo new privacy.md
hugo server -w -D
curl -L localhost:1313/privacy/
Note: You have to either use a theme or provide your own layout template to get something more than a blank page. And of course, some Markdown in privacy.md would also make it even nicer.
See http://gohugo.io/overview/introduction for up-to-date documentation.
I had a similar requirement, to add static page (aboutus in this case). Following steps did the trick,
Created an empty file content/aboutus/_index.md
Created aboutus.html page layouts/section/aboutus.html
Make you have some default frontmatter set in archetypes/default.md
# archetypes/default.md
+++
title: "{{ replace .Name "-" " " | title }}"
date: {{ .Date }}
draft: true
+++
And the single layout in layouts/_default/single.html to render some variable or content
# tags to render markdown content
<h1>{{ .Title }}</h1>
<p>{{ .Content }}</p>
<span>{{ .Params.date }}</span>
Now type hugo new privacy.md which will create a new page on the following directory in content/privacy.md
Take "About" as example:
# will create content/about.md
hugo new about.md
Edit about.md and add the last 2 lines, the metadata/front matter looks like:
title: "About"
date: 2019-03-26
menu: "main"
weight: 50
That should work.
I've been following an earlier post to check if an asset exists, which works great when using specific filenames.
Symfony2 and Twig - Check if an asset exists
However instead of checking for a specific image filename, how do you check for an image type? (all files with the .jpg extension)
Example: *.jpg (which doesn't work neither does .jpg)
{% if asset_exists('/images/*.jpg') %}
<div class="entry-thumbnail">
<img width="230" height="172" src="{{ asset(['images/', post.image]|join) }}" class="" alt=""/>
</div>
{% endif %}
As soon as you are using:
{{ asset(['images/', post.image]|join) }}`
Why not using:
{% if asset_exists(['images/', post.image]|join) %}
Tip: replace ['images/', post.image]|join by using the concat operator ~: 'images/' ~ post.image
You'd have to modify the Twig Extension and replace !is_file($toCheck) with count(glob($toCheck)) < 1
glob function (php.net)