question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Make features more declarative

See original GitHub issue

Given the trouble we’re having with ajaxed features and the increasingly-dynamic nature of GitHub, I’m starting to think we should have a better way to define features.

selector-observer gets us almost there, but it awaits Dom-ready so we can’t use it all the time.

For example if we expect a tab to be added on the tab bar, I’d expect to write something like:

register({
	include: [isRepo],
	selector: 'xyz',
	action: 'append',
	ourClass: 'rgh-releases-tab'
	element: async () => <a href={…} class="rgh-releases-tab">Releases</a>,
})

And the feature manager would automatically look for selector, on isRepo, and append the element unless ourClass already exists at that location.

This basically means we we’ll have to use MutationObserver with subtree: true… but oh well.

Ideally though, this would be even higher level:

register({
	location: 'repo-tab',
	element: async () => <a href={…}>Releases</a>,
})

With locations/repo-tab.tsx that knows exactly where that location appears (isRepo), which selector to use and whether to append/prepend/insertBefore/etc. It could even detect the tab with its own auto-generated class.

For features that don’t just add an element, there could be additional onInit/onAdd/onRemove handlers.

There can also be a way to remove elements, like:

register({
	location: 'repo-sidebar',
	action: async () => { /*manually remove elements as usual*/},
})

The difference would be that the location definition would know how to handle the sidebar and know when to run action (e.g. when the sidebar is regenerated)


Too complicated? 😬

If anyone wants to try this, you can start prototyping outside features/index (no options, etc) just to see what it could look like and if it’s feasible.

Technically this register function could also just live inside our regular init, even if it can’t return false, that’s ok:

features.add({
	init: () => {
		register(...)
	},
	deduplicate: 'disabled', // Has its own logic, this string disables ajaxing completely
	awaitDomReady: false, // Has its own logic
})

Issue Analytics

  • State:closed
  • Created 2 years ago
  • Reactions:2
  • Comments:6 (6 by maintainers)

github_iconTop GitHub Comments

2reactions
fregantecommented, Sep 19, 2021

Unfortunately ain’t nobody got time for that. Such a system would require a lot of research work and trial and error, as well as rewriting existing features and the system itself as we regularly reach its design limits.

I think selector-observer already gets us 50% there if used correctly. We can start migrating to using that exclusively instead of using custom events (unless they’re really simple).

The only issue is that it awaits DOM ready, but for many features that’s not an issue, and we could look for an alternative library without such limitation if necessary.

1reaction
fregantecommented, Sep 21, 2021

I just don’t think it’s worth going too far off the current loading setup if we don’t plan on going all in. I don’t want to have just a few features that handle loading completely differently.

I’m not a fan of keeping “Let’s rewrite the core” issues open because nobody except current maintainers will pick them up. We can still discuss it though and exploratory PRs can still be opened.

Generally though I think that there aren’t many features that can be generalized this way. Sometimes we have nested ajaxed elements so even if I could target repo-sidebar nothing is still stopping GitHub from adding an ajaxed component inside and breaking all of our deduplication logic. Only specific selector-observer calls really can do that.

If there are reusable pieces, we can wrap whatever mechanism we have in functions like we’re already doing: https://github.com/sindresorhus/refined-github/blob/main/source/github-events/on-pr-merge-panel-open.ts

Read more comments on GitHub >

github_iconTop Results From Across the Web

The Complete Guide to Declarative Programming | Capital One
Declarative programming keeps code simple. Learn how to leverage declarative programming languages in your organization to deliver business ...
Read more >
Declarative Programming: Is It A Real Thing? - Toptal
In a nutshell, declarative programming consists of instructing a program on what needs to be done, instead of telling it how to do...
Read more >
Thinking in Compose | Jetpack Compose - Android Developers
Compose makes it easier to write and maintain your app UI by providing a declarative API that allows you to render your app...
Read more >
Declarative vs imperative programming: 5 key differences
Imperative and declarative programming are two of the most popular programming paradigms in software development. Programming paradigms are ...
Read more >
A brief breakdown of declarative vs. imperative programming
Learn the key differences between declarative and imperative programming, including their internal mechanisms and code structure.
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found