Search code examples
javascriptgoogle-chrome-extensionmodulegoogle-chrome-devtoolsflatpickr

Is it possible for a Chrome Extension using the modules already loaded by the website?


I am developing a Chrome extension for auto filling infomation to a website.

However, I get some problem when I dealing with this "flatpickr" element. I was tried to use the "setDate" function of a "flatpickr" instance but there is always a "TypeError: Cannot read properties of undefined".

I check the DevTool and saw that there is already a flatpickr module loaded by the website. And my code is working in the DevTool console.

All in all, is it possible that I may use that flatpickr module loaded by the website? Or do I need to import one in my scripts?

I am not familiar with the java script and website structure yet. Please give me some thoughts or helps on this!

The flatpickr module loaded by the website

HTML of Website

//...
<div>
    <div class="form-group" data-triptype="oneway">
        <span class="material-icons-outlined">today</span>
        <label for="">Date</label>
        <input date="2024/01/22" flimit="" isdpromotion="false" type="hidden" slimit="2024/02/19" isspromotion="false" plimit="2024/01/26" name="toTimeInputField" limit="2024/02/19" id="toTimeInputField" class="uk-input out-date flatpickr-input" value="2024/01/22" isfreeseat="false"><input class="uk-input" placeholder="" tabindex="0" type="text" readonly="readonly">
    </div>
    // ...
</div>
//...

manifest.json

{
  "manifest_version": 3,
  "name": "AutoFill",
  "version": "1.0",
  "description": "",
  "content_scripts": [
    {
      "matches": ["https://*"],
      "js": ["query_page_script.js"]
    }
  ],
  "permissions": [
    "storage"
  ],
  "action": {
    "default_popup": "popup/index.html"
  }
}

query_page_script.js


const columns_name = [
    'toTimeInputField'
];

const data = {
    toTimeInputField: ['date', '2024/02/08']
};

columns_name.forEach(e => {
    const target = document.getElementsByName(e);
    if (target && data[e]) {
        if (data[e][0] === 'date') {
            target[0]._flatpickr.setDate(data[e][1], true, 'Y/d/m');
        } else {
            target[0].value = data[e];
        }
    };
    console.log("End.");
});

Solution

  • Website execution world

    To a chrome extension, the javascript execution environment is divided into two worlds :

    • "ISOLATED": Specifies the isolated world, which is the execution environment unique to this extension.

    • "MAIN": Specifies the main world of the DOM, which is the execution environment shared with the host page's JavaScript.

    Why your code from the extension won't work?

    The reasons your code does not work is that it is being injected as a content script with no world option:

    "content_scripts": [
    {
      "matches": ["https://*"],
      "js": ["query_page_script.js"]
    }],
    

    This will make the extension take in the ISOLATED value for the world option as the default value and hence, inject your code to a totally isolated environment from the javascript execution environment of the main webpage as documented. At this point, apart from the code you just inject, the rest of this execution environment is totally empty.

    Why your code in the console work?

    Simply, because the console displays both console log from all the "worlds" in default but the input it takes in will be classified to MAIN world - the same environment with the website and therefore will work normally just like that website's javascript code.

    Solution

    I believe that adding world option to your manifest file will fix this issue.

    "content_scripts": [
    {
      "matches": ["https://*"],
      "js": ["query_page_script.js"]
      "world": "MAIN"
    }],
    

    With this, your code will be executed in the same environment of the website and allow it to use the loaded javascript. Another suggestion is that you might want to load the content script after the page is fully loaded to ensure the viability of the modules. You can check this link for more information. Hope this can help!