Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Efficient way to add more content scripts #37

Open
brandonmp opened this issue Mar 27, 2016 · 7 comments
Open

Efficient way to add more content scripts #37

brandonmp opened this issue Mar 27, 2016 · 7 comments

Comments

@brandonmp
Copy link
Contributor

I'm new to Chrome extensions, so forgive me if this question isn't unique to this project.

I'm trying to add multiple content scripts, each of which injects into a different url.

Is there a straightforward way to do this? So far the best i can figure out is:

  1. Add new content .js file to browser/extension/inject
  2. update manifest.json to inject the new script into the correct URL
  3. update the extension webpack to bundle the new script into a separate bundle
  4. update the dev webpack to output the new script separately

However, that a) seems way too complicated and b) isn't working for me.

has anyone done this? My content scripts are too big to inject in every page.

@zalmoxisus
Copy link
Owner

You can inject scripts via manifest (which I'd recommend) or by using an inject script as we do in development. For both cases you have to generate every bundle. Probably a better a way in your case would be to delegate a part of the functionality to the background script. So you can have a small universal injected script, which will just investigate the page and will communicate with the background (sending specific commands and receiving the response from the background script).

@brandonmp
Copy link
Contributor Author

thanks for the quick & thorough answer, @zalmoxisus

if i can ask a followon:

one of my scripts that might be too big to load everywhere is a scraper that fetches a few dozen DOM nodes with numerous document.querySelector().

I ended up putting it in the injection function because I didn't think I could access raw DOM nodes thru React components. Most of my scripts either scrape, or populate existing DOM nodes, in fact.

Are those types of functions possible within React components in this setup? Or are those best left to regular injection functions?

I thought of sending the entire DOM to the background to parse there, but I imagine that would be even more of a burden on the UX than the slight lag in loading the current technique experiences.

@zalmoxisus
Copy link
Owner

Yes, you shouldn't include React there for sure, probably you'll use something like here.

If you don't want to have a lot of files with scripts for every case, then yes, better not to inject through manifest, but just inject the script body directly. Something like here.

@brandonmp
Copy link
Contributor Author

thanks @zalmoxisus . so far injecting through the script body is working great with minimal hits to load times.

One more question: if I inject a content script that dispatches an action creator (e.g., store.dispatch(doAction())), does -all- of the code in that action creator get injected? or does a message fire back to the extension and the code runs there?

I ask b/c I have an action creator that does some async stuff, and i'd like to keep it contained in the background.

I tried figuring it out from the src code, but having trouble connecting the dots

@zalmoxisus
Copy link
Owner

Hey @brandonmp,

Sure, everything you import in that injected script will be part of it. Unlike windows, the injected scripts are independent from the background script. You can have a different store and different action creators there. So you can have in the injected script an action which requests an async request and on background another action that executes the async stuff.

@brandonmp
Copy link
Contributor Author

Okay, I took a much closer look at the counter example and I think I was just missing some key points in how the extension/background communicate. Can you tell me if this understanding is correct?

  1. Action creator is invoked, action is returned.
  2. the local store is updated via its own reducers (e.g., a content script updates its own store, or a background script updates its own store),
  3. the redux-notify event listener dispatches sendNotification()
  4. sendNotification() invokes sendMessage() from cross-messaging, which either sends a message to the background or content script, depending on where it's invoked
  5. finally, listeners in either getStateFromBg or getStateToBg catch the redux-notify object from sendMessage(), and dispatch the receiveNotification() action creator, which simply dispatches the original action from step 1.

So, if all that is correct, it seems like the best way to keep logic in the background is to have two separate action creators for a process foo:

triggerFoo(): invoked from content-script, returns simply {type: FOO_TRIGGERED}
doFoo(): executes process logic. only invoked via event listeners in redux-notify, therefore never directly injected into the content script.

Appreciate your help with this. This project has been a tremendous help in learning more about extensions (and redux too)

eta: if i'm correct about the process and it'd be helpful, i'm happy to extend the repo's readme

@zalmoxisus
Copy link
Owner

Yes, you got the point, and having several action types dispatched for an async task is a good practice. For example: FETCH_REQUEST, FETCH_SUCCESS, FETCH_ERROR. You can find an example with redux-saga here.

In some projects I don't have action creators at all, and just do dispatch({ type: 'ACTION_NAME' }) as everything else is inside sagas.

About extending the repo's readme, it would be really welcome to have a docs/recipes.md.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants