vue-cli3開發Chrome插件實踐

以前找了很多如何開發谷歌插件的文章,結果發現都是些很基礎的內容,並無寫到如何快速編譯打包插件。我就在想爲何不能經過webpack來打包插件呢?若是經過webpack編譯的話,就能使開發過程變得更舒服,使文件結構趨向模塊化,而且打包的時候直接編譯壓縮代碼。後來發現了vue-cli-plugin-chrome-ext插件,經過這個插件能很方便地用vue-cli3來開發谷歌插件,並能直接引用各類UI框架跟npm插件。javascript

tip:若是你沒接觸過谷歌插件開發的話建議先看看基礎文檔:css

搭建環境

  1. 建立一個vue-cli3項目: vue create vue-extension,對話流程選擇默認就行。
  2. 進入項目cd vue-extension
  3. 安裝vue-cli-plugin-chrome-ext插件:vue add chrome-ext,根據安裝對話選項設置好。
  4. 刪除vue-cli3無用文件跟文件夾:src/main.jssrc/components

運行項目

  • npm run build-watch 運行開發環境,對修改文件進行實時編譯並自動在根目錄下生成dist文件夾,而後在瀏覽器上加載dist文件夾完成插件安裝。(注意:修改background文件跟manifest.json文件並不能實時刷新代碼,須要從新加載插件才行。 後面已經有實時刷新的解決方法) html

  • npm run build 運行生產環境編譯打包,將全部文件進行整合打包。前端

引入element UI

目前的插件加載到瀏覽器後彈出頁面是這種界面: vue

平時咱們確定要引入好看的UI框架的,在這裏咱們能夠引入 element-ui,首先安裝:

npm install element-ui
複製代碼

考慮到插件打包後的文件大小,最後經過按需加載的方式來引入組件,按照element-ui官方的按需加載方法,要先安裝babel-plugin-component插件:java

npm install babel-plugin-component -D
複製代碼

而後,將babel.config.js修改成:webpack

module.exports = {
  presets: [
    '@vue/app'
  ],
  "plugins": [
    [
      "component",
      {
        "libraryName": "element-ui",
        "styleLibraryName": "theme-chalk"
      }
    ]
  ]
}
複製代碼

接下來修改popup相關文件引入所需組件, src/popup/index.js內容:git

import Vue from "vue";
import AppComponent from "./App/App.vue";

Vue.component("app-component", AppComponent);

import {
  Card
} from 'element-ui';

Vue.use(Card);

new Vue({
  el: "#app",
  render: createElement => {
    return createElement(AppComponent);
  }
});
複製代碼

src/popup/App/App.vue 內容:github

<template>
  <el-card class="box-card">
    <div slot="header" class="clearfix" >
      <span>卡片名稱</span>
      <el-button style="float: right; padding: 3px 0" type="text" >操做按鈕</el-button>
    </div>
    <div v-for="o in 4" :key="o" class="text item" >
      {{'列表內容 ' + o }}
    </div>
  </el-card>
</template>

<script> export default { name: 'app', } </script>

<style> .box-card { width: 300px; } </style>
複製代碼

渲染效果: web

固然,不單單是插件內部的頁面,還能夠將element-ui組件插入到content頁面。

content.js使用element-ui組件

content.js主要做用於瀏覽網頁,對打開的網頁進行插入、修改DOM,對其進行操做交互。別以爲element-ui只能配合vue使用,其實就是一個前端框架,只要咱們引入了就能使用,webpack會自動幫咱們抽離出來編譯打包。

根據評論的朋友提示,能夠經過Chrome插件的chrome.extension.getURLAPI來引入字體文件,解決element-ui沒法引入相對路徑的字體文件問題。

首先咱們建立src/content/index文件,在裏面咱們經過chrome.extension.getURLAPI來引入插件的字體文件,內容:

import {
    Message,
    MessageBox
} from 'element-ui';

// 經過Chrome插件的API加載字體文件
(function insertElementIcons() {
    let elementIcons = document.createElement('style')
    elementIcons.type = 'text/css';
    elementIcons.textContent = ` @font-face { font-family: "element-icons"; src: url('${ window.chrome.extension.getURL("fonts/element-icons.woff")}') format('woff'), url('${ window.chrome.extension.getURL("fonts/element-icons.ttf ")}') format('truetype'); /* chrome, firefox, opera, Safari, Android, iOS 4.2+*/ } `
    document.head.appendChild(elementIcons);
})();

MessageBox.alert('這是一段內容', '標題名稱', {
    confirmButtonText: '肯定',
    callback: action => {
        Message({
            type: 'info',
            message: `action: ${ action }`
        });
    }
})
複製代碼

vue.config.js增長content.js文件的打包配置,由於content.jsbackground.js一樣能夠只生成js文件)只有js文件,不用像app模式那樣打包生成相應的html文件。這裏咱們還要對字體打包配置處理下,由於默認打包後的文件名是帶有hash值的,在這裏咱們要去除掉,完整內容以下:

const CopyWebpackPlugin = require("copy-webpack-plugin");
const path = require("path");

// Generate pages object
const pagesObj = {};

const chromeName = ["popup", "options"];

chromeName.forEach(name => {
  pagesObj[name] = {
    entry: `src/${name}/index.js`,
    template: "public/index.html",
    filename: `${name}.html`
  };
});

// 生成manifest文件
const manifest =
  process.env.NODE_ENV === "production" ? {
    from: path.resolve("src/manifest.production.json"),
    to: `${path.resolve("dist")}/manifest.json`
  } : {
    from: path.resolve("src/manifest.development.json"),
    to: `${path.resolve("dist")}/manifest.json`
  };

const plugins = [
  CopyWebpackPlugin([
    manifest
  ])
]

module.exports = {
  pages: pagesObj,
  // // 生產環境是否生成 sourceMap 文件
  productionSourceMap: false,

  configureWebpack: {
    entry: {
      'content': './src/content/index.js'
    },
    output: {
      filename: 'js/[name].js'
    },
    plugins: plugins
  },
  css: {
    extract: {
      filename: 'css/[name].css'
      // chunkFilename: 'css/[name].css'
    }
  },
  chainWebpack: config => {
    // 處理字體文件名,去除hash值
    const fontsRule = config.module.rule('fonts')

    // 清除已有的全部 loader。
    // 若是你不這樣作,接下來的 loader 會附加在該規則現有的 loader 以後。
    fontsRule.uses.clear()
    fontsRule.test(/\.(woff2?|eot|ttf|otf)(\?.*)?$/i)
      .use('url')
      .loader('url-loader')
      .options({
        limit: 1000,
        name: 'fonts/[name].[ext]'
      })
  }
};
複製代碼

最後在manifest.development.json加載content.js文件,以及將字體文件添加到網頁可加載資源字段web_accessible_resources裏去:

{
    "manifest_version": 2,
    "name": "vue-extension",
    "description": "a chrome extension with vue-cli3",
    "version": "0.0.1",
    "options_page": "options.html",
    "browser_action": {
        "default_popup": "popup.html"
    },
    "content_security_policy": "script-src 'self' 'unsafe-eval'; object-src 'self'",
    "content_scripts": [{
        "matches": [
            "*://*.baidu.com/*"
        ],
        "css": [
            "css/content.css"
        ]
        "js": [
            "js/content.js"
        ],
        "run_at": "document_end"
    }],
    "web_accessible_resources": ["fonts/*"]
}
複製代碼

而後瀏覽器從新加載插件後打開https://www.baidu.com/網址後可看到:

實時刷新插件

以前寫的時候發現單純地經過vue-cli3更新代碼並不能使插件的background.jscontent.js也跟着更新,由於代碼已經加載到瀏覽器了,瀏覽器並不會監聽這些文件的變化。也是經過評論的朋友推薦,經過crx-hotreload能夠完美實現實時刷新功能,而不用從新手動加載。代碼還簡單易用,在這裏咱們直接將代碼複製到src/utils/hot-reload.js文件:

// 代碼來源:https://github.com/xpl/crx-hotreload/edit/master/hot-reload.js
const filesInDirectory = dir => new Promise(resolve =>
    dir.createReader().readEntries(entries =>
        Promise.all(entries.filter(e => e.name[0] !== '.').map(e =>
            e.isDirectory ?
            filesInDirectory(e) :
            new Promise(resolve => e.file(resolve))
        ))
        .then(files => [].concat(...files))
        .then(resolve)
    )
)

const timestampForFilesInDirectory = dir =>
    filesInDirectory(dir).then(files =>
        files.map(f => f.name + f.lastModifiedDate).join())

const reload = () => {
    window.chrome.tabs.query({
        active: true,
        currentWindow: true
    }, tabs => { // NB: see https://github.com/xpl/crx-hotreload/issues/5
        if (tabs[0]) {
            window.chrome.tabs.reload(tabs[0].id)
        }
        window.chrome.runtime.reload()
    })
}

const watchChanges = (dir, lastTimestamp) => {
    timestampForFilesInDirectory(dir).then(timestamp => {
        if (!lastTimestamp || (lastTimestamp === timestamp)) {
            setTimeout(() => watchChanges(dir, timestamp), 1000) // retry after 1s
        } else {
            reload()
        }
    })
}

window.chrome.management.getSelf(self => {
    if (self.installType === 'development') {
        window.chrome.runtime.getPackageDirectoryEntry(dir => watchChanges(dir))
    }
})
複製代碼

而後在vue.config.js對熱刷新代碼進行處理,若是是開發環境的話就將其複製到assets文件夾裏面:

// vue.config.js
...

// 在這段下面添加
const plugins = [
  CopyWebpackPlugin([
    manifest
  ])
]

// 開發環境將熱加載文件複製到dist文件夾
if (process.env.NODE_ENV !== 'production') {
  plugins.push(
    CopyWebpackPlugin([{
      from: path.resolve("src/utils/hot-reload.js"),
      to: path.resolve("dist")
    }])
  )
}

...
複製代碼

最後只要在開發環境manifest.development.json裏配置一下,將hot-reload.js加載到background運行環境中便可:

"background": { "scripts": ["hot-reload.js"] }
複製代碼

添加打包文件大小預覽配置

既然用了vue-cli3了,怎能不繼續折騰呢,咱們平時用webpack開發確定離不開打包組件預覽功能,才能分析哪些組件佔用文件大,該有的功能一個都不能少😎。這麼實用的功能,實現起來也無非就是添加幾行代碼的事:

// vue.config.js

module.export = {
  /* ... */

  chainWebpack: config => {
    // 查看打包組件大小狀況
    if (process.env.npm_config_report) {
      // 在運行命令中添加 --report參數運行, 如:npm run build --report
      config
        .plugin('webpack-bundle-analyzer')
        .use(require('webpack-bundle-analyzer').BundleAnalyzerPlugin)
    }
  }
}
複製代碼

就辣麼簡單,而後運行npm run build --report看看效果:

自動打包zip

作過Chrome插件的都知道,提交到谷歌插件市場的話須要打包爲zip文件才行。若是每次咱們都須要將編譯文件打包成zip的話就太麻煩了,這種每次都要經歷的重複流程固然是交給程序來處理啦。 想打包zip的話首先要安裝zip-webpack-plugin插件到開發環境:

npm install --save-dev zip-webpack-plugin
複製代碼

而後添加打包代碼到vue.config.js:

// vue.config.js
...

// 開發環境將熱加載文件複製到靜態文件夾(在這段下面添加)
if (process.env.NODE_ENV !== 'production') {
    /*...*/
}

// 生產環境下打包dist爲zip
if (process.env.NODE_ENV === 'production') {
  plugins.push(
    new ZipPlugin({
      path: path.resolve("dist"),
      filename: 'dist.zip',
    })
  )
}

...
複製代碼

搞定收工!

結語

事實證實,vue-cli3很強大,vue相關的插件並非不能應用於開發瀏覽器插件,element-ui也不只限於vue的運用。只有你想不到,沒有作不到的事😁。

tip:若是你懶得從頭開始搭建模板的話也能夠從GitHub拉取vue-extension-template

相關文章
相關標籤/搜索