可以随意导入静态资源!CRXJS会自动将导入的内容脚本依赖项声明为清单中的web_accessible_resources。
内容脚本共享宿主页面的来源,因此使用Chrome API将导入的静态资源转换为扩展来源。
import logo from './logo.png'
const url = chrome.runtime. getURL (logo)
CRXJS通常会通过异步loader运行内容脚本。这个loader可以启用Vite HMR
并支持常规ESM导入,但对于必须在页面代码运行前修补宿主页面API的
document_start脚本来说,它可能太晚。
如果需要在main world中拦截fetch、XMLHttpRequest、DOM事件或全局变量
等时序敏感逻辑,请使用IIFE内容脚本。CRXJS会将脚本输出为独立bundle,
并内联它的导入,Chrome会直接运行该文件。
IIFE内容脚本不支持就地Vite HMR。开发期间CRXJS会重新构建独立文件,
但更新后的脚本只会在宿主页面重新加载或再次导航后运行。
请尽量将大部分扩展逻辑放在默认的isolated world内容脚本中。它与页面
JavaScript隔离,可以使用内容脚本可用的扩展API,并且在开发期间支持完整
的Vite HMR。
只有必须在宿主页面环境中执行的部分才使用MAIN world IIFE。把它当作一个
小型bridge:在document_start安装早期hook,然后通过window.postMessage、
CustomEvent或DOM事件把命令或数据传给isolated内容脚本。这样可以让不支持
HMR的脚本保持小而稳定。
文件名 standaloneFiles 动态注册
在源文件扩展名前添加.iife。支持.iife.ts、.iife.tsx、.iife.js
和.iife.jsx。
manifest.config.ts
import { defineManifest } from '@crxjs/vite-plugin'
export default defineManifest ({
manifest_version: 3 ,
name: 'My Extension' ,
version: '1.0.0' ,
content_scripts: [{
js: [ 'src/content/interceptor.iife.ts' ],
matches: [ 'https://example.com/*' ],
run_at: 'document_start' ,
world: 'MAIN' ,
}],
})
如果不能重命名文件,请在contentScripts.standaloneFiles中列出它。
vite.config.ts
import { crx } from '@crxjs/vite-plugin'
import { defineConfig } from 'vite'
import manifest from './manifest.config'
export default defineConfig ({
plugins: [
crx ({
manifest,
contentScripts: {
standaloneFiles: [ 'src/content/interceptor.ts' ],
},
}),
],
})
对于通过chrome.scripting注册的脚本,可以使用?iife导入生成的文件路径,
或使用.iife文件名约定加?script。
background.ts
import interceptor from './content/interceptor.ts?iife'
// import interceptor from './content/interceptor.iife.ts?script'
chrome.scripting. registerContentScripts ([{
id: 'network-interceptor' ,
js: [interceptor],
matches: [ 'https://example.com/*' ],
runAt: 'document_start' ,
world: 'MAIN' ,
}])
可以使用iframe将扩展页面注入到宿主页面中。即使宿主页面指定了frame-src策略,宿主页面的CSP也不会影响注入的iframe。
注入的扩展页面加载在跨域iframe中,因此它不像内容脚本那样可以访问宿主页面的DOM。
content-script.js
const src = chrome.runtime. getURL ( 'pages/iframe.html' )
const iframe = new DOMParser (). parseFromString (
`<iframe class="crx" src="${ src }"></iframe>` ,
).body.firstElementChild
document.body. append (iframe)
然而,注入的扩展页面确实可以访问完整的Chrome API。
如果从内容脚本加载HTML文件,您需要将该文件声明为web可访问资源。
manifest.config.ts
import { defineManifest } from '@crxjs/vite-plugin'
import pkg from './package.json'
export default defineManifest ({
manifest_version: 3 ,
name: pkg.name,
version: pkg.version,
action: {
default_popup: 'src/popup/index.html' ,
},
content_scripts: [{
js: [ 'src/content/main.ts' ],
matches: [ 'https://*/*' ],
}],
web_accessible_resources: [{
resources: [ "pages/iframe.html" ],
matches: [ "https://*.google.com/*" ]
}]
})
您还需要将HTML文件添加到Vite配置的build.rollupOptions.input下。
vite.config.ts
export default defineConfig ({
build: {
rollupOptions: {
input: {
welcome: 'pages/iframe.html' ,
},
},
},
})
如果需要在没有框架的情况下在内容脚本中渲染复杂的HTML,可以通过使用?raw查询将其作为文本导入,HTML文件可以作为静态片段。此技术不需要文件是web可访问的,也不需要您在Vite配置中声明它。
import html from './root.html?raw'
const iframe = new DOMParser (). parseFromString (html).body.firstElementChild
iframe.src = chrome.runtime. getURL ( 'pages/iframe.html' )
document.body. append (iframe)
将HTML文件作为文本导入可以让您利用IDE的语言服务功能来处理HTML文件。根据您的HTML内容,这种技术可能比使用document.createElement()更简洁。