adambullmer / vue-cli-plugin-browser-extension

Browser extension development plugin for vue-cli 3.0
GNU Lesser General Public License v3.0
427 stars 76 forks source link

add support for Manifest v3 #107

Open realrecordzLab opened 3 years ago

realrecordzLab commented 3 years ago

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?

e-roy commented 3 years ago

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?

realrecordzLab commented 3 years ago

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.

e-roy commented 3 years ago

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?

realrecordzLab commented 3 years ago

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

e-roy commented 3 years ago

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.

realrecordzLab commented 3 years ago

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

e-roy commented 3 years ago

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 ***

leoplct commented 3 years ago

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

awardx commented 3 years ago

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.

e-roy commented 3 years ago

@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 :)

daviid-kovacs commented 3 years ago

@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.

shuhankuang commented 3 years ago

any update?

alancheatham commented 3 years ago

also interested in this

adamskeeled commented 3 years ago

any update on this?

martindzejky commented 3 years ago

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 commented 3 years ago

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
hizml commented 3 years ago

any update?

rockstox commented 2 years ago

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 }

leodev87 commented 2 years ago

Still need this

alancheatham commented 2 years ago

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.

awardx commented 2 years ago

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:

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

alancheatham commented 2 years ago

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

awardx commented 2 years ago

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.

alancheatham commented 2 years ago

No just in my own project, vue 2.6.10

awardx commented 2 years ago

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

symonxdd commented 2 years ago

@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?

awardx commented 2 years ago

@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

khata-jp commented 2 years ago

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.

achrafbou1 commented 2 years ago

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"
       ...
  6. Commit your patch file to version control
  7. Whenever you run npm install your patch will be applied to the package
SunLightDev112 commented 2 years ago

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';"
}
sherifmayika commented 2 years ago

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

installed and moved the files. backgroup script gives error as below EvalError: Refused to evaluate a string as JavaScript because 'unsafe-eval' is not an allowed source of script in the following Content Security Policy directive: "script-src 'self' 'wasm-unsafe-eval'".

sherifmayika commented 2 years ago

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

installed and moved the files. backgroup script gives error as below EvalError: Refused to evaluate a string as JavaScript because 'unsafe-eval' is not an allowed source of script in the following Content Security Policy directive: "script-src 'self' 'wasm-unsafe-eval'". SOLVED by adding this to webpack.config.js:

module.exports.node = {
  global: false,
}
sherifmayika commented 2 years ago

I had to run npm update to update the node modules see this >> https://v2.vuejs.org/v2/guide/installation.html#CSP-environments which avoided below error

// In sloppy mode, unbound `this` refers to the global object, fallback to
// Function constructor if we're in global strict mode. That is sadly a form
// of indirect eval which violates Content Security Policy.
function () {
  return this;
}() || window);
sherifmayika commented 2 years ago

3 step solution would be 1 ) run npm update to update the node modules 2) add "vue-mv3-hot-reload": "github:awardx/vue-extension-mv3-hot-reload", package.json run npm install to install hot reloader and copy file as on https://github.com/awardx/vue-extension-mv3-hot-reload 3) vue.config.js like this:

module.exports = { // ...

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

};

you are done.

sherifmayika commented 2 years ago

popup page is not refreshing any suggestion?

himanshush200599 commented 2 years ago

Hey how i can add support for regex in CSP connect-src , because i want my extension to connect with all the domains of this type --> https://*.example.com , Because of this getting Error like - Refused to connect to <<api-endpoint>> because it violates the following Content Security Policy directive: "default-src 'self'". Note that 'connect-src' was not explicitly set, so 'default-src' is used as a fallback.

himanshush200599 commented 2 years ago

Hey @awardx can you please help with my above comment , i used your config files from your repo. Will be grateful for your time. Thanks

sherifmayika commented 1 year ago

MV 3 works for me thanks auto reload works

esteban-aloware commented 1 month ago

Hey how i can add support for regex in CSP connect-src , because i want my extension to connect with all the domains of this type --> https://*.example.com , Because of this getting Error like - Refused to connect to <<api-endpoint>> because it violates the following Content Security Policy directive: "default-src 'self'". Note that 'connect-src' was not explicitly set, so 'default-src' is used as a fallback.

did you solve this some way?