add support for Manifest v3
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?
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?
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.
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 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
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.
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
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 *******
Any news on this? How can I manually use a manifest v3 without adding "content_security_policy"automatically at the end?
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 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 :)
@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.
any update?
also interested in this
any update on this?
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.
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
any update?
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 }
Still need this
Here's what I did to update to v3 with hot reloading (in addition to what google says in the docs):
- In
manifest.jsonchange"scripts": [ "js/background.js"]to"service_worker": "background.js", "type": "module" - In
babel.config.jschangebrowsers: ['> 0.25%', 'not ie 11', 'not op_mini all']tochrome: '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. - Add/change
"content_security_policy"to"content_security_policy": {"extension_pages": "default-src 'self'; style-src 'self' 'unsafe-inline'"}(I needed inline styles) - In
vue.config.jsadddevtool: 'cheap-module-source-map'toconfigureWebpack - In the
vue-cli-plugin-browser-extensionbundle, inindex.jschange
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/)'
- For hotreloading, clone the
webpack-extension-reloaderpackage and inwer-middleware.raw.tsremovewindow?.fromwindow?.location.reload()in the two spots its there. - Build the package and drop the built file in the
libfolder invue-cli-plugin-browser-extensionand inindex.jsreplace theExtensionReloaderimport at the top withconst 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.
Here's what I did to update to v3 with hot reloading (in addition to what google says in the docs):
- In
manifest.jsonchange"scripts": [ "js/background.js"]to"service_worker": "background.js", "type": "module"- In
babel.config.jschangebrowsers: ['> 0.25%', 'not ie 11', 'not op_mini all']tochrome: '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.- Add/change
"content_security_policy"to"content_security_policy": {"extension_pages": "default-src 'self'; style-src 'self' 'unsafe-inline'"}(I needed inline styles)- In
vue.config.jsadddevtool: 'cheap-module-source-map'toconfigureWebpack- In the
vue-cli-plugin-browser-extensionbundle, inindex.jschange
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, deletemanifest.content_security_policy = manifest.content_security_policy.replace(/'unsafe-eval'/, '')If you want hot reloading, make an
elseblock after theisProductionifblock and add
manifest.content_security_policy.extension_pages += '; connect-src ws://localhost:9090/)'
- For hotreloading, clone the
webpack-extension-reloaderpackage and inwer-middleware.raw.tsremovewindow?.fromwindow?.location.reload()in the two spots its there.- Build the package and drop the built file in the
libfolder invue-cli-plugin-browser-extensionand inindex.jsreplace theExtensionReloaderimport at the top withconst ExtensionReloader = require('./lib/webpack-extension-reloader')I used
patch-packageto 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
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 @awardx,
patch-packageis 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
windowin 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.
No just in my own project, vue 2.6.10
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 '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 '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
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.
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:
- Install patch-package
- 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'/, '') - Run
npx patch-package vue-cli-plugin-browser-extension - A patch file will be created under
patches/vue-cli-plugin-browser-extension+<version_number>.patch - Add the following line under the "scripts" section in
package.json:
"scripts": {
"postinstall": "patch-package"
...
- Commit your patch file to version control
- Whenever you run
npm installyour patch will be applied to the package
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';"
}