Say hi to ceci 💅
ceci provides 4 layers to use in your Chrome Extension and allow to execute code in the page's context of different targets.
ceci is dividen in modules to allow to inject only the necessary code in each layer.
- content-script
- devtools
- event-page
- page-agent
- page-executor
- subscriber
import ceci from 'ceci/content-script' // Best option, will only inject the necessary code
import { contentScript as ceci } from 'ceci' // Also works, but the final bundle will be bigger
This is the minimal setup necessary to work with ceci.
This script is an Agent that will take care of all the heavy part of interpretare your code, run it, return values, etc. It's the heart ❤️ of ceci
This Agent will be injected in every tab that the extension has permissions (by domain) by the Content Script layer
The script will implement the ceci's page-agent module, like this:
import ceci from 'ceci/page-agent'
ceci()
Normally there is not need to have extra code in this script because ceci will take care of everything. But, this script will be executed in the context of the page, you can add helper code here and reuse it in you injected code.
This Content Script
will not be injected through manifest.json
, this file will be injected by the Event Page layer
The Content Script
's code will implement the ceci's content-script module, like this:
import ceci from 'ceci/content-script'
//URL to the script that implements the ceci's page-agent layer
const pageAgentUrl = 'page-agent.js'
ceciContentScript(pageAgentUrl)
.then(({run, reactive}) => {
// run and reactive are two ways to inject code into the pages (see the doc below)
/*
Your Event Page's code
*/
})
You need to configure a Event Page
in you manifest.json
, like this:
{
"background": {
"scripts": ["event-page.js"],
"persistent": false
}
}
The Event Page
's code will implement the ceci's event-page module, like this:
import ceci from 'ceci/event-page'
//URL to the content-script that implements the ceci's content-script layer
const contentScriptUrl = 'content-script.js'
// run and reactive are two ways to inject code into the pages (see the doc below)
const { run, reactive } = ceci(contentScriptUrl)
/*
Your Event Page's code
*/
This two types of layers are really useful but there is no need to have it to work with ceci.
The devtools layer allow to run code in the inspected code very easily, like this:
import ceci from 'ceci/devtools'
// run and reactive are two ways to inject code into the pages (see the doc below)
const {run, reactive} = ceci()
This module can be used in any layer, contains the run
and reactive
to be used from anywhere. This module doesn't run all the bootstrap code that the other layers runs. So this is useful when you have multiple content scripts, event pages or even browser actions.
// run and reactive are two ways to inject code into the pages (see the doc below)
import {run, reactive} from 'ceci/page-executor'
ceci needs tabs
and activeTab
extensions permissions to work, also the Page Agent must be accesible from the web using web_accessible_resources
.
ceci will only work with tabs which has permission. Do not execute run
or reactive
if you don't have permission to the domain of the tab.
All the modules only expose two functions to run code.
This will run a sync or async function into the page.
run(function)
run(function, parameters)
run(function, parameters, tabId)
- function: Function to be executed in the page context
- parameters: Array of parameters to use to call the function (using apply)
- tabId: Tab's id to find the tab where run the code. Only available when is called from page-executor or event-page
Promise
that will resolve with the value that the function
returns, will catch any error thrown by the function
. If the function returns a Promise
the promises are chained.
import { run } from 'ceci/page-executor'
let username = 'manrueda'
let execution = run(username => {
// The parameters will respect the array order
return fetch(`/api/user/${id}`)
.then(r => r.json())
}, [username])
execution.then(user => {
console.log(user)
}).catch(error => {
console.warn(error)
})
This allow to run code in the page and subscribe the extension to events that the function can emit. This is to avoid polling the page to detect changes.
reactive(function)
reactive(function, parameters)
reactive(function, parameters, tabId)
- function: Function to be executed in the page context
- parameters: Array of parameters to use to call the function (using apply)
- tabId: Tab's id to find the tab where run the code. Only available when is called from page-executor or event-page
Subscriber
instance (see below) that can be used to subscribe to event emitted by the code.
import { reactive } from 'ceci/page-executor'
let username = 'manrueda'
let subscriber = reactive((emit, username) => {
// The parameters will respect the array order, but always the first one will be the emit
// Every 150ms this code will emit an event with the username using the emit function
const interval = setInterval(function () {
emit({username})
}, 150)
// The returned value must be a function that will be called when the Subscriber instance in the extension is disposed
return () => {
clearInterval(interval)
}
}, [username])
// The subscribe method will register listeners for errors and events
subscriber.subscribe(event => {
console.log(event)
}, error => {
console.warn(error)
subscriber.dispose()
})
-
subscribe([eventListener, [errorListener]]): This function attach zero, one or both type of listeners to the subscribers. Those listener will be called if an event or error is emitted in the
Subscriber
. - dispose(): Will trigger the dispose of this instance and the code in the page related with it.
-
emit([error, [event]]): This method can be called to emit events or errors in the
Subscriber
. Normally only used internally.