Git Product home page Git Product logo

djinnjs's People

Contributors

bamccaul-dev avatar codewithkyle avatar nicholashamilton avatar peter-tell avatar

Stargazers

 avatar

Watchers

 avatar  avatar  avatar

djinnjs's Issues

Page Jump Bug

When loading a website for the first time Djinn always scrolls to the top of the site even when a hash is provided.

Mount utility

import { mount } from "djinnjs/utilities";
import { CustomComponent } from "./custom-component";
mount("custom-component", CustomComponent);
function mount(tagName:string, className:CustomElementConstructor):void{
    if (!customElements.get(tagName)){
        customElements.define(tagName, className);
    }
}

CDN and Dynamic loading

We need to investigate how well the dynamic loading works with Djinn, and if there are any further optimizations that can take place with a CDN such as CloudFlare.

Expanded CSS Loading Attributes

We should consider splitting CSS into 3 separate loading stages.

Stage 1

critical-css attribute should be used to inform the system what CSS files are critical and must be loaded before the page is revealed.

Stage 2

eager-css attribute should be used to load CSS after the page is revealed. All the eager-css files are loaded in one large batch per page.

Stage 3

lazy-css attribute should be used to load CSS using JIT similar to the web component loading process. When a component is observed using the Intersection Observer the CSS files are parsed and loaded.

Cache Warming

We should allow developers to set an endpoint within the config file that provides an array of all the URLs a developer would like us to cache. See Cache API for details.

Manual PJAXing with Ticket Resolution

What

When manually loading a page via the PJAX inbox the data should support an array of ticket strings and after the new page has loaded all the tickets are resolved.

Why

Sometimes we want to set a loading animation using the Env classes ticketing system and we want the soft loading animation to continue until the new page has been loaded instead of ending the animation and starting the page loading animation.

Alternative Solution

A developer could place the ticket in a variable attached to the web component and could resolve on the disconnectedCallback() method.

However, if a component has several methods that generate tickets each ticket might require it's own variable and it would be easier to resolve all tickets via PJAX. Also, from a UX perspective, keeping one continuous animation is less jarring than switching between the two.

Query any element with a file attribute

let el: HTMLLinkElement = document.head.querySelector(`link[file="${filename}"]`) || document.head.querySelector(`link[href="${filename}"]`) || null;

let el: HTMLLinkElement = document.head.querySelector(`link[file="${filename}"]`) || document.head.querySelector(`link[href="${filename}"]`) || null;

should be

let el: HTMLLinkElement = document.head.querySelector(`[file="${filename}"]`) || document.head.querySelector(`link[href="${filename}"]`) || null;

in order to not load files twice (once via CSS injection & and a second time via the lazy loaded link element).

Update Pjax Page Jumps

Since HTML5 the id attribute used for page jumps. Pjax should be updated to use document.body.querySelector(location.hash) instead of looking for the obsolete name attribute.

Allow Redirects

In the service worker when we match or the method is not GET the fetch request should to allow redirects.

Env Class Documentation

The Env class contains several useful utilities, it's functionality should be documented.

Switch File Extension

We should follow the suggested file extension of .mjs for our scripts since they are ES Modules.

On large projects it could be helpful to look at the incoming file URLs to determine when files are plain JS and what files are ES Modules. Otherwise we have to preview the response and look for any exports within each file.

Reference

Pjax View Verification

During swapPjaxContent() when setting the selector we need to verify the following:

  • the selector exists within the current view
  • the selector exists within the incoming view
  • resorts to native browsing when views are missing
  • the <main> (default) selector checks for a pjax-id and resorts to native if missing or mismatched since base templates could change

Browser Detection

We should add a browser public variable to the Env class along with appending the browsers name to the documents class list. Most of the time this will used to handle Safari CSS limitations and bugs.

JavaScript features should not be checked or enabled on a browser-by-browser basis, instead using the if ('feature' in someObject) feature detection format.

Refactor Multi Site Config

We set up the multi site config with the expectation for the front end to handle each site in Djinn. We are recommending developers handle a multi site config with separate instances of the Djinn and separate build processes for each site.

Transition Manager

The Transition Manager needs to be reworked to support custom transitions.

PJAX Redirect

When a PJAX request is redirected we need to abort the navigation hijacking and resort to native.

Service Worker Redirects

This warning is appearing when hosting websites with GitHub pages The FetchEvent for "<URL>" resulted in a network error response: a redirected response was used for a request whose redirect mode is not "follow".

The fallback fetch should include:

{
    credentials: 'include',
    redirect: 'follow',
}

We shouldn't cache redirects:

if (!response || response.status !== 200 || response.type !== 'basic' || response.headers.get('PWA-Cache') === 'no-cache' || response.redirected) {
    return response;
}

Service Worker Fails

When setting the fallback contact cache ID value the Date().now() is incorrect, it should be Date.now().

Components

Create & export a Component class:

  • Components extend HTMLElements
  • Components have a transferable state object
  • Components have a render() method
    • called whenever the state is updated
  • Components have a setState() function -- returns a promise
  • Component states are managed asynchronously OMT via a static Web Worker
  • Components have a uid

Performance Updates

CSS

Lazy load (rel="preload") CSS links via fetchCSS()

JavaScript

  1. Default to defer JS scripts via fetchJS() when not async or type="module"
  2. New connection-type web component attribute sets the minimum connection type to load the component. For example a hero carousel could have connection-type="3g" and any slow 3g or 2g connections will ignore the component. When the connection type changes we should tell the runtime to check all ignored components.

Prefetching

  • Developers can choose to opt-in or opt-out with a opt-out default.
  • Developers can override default class: ["prefetch"] or ["no-prefetch"]
  • Drop prefetching config -- always support prefetching since developers can "opt-out"

Web Component Race Conditions

If a web component uses it's connected and disconnected callbacks to enable/disable a global component the following is expected when transitioning from a page with the component to another page with the same web component:

  • connected callbacks
  • start page transition
  • disconnected callbacks
  • connected callbacks
  • end page transition

Currently, the system performs the actions in this order:

  • connected callbacks
  • start page transition
  • connected callbacks
  • disconnected callbacks
  • end page transition

This is due to the fact that we generate a temporary document and use it to verify that the pages contain the same selectors. Instead of the current implementation, we should clear the HTML of the current selectors (forcing disconnected callbacks) before implementing a temporary document. At this point, if the new document doesn't contain the same selectors we can still fail the transition and resort to native. Functionally it's the same we just move the selector matching verification step from the beginning of the transition process to the end.

Debounce Utility

export function debounce(func: Function, wait: number, immediate: boolean): Function {
	let timeout;
	return function () {
		const context = this,
			args = arguments;
		const later = function () {
			timeout = null;
			if (!immediate) func.apply(context, args);
		};
		const callNow = immediate && !timeout;
		clearTimeout(timeout);
		timeout = setTimeout(later, wait);
		if (callNow) func.apply(context, args);
	};
}

Remove Broadcaster from core and make as a peer dependency

I'm struggling to remember why we need a broadcaster. I know WWIBS can help communicate between Web Components and IIFE wrapped component libraries like Preact but I don't know why we need it in Djinn. It seems to solve the same problem as import statements.

With WWIBS sending a message becomes a messy process as different components begin pinging messages back and forth. It's hard to read and debug compared to imported functions and classes.

In Djinn we can write a controller that imports a web component and register's it within the constructor. Within the web component connected callback we can call a public function imported from the controller that links the instance by passing a reference to the web components DOM node. Once everything (views/web workers) have registered the controller could call an init method and begin managing the application state. Data can be passed using function calls. Along with easier debugging we can begin to provide inline documentation using jsdocs.

The only downside I can see is that we lose the pjax completed message. However, so far the only time I know we've hooked into the completed message is to style a navigation link based on the new pages URL. In my opinion loading several KBs of extra JavaScript just to underline a link is a waste of the users data and an unnecessary Lighthouse performance hit. We could leverage the CustomEvent API for this since it's easy to use and native.

PJAX Script Mounting

When Pjax mounts a script during navigation it doesn't maintain the type attribute breaking any module typed scripts. We need to copy along the type value and the nomodule value whenever possible.

Pjax Breaks Inline Scripts

When Pjax loads a page that contains <script> elements they don't run. We need to add a new step in the navigation process that creates new <script> elements by injecting any innerHTML or setting the src value before appending the scripts to the DOM.

Connection Hooks

When we need to request feedback from the user on how to handle a <=3g connection we need to send a message and the developer needs to handle prompting the user.

We should do the same thing when we discover that the user is viewing a stale page when using the offline first service worker.

Scrubber Script Bug

If we import flatpickr from "flatpickr" the first instance of flatpickr is replaced with the path to the public JavaScript file.

For example

import { flatpickr } from "flatpickr";

Is output as

import { ./flatpicker.js } from "flatpickr";

The Regex for replacing the file path should look for single and double quotes.

data = data.replace(`"${path}"`, `"./${pathFileName}.js"`).replace(`'${path}'`, `"./${pathFileName}.js"`);

Update CSS loading

With the new Lighthouse performance metrics we will need to update our CSS loading documentation to include the new recommended best practices. From my initial testing I've determined that using Djinns eager-css will always hinder the page's overall performance metric due to the content behind the loading screen is shifting as CSS files are loaded. This usually causes a CLS value 10x the advised amount. Below is an overview of what I've discovered throughout my testing.

Loading critical CSS using the eager-css attribute will always cause a high CLS value.

Loading critical CSS using the <link> element will fix the CLS issue but causes issues with other performance metrics (FID, FCP, LCP). From what I've seen the performance metrics overall score is slightly lower with this method when compared to the eager-css version.

Injecting critical CSS into a <style> element within the head fixes all performance issues. The overall performance went from an average of 90 to a constant 99.

Since injecting critical CSS into the document is a server-side task all we can do is document this recommendation.

Fix CLI Pathing

Fix filename regex patterns (.*\/)|(.*\\) to handle Windows file paths.

Also double check that all paths use path.resolve(path.cwd(), '../../user/provided/directory-name')

Strict Filename Checks

We should loop though all the files and ensure that files do not have the same name, if they do we should throw an error and alert the developer. Ideally we should provide full paths to the two conflicting file names.

Preventing Pjax Bug

The prevent-pjax attribute and the no-transition class is not preventing Pjax from hijacking the click event.

Fade Transition Updates

The fade transition should allow developers to control the fade duration using the pjax-transition-data attribute.

{
    "scroll": "no-scroll",
    "duration": "150"
}

Scroll could be no-scroll || smooth-scroll and will default to smooth-scroll

Duration is in milliseconds.

Web Worker Thread Pool

Concept

The Env class should calculate how many workers we are allowed to register.

Developers can request permission to register a new worker and as high or low priority. If the pool limit has been reached a low priority worker is terminated. If there are no low priority workers to be terminated the system should break & throw errors informing the developer of the issue.

It is on the developer to determine how to split the work between the workers, the priority levels, and the minimum device specs the application can support.

References

https://en.wikipedia.org/wiki/Service_locator_pattern
https://en.wikipedia.org/wiki/Dependency_injection
https://en.wikipedia.org/wiki/Factory_(object-oriented_programming)

FetchJS Bug

In fetchJS() the URL version should not append .js to the end of the provided URL. For example, when loading Google reCAPTCHA script the public API key is provided so the string doesn't end in .js and our regex to trip the .js extension fails.

Resource Fetching

The fetchJS() and fetchCSS functions should be moved into one file.

import { fetchJS, fetchCSS } from 'djinnjs/fetch';

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.