[extention] extention 项目构建

是这样的,最近想要开发一个浏览器拓展的应用,刚开始就给我恶心到了,每天都用着第三方模块和 import export 切分文件的我面对一个个独立的js竟无从下手,那么就用webpack来构建一个模块化的 extention 项目吧~

项目地址:https://gitee.com/boboanzuiniubi/ext-xhr-proxy
这个是个xhr劫持的拓展工具,我会在做完功能之后,把项目模板拆出来~

先分析一下要做什么吧

manifest.json:

{
    "manifest_version": 2,
    "name": "zcr",
    "description": "ceshi",
    "version": "1.0",
    "content_scripts": [{ "matches": ["<all_urls>"], "css": [], "js": ["./content_scripts/inject_xhr.js"] }]
}

manifest.json 是位于项目根目录下的拓展应用的清单文件,这里面是拓展应用的描述,和 content_scripts/page/icon 等等资源的地址。大多属性是静态的,资源地址 是整个构建流程需要处理的,要做的是将构建后的资源目录,写入 manifest.json ,亦或者是按照 manifest 上写的路径去构建资源。

load scripts:

拓展中的 content_scriptinject_script 都是需要打包起来的 js 文件,各种单页面 page 也需要打包一个入口文件,那我们就需要写一段 js 去按路径读取这些 js 入口文件,并且要将output的文件地址写入 manifest

load pages:

拓展(extention)中是有一些页面的,比如 popup page / background page / devtools page 都是一个html,我们可以用 html-webpack-plugin 和三大框架构建一个单页面应用来快速开发

目录结构与构建流程

image.png

细化

eslint

(todo 但又不完全todo) 在纠结要不要引,因为项目不是很大,不是很关键

friendly-errors-webpack-plugin

friendly-errors-webpack-plugin用来输出webpackl的报错真是简单又好用,省得你去研究怎么输出异常。

plugin

我这里用的 plugin 是为了在每个模块构建完成时,记录一下需要写入 manifest 的 output 地址的
找一个合适的钩子获取 output 的地址


1623833203(1).png

比如传入一个记事本对象,并在构建结束后重写manifest.json

const manifest_content_scripts = {
  matches: ['<all_urls>'],
  css: [],
  js: []
}
config.plugins.push(new ContentScriptPlugin(manifest_content_scripts))

webpack(config, (err, stats) => {
  if (err || stats.hasErrors()) {

  } else {
    // 重写manifest
    fs.writeFileSync(path.resolve(__dirname, '../output/manifest.json'), JSON.stringify({
      ...manifest,
      web_accessible_resources: mainfest_web_accessible_resources,
      content_scripts: [manifest_content_scripts]
    }))
  }
});
...
// 这个plugin在构建模块时,记录一条需要注入的content_script

const isContentJs = (name) => /content_scripts\/.+\.js$/.test(name)
const isContentCss = (name) => /content_scripts\/.+\.css$/.test(name)

module.exports = class ContentScriptPlugin {
  constructor(manifest_content_script) {
    this.manifest_content_script = manifest_content_script
  }
  apply(compiler) {
    compiler.hooks.assetEmitted.tap(
      'ContentScriptPlugin',
      (file, { content, source, outputPath, compilation, targetPath }) => {
        if (isContentJs(file)) {
          this.manifest_content_script.js.push(file)
        } else if (isContentCss(file)) {
          this.manifest_content_script.css.push(file)
        }
      }
    )
  }
}

react

用 react 加其周边的组件库 可以很快速的开发 html 页面,需要babel-loaderhtml-webpack-plugin去执行jsx语法转换和创建页面。

配置 babel

// babel.config.json
{
  "presets": [
    "@babel/env",
    "@babel/preset-react"
  ]
}

添加 rules

// rules 只处理页面部分的js就可以了,可以加载ext的浏览器并没有兼容性问题
rules: [{
      test: /\.jsx?$/,
      loader: "babel-loader",
      include: [src('./popup')]
    },
    ...
]

打包入口

entry: {
    ...content_scripts,
    ...inject_scripts,
    background: src('./background.js'),
    popup: src('./popup/index.js')
},

配置 html plugin

plugins: [
    new HtmlWebpackPlugin({
      filename: 'popup.html',
      template: src('./popup/index.html'),
      chunks: ['popup']
    }),
   ...
  ],

shelljs

用 node 的 file system 处理文件会有各个node版本fs api的兼容性问题,太烦了,用shelljs兼容性问题会少点

file-loader

拓展应用中的资源文件会有 icon img 这种 图片资源,统一就用file-loader 去放到一个img目录下好了,在manifest中就按照命名引用img目录下的资源

rules: [
    ...   
   ,{
      test: /\.(png|jpe?g|gif)$/i,
      use: [
        {
          loader: 'file-loader',
          options: {
            name: 'img/[name].[ext]'
          }
        }
      ]
    }]
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容