Plasmo Content Script Independent Configuration Mechanism Explained
While working on Chrome extensions, I discovered a particularly useful feature of the Plasmo framework: every file in the contents directory can have its own independent PlasmoCSConfig, and they don’t interfere with each other at all.
Why Independent Configuration Matters
In real-world projects, we often need to write specialized content scripts for different pages or functionalities. For example:
- Some scripts only need to run on specific domains
- Some need to execute at different stages of page loading
- Some need to inject UI components, while others only handle data processing
If all scripts shared the same configuration, configuration conflicts would be common. Plasmo’s design elegantly solves this problem.
Practical Applications of Independent Configuration
Domain-Specific Scripts
// contents/vulcan.ts - runs only on specific domains
export const config: PlasmoCSConfig = {
matches: ["https://vulcan.plasmo.com/*", "https://www.nowarpls.org/*"]
}
// contents/nested/index.tsx - runs on a different domain
export const config: PlasmoCSConfig = {
matches: ["https://itero.plasmo.com/*"]
}Different Execution Timings
// contents/content-isolated.ts - runs when page is idle
export const config: PlasmoCSConfig = {
matches: ["https://www.plasmo.com/*"],
run_at: "document_idle"
}
// contents/relay.ts - runs immediately at document start
export const config: PlasmoCSConfig = {
matches: ["https://www.plasmo.com/*"],
run_at: "document_start"
}Special Execution Environments
// contents/plasmo-main.ts - runs in main world
export const config: PlasmoCSConfig = {
matches: ["https://www.plasmo.com/*"],
world: "MAIN",
run_at: "document_start"
}UI Component Injection Scripts
// contents/plasmo-overlay.tsx - Overlay component with styles
export const config: PlasmoCSConfig = {
matches: ["https://www.plasmo.com/*"],
css: ["font.css"]
}
// contents/plasmo-inline.tsx - Simple inline component
export const config: PlasmoCSConfig = {
matches: ["https://www.plasmo.com/*"]
}Technical Implementation Details
PlasmoCSConfig Type Definition
PlasmoCSConfig is essentially a wrapper around the ManifestContentScript type, but excludes the js field since Plasmo automatically handles JavaScript file paths:
export type PlasmoCSConfig = Omit<Partial<ManifestContentScript>, "js">Configuration Isolation Mechanism
Plasmo implements configuration isolation through its manifest factory system. Each content script is handled independently via the toggleContentScript method:
- Extract configuration metadata:
const metadata = await extractContentScriptConfig(path) - Apply independent configuration: Each script’s configuration is processed separately
- Store in Map:
this.contentScriptMap.set(path, contentScript)
The key insight is that configurations are stored in a Map using file paths as keys, ensuring complete isolation for each script’s configuration.
Final Merging Process
When generating the manifest, all independent configurations are merged into the content_scripts array:
base.content_scripts = [
...Array.from(this.contentScriptMap.values()).filter(
(s) => s.world !== "MAIN"
),
...(overrideContentScripts! || [])
]Practical Recommendations
Based on my experience, this independent configuration design offers several clear benefits:
1. Better Code Organization
Each functional module has its own configuration, making it easy to locate and modify.
2. Avoid Configuration Conflicts
Different scripts can have different matches, run_at, and other configurations without interfering with each other.
3. Enhanced Team Collaboration
In multi-developer environments, each developer can independently configure their scripts, reducing merge conflicts.
4. Flexible Deployment Strategies
You can enable or disable specific content scripts as needed.
Frequently Asked Questions
Q: What happens if multiple scripts configure the same matches?
A: No problem at all! Each script will run independently on matching pages without interference.
Q: How are CSS files in the configuration handled?
A: Plasmo automatically resolves relative paths and correctly associates CSS files with their corresponding content scripts.
Q: What’s special about main world scripts?
A: Main world scripts (world: "MAIN") currently require special handling and are temporarily filtered out during final merging, awaiting Chrome’s native support.
Conclusion
Plasmo’s modular design is genuinely practical, making content script management straightforward and clear. Each script can focus on its specific functionality with clean, independent configurations, significantly improving development efficiency and code maintainability.
If you’re also using Plasmo for Chrome extension development, I strongly recommend leveraging this feature to organize your content scripts effectively. Feel free to reach out if you have any questions or want to discuss further!