In chrome when you install a extension it clears the local storage associated with that extension. This doesn't seem to be the case for Firefox.
The only possible solution I can find is
https://developer.mozilla.org/en-US/Add-ons/SDK/Tutorials/Listening_for_load_and_unload
To listen for the 'install' event and clear it manually.
The problem Im having with this is that at the time main.js gets this event, my page-workers are already unloaded. I need to clear local storage which main.js cannot. So I need to emit to the page-worker so it can do so but the page-worker is already unloaded at this time.
The Firefox add-on SDK doesn't integrate with HTML5 local storage. So one solution is to use message passing and simple storage instead, then it should be wiped for you, as expected.
If it isn't, in main.js, you can simply write:
const { storage } = require('sdk/simple-storage');
exports.main = function({ loadReason }) {
if (loadReason==='install') for (var prop in storage) delete storage[prop];
}
If you need to use localStorage, store an array of affected pages in simple storage, then create a page-worker for each site on install and clear localStorage from each new content script.
Related
Edit: While I still do not understand the differences between the session and webFrame cache, webFrame.clearCache() can simply be called from the within the preload script.
Problem
I have an Electron application which involves renaming and reordering images on the local filesystem. This often results in files swapping their filenames which causes caching issues that are not resolved until the window is reloaded. I am unable to clear or disable the cache.
Methods that work (unsatisfactory)
Calling require("electron").webFrame.clearCache(); from within the renderer process. This is not a satisfactory solution as it requires nodeIntegration to be enabled. (The WebFrameMain class available to the main process does not have a clearCache method).
Checking "Disable cache" from Chrome DevTools. Obviously this is not a solution for production.
Methods that don't work
Clearing the session cache. I noted that the session cache size was always 0.
mainWindow.webContents.session.clearCache();
Clearing the session storage data.
mainWindow.webContents.session.clearStorageData();
Adding the following command line switches to the main process.
app.commandLine.appendSwitch("disk-cache-size", "0");
app.commandLine.appendSwitch("disable-http-cache");
Providing a session object with cache disabled when creating the window.
webPreferences: {
preload: path.join(__dirname, "preload.js"),
session: session.fromPartition("example", { cache: false })
}
There are clearly components to the caching system I do not understand. It seems that the session cache and webFrame cache must be two different things, and I can not find a way to access the later from the main process or without nodeIntegration.
A minimal project which shows this issue can be found here: https://github.com/jacob-c-bickel/electron-clear-cache-test. Clicking the button swaps the filenames of the two images, however no visible change occurs until the window is reloaded.
I am using Electron 13.1.4 and Windows 10 2004.
You can create a function to clearCache with require("electron").webFrame.clearCache(); and attach it to the windows object in your preLoad script, then use that in your isolated renderer.
Google "electron preload"
Yeah – webFrame is meant to be used inside the browser, so that's usually going to mean preload.js. You then can use Electron's Inter-Process Communication (IPC) techniques to expose that method globally on the window object, allowing use elsewhere in your app!
It's like you're carving out a path through each level of your app for access to the right functions.
Altogether, that will look like this:
preload.js:
import { contextBridge, webFrame } from 'electron';
export const RendererApi = {
clearCache() {
webFrame.clearCache()
},
};
contextBridge.exposeInMainWorld("api", RendererApi);
And then anywhere inside your rendering process:
window.api.clearCache();
I'm attempting to use BlockBlobClient in a browser page to upload a file using a server-supplied sastoken / URL, similar to this C# code:
var blob = new CloudBlockBlob(new Uri(assetUploadUrl));
blob.UploadFromFile(FilePath, null, new BlobRequestOptions {RetryPolicy = new ExponentialRetry()});
Although the docs suggest BlockBlobClient is available in #azure/storage-blob and should be able to upload browser data from an input[type=file] element using uploadBrowserData, I can find no reference to BlockBlobClient in the browser library source. I looked into modifying the browserify export scripts but I can't find any references in the main package source either. Also the example code suggests that using #azure/storage-blog gives you a BlobServiceClient by default:
const { BlobServiceClient } = require("#azure/storage-blob");
Is BlockBlobClient actually available in the JavaScript client library?
Okay I've figured this out, I need to use the Azure Storage client library for JavaScript, there's even a sample of doing exactly what I need to do. Now I just need to figure out how to bundle npm package files for use in Razor pages.
I'm doing a tiny offline-able web app / PWA. It's meant to be opened from a home screen icon and mimic a regular app by loading entirely from a cache when offline.
The app is written using Vue and to accomplish the above I'm just using their PWA template and whatever it generates. To the best of my knowledge what this does is set up workbox using the GenerateSW plugin to precache everything in the Webpack build, and registers it using register-service-worker. That is, I have fairly little control out of the box over the fine details, it's meant to be a turnkey solution.
That said, I'm not sure how to actually load a new build of the application when it's available. The above can detect this - the generated SW registration file with my changes looks like this:
import debug from 'debug';
import { register } from 'register-service-worker';
if (process.env.NODE_ENV === 'production') {
register(`${process.env.BASE_URL}service-worker.js`, {
ready(...args) {
log('App is being served from cache by a service worker.\n', ...args);
},
cached(...args) {
log('Content has been cached for offline use.', ...args);
},
updated(...args) {
log('New content is available; please refresh.', ...args);
},
offline(...args) {
log('No internet connection found. App is running in offline mode.', ...args);
},
error(error, ...args) {
log('Error during service worker registration:', error, ...args);
}
});
}
When I make a new build of the application, and I refresh the app in a browser, the updated() callback is executed, but nothing else is done. When I tried adding:
window.location.reload(true);
which should be a forced refresh, I just get a refresh loop. I'm assuming this is because the service worker cache is completely independent from the browser cache and unaffected by things like the above or Ctrl+F5. (Which makes the "please refresh" rather misleading.)
Since this is going to mimic a native app, and it's supposed to be a simple line-of-business tool, I don't really need to do anything more complicated than immediately reload to the new version of the app when an update is available. How can I achieve this?
Okay so the behaviour I've observed is that the update does happen automatically, it's just not obvious as to what the exact sequence of events is. I'll try to describe my best understanding of how the generated service worker works in the installed PWA scenario. I'll speak in terms of "app versions" for simplicity, because the mental model behind this is closer to how apps, not webpages work:
You deploy v1 of your application to a server, install / precache it on a device, and run it for the first time.
When you suspend and resume your app, it does not hit your servers at all.
The app will check for an update when it's either cold-started, or you reload the page, i.e. using the pull down gesture on Android.
(Possibly also periodically as the cached version goes stale, but I haven't checked this.)
Say you've deployed v2 of your app in the meantime. Reloading an instance of v1 of the app will find this update, and precache it.
(One reason why prompting the user to reload doesn't seem to make sense. Whatever the reloading is meant to accomplish has already happened.)
Reloading an instance of v1 again does absolutely nothing. The app remains running between reloads, and you'll just get v1 afterwards.
(Reason number two why prompting the user to reload is pointless - it's not what causes a new version of an app to load.)
However, next time you cold start your app - e.g. nuke it from the task switcher and reopen - v2 of your app will be loaded and I'm guessing v1 will get cleaned out. That is, your app must fully shut down so an update will load.
In short, for an application to be updated from v1 to v2, the following steps need to occur:
Deploy v2 to server
Refresh instance of v1 on device, or shut down and reopen the app.
Shut down and reopen the app (again).
Im creating a web extension and porting from XUL. I used to be able to easily read files with
var dJsm = Components.utils.import("resource://gre/modules/Downloads.jsm").Downloads;
var tJsm = Components.utils.import("resource://gre/modules/Task.jsm").Task;
var fuJsm = Components.utils.import("resource://gre/modules/FileUtils.jsm").FileUtils;
var nsiPromptService = Components.classes["#mozilla.org/embedcomp/prompt-service;1"].getService(Components.interfaces.nsIPromptService);
....
NetUtil.asyncFetch(file, function(inputStream, status) {
if (!Components.isSuccessCode(status)) {
return;
}
var data = NetUtil.readInputStreamToString(inputStream, inputStream.available());
var data = window.btoa(data);
var encoded_data_to_send_via_xmlhttp = encodeURIComponent(data);
...
});
This above will be deprecated.
I can use the downloads.download() to know what was the last download but I can NOT read the file and then get the equivalent for encoded_data_to_send_via_xmlhttp
Also in Firefox 57 onwards, means that I have to try to fake a user action by a button click or something, or upload a file.
Access to file:// URLs or reading files without any explicit user input
isnt there an easy way to read the last downloaded file?
The WebExtension API won't allow extensions to read local files anymore. You could let the extension get CORS privilege and read the content directly from the URL via fetch() or XMLHttpRequest() as blob and store directly to IndexedDB or memory, then encode and send to server. This comes with many restrictions and limitations such as to which origin you can read from and so forth.
Also, this would add potentially many unneeded steps. If the purpose is, as it seem to be in the question at the moment, to share the downloaded file with a server, I would instead suggest that you obtain the last DownloadItem object, extract the URL (.url) from that object and send the URL back to server.
This way the server can load directly from that URL (and encode it on server if needed). The network load will be about the same (a little less actually since there is no Base64 encoding involved which adds 33% to the size), and much less load on the client. The server would read the data as a binary/byte data stream; about the same as if the data was sent directly from the extension.
To obtain the last downloaded file you would do the following from a privileged script:
browser.downloads.search({
limit: 1,
orderBy: ["-startTime"]
})
.then(getLastDownload);
function getLastDownload(downloads) {
if (downloads.length) {
var url = downloads[0].url;
// ... send url to the server and let server fetch the data from it directly
}
}
According to this support mozilla question.
(2) Local file security
Firefox limits access from pages on web servers to pages on local disk or UNC paths. [...]).
Which solution ?
Use local-filesystem-links firefox addon (not tested)
and/or
run a small local webserver on client side, supposing server was run with sufficient privileges, you may finally access any local content via http:// (but still cannot with file:///)
I am trying to make a playground like plunker. I just noticed a very odd behavior on production (with active mode in Cloudflare), whereas it works well in localhost.
By iframe, the playground previews index_internal.html which may contain links to other files (eg, .html, .js, .css). iframe is able to interpret external links such as <script src="script.js"></script>.
So each time a user modifies their file (eg, script.js) on the editor, my program saves the new file into a temporary folder on the server, then refresh the iframe by iframe.src = iframe.src, it works well on localhost.
However, I realized that, in production, the browser always keeps loading the initial script.js, even though users modify it in the editor and a new version is written in the folder in the server. For example, what I see in Dev Tools ==> Network is always the initial version of script.js, whereas I can check the new version of script.js saved in the server by less on the left hand.
Does anyone know why it is like this? And how to fix it?
Edit 1:
I tried the following, which did not work with script.js:
var iframe = document.getElementById('myiframe');
iframe.contentWindow.location.reload(true);
iframe.contentDocument.location.reload(true);
iframe.contentWindow.location.href = iframe.contentWindow.location.href
iframe.contentWindow.src = iframe.contentWindow.src
iframe.contentWindow.location.replace(iframe.contentWindow.location.href)
I tried to add a version, it worked with index_internal.html, but did not reload script.js:
var newSrc = iframe.src.split('?')[0]
iframe.src = newSrc + "?uid=" + Math.floor((Math.random() * 100000) + 1);
If I turn Cloudflare to development mode, script.js is reloaded, but I do want to keep Cloudflare in active mode.
I found it.
We can create a custom rule for caching in CloudFlare:
https://support.cloudflare.com/hc/en-us/articles/200168306-Is-there-a-tutorial-for-Page-Rules-#cache
For example, I could set Bypass as Cache Level for the folder www.mysite.com/tmp/*.