Open realrecordzLab opened 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?
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):
manifest.json
change "scripts": [ "js/background.js"]
to "service_worker": "background.js", "type": "module"
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."content_security_policy"
to "content_security_policy": {"extension_pages": "default-src 'self'; style-src 'self' 'unsafe-inline'"}
(I needed inline styles)vue.config.js
add devtool: 'cheap-module-source-map'
to configureWebpack
vue-cli-plugin-browser-extension
bundle, in index.js
changejs/[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/)'
webpack-extension-reloader
package and in wer-middleware.raw.ts
remove window?.
from window?.location.reload()
in the two spots its there. 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.
Here's what I did to update to v3 with hot reloading (in addition to what google says in the docs):
- In
manifest.json
change"scripts": [ "js/background.js"]
to"service_worker": "background.js", "type": "module"
- In
babel.config.js
changebrowsers: ['> 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.js
adddevtool: 'cheap-module-source-map'
toconfigureWebpack
- In the
vue-cli-plugin-browser-extension
bundle, inindex.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
, deletemanifest.content_security_policy = manifest.content_security_policy.replace(/'unsafe-eval'/, '')
If you want hot reloading, make an
else
block after theisProduction
if
block and add
manifest.content_security_policy.extension_pages += '; connect-src ws://localhost:9090/)'
- For hotreloading, clone the
webpack-extension-reloader
package and inwer-middleware.raw.ts
removewindow?.
fromwindow?.location.reload()
in the two spots its there.- Build the package and drop the built file in the
lib
folder invue-cli-plugin-browser-extension
and inindex.js
replace theExtensionReloader
import 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.
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
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-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.
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.
@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:
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'/, '')
npx patch-package vue-cli-plugin-browser-extension
patches/vue-cli-plugin-browser-extension+<version_number>.patch
package.json
:
"scripts": {
"postinstall": "patch-package"
...
npm install
your 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';"
}
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.
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'".
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,
}
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);
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.
popup page is not refreshing any suggestion?
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.
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
MV 3 works for me thanks auto reload works
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?
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?