vue-cli-plugin-browser-extension icon indicating copy to clipboard operation
vue-cli-plugin-browser-extension copied to clipboard

add support for Manifest v3

Open realrecordzLab opened this issue 4 years ago • 39 comments

Manifest v3 is coming and as writed on the chrome extension developers documentations it will be soon mandatory to use it. Will this cli plugin support manifest v3 soon?

realrecordzLab avatar Dec 15 '20 17:12 realrecordzLab

I'm working through migrating an extension to Manifest 3 https://developer.chrome.com/docs/extensions/mv3/intro/mv3-migration/

It's semi straight forward. v3 changes the background pages to service workers. The problem I'm finding is there is a known issue with service workers only working in the root directory https://groups.google.com/a/chromium.org/g/chromium-extensions/c/eOosUOIh7cE/m/lP3DgUeEAwAJ

*some examples of extensions using v3 https://groups.google.com/a/chromium.org/g/chromium-extensions/c/16yaQeg07t4

It doesn't look like this will be fixed soon. So I'm stuck trying to figure out how to move the background.js file to the root directory on build. What can I do to the vue.config.js file to change the output? I'm looking through all the cli.vuejs.org docs and it's not clear to me how to do it. Any suggestions anyone? or @adambullmer?

e-roy avatar Jan 27 '21 08:01 e-roy

I'm working through migrating an extension to Manifest 3 https://developer.chrome.com/docs/extensions/mv3/intro/mv3-migration/

It's semi straight forward. v3 changes the background pages to service workers. The problem I'm finding is there is a known issue with service workers only working in the root directory https://groups.google.com/a/chromium.org/g/chromium-extensions/c/eOosUOIh7cE/m/lP3DgUeEAwAJ

*some examples of extensions using v3 https://groups.google.com/a/chromium.org/g/chromium-extensions/c/16yaQeg07t4

It doesn't look like this will be fixed soon. So I'm stuck trying to figure out how to move the background.js file to the root directory on build. What can I do to the vue.config.js file to change the output? I'm looking through all the cli.vuejs.org docs and it's not clear to me how to do it. Any suggestions anyone? or @adambullmer?

As I know the issue about background.js will be not fixed. I'm looking at the plugin code and this line seems to be responsable to generate the background file. I think the best solution is to edit the plugin code to reflect the manifest v3 changes, this until the author will release an update that is compilant with v3.

realrecordzLab avatar Jan 27 '21 11:01 realrecordzLab

I agree, I will post the code to change the vue.config.js file if I figure it out. But, I'm also having trouble writing the correct code to put the background.js file into the root folder on build. Anyone know how to do this?

e-roy avatar Jan 27 '21 22:01 e-roy

I agree, I will post the code to change the vue.config.js file if I figure it out. But, I'm also having trouble writing the correct code to put the background.js file into the root folder on build. Anyone know how to do this?

I'm not sure that the change to have the background file in the project root can be done from vue.config.js file but let me know if there is any news about. In the next days I will create a fork of this project to try implementing manifest v3

realrecordzLab avatar Jan 29 '21 13:01 realrecordzLab

Sorry, I misunderstood your first message. I was able to get all of the js files to the root folder on build by adding this to vue.config.js

  configureWebpack: {
    output: {
      filename: "[name].js",
      chunkFilename: "[name].js",
    },
  },

But I'm still getting 'Service worker registration failed' error. I'm getting closer to convincing myself to create a fork also and try from that direction also.

e-roy avatar Jan 29 '21 13:01 e-roy

Sorry, I misunderstood your first message. I was able to get all of the js files to the root folder on build by adding this to vue.config.js

  configureWebpack: {
    output: {
      filename: "[name].js",
      chunkFilename: "[name].js",
    },
  },

But I'm still getting 'Service worker registration failed' error. I'm getting closer to convincing myself to create a fork also and try from that direction also.

how is the code inside your background.js file? NB: You don't really need to register a service worker inside the background js file, they have changed only the name in the manifest

realrecordzLab avatar Jan 29 '21 14:01 realrecordzLab

Did configureWebpack help you on your situation?

I'm using my background.js to open the extension. I'm getting closer, right now I'm battling 2 issues. Getting the extension to activate when running npm run serve Service worker registration failed (not sure where to look for this yet)

and writing the manifest on npm run build manifest.content_security_policy.replace is not a function (I think I can adjust it through something like adding devtools, I think it's from the MV3 changer here)

******* Edit : Fix Below **********

To run the service worker during hot reloading and fix manifest on build, change line 37 to

\node_modules\vue-cli-plugin-browser-extension\lib\manifest.js

37 manifest.content_security_policy.extension_pages = manifest.content_security_policy.extension_pages.replace(/'unsafe-eval'/, '')

and then add this script to your package.json file

"prod": "vue-cli-service build --mode production --watch",

then you can run

npm run prod

****** Note: This does slow down hot-reload, a lot. Not recommended environment for development, will need to refresh the extension after saving *******

e-roy avatar Jan 29 '21 18:01 e-roy

Any news on this? How can I manually use a manifest v3 without adding "content_security_policy"automatically at the end?

leoplct avatar Mar 22 '21 15:03 leoplct

Did configureWebpack help you on your situation?

I'm using my background.js to open the extension. I'm getting closer, right now I'm battling 2 issues. Getting the extension to activate when running npm run serve Service worker registration failed (not sure where to look for this yet)

and writing the manifest on npm run build manifest.content_security_policy.replace is not a function (I think I can adjust it through something like adding devtools, I think it's from the MV3 changer here)

******* Edit : Fix Below **********

To run the service worker during hot reloading and fix manifest on build, change line 37 to

\node_modules\vue-cli-plugin-browser-extension\lib\manifest.js

37 manifest.content_security_policy.extension_pages = manifest.content_security_policy.extension_pages.replace(/'unsafe-eval'/, '')

and then add this script to your package.json file

"prod": "vue-cli-service build --mode production --watch",

then you can run

npm run prod

****** Note: This does slow down hot-reload, a lot. Not recommended environment for development, will need to refresh the extension after saving *******

I was getting an error Cannot read property 'replace' of undefined This only worked for me when I changed line 30 to the following manifest.content_security_policy || { "extension_pages": "script-src 'self' 'unsafe-eval'; object-src 'self'" }

@e-roy many thanks for your input, really helpful. Any ideas why this is not auto refreshing extension after saving? Have you tried tweaking the https://github.com/rubenspgcavalcante/webpack-extension-reloader plugin? I'm thinking to explore that direction, only wanted to know how far did you get with that (if any) and continue from where you left off.

awardx avatar Apr 04 '21 11:04 awardx

@awardx I only made it as far as creating "band-aids" inside my project to be able to get MV3 working. Running in --watch and production mode forced to rebuild the extension code every time a change was made, which meant refreshing the extension in your browser. At the time I decided after I got it working with MV3, I would copy the manifest code to a txt file to use for when I build for production and continue developing with MV2. I hadn't tried tweaking the webpack-extension-reloader.

The added layer of service workers to MV3 adds a different level of complexity. Best of luck to figuring it out :)

e-roy avatar Apr 04 '21 12:04 e-roy

@awardx I managed to fix the Service worker registration failed issue...

It seems like the background.js must be in the root folder with the original content in order to work.

After I moved my script to the root (thanks @e-roy ) I was getting the same error message so I tried to install a demo Extension provided by Google to see what is going on and when I compared the background scripts I noticed the generated version contains a lots of markups so I tried to remove everything and just paste my background.js code and it started to work.

So apparently the Service Worker is not able to register because of the generated background.js.

I tried to find a way to build the background.js without the additional bits but I could not.

So as a quick fix I moved the background.js to the public folder so after the build the file goes to the root folder with the original content.

I had to change the browser.runtime bits to chrome.runtime though... I think because I don't have the browser polyfill included this way.

daviid-kovacs avatar Jun 30 '21 20:06 daviid-kovacs

any update?

shuhankuang avatar Jul 12 '21 05:07 shuhankuang

also interested in this

alancheatham avatar Jul 16 '21 21:07 alancheatham

any update on this?

adamskeeled avatar Aug 10 '21 14:08 adamskeeled

I just managed to upgrade my small extension from manifest v2 to v3. Apart from things mentioned in the migration guide, I had to do these things specifically when using the vue-cli-plugin-browser-extension plugin:

I had to explicitely include the CSP config in my manifest.json:

"content_security_policy": {
    "extension_pages": "default-src 'self'; style-src 'self' 'unsafe-inline'"
}

This is required because if you don't speficy it in your manifest.json explicitely, vue-cli-plugin-browser-extension sets it to an invalid value (for manifest v3) – this can be seen here. Note that I had to allow 'unsafe-inline' for style-src because Vue in development mode inserts all CSS styles using inline <style> tags.

Then, I had to set Webpack's devtool mode to 'source-map' in my vue.config.js like this:

module.exports = {
    // ...

    configureWebpack: {
        devtool: 'source-map',
    },
};

This is required because by default Vue CLI instructs Webpack to use devtool: 'eval' in development mode, and Webpack uses a lot of eval() statements in your compiled code. This violates the configured CSP, eval is not permitted in browser extensions using manifest v3 (you cannot include 'unsafe-eval' in the manifest file).

Hope that helps. 🙂


EDIT: see the following comment for one more issue and a proposed fix.

martindzejky avatar Aug 13 '21 09:08 martindzejky

And just after finishing the last comment, I checked our CI pipelines and found an error: manifest.content_security_policy.replace is not a function! 😭 This is probably caused by this piece of code in the plugin. It appears that the author of the plugin is not responding to issues, so I guess a patch or a fork is necessary for fixing this, unfortunately.


EDIT: 🎉 I fixed this in my own project by using patch-package and the following patch:

diff --git a/node_modules/vue-cli-plugin-browser-extension/lib/manifest.js b/node_modules/vue-cli-plugin-browser-extension/lib/manifest.js
index c62792c..bb4df13 100644
--- a/node_modules/vue-cli-plugin-browser-extension/lib/manifest.js
+++ b/node_modules/vue-cli-plugin-browser-extension/lib/manifest.js
@@ -34,7 +34,6 @@ module.exports = (api, pluginOptions, packageJson) => async (content) => {
   // If building for production (going to web store) abort early.
   // The browser extension store will hash your signing key and apply CSP policies.
   if (isProduction) {
-    manifest.content_security_policy = manifest.content_security_policy.replace(/'unsafe-eval'/, '')
 
     // validate minimum options

martindzejky avatar Aug 13 '21 09:08 martindzejky

any update?

hizml avatar Aug 23 '21 09:08 hizml

As far as I understand it, Chrome either currently ( > 90 ) or very soon will support having the service worker in a sub folder if you add module: true.

So something like this : "background":{ "service_worker": "js/background.js", "module": true }

rockstox avatar Dec 09 '21 18:12 rockstox

Still need this

leodev87 avatar Jan 11 '22 22:01 leodev87

Here's what I did to update to v3 with hot reloading (in addition to what google says in the docs):

  1. In manifest.json change "scripts": [ "js/background.js"] to "service_worker": "background.js", "type": "module"
  2. In babel.config.js change browsers: ['> 0.25%', 'not ie 11', 'not op_mini all'] to chrome: '58'. Forget why I did this, think it was a build error. If you need other browsers you should be able to find the versions that don't break it.
  3. Add/change "content_security_policy" to "content_security_policy": {"extension_pages": "default-src 'self'; style-src 'self' 'unsafe-inline'"} (I needed inline styles)
  4. In vue.config.js add devtool: 'cheap-module-source-map' to configureWebpack
  5. In the vue-cli-plugin-browser-extension bundle, in index.js change

js/[name]${isLegacyBundle ? `-legacy` : ``}${isProduction && options.filenameHashing && !userScripts.includes(file.chunk.name) ? '.[contenthash:8]' : ''}.js

to

${file.chunk.name === 'background' ? '' : 'js/'}[name]${isLegacyBundle ? `-legacy` : ``}${isProduction && options.filenameHashing && !userScripts.includes(file.chunk.name) ? '.[contenthash:8]' : ''}.js

in lib/manifest.js, delete manifest.content_security_policy = manifest.content_security_policy.replace(/'unsafe-eval'/, '')

If you want hot reloading, make an else block after the isProduction if block and add

manifest.content_security_policy.extension_pages += '; connect-src ws://localhost:9090/)'

  1. For hotreloading, clone the webpack-extension-reloader package and in wer-middleware.raw.ts remove window?. from window?.location.reload() in the two spots its there.
  2. Build the package and drop the built file in the lib folder in vue-cli-plugin-browser-extension and in index.js replace the ExtensionReloader import at the top with const ExtensionReloader = require('./lib/webpack-extension-reloader')

I used patch-package to make the bundle changes. Think that should be it. Pretty hacky but seems like it works. The exact code I mentioned above my not be exactly right since I modified some for the post and I made the changes a few months ago but hopefully it steers you in the right direction.

alancheatham avatar Jan 12 '22 20:01 alancheatham

Here's what I did to update to v3 with hot reloading (in addition to what google says in the docs):

  1. In manifest.json change "scripts": [ "js/background.js"] to "service_worker": "background.js", "type": "module"
  2. In babel.config.js change browsers: ['> 0.25%', 'not ie 11', 'not op_mini all'] to chrome: '58'. Forget why I did this, think it was a build error. If you need other browsers you should be able to find the versions that don't break it.
  3. Add/change "content_security_policy" to "content_security_policy": {"extension_pages": "default-src 'self'; style-src 'self' 'unsafe-inline'"} (I needed inline styles)
  4. In vue.config.js add devtool: 'cheap-module-source-map' to configureWebpack
  5. In the vue-cli-plugin-browser-extension bundle, in index.js change

js/[name]${isLegacyBundle ? `-legacy` :}${isProduction && options.filenameHashing && !userScripts.includes(file.chunk.name) ? '.[contenthash:8]' : ''}.js ``

to

${file.chunk.name === 'background' ? '' : 'js/'}[name]${isLegacyBundle ? `-legacy` :}${isProduction && options.filenameHashing && !userScripts.includes(file.chunk.name) ? '.[contenthash:8]' : ''}.js ``

in lib/manifest.js, delete manifest.content_security_policy = manifest.content_security_policy.replace(/'unsafe-eval'/, '')

If you want hot reloading, make an else block after the isProduction if block and add

manifest.content_security_policy.extension_pages += '; connect-src ws://localhost:9090/)'

  1. For hotreloading, clone the webpack-extension-reloader package and in wer-middleware.raw.ts remove window?. from window?.location.reload() in the two spots its there.
  2. Build the package and drop the built file in the lib folder in vue-cli-plugin-browser-extension and in index.js replace the ExtensionReloader import at the top with const ExtensionReloader = require('./lib/webpack-extension-reloader')

I used patch-package to make the bundle changes. Think that should be it. Pretty hacky but seems like it works. The exact code I mentioned above my not -be exactly right since I modified some for the post and I made the changes a few months ago but hopefully it steers you in the right direction.

Hi @alancheatham, thanks for sharing this.

Followed each step but still get the same error:

  • Service worker registration failed
  • Uncaught ReferenceError: window is not defined

I might be missing something with the final step involving patch-package. I've used it on vue-cli-plugin-browser-extension plugin and it generated the patch folder in the root. Is there anything else you did with the patch-package?

BTW: I tried to replicate your steps in Kocal/vue-web-extension package files. Was it the same for you?


EDIT: step 6 was inaccurate, hence the window is not defined error, however, this was a good clue to find the solution. I found the solution here: https://github.com/khlevon/webpack-extension-reloader/blob/38d38ff25b2a4f98208bcfe1a9fa33ed8c580330/src/middleware/wer-middleware.raw.ts

awardx avatar Jan 13 '22 10:01 awardx

Hi @awardx, patch-package is used just so when someone downloads your project and installs dependencies, your package changes will be applied to theirs as well. It shouldn't change anything in the functionality of your project.

Make sure you're not referencing window in your background / service worker page, and make sure the built background.js doesn't either. Try replacing everything in the built background.js file with a console log and see if you can load the extension. Not sure how much more help I can be as these are the steps that I took.

I haven't tried it on the Kocal/vue-web-extension repo

alancheatham avatar Jan 13 '22 18:01 alancheatham

Hi @awardx, patch-package is used just so when someone downloads your project and installs dependencies, your package changes will be applied to theirs as well. It shouldn't change anything in the functionality of your project.

Make sure you're not referencing window in your background / service worker page, and make sure the built background.js doesn't either. Try replacing everything in the built background.js file with a console log and see if you can load the extension. Not sure how much more help I can be as these are the steps that I took.

I haven't tried it on the Kocal/vue-web-extension repo

Hi @alancheatham

Did you use any package at all to make your changes as described above? Or did you use your own Vue project? If so, which Vue version did you use?

I intend to replicate your process from the ground up to make it work as it did for you.

awardx avatar Jan 13 '22 19:01 awardx

No just in my own project, vue 2.6.10

alancheatham avatar Jan 13 '22 19:01 alancheatham

Finally got it working thanks to Alan and Martin's comments. Although all steps were provided by Alan, some steps were redundant and some required further studies and searching on the web.

To make someone's life a bit easier, I've created a fresh and ready-to-run repo project with a manifest v3 web extension and service worker hot reloading enabled.

https://github.com/awardx/vue-extension-mv3-hot-reload

awardx avatar Jan 14 '22 23:01 awardx

@awardx 's solution is the first one I've found on the internet, impressive. Many thanks! Though... I don't want to be skeptical, but there's these 3 config files you need to replace inside the node_modules folder of the official extension of which there's 2 to be overwritten, and 1 to be added: webpack-extension-reloader.js.

The first 2 are easy to compare with a text diff tool. What about the latter?

There's 5888 lines of compiled Webpack code in there, is there any way to know it's all safe and good?

symonxdd avatar Feb 07 '22 23:02 symonxdd

@awardx 's solution is the first one I've found on the internet, impressive. Many thanks! Though... I don't want to be skeptical, but there's these 3 config files you need to replace inside the node_modules folder of the official extension of which there's 2 to be overwritten, and 1 to be added: webpack-extension-reloader.js.

The first 2 are easy to compare with a text diff tool. What about the latter?

There's 5888 lines of compiled Webpack code in there, is there any way to know it's all safe and good?

@symonxdd you can read Alan's comments to see where this file comes from and how it's been compiled. You can recreate then compare that file with a diff tool too.

Check webpack-extension-reloader. Hope that helps

awardx avatar Feb 11 '22 18:02 awardx

I had been trouble with same problem. After trying a lot, I came up with the idea that just installing a additional plugin for manifest.json v3 would be fine.

cd project-repo
npm uninstall vue-cli-plugin-chrome-extension-cli # Maybe you don't have to do this
vue add chrome-extension-cli
# Answer several questions. In these, you can select manifest version 3 

In my case, above procedure alone almost solved the problem.

khata-jp avatar Feb 20 '22 03:02 khata-jp

Adding up to @martindzejky's solution and following patch-package's documentation , you would probably need to keep your custom CSP, especially if you are using the extension to send requests and download resources from CDNs, I fixed it with the following steps:

  1. Install patch-package
  2. In ./node_modules/vue-cli-plugin-browser-extension/lib/manifest.js change the following lines (as of version 0.25.2): Line 28: From: manifest.content_security_policy = manifest.content_security_policy || "script-src 'self' 'unsafe-eval'; object-src 'self'" To: manifest.content_security_policy = {} manifest.content_security_policy.extension_pages = manifest.content_security_policy?.extension_pages || "script-src 'self'; object-src 'self'" Line 36: From: manifest.content_security_policy = manifest.content_security_policy.replace(/'unsafe-eval'/, '') To: manifest.content_security_policy.extension_pages = manifest.content_security_policy?.extension_pages.replace(/'unsafe-eval'/, '')
  3. Run npx patch-package vue-cli-plugin-browser-extension
  4. A patch file will be created under patches/vue-cli-plugin-browser-extension+<version_number>.patch
  5. Add the following line under the "scripts" section in package.json:
   "scripts": {
       "postinstall": "patch-package"
       ...
  1. Commit your patch file to version control
  2. Whenever you run npm install your patch will be applied to the package

achrafbou1 avatar Mar 10 '22 16:03 achrafbou1

Hello, How are you? I'm trying to migrate the version of extension from 2 to 3 by using your solution. For now, I want to get the result of build with version 3 so that I can upload it to the store. This is main reason why I'm migrating the extension. When I tried above solution, there was a memory error. When I start build, it was run out of memory so I couldn't do anything.

It would be greatly appreciated if you give more detailed solutions to be matched with my project? Looking forward to hearing from you.

This is origin manifest file. If you need more detail, I will provide.

{
  "manifest_version": 2,
  "version": "0.9.9",
  "name": "AAAAAA",
  "description": "BBBBBB",
  "homepage_url": "https://AAA.co",
  "permissions": [
    "notifications",
    "storage",
    "activeTab",
    "unlimitedStorage"
  ],
  "icons": {
    "16": "icons/icon.png",
    "48": "icons/icon.png",
    "128": "icons/icon.png",
    "256": "icons/icon.png",
    "512": "icons/icon.png",
    "1024": "icons/icon.png"
  },
  "background": {
    "scripts": [
      "js/background.js"
    ],
    "persistent": true
  },
  "content_scripts": [
    {
      "matches": [
        "file://*/*",
        "http://*/*",
        "https://*/*"
      ],
      "js": [
        "js/content-script.js"
      ],
      "run_at": "document_start",
      "all_frames": false
    }
  ],
  "browser_action": {
    "default_popup": "popup.html",
    "default_icon": {
      "16": "icons/icon.png",
      "48": "icons/icon.png",
      "128": "icons/icon.png",
      "256": "icons/icon.png",
      "512": "icons/icon.png",
      "1024": "icons/icon.png"
    }
  },
  "content_security_policy": "script-src 'self' 'unsafe-eval' https://cdn.segment.com 'sha256-ZgDy59Dh4jH9g/vcPYFpoQ1wumB4IdPEOS1BJc08i+Y='; object-src 'self';"
}

SunLightDev112 avatar Jun 16 '22 20:06 SunLightDev112