pageworks / djinnjs Goto Github PK
View Code? Open in Web Editor NEWDjinnJS is a lightweight JavaScript & CSS bootstraper built on ES Modules and Web Components.
Home Page: https://djinnjs.com/
License: GNU General Public License v3.0
DjinnJS is a lightweight JavaScript & CSS bootstraper built on ES Modules and Web Components.
Home Page: https://djinnjs.com/
License: GNU General Public License v3.0
When loading a website for the first time Djinn always scrolls to the top of the site even when a hash is provided.
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);
}
}
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.
We should consider splitting CSS into 3 separate loading stages.
critical-css
attribute should be used to inform the system what CSS files are critical and must be loaded before the page is revealed.
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.
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.
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.
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.
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.
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.
We need to move the documentation for Djinn to utilize dev-docks for output of documentation on local dev devices.
Line 18 in e2aa741
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).
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.
In the service worker when we match or the method is not GET
the fetch request should to allow redirects.
Drop static runtime and switch to dynamic runtime.
The Env
class contains several useful utilities, it's functionality should be documented.
Custom elements should be djinnjs-file-loading-value
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.
Rewrite the documentation and add a cookbook section full of (almost) production ready JavaScript, CSS, and HTML snippets.
During swapPjaxContent()
when setting the selector we need to verify the following:
<main>
(default) selector checks for a pjax-id
and resorts to native if missing or mismatched since base templates could changeWe 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.
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.
The Transition Manager needs to be reworked to support custom transitions.
When a PJAX request is redirected we need to abort the navigation hijacking and resort to native.
Do HEAD
check before serving the cached page, if not onLine
display cached page.
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;
}
When setting the fallback contact cache ID value the Date().now()
is incorrect, it should be Date.now()
.
Create & export a Component class:
render()
method
setState()
function -- returns a promiseuid
Lazy load (rel="preload"
) CSS links via fetchCSS()
defer
JS scripts via fetchJS()
when not async
or type="module"
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.opt-in
or opt-out
with a opt-out
default.["prefetch"]
or ["no-prefetch"]
prefetching
config -- always support prefetching since developers can "opt-out"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:
Currently, the system performs the actions in this order:
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.
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);
};
}
When jumping to a hash add 100px by default, allow user config.
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.
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.
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.
We need to make Pjax be a peer dependency for Djinn. We don't always need that functionality, but having it be baked into and leveraging Djinn has its benefits.
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.
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"`);
When a URL has a location.hash
Pjax isn't scrolling the page to the <a name='some-hash'>
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 filename regex patterns (.*\/)|(.*\\)
to handle Windows file paths.
Also double check that all paths use path.resolve(path.cwd(), '../../user/provided/directory-name')
Page position is not accurate at certain breakpoints when page is loaded
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.
The prevent-pjax
attribute and the no-transition
class is not preventing Pjax from hijacking the click event.
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.
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.
https://en.wikipedia.org/wiki/Service_locator_pattern
https://en.wikipedia.org/wiki/Dependency_injection
https://en.wikipedia.org/wiki/Factory_(object-oriented_programming)
This should be a part of the CLI process
/assets/
publicDir
to output
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.
The fetchJS()
and fetchCSS
functions should be moved into one file.
import { fetchJS, fetchCSS } from 'djinnjs/fetch';
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.