0

I'm developing a Chrome Extension using React/Redux. For that, I'm using Webpack and now I'm migrating some resources to a separated file using the WebPack DLLReference plugin to optimize the build process.

Then I need to load the generated dll/dll.vendor.js into both my popup and injected content. For the popup it works fine, but it's not working for the injected content.

I've added it to the manifest

"web_accessible_resources": [
    "dll/dll.vendor.js"
],

The file is there, I can even access it using the path: chrome-extension:///dll/dll.vendor.js

But it's not present in the injected content, as I can see opening the Developer Tools -> Sources Which, of course, generate errors of missing objects later on.

Everything was working fine before migrating to DLLReferencePlugin.

My DLL webpack config file: https://pastebin.com/z9RjRUqm

My Content webpack config file: https://pastebin.com/0Niw2Fqm

The error I'm receiving

The line that triggers the error:

module.exports = vendor;

If I check the popup, it has the same line, if I set a breakpoint there and watch the variable it's defined, the problem only happens in the content.

The code to inject my Extension toolbar into the page: content/src/index.js

import React from 'react';
import {render} from 'react-dom';
import {Provider} from 'react-redux';
import {Store} from 'react-chrome-redux';

const anchor = document.createElement('div');
anchor.id = 'my-anchor';
document.body.appendChild(anchor)

const vendorUrl = chrome.runtime.getURL("dll/dll.vendor.js")

render(
  <Provider store={proxyStore}>
      <div>
          <script src={vendorUrl}></script>
          <link id='semantic-ui' rel='stylesheet' type='text/css'
                href='https://cdnjs.cloudflare.com/ajax/libs/semantic-ui/2.2.2/semantic.min.css' media='all' />
          <AppContainer>
              <ToolbarContent />
          </AppContainer>
      </div>
  </Provider>
  , document.getElementById('my-anchor'));

Any idea what else could be the cause for this issue? Any better way to debug why the resource is not being available to the content environment?

UPDATE

Based on my last findings it happens because the code depending on dll.vendor is executed before the injection happens on the page, but I don't know how can I avoid this to happen.

Vadim Kotov
  • 8,084
  • 8
  • 48
  • 62
dfranca
  • 5,156
  • 2
  • 32
  • 60
  • And how are you injecting that content? It's missing from your question. – Xan May 31 '17 at 14:34
  • Through render of – dfranca May 31 '17 at 14:42
  • But anyway, it should at least be listed among the source files, right? – dfranca May 31 '17 at 14:42
  • And why would it be a relative path? Use `chrome.runtime.getURL()` – Xan May 31 '17 at 14:42
  • Same error, It seems that the error actually happens before the injection, which makes other stuff fail and then the script is not loaded. Even removing the script tag gives me the same error: Uncaught ReferenceError: vendor is not defined – dfranca May 31 '17 at 15:00
  • Well, at this point one thing is clear: without more relevant code, your question is unanswerable. – Xan May 31 '17 at 15:01
  • Okay, I was thinking that could be something stupid I missed in the documentation... in that case I'll update adding a minimum relevant code. – dfranca May 31 '17 at 15:29
  • @Xan Just added more code, hope it helps – dfranca May 31 '17 at 15:40
  • Probably it's not the best solution, but I was able to make it work adding both scripts to the manifest with the exact same match patterns and adding run_at "document_start" to the vendor one. But I feel it's a poor solution, if you can point a better one, let me know. – dfranca May 31 '17 at 16:37
  • Just to be clear: is any of your content script code depending on the contents of that file? Or are you explicitly trying to inject this into the page context for the page code? – Xan May 31 '17 at 16:40
  • 1
    Pretty much all the libraries I use in the content code are in this file. – dfranca May 31 '17 at 16:51
  • 1
    `how can I avoid this to happen` - use the standard onload event of the `script` DOM element for your vendor js, then construct the app inside the onload callback? – wOxxOm May 31 '17 at 16:55

1 Answers1

1

There's one thing missing from your understanding of content scripts, the Isolated World paradigm:

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.

How does this relate? Well, if you're adding a <script> element to the page's DOM, the code will execute in the page's context - not your content script's context. This technique is called "page level" or "injected" scripts.

However, that's not what you want. You want it in the content script context, so you can use the libraries. Then you have options:

  1. If you always need the same script configuration, adding scripts as an array in the manifest is probably best. Load order matters:

    "js" : [ "library.js", "actual_code.js" ]
    
  2. If you for some reason need to load code dynamically at runtime from an existing content script, you can request the background page to inject it programmatically for you. If you're already doing it, just chain the calls in the right order.

  3. Not a technically ideal solution, but you could XHR your internal resource and then eval() from the content script context.

Xan
  • 74,770
  • 16
  • 179
  • 206
  • Thanks for the detailed explanation. The solution 1 works like a charm... When I tried to add my script to the list I added it as the second one, order matters =| – dfranca May 31 '17 at 17:04
  • 1
    As a comment, in this case you _don't_ need `web_accessible_resources`. In fact, it can be considered harmful: you're exposing yourself to fingerprinting as anything can try to request a well-known resource in your extension. – Xan May 31 '17 at 17:18