Javascript – chrome extension throws “not defined” on defined variable

google-chrome-extensionjavascript

I am trying to access a local var using a chrome extension.
When trying console.info(myVar) inside a page script, I am getting myVar is not defined

However, when using the chrome developer tools and executing the same snippet in the debugging console, I am getting the full content of myVar.

Same behaviour when trying to access window.myVar, which is simply undefined when printing through a chrome extension.

Injecting a script tag into the body, using the following snippet through dev tools and page script, results in the exact same behaviour.

   $("body").append($("<script />", {
      html: "console.info(myVar);"
   }));

Variable gets printed when executing in dev tools but javascript error in pagescripts

Best Solution

What you see is expected behavior.

Content scripts execute in a special environment called an isolated world. They have access to the DOM of the page they are injected into, but not to any JavaScript variables or functions created by the page. It looks to each content script as if there is no other JavaScript executing on the page it is running on. The same is true in reverse: JavaScript running on the page cannot call any functions or access any variables defined by content scripts.

http://developer.chrome.com/extensions/content_scripts.html#execution-environment

When you run console.info(myVar); from the page, the console of Chrome dev tools or from the injected script, it runs in the context of the page and thus sees the variable as defined.

However, when running the same code from inside of your extension code, you're operating in a completely different environment, so myVar is undefined.

You can work around this using shared DOM perhaps.
http://developer.chrome.com/extensions/content_scripts.html#host-page-communication

EDIT

Unless someone corrects me, the console.info(myVar); code below is injected into script element while still being executed in the context of the extension:

$("<script />", {
    html: "console.info(myVar);" // myVar points to extension's myVar, not page's
});

A simple test can be run by logging chrome.extension object or declaring myVar inside of the contentscript – the chrome.extension will be available and myVar will be logged exactly as defined in the contentscript.

The suggestion is to use an external script (which is also better for modularity), add it to web_accessible_resources and create a script element with a src property pointing to that external script.

The example extension code below alerts "test" when loading the test.html page with extension enabled.

manifest.json

{
    "name": "Test",
    "version": "0.1.0",
    "manifest_version": 2,
    "description": "Just a test.",
    "content_scripts": [{
        "matches": ["<all_urls>"],
        "js": ["contentscript.js"]
    }],
    "web_accessible_resources": [
        "myscript.js"
    ]
}

test.html (the visited page)

<!DOCTYPE html>
<html>
<head>
    <script>
        window.test = 'test';
    </script>
</head>
<body>
</body>
</html>

contentscript.js

var script = document.createElement('script');
script.type = 'text/javascript';
script.src = chrome.extension.getURL('myscript.js');
document.getElementsByTagName('head')[0].appendChild(script);

myscript.js (this is the external script that will run in the context of the page)

alert(window.test);