Remove double load of css, second time from the browser

merge-requests/30/head
Bob Mottram 2020-11-12 15:55:08 +00:00
parent b987fae6e7
commit a7bbe4a7d9
6 changed files with 196 additions and 275 deletions

View File

@ -9,7 +9,6 @@ __status__ = "Production"
import os
from shutil import copyfile
from utils import getConfigParam
from utils import getCSS
from utils import getNicknameFromActor
from posts import isEditor
from webapp_utils import htmlPostSeparator
@ -201,13 +200,6 @@ def htmlLinksMobile(cssCache: {}, baseDir: str,
if os.path.isfile(baseDir + '/epicyon.css'):
cssFilename = baseDir + '/epicyon.css'
profileStyle = getCSS(baseDir, cssFilename, cssCache)
if profileStyle:
# replace any https within the css with whatever prefix is needed
if httpPrefix != 'https':
profileStyle = \
profileStyle.replace('https://', httpPrefix + '://')
iconsDir = getIconsDir(baseDir)
# is the user a site editor?
@ -220,7 +212,7 @@ def htmlLinksMobile(cssCache: {}, baseDir: str,
if ':' in domain:
domain = domain.split(':')[0]
htmlStr = htmlHeaderWithExternalStyle(cssFilename, profileStyle)
htmlStr = htmlHeaderWithExternalStyle(cssFilename)
bannerFile, bannerFilename = getBannerFile(baseDir, nickname, domain)
htmlStr += \
'<a href="/users/' + nickname + '/' + defaultTimeline + '">' + \
@ -263,16 +255,10 @@ def htmlEditLinks(cssCache: {}, translate: {}, baseDir: str, path: str,
if os.path.isfile(baseDir + '/links.css'):
cssFilename = baseDir + '/links.css'
editCSS = getCSS(baseDir, cssFilename, cssCache)
if editCSS:
if httpPrefix != 'https':
editCSS = \
editCSS.replace('https://', httpPrefix + '://')
# filename of the banner shown at the top
bannerFile, bannerFilename = getBannerFile(baseDir, nickname, domain)
editLinksForm = htmlHeaderWithExternalStyle(cssFilename, editCSS)
editLinksForm = htmlHeaderWithExternalStyle(cssFilename)
# top banner
editLinksForm += \

View File

@ -12,7 +12,6 @@ from shutil import copyfile
from content import removeLongWords
from utils import locatePost
from utils import loadJson
from utils import getCSS
from utils import getConfigParam
from utils import votesOnNewswireItem
from utils import getNicknameFromActor
@ -305,16 +304,9 @@ def htmlCitations(baseDir: str, nickname: str, domain: str,
if os.path.isfile(baseDir + '/epicyon.css'):
cssFilename = baseDir + '/epicyon.css'
profileStyle = getCSS(baseDir, cssFilename, cssCache)
if profileStyle:
# replace any https within the css with whatever prefix is needed
if httpPrefix != 'https':
profileStyle = \
profileStyle.replace('https://', httpPrefix + '://')
# iconsDir = getIconsDir(baseDir)
htmlStr = htmlHeaderWithExternalStyle(cssFilename, profileStyle)
htmlStr = htmlHeaderWithExternalStyle(cssFilename)
# top banner
bannerFile, bannerFilename = getBannerFile(baseDir, nickname, domain)
@ -402,14 +394,6 @@ def htmlNewswireMobile(cssCache: {}, baseDir: str, nickname: str,
if os.path.isfile(baseDir + '/epicyon.css'):
cssFilename = baseDir + '/epicyon.css'
profileStyle = getCSS(baseDir, cssFilename, cssCache)
if profileStyle:
# replace any https within the css with whatever prefix is needed
if httpPrefix != 'https':
profileStyle = \
profileStyle.replace('https://',
httpPrefix + '://')
iconsDir = getIconsDir(baseDir)
if nickname == 'news':
@ -424,7 +408,7 @@ def htmlNewswireMobile(cssCache: {}, baseDir: str, nickname: str,
showPublishButton = editor
htmlStr = htmlHeaderWithExternalStyle(cssFilename, profileStyle)
htmlStr = htmlHeaderWithExternalStyle(cssFilename)
bannerFile, bannerFilename = getBannerFile(baseDir, nickname, domain)
htmlStr += \
@ -470,16 +454,10 @@ def htmlEditNewswire(cssCache: {}, translate: {}, baseDir: str, path: str,
if os.path.isfile(baseDir + '/links.css'):
cssFilename = baseDir + '/links.css'
editCSS = getCSS(baseDir, cssFilename, cssCache)
if editCSS:
if httpPrefix != 'https':
editCSS = \
editCSS.replace('https://', httpPrefix + '://')
# filename of the banner shown at the top
bannerFile, bannerFilename = getBannerFile(baseDir, nickname, domain)
editNewswireForm = htmlHeaderWithExternalStyle(cssFilename, editCSS)
editNewswireForm = htmlHeaderWithExternalStyle(cssFilename)
# top banner
editNewswireForm += \
@ -598,13 +576,7 @@ def htmlEditNewsPost(cssCache: {}, translate: {}, baseDir: str, path: str,
if os.path.isfile(baseDir + '/links.css'):
cssFilename = baseDir + '/links.css'
editCSS = getCSS(baseDir, cssFilename, cssCache)
if editCSS:
if httpPrefix != 'https':
editCSS = \
editCSS.replace('https://', httpPrefix + '://')
editNewsPostForm = htmlHeaderWithExternalStyle(cssFilename, editCSS)
editNewsPostForm = htmlHeaderWithExternalStyle(cssFilename)
editNewsPostForm += \
'<form enctype="multipart/form-data" method="POST" ' + \
'accept-charset="UTF-8" action="' + path + '/newseditdata">\n'

View File

@ -8,7 +8,6 @@ __status__ = "Production"
import os
from utils import isPublicPostFromUrl
from utils import getCSS
from utils import getNicknameFromActor
from utils import getDomainFromActor
from webapp_utils import getIconsDir
@ -253,12 +252,6 @@ def htmlNewPost(cssCache: {}, mediaInstance: bool, translate: {},
if os.path.isfile(baseDir + '/epicyon.css'):
cssFilename = baseDir + '/epicyon.css'
newPostCSS = getCSS(baseDir, cssFilename, cssCache)
if newPostCSS:
if httpPrefix != 'https':
newPostCSS = newPostCSS.replace('https://',
httpPrefix + '://')
if '?' in path:
path = path.split('?')[0]
pathBase = path.replace('/newreport', '').replace('/newpost', '')
@ -558,7 +551,7 @@ def htmlNewPost(cssCache: {}, mediaInstance: bool, translate: {},
dateAndLocation += '<input type="text" name="category">\n'
dateAndLocation += '</div>\n'
newPostForm = htmlHeaderWithExternalStyle(cssFilename, newPostCSS)
newPostForm = htmlHeaderWithExternalStyle(cssFilename)
newPostForm += \
'<a href="/users/' + nickname + '/' + defaultTimeline + '" title="' + \

View File

@ -10,7 +10,6 @@ import os
from shutil import copyfile
import urllib.parse
from datetime import datetime
from utils import getCSS
from utils import loadJson
from utils import getDomainFromActor
from utils import getNicknameFromActor
@ -48,49 +47,47 @@ def htmlSearchEmoji(cssCache: {}, translate: {},
if os.path.isfile(baseDir + '/epicyon.css'):
cssFilename = baseDir + '/epicyon.css'
emojiCSS = getCSS(baseDir, cssFilename, cssCache)
if emojiCSS:
emojiLookupFilename = baseDir + '/emoji/emoji.json'
emojiLookupFilename = baseDir + '/emoji/emoji.json'
# create header
emojiForm = htmlHeaderWithExternalStyle(cssFilename, emojiCSS)
emojiForm += '<center><h1>' + \
translate['Emoji Search'] + \
'</h1></center>'
# does the lookup file exist?
if not os.path.isfile(emojiLookupFilename):
emojiForm += '<center><h5>' + \
translate['No results'] + '</h5></center>'
emojiForm += htmlFooter()
return emojiForm
emojiJson = loadJson(emojiLookupFilename)
if emojiJson:
results = {}
for emojiName, filename in emojiJson.items():
if searchStr in emojiName:
results[emojiName] = filename + '.png'
for emojiName, filename in emojiJson.items():
if emojiName in searchStr:
results[emojiName] = filename + '.png'
headingShown = False
emojiForm += '<center>'
msgStr1 = translate['Copy the text then paste it into your post']
msgStr2 = ':<img loading="lazy" class="searchEmoji" src="/emoji/'
for emojiName, filename in results.items():
if os.path.isfile(baseDir + '/emoji/' + filename):
if not headingShown:
emojiForm += \
'<center><h5>' + msgStr1 + \
'</h5></center>'
headingShown = True
emojiForm += \
'<h3>:' + emojiName + msgStr2 + \
filename + '"/></h3>'
emojiForm += '</center>'
# create header
emojiForm = htmlHeaderWithExternalStyle(cssFilename)
emojiForm += '<center><h1>' + \
translate['Emoji Search'] + \
'</h1></center>'
# does the lookup file exist?
if not os.path.isfile(emojiLookupFilename):
emojiForm += '<center><h5>' + \
translate['No results'] + '</h5></center>'
emojiForm += htmlFooter()
return emojiForm
emojiJson = loadJson(emojiLookupFilename)
if emojiJson:
results = {}
for emojiName, filename in emojiJson.items():
if searchStr in emojiName:
results[emojiName] = filename + '.png'
for emojiName, filename in emojiJson.items():
if emojiName in searchStr:
results[emojiName] = filename + '.png'
headingShown = False
emojiForm += '<center>'
msgStr1 = translate['Copy the text then paste it into your post']
msgStr2 = ':<img loading="lazy" class="searchEmoji" src="/emoji/'
for emojiName, filename in results.items():
if os.path.isfile(baseDir + '/emoji/' + filename):
if not headingShown:
emojiForm += \
'<center><h5>' + msgStr1 + \
'</h5></center>'
headingShown = True
emojiForm += \
'<h3>:' + emojiName + msgStr2 + \
filename + '"/></h3>'
emojiForm += '</center>'
emojiForm += htmlFooter()
return emojiForm
@ -114,155 +111,153 @@ def htmlSearchSharedItems(cssCache: {}, translate: {},
if os.path.isfile(baseDir + '/epicyon.css'):
cssFilename = baseDir + '/epicyon.css'
sharedItemsCSS = getCSS(baseDir, cssFilename, cssCache)
if sharedItemsCSS:
sharedItemsForm = \
htmlHeaderWithExternalStyle(cssFilename, sharedItemsCSS)
sharedItemsForm += \
'<center><h1>' + translate['Shared Items Search'] + \
'</h1></center>'
resultsExist = False
for subdir, dirs, files in os.walk(baseDir + '/accounts'):
for handle in dirs:
if '@' not in handle:
continue
contactNickname = handle.split('@')[0]
sharesFilename = baseDir + '/accounts/' + handle + \
'/shares.json'
if not os.path.isfile(sharesFilename):
continue
sharedItemsForm = \
htmlHeaderWithExternalStyle(cssFilename)
sharedItemsForm += \
'<center><h1>' + translate['Shared Items Search'] + \
'</h1></center>'
resultsExist = False
for subdir, dirs, files in os.walk(baseDir + '/accounts'):
for handle in dirs:
if '@' not in handle:
continue
contactNickname = handle.split('@')[0]
sharesFilename = baseDir + '/accounts/' + handle + \
'/shares.json'
if not os.path.isfile(sharesFilename):
continue
sharesJson = loadJson(sharesFilename)
if not sharesJson:
continue
sharesJson = loadJson(sharesFilename)
if not sharesJson:
continue
for name, sharedItem in sharesJson.items():
matched = True
for searchSubstr in searchStrLowerList:
subStrMatched = False
searchSubstr = searchSubstr.strip()
if searchSubstr in sharedItem['location'].lower():
subStrMatched = True
elif searchSubstr in sharedItem['summary'].lower():
subStrMatched = True
elif searchSubstr in sharedItem['displayName'].lower():
subStrMatched = True
elif searchSubstr in sharedItem['category'].lower():
subStrMatched = True
if not subStrMatched:
matched = False
for name, sharedItem in sharesJson.items():
matched = True
for searchSubstr in searchStrLowerList:
subStrMatched = False
searchSubstr = searchSubstr.strip()
if searchSubstr in sharedItem['location'].lower():
subStrMatched = True
elif searchSubstr in sharedItem['summary'].lower():
subStrMatched = True
elif searchSubstr in sharedItem['displayName'].lower():
subStrMatched = True
elif searchSubstr in sharedItem['category'].lower():
subStrMatched = True
if not subStrMatched:
matched = False
break
if matched:
if currPage == pageNumber:
sharedItemsForm += '<div class="container">\n'
sharedItemsForm += \
'<p class="share-title">' + \
sharedItem['displayName'] + '</p>\n'
if sharedItem.get('imageUrl'):
sharedItemsForm += \
'<a href="' + \
sharedItem['imageUrl'] + '">\n'
sharedItemsForm += \
'<img loading="lazy" src="' + \
sharedItem['imageUrl'] + \
'" alt="Item image"></a>\n'
sharedItemsForm += \
'<p>' + sharedItem['summary'] + '</p>\n'
sharedItemsForm += \
'<p><b>' + translate['Type'] + \
':</b> ' + sharedItem['itemType'] + ' '
sharedItemsForm += \
'<b>' + translate['Category'] + \
':</b> ' + sharedItem['category'] + ' '
sharedItemsForm += \
'<b>' + translate['Location'] + \
':</b> ' + sharedItem['location'] + '</p>\n'
contactActor = \
httpPrefix + '://' + domainFull + \
'/users/' + contactNickname
sharedItemsForm += \
'<p><a href="' + actor + \
'?replydm=sharedesc:' + \
sharedItem['displayName'] + \
'?mention=' + contactActor + \
'"><button class="button">' + \
translate['Contact'] + '</button></a>\n'
if actor.endswith('/users/' + contactNickname):
sharedItemsForm += \
' <a href="' + actor + '?rmshare=' + \
name + '"><button class="button">' + \
translate['Remove'] + '</button></a>\n'
sharedItemsForm += '</p></div>\n'
if not resultsExist and currPage > 1:
postActor = \
getAltPath(actor, domainFull,
callingDomain)
# previous page link, needs to be a POST
sharedItemsForm += \
'<form method="POST" action="' + \
postActor + \
'/searchhandle?page=' + \
str(pageNumber - 1) + '">\n'
sharedItemsForm += \
' <input type="hidden" ' + \
'name="actor" value="' + actor + '">\n'
sharedItemsForm += \
' <input type="hidden" ' + \
'name="searchtext" value="' + \
searchStrLower + '"><br>\n'
sharedItemsForm += \
' <center>\n' + \
' <a href="' + actor + \
'" type="submit" name="submitSearch">\n'
sharedItemsForm += \
' <img loading="lazy" ' + \
'class="pageicon" src="/' + iconsDir + \
'/pageup.png" title="' + \
translate['Page up'] + \
'" alt="' + translate['Page up'] + \
'"/></a>\n'
sharedItemsForm += ' </center>\n'
sharedItemsForm += '</form>\n'
resultsExist = True
ctr += 1
if ctr >= resultsPerPage:
currPage += 1
if currPage > pageNumber:
postActor = \
getAltPath(actor, domainFull,
callingDomain)
# next page link, needs to be a POST
sharedItemsForm += \
'<form method="POST" action="' + \
postActor + \
'/searchhandle?page=' + \
str(pageNumber + 1) + '">\n'
sharedItemsForm += \
' <input type="hidden" ' + \
'name="actor" value="' + actor + '">\n'
sharedItemsForm += \
' <input type="hidden" ' + \
'name="searchtext" value="' + \
searchStrLower + '"><br>\n'
sharedItemsForm += \
' <center>\n' + \
' <a href="' + actor + \
'" type="submit" name="submitSearch">\n'
sharedItemsForm += \
' <img loading="lazy" ' + \
'class="pageicon" src="/' + iconsDir + \
'/pagedown.png" title="' + \
translate['Page down'] + \
'" alt="' + translate['Page down'] + \
'"/></a>\n'
sharedItemsForm += ' </center>\n'
sharedItemsForm += '</form>\n'
break
if matched:
if currPage == pageNumber:
sharedItemsForm += '<div class="container">\n'
sharedItemsForm += \
'<p class="share-title">' + \
sharedItem['displayName'] + '</p>\n'
if sharedItem.get('imageUrl'):
sharedItemsForm += \
'<a href="' + \
sharedItem['imageUrl'] + '">\n'
sharedItemsForm += \
'<img loading="lazy" src="' + \
sharedItem['imageUrl'] + \
'" alt="Item image"></a>\n'
sharedItemsForm += \
'<p>' + sharedItem['summary'] + '</p>\n'
sharedItemsForm += \
'<p><b>' + translate['Type'] + \
':</b> ' + sharedItem['itemType'] + ' '
sharedItemsForm += \
'<b>' + translate['Category'] + \
':</b> ' + sharedItem['category'] + ' '
sharedItemsForm += \
'<b>' + translate['Location'] + \
':</b> ' + sharedItem['location'] + '</p>\n'
contactActor = \
httpPrefix + '://' + domainFull + \
'/users/' + contactNickname
sharedItemsForm += \
'<p><a href="' + actor + \
'?replydm=sharedesc:' + \
sharedItem['displayName'] + \
'?mention=' + contactActor + \
'"><button class="button">' + \
translate['Contact'] + '</button></a>\n'
if actor.endswith('/users/' + contactNickname):
sharedItemsForm += \
' <a href="' + actor + '?rmshare=' + \
name + '"><button class="button">' + \
translate['Remove'] + '</button></a>\n'
sharedItemsForm += '</p></div>\n'
if not resultsExist and currPage > 1:
postActor = \
getAltPath(actor, domainFull,
callingDomain)
# previous page link, needs to be a POST
sharedItemsForm += \
'<form method="POST" action="' + \
postActor + \
'/searchhandle?page=' + \
str(pageNumber - 1) + '">\n'
sharedItemsForm += \
' <input type="hidden" ' + \
'name="actor" value="' + actor + '">\n'
sharedItemsForm += \
' <input type="hidden" ' + \
'name="searchtext" value="' + \
searchStrLower + '"><br>\n'
sharedItemsForm += \
' <center>\n' + \
' <a href="' + actor + \
'" type="submit" name="submitSearch">\n'
sharedItemsForm += \
' <img loading="lazy" ' + \
'class="pageicon" src="/' + iconsDir + \
'/pageup.png" title="' + \
translate['Page up'] + \
'" alt="' + translate['Page up'] + \
'"/></a>\n'
sharedItemsForm += ' </center>\n'
sharedItemsForm += '</form>\n'
resultsExist = True
ctr += 1
if ctr >= resultsPerPage:
currPage += 1
if currPage > pageNumber:
postActor = \
getAltPath(actor, domainFull,
callingDomain)
# next page link, needs to be a POST
sharedItemsForm += \
'<form method="POST" action="' + \
postActor + \
'/searchhandle?page=' + \
str(pageNumber + 1) + '">\n'
sharedItemsForm += \
' <input type="hidden" ' + \
'name="actor" value="' + actor + '">\n'
sharedItemsForm += \
' <input type="hidden" ' + \
'name="searchtext" value="' + \
searchStrLower + '"><br>\n'
sharedItemsForm += \
' <center>\n' + \
' <a href="' + actor + \
'" type="submit" name="submitSearch">\n'
sharedItemsForm += \
' <img loading="lazy" ' + \
'class="pageicon" src="/' + iconsDir + \
'/pagedown.png" title="' + \
translate['Page down'] + \
'" alt="' + translate['Page down'] + \
'"/></a>\n'
sharedItemsForm += ' </center>\n'
sharedItemsForm += '</form>\n'
break
ctr = 0
if not resultsExist:
sharedItemsForm += \
'<center><h5>' + translate['No results'] + '</h5></center>\n'
sharedItemsForm += htmlFooter()
ctr = 0
if not resultsExist:
sharedItemsForm += \
'<center><h5>' + translate['No results'] + '</h5></center>\n'
sharedItemsForm += htmlFooter()
return sharedItemsForm
@ -288,9 +283,7 @@ def htmlSearchEmojiTextEntry(cssCache: {}, translate: {},
if os.path.isfile(baseDir + '/follow.css'):
cssFilename = baseDir + '/follow.css'
profileStyle = getCSS(baseDir, cssFilename, cssCache)
emojiStr = htmlHeaderWithExternalStyle(cssFilename, profileStyle)
emojiStr = htmlHeaderWithExternalStyle(cssFilename)
emojiStr += '<div class="follow">\n'
emojiStr += ' <div class="followAvatar">\n'
emojiStr += ' <center>\n'
@ -330,9 +323,7 @@ def htmlSearch(cssCache: {}, translate: {},
if os.path.isfile(baseDir + '/search.css'):
cssFilename = baseDir + '/search.css'
profileStyle = getCSS(baseDir, cssFilename, cssCache)
followStr = htmlHeaderWithExternalStyle(cssFilename, profileStyle)
followStr = htmlHeaderWithExternalStyle(cssFilename)
# show a banner above the search box
searchBannerFile, searchBannerFilename = \
@ -506,8 +497,6 @@ def htmlHashtagSearch(cssCache: {},
if os.path.isfile(baseDir + '/epicyon.css'):
cssFilename = baseDir + '/epicyon.css'
hashtagSearchCSS = getCSS(baseDir, cssFilename, cssCache)
# ensure that the page number is in bounds
if not pageNumber:
pageNumber = 1
@ -523,7 +512,7 @@ def htmlHashtagSearch(cssCache: {},
# add the page title
hashtagSearchForm = \
htmlHeaderWithExternalStyle(cssFilename, hashtagSearchCSS)
htmlHeaderWithExternalStyle(cssFilename)
if nickname:
hashtagSearchForm += '<center>\n' + \
'<h1><a href="/users/' + nickname + '/search">#' + \
@ -813,9 +802,7 @@ def htmlSkillsSearch(cssCache: {}, translate: {}, baseDir: str,
if os.path.isfile(baseDir + '/epicyon.css'):
cssFilename = baseDir + '/epicyon.css'
skillSearchCSS = getCSS(baseDir, cssFilename, cssCache)
skillSearchForm = htmlHeaderWithExternalStyle(cssFilename, skillSearchCSS)
skillSearchForm = htmlHeaderWithExternalStyle(cssFilename)
skillSearchForm += \
'<center><h1>' + translate['Skills search'] + ': ' + \
skillsearch + '</h1></center>'
@ -878,9 +865,8 @@ def htmlHistorySearch(cssCache: {}, translate: {}, baseDir: str,
if os.path.isfile(baseDir + '/epicyon.css'):
cssFilename = baseDir + '/epicyon.css'
historySearchCSS = getCSS(baseDir, cssFilename, cssCache)
historySearchForm = \
htmlHeaderWithExternalStyle(cssFilename, historySearchCSS)
htmlHeaderWithExternalStyle(cssFilename)
# add the page title
historySearchForm += \

View File

@ -9,7 +9,6 @@ __status__ = "Production"
import os
from datetime import datetime
import time
from utils import getCSS
from utils import removeIdEnding
from follow import followerApprovalActive
from person import isPersonSnoozed
@ -121,17 +120,6 @@ def htmlTimeline(cssCache: {}, defaultTimeline: str,
if timeDiff > 100:
print('TIMELINE TIMING ' + boxName + ' 1 = ' + str(timeDiff))
profileStyle = getCSS(baseDir, cssFilename, cssCache)
if not profileStyle:
print('ERROR: css file not found ' + cssFilename)
return None
# replace any https within the css with whatever prefix is needed
if httpPrefix != 'https':
profileStyle = \
profileStyle.replace('https://',
httpPrefix + '://')
# is the user a moderator?
if not moderator:
moderator = isModerator(baseDir, nickname)
@ -263,7 +251,7 @@ def htmlTimeline(cssCache: {}, defaultTimeline: str,
eventsButton + '"><span>' + translate['Events'] + \
'</span></button></a>'
tlStr = htmlHeaderWithExternalStyle(cssFilename, profileStyle)
tlStr = htmlHeaderWithExternalStyle(cssFilename)
# benchmark 4
timeDiff = int((time.time() - timelineStartTime) * 1000)

View File

@ -437,15 +437,11 @@ def htmlHeader(cssFilename: str, css: str, lang='en') -> str:
return htmlStr
def htmlHeaderWithExternalStyle(cssFilename: str, css: str, lang='en') -> str:
def htmlHeaderWithExternalStyle(cssFilename: str, lang='en') -> str:
htmlStr = '<!DOCTYPE html>\n'
htmlStr += '<html lang="' + lang + '">\n'
htmlStr += ' <head>\n'
htmlStr += ' <meta charset="utf-8">\n'
fontName, fontFormat = getFontFromCss(css)
if fontName:
htmlStr += ' <link rel="preload" as="font" type="' + \
fontFormat + '" href="' + fontName + '" crossorigin>\n'
cssFile = cssFilename.split('/')[-1]
htmlStr += ' <link rel="stylesheet" href="' + cssFile + '">\n'
htmlStr += ' <link rel="manifest" href="/manifest.json">\n'