Migrating Fake Data from MV2 to MV3

Introduction

In web extensions world, the manifest version represents a set of rules and APIs that an extension can use once installed in a browser. As of January 2022, all browser extensions were using what is called Manifest Version 2, or MV2. which was the only stable and accepted Manifest version that a browser extension could use.

In December 2020, Google announcedopen in new window a public beta for the next manifest version, called Manifest Version 3, or MV3. On September 2021 announcedopen in new window the final timeline for developers to transition from MV2 to MV3, giving them time until June 2024 to completely migrate to the new API.

This change will affect all extensions, not only Fake Data. After June 2024, all extensions that are using MV2 will stop working for Chrome and soon for the rest of the browsers.

What does this mean for Fake Data?

Unfortunately, the transition from MV2 to MV3 is big and with a lot of changes. Some of them with breaking functionality.

One of the biggest change that affects Fake Data and you guys, the users, is that it will not allow the execution of remote hosted code. For Google, remote hosted code means any code that is not bundled with the extension. This basically means any code that you write for Custom Generators inside Fake Data will not be able to run as before.

There is one exception, however. It is allowed, for now at least, user code to be run in a sandboxed page. This is still inconvenient, but at least it's better than nothing.

Try out a MV3 version of Fake Data in Google Chrome

I highly recommend you try out the beta version of Fake Data which is running with the new MV3 APIs, and make sure all your scripts are working properly. You can install the beta version from the following URL: https://chromewebstore.google.com/detail/fake-data-beta/cgdofifkggagondhlalkbfpdgneifkkkopen in new window

INFO

For now only the Google Chrome version of Fake Data will transition to MV3. Other browsers will transition at a later date that will be announced in the future.

The sandboxed page in Fake Data

A sandboxed page in web extensions is a page that does not have access to any of the API functions for extensions, nor does not have access to the main page DOM. It's basically a page isolated from everything that cannot do any harm if hijacked.

The use of this sandboxed page in Fake Data is to execute the custom codes that you created in "Custom Generators" or loaded through "Loaded Libraries".

To get more technical, everytime you will trigger an action that you set to run custom javascript code, Fake Data will create a new <iframe> element inside the active page that points to its internal sandboxed page. That iframe will eval() the code you requested and result of this code will then be sent to the extension's background page (or service worker in MV3).

In MV2 version, there was no need for this sandboxed page because the background script of the extension was able to run the eval() function and execute any code provided. With MV3 this is not possible anymore, and the only solution is to add this extra step of using a sandboxed page.

Limitations of the new sandboxed page

Having the code executed in this new iframe element comes with some disadvantages, unfortunately.

  • The obvious one is that it's much slower (but hopefully not that noticeable) than executing the code in the background script. In order to speed things up a little, the iframe element is created once and then re-used until the page reloads.
  • If you were relying on chrome APIs for your code, that is no longer possible.
  • The sandboxed page does not have access to the parent DOM, so no direct manipulation of elements anymore. But since Fake Data is an awesome extension, an API is provided and described in the next part.
  • There will be a lot of message passing back and forth with the content script of the extension in order to run all the custom codes.

The FakeDOM API

As mentioned previously, the sandboxed iframe does not have access to the main page DOM, but this doesn't mean that you will not be able to manipulate it or retrieve values from it anymore.

Meet the FakeDom class - a proxy to document and window objects!

The FakeDom class is a new API inside Fake Data that will allow you to interact with main page's DOM elements through proxy functions. You can access it through the already instantiated object called fakeDom.

In order to get started you should remember that everywhere where you would use a method that belongs to document or window in your code, you will have to replace with fakeDom.document and fakeDom.window.

For example, document.getElementById() will become fakeDom.document.getElementById(). Pretty easy and cool, right?

There is a catch though. Each of these fakeDom methods might look the same as the native ones, but they will not behave exactly like those. Each of these will return a Promise. These Promises will then be resolved to whatever these functions would natively return, almost.

Native functions would normally return an Element, will now return a FakeDOMElement.

Confused already? Don't be, it's easy if you keep in mind that everything is a Promise now.

Examples using the new FakeDom proxy

Setting a value to an attribute

Let's take for example this code that changes the value of an input field:

// Native JS
document.getElementById('my-input').value = 'Fake Data is awesome!';


// FakeDOM API
fakeDom.document.getElementById('my-input').value = 'Fake Data is awesome!';

Nothing changed here other than chaining "fakeDom" at the beginning of the statement.

Add an event listener

Another example of how simple it is to use, is the following one that adds an event listener to an element:

// Native JS
document.getElementById('my-input').addEventListener('change', function() {
    console.log('Input changed!');
});

// FakeDOM API
fakeDom.document.getElementById('my-input').addEventListener('change', function() {
    console.log('Input changed!');
});

TIP

Keep in mind that the listener function is executed in the sandbox page, not in the main page.

Reading the value of an attribute

Let's take now another example to see how you would use the returned Promises. Let's print to console the value of an input field:

// Native JS
console.log(document.getElementById('my-input').value);


// FakeDOM API
console.log(await fakeDom.document.getElementById('my-input').value);

As you can see, the code is pretty similar, but this time we had to use the await keyword. That's because the "value" attribute returned a Promise.

TIP

You can chain methods like you would normally do when accessing DOM elements, but if you want to use the result from them, you will need to await the returned Promise to be resolved.

Methods returning an array of elements

Some javascript methods, like document.querySelectorAll() or document.getElementsByTagName() would natively return a collection of elements. In the new FakeDOM API, these will return an array of FakeDomElement objects. Below is an example of how to loop through multiple input elements and attach an event listener to them:

// Native JS
document.querySelectorAll('input').forEach(function(el) {
    el.addEventListener('click', console.log);
});

// FakeDOM API
(await fakeDom.document.querySelectorAll('input')).forEach(function(el) {
    el.addEventListener('click', console.log);
});

You will notice that the code is similar, but on the FakeDOM version you will first have to await the querySelectorAll method to be resolved before looping through the returned array.

How does the new FakeDom proxy class works

The FakeDom class contains a lot of methods named identically to the native ones but which under the hood behave completely different. Each time you call a method like fakeDom.document.getElementById() or trigger getter / setter for an element attribute, the sandboxed page will communicate with the main document through Message Channelsopen in new window. The iframe will basically tell the main document to execute whatever the requested method was and pass back the result.

Because each method needs to be explicitly implemented, you might find that some methods will not work immediately when you call them through the fakeDom API. Most common methods and functions should be already implemented, but if you find any that does not work, don't hesitate to open an issue report.

When it comes to returning DOM elements, you might know that these are not serializable. So normally you would not be able to pass DOM element references through a communication channel or convert them to JSON text. For these elements, FakeDOM API will save a reference internally in the main document memory and pass down to the iframe a unique ID of that element, so the iframe and the main document will both know how to reference it the next time it needs it.

TIP

To learn more about the new FakeDOM API, go to this page.

Running custom codes in background script and foreground script

In MV2 version of Fake Data the custom javascript code was by default executed in the background script of the extension. If you wanted to run code in the content script, in order to access the DOM elements, you had to return a function from the background script that would have been executed in the content script.

In MV3, there is no more separation between these two places of execution. Everything will be executed in the same sandboxed page. For backwards compatibility reasons, returning a function from your code will continue to be executed and result filled in your inputs.

Here are a few examples:

// MV2
return function() {
    return window.location.href;
}

// MV3
return fakeDom.window.location.href;


// MV3 - alternative #2 -- for easy backwards compatibility
return function() {
    return fakeDom.window.location.href;
}

With the above example, Fake Data will fill the input field with the link of the current page. In MV2 for this to work, you had to return a function that would return the link, while in MV3 you don't have to do that anymore unless you really want to. Also, please not the use of fakeDom.window instead of window for MV3.

How will the Loaded Libraries work in the new MV3

The Loaded Libraries feature will be executed the same way as the custom codes will. In the MV2 version of the extension, there was a clear separation between background libraries and foreground libraries. The background ones were executed in the background page of the extension, completely separated from the main document and with no access to the DOM, while the foreground libraries were executed in the content script, which had access to the DOM.

In MV3, there will be no background or foreground libraries, but just loaded libraries. These will be executed on every page load, similar to the foreground libraries, but this time in the sandboxed iframe. Similar to the custom codes for generators, you will have to use the FakeDOM API if you want to work with DOM elements.

Needless to say, libraries that manipulated DOM elements, like jQuery, will not work anymore with the new sandboxed page. If you were using them, you will need to rewrite your scripts to not use them.

What to do next?

If you are using custom scripts or loaded libraries that don't use the DOM at all. For example, you might have scripts that generate some types of data that Fake Data extension does not provide, then you might be safe and don't need to do anything. Those will continue to work with no modification.

If you are using custom codes or loaded libraries that use DOM elements or custom integrations, you will want to adapt them to use the new FakeDOM API. Depending on what your script does, this might be a quick update or a breaking one.

If you rely on DOM manipulation libraries, like jQuery for your scripts, you will need to rewrite your code to not use them anymore since these will not work on the new update.

There is still work in progress that is happening to support as many scenarios as possible. At this moment you cannot register Custom Elements in the Beta version of Fake Data, but this will be fixed soon.

Please follow this GitHub issueopen in new window to find out about updates related to the migration to MV3, as well as post the issues that you find while migrating your code.