Skip to content

Commit

Permalink
refactor main js bundle load sequence
Browse files Browse the repository at this point in the history
Signed-off-by: weru <fromweru@gmail.com>
  • Loading branch information
onweru committed Feb 23, 2023
1 parent 62662eb commit 8496fdf
Show file tree
Hide file tree
Showing 4 changed files with 156 additions and 154 deletions.
241 changes: 90 additions & 151 deletions assets/js/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -131,13 +131,10 @@ function customizeSidebar() {
}
}

const paragraphs = elems('p');
if (paragraphs) {
paragraphs.forEach(function(p){
const buttons = elems('.button', p);
buttons.length > 1 ? pushClass(p, 'button_grid') : false;
});
}
elems('p').forEach(function(p){
const buttons = elems('.button', p);
buttons.length > 1 ? pushClass(p, 'button_grid') : false;
});
}

function markExternalLinks() {
Expand All @@ -163,185 +160,127 @@ function markExternalLinks() {
}
}

function loadActions() {
updateDate();
customizeSidebar();
markExternalLinks();

let heading_nodes = [], results, link, icon, current, id,
tags = ['h2', 'h3', 'h4', 'h5', 'h6'];
function sanitizeURL(url) {
// removes any existing id on url
const position_of_hash = url.indexOf(hash);
if(position_of_hash > -1 ) {
const id = url.substr(position_of_hash, url.length - 1);
url = url.replace(id, '');
}
return url
}

current = document.URL;
function createDeepLinks() {
let heading_nodes = [];

tags.forEach(function(tag){
results = document.getElementsByTagName(tag);
Array.prototype.push.apply(heading_nodes, results);
[...Array(6).keys()].forEach(function(i){
Array.prototype.push.apply(heading_nodes, document.getElementsByTagName(`h${i+1}`));
});

function sanitizeURL(url) {
// removes any existing id on url
const hash = '#';
const position_of_hash = url.indexOf(hash);
if(position_of_hash > -1 ) {
const id = url.substr(position_of_hash, url.length - 1);
url = url.replace(id, '');
}
return url
}

heading_nodes.forEach(function(node){
link = createEl('a');
icon = createEl('img');
let link = createEl('a');
let icon = createEl('img');
icon.src = '{{ absURL "icons/link.svg" }}';
link.className = 'link icon';
link.appendChild(icon);
id = node.getAttribute('id');
let id = node.getAttribute('id');
if(id) {
link.href = `${sanitizeURL(current)}#${id}`;
link.href = `${sanitizeURL(document.URL)}#${id}`;
node.appendChild(link);
pushClass(node, 'link_owner');
}
});
}

function copyFeedback(parent) {
const copy_txt = document.createElement('div');
const yanked = 'link_yanked';
copy_txt.classList.add(yanked);
copy_txt.innerText = copied_text;
if(!elem(`.${yanked}`, parent)) {
const icon = parent.getElementsByTagName('img')[0];
const original_src = icon.src;
icon.src = '{{ absURL "icons/check.svg" }}';
parent.appendChild(copy_txt);
setTimeout(function() {
parent.removeChild(copy_txt)
icon.src = original_src;
}, 2250);
}
}

(function copyHeadingLink() {
let deeplink, deeplinks, new_link, parent, target;
deeplink = 'link';
deeplinks = elems(`.${deeplink}`);
if(deeplinks) {
document.addEventListener('click', function(event)
{
target = event.target;
parent = target.parentNode;
if (target && containsClass(target, deeplink) || containsClass(parent, deeplink)) {
event.preventDefault();
new_link = target.href != undefined ? target.href : target.parentNode.href;
copyToClipboard(new_link);
target.href != undefined ? copyFeedback(target) : copyFeedback(target.parentNode);
}
});
}
})();

function prefersColor(mode){
return `(prefers-color-scheme: ${mode})`;
function copyFeedback(parent) {
const copy_txt = document.createElement('div');
const yanked = 'link_yanked';
copy_txt.classList.add(yanked);
copy_txt.innerText = copied_text;
if(!elem(`.${yanked}`, parent)) {
const icon = parent.getElementsByTagName('img')[0];
const original_src = icon.src;
icon.src = '{{ absURL "icons/check.svg" }}';
parent.appendChild(copy_txt);
setTimeout(function() {
parent.removeChild(copy_txt)
icon.src = original_src;
}, 2250);
}
}

function systemMode() {
if (window.matchMedia) {
const prefers = prefersColor(dark);
return window.matchMedia(prefers).matches ? dark : light;
}
return light;
function copyHeadingLink() {
let deeplink, deeplinks, new_link, parent, target;
deeplink = 'link';
deeplinks = elems(`.${deeplink}`);
if(deeplinks) {
document.addEventListener('click', function(event)
{
target = event.target;
parent = target.parentNode;
if (target && containsClass(target, deeplink) || containsClass(parent, deeplink)) {
event.preventDefault();
new_link = target.href != undefined ? target.href : target.parentNode.href;
copyToClipboard(new_link);
target.href != undefined ? copyFeedback(target) : copyFeedback(target.parentNode);
}
});
}
}

function currentMode() {
let acceptable_chars = light + dark;
acceptable_chars = [...acceptable_chars];
let mode = getComputedStyle(doc).getPropertyValue(key).replace(/\"/g, '').trim();

mode = [...mode].filter(function(letter){
return acceptable_chars.includes(letter);
function makeTablesResponsive() {
const tables = elems('table');
if (tables) {
tables.forEach(function(table){
const table_wrapper = createEl();
pushClass(table_wrapper, 'scrollable');
wrapEl(table, table_wrapper);
});

return mode.join('');
}
}

function changeMode(is_dark_mode) {
if(is_dark_mode) {
bank.setItem(storageKey, light)
elemAttribute(doc, mode_data, light);
function backToTop(){
const toTop = elem("#toTop");
window.addEventListener("scroll", () => {
const last_known_scroll_pos = window.scrollY;
if(last_known_scroll_pos >= 200) {
toTop.style.display = "flex";
pushClass(toTop, active);
} else {
bank.setItem(storageKey, dark);
elemAttribute(doc, mode_data, dark);
deleteClass(toTop, active);
}
}
});
}

(function lazy() {
function lazyLoadMedia(element) {
let media_items = elems(element);
if(media_items) {
Array.from(media_items).forEach(function(item) {
item.loading = "lazy";
});
}
}
lazyLoadMedia('iframe');
lazyLoadMedia('img');
})();

(function makeTablesResponsive(){
const tables = elems('table');
if (tables) {
tables.forEach(function(table){
const table_wrapper = createEl();
pushClass(table_wrapper, 'scrollable');
wrapEl(table, table_wrapper);
function lazyLoadMedia(elements = []) {
elements.forEach(element => {
let media_items = elems(element);
if(media_items) {
Array.from(media_items).forEach(function(item) {
item.loading = "lazy";
});
}
})();

function pickModePicture(mode) {
elems('picture').forEach(function(picture){
let source = picture.firstElementChild;
const picture_data = picture.dataset;
const images = [picture_data.lit, picture_data.dark];
source.src = mode == 'dark' ? images[1] : images[0];
});
}
})
}

function setUserColorMode(mode = false) {
const is_dark_mode = currentMode() == dark;
const stored_mode = bank.getItem(storageKey);
const sys_mode = systemMode();
if(stored_mode) {
mode ? changeMode(is_dark_mode) : elemAttribute(doc, mode_data, stored_mode);
} else {
mode === true ? changeMode(is_dark_mode) : changeMode(sys_mode!==dark);
}
const user_mode = doc.dataset.mode;
doc.dataset.systemmode = sys_mode;
user_mode ? pickModePicture(user_mode) : false;
}
function loadActions() {
updateDate();
customizeSidebar();
markExternalLinks();
createDeepLinks();
copyHeadingLink();
makeTablesResponsive();
backToTop();

setUserColorMode();
lazyLoadMedia(['iframe', 'img']);

doc.addEventListener('click', function(event) {
doc.addEventListener('click', event => {
let target = event.target;
let mode_class = 'color_choice';
let is_mode_toggle = containsClass(target, mode_class);
is_mode_toggle ? setUserColorMode(true) : false;
toggleMenu(event);
});

(function backToTop(){
const toTop = elem("#toTop");
window.addEventListener("scroll", () => {
const last_known_scroll_pos = window.scrollY;
if(last_known_scroll_pos >= 200) {
toTop.style.display = "flex";
pushClass(toTop, active);
} else {
deleteClass(toTop, active);
}
});
})();
}

window.addEventListener('load', loadActions());
59 changes: 59 additions & 0 deletions assets/js/mode.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
function prefersColor(mode){
return `(prefers-color-scheme: ${mode})`;
}

function systemMode() {
if (window.matchMedia) {
const prefers = prefersColor(dark);
return window.matchMedia(prefers).matches ? dark : light;
}
return light;
}

function currentMode() {
let acceptable_chars = light + dark;
acceptable_chars = [...acceptable_chars];
let mode = getComputedStyle(doc).getPropertyValue(key).replace(/\"/g, '').trim();

mode = [...mode].filter(function(letter){
return acceptable_chars.includes(letter);
});

return mode.join('');
}

function changeMode(is_dark_mode) {
if(is_dark_mode) {
bank.setItem(storageKey, light)
elemAttribute(doc, mode_data, light);
} else {
bank.setItem(storageKey, dark);
elemAttribute(doc, mode_data, dark);
}
}


function pickModePicture(mode) {
elems('picture').forEach(function(picture){
let source = picture.firstElementChild;
const picture_data = picture.dataset;
const images = [picture_data.lit, picture_data.dark];
source.src = mode == 'dark' ? images[1] : images[0];
});
}

function setUserColorMode(mode = false) {
const is_dark_mode = currentMode() == dark;
const stored_mode = bank.getItem(storageKey);
const sys_mode = systemMode();
if(stored_mode) {
mode ? changeMode(is_dark_mode) : elemAttribute(doc, mode_data, stored_mode);
} else {
mode === true ? changeMode(is_dark_mode) : changeMode(sys_mode!==dark);
}
const user_mode = doc.dataset.mode;
doc.dataset.systemmode = sys_mode;
user_mode ? pickModePicture(user_mode) : false;
}

setUserColorMode();
1 change: 1 addition & 0 deletions assets/js/variables.js
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ const panel_from = 'panel_from';
const full_height = 'initial';
const highlight = 'highlight';
const highlight_wrap = 'highlight_wrap'
const hash = '#';

const light = 'light';
const dark = 'dark';
Expand Down
9 changes: 6 additions & 3 deletions layouts/partials/scripts/bundle.html
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@
{{- $searchPath := "js/search.js" }}
{{- $search := resources.Get $searchPath | resources.ExecuteAsTemplate $searchPath . }}

{{- $modePath := "js/mode.js" }}
{{- $mode := resources.Get $modePath | resources.ExecuteAsTemplate $modePath . }}

{{- $mainScriptPath := "js/index.js" }}
{{- $main := resources.Get $mainScriptPath | resources.ExecuteAsTemplate $mainScriptPath . }}

Expand All @@ -22,14 +25,14 @@
{{ end }}
{{- $custom := resources.Get $customScriptPath | resources.ExecuteAsTemplate $customScriptPath . }}

{{- $bundle := slice $variables $functions $code $main $fuse $search $custom | resources.Concat "js/bundle.js" | resources.Fingerprint "sha512" }}
<script src="{{ $bundle.Permalink }}"></script>
{{- $bundle := slice $variables $functions $code $mode $main $fuse $search $custom | resources.Concat "js/bundle.js" | resources.Fingerprint "sha512" }}
<script src="{{ $bundle.Permalink }}" async></script>

{{- partialCached "hooks/scripts" . -}}

{{- $sp := .Site.Params }}
{{- with $sp.customJS }}
{{- range . -}}
<script src="{{ . }}"></script>
<script src="{{ . }}" async></script>
{{- end }}
{{- end -}}

6 comments on commit 8496fdf

@ltguillaume
Copy link
Contributor

@ltguillaume ltguillaume commented on 8496fdf Feb 24, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems that this way, mode.js is still run at the very end of the document, albeit earlier within the bundle. I don't think this will properly prevent actual flickering on all devices. I'm afraid the only way would be to run $variables and $mode (don't know if $functions or $code are needed for this) from the <head> of the page.

@onweru
Copy link
Owner Author

@onweru onweru commented on 8496fdf Feb 24, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ltguillaume, I'm trying not to load any javascript at all in the head. This change needs one additional css change to work. I'll add it soon.

@onweru
Copy link
Owner Author

@onweru onweru commented on 8496fdf Feb 24, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's a good chance it might be inadequate, in which case I will have no option but to follow your lead.

@ltguillaume
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ltguillaume, I'm trying not to load any javascript at all in the head. This change needs one additional css change to work. I'll add it soon.

Is there any specific reason (I am evidently unaware of 😅) as to why this is best practice?

@onweru
Copy link
Owner Author

@onweru onweru commented on 8496fdf Feb 28, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ltguillaume, scripts can be render blocking. Best if they're in the footer. I inlined the main script in the footer, 3230e2b. Not sure if it made the right dent. CSS changes not in yet, so not to worry.

@ltguillaume
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, I can still see a clear white flash before every page load when in dark mode on Chromium-based browsers. Somehow Firefox-based browsers don't show a flash anymore.

Please sign in to comment.