Homepage override unexpected behavior

This is part of my manifest.json :

...
 "chrome_url_overrides" : {
    "newtab": "index.html"
  },
 "chrome_settings_overrides" : {
  "homepage": "index.html"
} 
...

index.html is loaded fine on every new tab.
However new windows, and on startup, all I get is a blank page.

I tried manually just setting the homepage in preferences as the URL for index.html as the extension itself for example:

moz-extension://1232131-32132131-321312-321321-321321/index.html

The behavior improves, but isn’t perfect. When I do this, the new windows load index.html fine but on a fresh start up (from closed application) all I see is a blank page again?

Any ideas what’s going wrong?

The reason for the blank page on startup is likely that your extension wasn’t loaded yet at the time the tab was opened. A fairly simple workaround should be:

browser.runtime.getViews() // this might return a promise
.filter(hasntLoaded) // implement this or just reload them all
.forEach(_=>_.location.reload());

Place that as the last thing in your background page.

May contain syntax errors, typos or slightly wrong APIs, but the semantics should be right.

That def helped push me in the right direction.

The extension wasn’t being loaded in time, in by background script I included:

function handleStartup() {
    browser.tabs.update(
        {
            url: "index.html"
        }
    )

browser.runtime.onStartup.addListener(handleStartup)

This theoretically should have gotten it working.
However, there was a gotcha.
My browser preference was to never remember browsing history which triggers Always use private browsing mode

According to documentation onStartup is not fired when a private browsing profile is loaded.

So instead, I tried getting the current tab and if the promise returned undefined value pushed handleStartup

var currentTab = browser.tabs.getCurrent()
currentTab.then((data)=>(checkTabData(data)))

So it works! Thanks for your help!

The issues with blank home-page when overriding by add-on are now occurring much more often in Firefox 62. Read part of this thread:

He created a new bug for this:

Please upvote it!

Got it. And upvoted.
And yes I was facing it in Firefox 62 as well.

Here’s the code I used as a workaround in my background.js:

function loadStart(){
    browser.tabs.update(
        {
            url: "index.html"
        }
    )
}

browser.runtime.onStartup.addListener(loadStart) // does not fire in private browsing, not recommended

function pushStart(data) {
    if (data == null) {
        loadStart()
    }
    else {
        // console.log("tab is well defined")
    }
}

var currentTab = browser.tabs.getCurrent()

currentTab.then((data)=>(pushStart(data)))

Does this work correctly when user has “Restore previous session” enabled?

My solution works for my scenario only (always use private browsing / restore session disabled)

If a user has “Restore previous session” enabled, it replaces the current tab with the bundled HTML file.

Setting and checking a flag in the tab’s session should work for “Restore previous session”, but will fail in private browsing.
Something along the lines of:

var stored = browser.sessions.getTabValue(tabId, "custom-new-tab");
if (stored){
    // do nothing
}
else {
    browser.tabs.update({url: "index.html});
    browser.sessions.setTabValue(tabId, "custom-new-tab", true);
   
}

The code I suggested should work in either situation.

The only thing it does not handle are restored tabs in a container other than the default one.
The only solution for those I can think of would be this instead:

(async () => {

const tabs = browser.tabs.query({ url: browser.extension.getURL('index.html'), });
(await Promise.all(tabs.map(({ id, }) => browser.tabs.reload(id))));

})();

May contain syntax errors, typos or slightly wrong APIs, but the semantics should be right.

@NilkasG I’d be grateful if you could clarify your original response.

Can’t call getViews() on runtime. The closest would be browser.extension.getViews() which returns an array of Window objects.

I guess you could reload the extension in the active tab of the current window. But that doesn’t change the blank page that to your bundled extension HTML file.

How would one check if the extension hasn’t loaded in your filter(hasntLoaded) line?

Can’t call getViews() on runtime . The closest would be browser.extension.getViews()

Yeah, that’s what I meant.

A while back (pretty sure it is fixed by now), the inline options frame of extensions would not load correctly if the extension was reloaded while it was open. It stayed blank, as if .stop() was called on the frame straight away. I suspect the same is happening here.

So I think the URL of those “blank tabs” is actually still the one of your bundled page, it just failed to load (and may not even be displayed correctly in the URL-bar).
If I am wrong about that, neither of my suggestions will work.
But if I am correct, reloading it should help.

How would one check if the extension hasn’t loaded in your filter(hasntLoaded) line?

Assuming that your page adds something to its body when it loads, and that the “blank” pages have an empty body, this should work:

function hasntLoaded(view) { return !view.document.body.textContent; }