最近需要制作一个浏览器插件,实现通过插件, 修改目标页面的时间。 这里选择svelte作为开发框架,svelte作为无运行时的框架,可以减少代码体积(顺便玩玩没用过的框架)。

关于svelte和vue体积的对比, 前端圈子争论不休,挑出几个风靡一时的帖子看一下:

fe-frameworks Jacek Scheae对多框架体积的对比图

浏览器插件简述

浏览器插件能做什么? chrome 给出三个能力分类:

  • 设计界面
  • 控制浏览器
  • 控制网络

详情可参考 chrome插件开发文档 了解具体使用。

项目结构

目前的结构是, popup 因为有页面,作为独立的svelte项目, 通过vite构建。 其他的部分, content.js, background.js 作为原生js编写,不需要构建,只需要从 public 移动到最终的dist 即可。

├── README.md
├── dist --------------------- 构建后的文件, 用于作为插件发布
│   ├── background
│   ├── content
│   ├── imgs
│   ├── manifest.json
│   ├── popup
│   ├── svelte
│   └── vite.svg
├── jsconfig.json ------------ vscode配置文件
├── manifest.json ------------ 插件配置文件
├── package-lock.json
├── package.json
├── popup --------------------- 插件弹窗, 其中为本次svelte项目
│   ├── App.svelte
│   ├── app.css
│   ├── assets
│   ├── index.html
│   ├── lib
│   └── main.js
├── public -------------------- 静态资源
│   ├── background
│   ├── content
│   ├── imgs
│   └── vite.svg
├── svelte.config.js ---------- svelte配置文件
├── vite-env.d.ts ------------- vite配置文件
└── vite.config.js

构建配置

目标是把所有的文件构建到 dist 目录下, 并保持manifest.json在根目录下, 各个部分在menifest.json的指定目录下。

vite.config.js

export default defineConfig(({ mode }) => {
  const isProd = mode === 'production'
  return {
    root: isProd ? '' : 'popup',
    plugins: [
      // 把manifest.json复制到dist目录下
      viteStaticCopy({
        targets: [
          { src: 'manifest.json', dest: '' }
        ]
      }),
      // svelte官方插件: 构建popup部分
      svelte()
    ],
    build: {
      minify: false,
      rollupOptions: {
        // 让popup作为vite的构建入口
        input: {
          popup: resolve(__dirname, 'popup/index.html'),
        },
        // 输出配置
        output: {
          entryFileNames: '[name]/[name].js',
          chunkFileNames: '[name]/[name].js',
          assetFileNames: '[name]/[name].[ext]',
          // svelte作为独立chunk
          manualChunks: {
            svelte: ['svelte'],
          }
        }
      },
      modulePreload: {
        // 禁用 modulepreload polyfill, 这个特性 chrome 66就支持了
        polyfill: false
      }
    },
  }
})

构建后的结构

最终构建后的目录如下:

./dist
├── background
│   ├── background.js
│   ├── insert.js
│   └── mockdate.js
├── content
│   └── content.js
├── imgs
│   └── icon.png
├── manifest.json
├── popup
│   ├── index.html
│   ├── popup.css
│   └── popup.js
├── svelte
│   └── svelte.js
└── vite.svg

其中 menifest.json 配置各部分如下:

{
  "manifest_version": 3,
  "name": "SimulatedTime",
  "description": "Change the current time to simulation time!",
  "version": "1.0",
  "action": {
    "default_popup": "popup/index.html",
    "default_icon": "imgs/icon.png"
  },
  "permissions": ["scripting", "activeTab", "storage"],
  "host_permissions": ["<all_urls>"],
  "background": {
    "service_worker": "background/background.js"
  },
  "content_scripts": [
    {
      "matches": ["<all_urls>"],
      "js": ["content/content.js"],
      "run_at": "document_start"
    }
  ]
}