Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

transformer-webextension: Cannot add Vue generated .css file to web_accessible_resources #7835

Closed
ArthurMelin opened this issue Mar 16, 2022 · 8 comments · Fixed by #7050
Closed

Comments

@ArthurMelin
Copy link

🐛 Bug report

I'm trying to inject a Vue app into a web page from a web extension content script, but I can't load the Vue generated CSS file from its Asset URL into the page because Parcel doesn't let me put the generated file's name into the web_accessible_resources property of the manifest.

🎛 Configuration (.babelrc, package.json, cli command)

.babelrc

{
    "extends": "@parcel/config-webextension"
}

🤔 Expected Behavior

Parcel should keep the content.css entry in web_accessible_resources.

😯 Current Behavior

content.css is removed from web_accessible_resources in the manifest during the build.

💁 Possible Solution

I don't really understand what the transformer does but I guess this TODO might have something to do with the fact the generated file is not found:

// TODO: this doesn't support Parcel resolution

🔦 Context

I'm building a web extension that injects stuff into web pages using its content script.

One of the thing I want to inject is a Vue app, I managed to make the Vue app mount to the injected DOM element but one thing is missing: the components style.

I tracked down that a content.css file is generated by Vue but since I'm using a content script, Parcel understandably doesn't know how to inject it anywhere (normally it would inject it as a <link rel="stylesheet"> element in the generated HTML file).

My solution was to try injecting the CSS file into the page myself using its Asset URL however when I try to add content.css to the
web_accessible_resources in the manifest, it gets removed by Parcel.

I also tried to add a placeholder content.css file in my source files but then Parcel complains about the non-unique bundle name.

💻 Code Sample

manifest.json

{
    "manifest_version": 2,
    "name": "Example",
    "description": "Example extension",
    "version": "0.0.1",
    "content_scripts": [
        {
            "matches": ["*://*/*"],
            "js": ["content.js"]
        }
    ],
    "web_accessible_resources": ["content.css"]
}

content.js

import browser from "webextension-polyfill";
import { createApp } from "vue";

import App from "./App.vue";

function injectStyle(url) {
    const linkElem = document.createElement("link");
    linkElem.rel = "stylesheet";
    linkElem.href = url;
    document.head.appendChild(linkElem);
}

function injectVue() {
    const appElem = document.createElement("div");
    appElem.id = "app";
    document.body.appendChild(appElem);

    createApp(App).mount("#app");
}

injectStyle(browser.runtime.getURL("content.css"));
injectVue();

App.vue

<template>
    <p>Hello! :)</p>
</template>

<style scoped>
p {
    color: red;
}
</style>

🌍 Your Environment

Software Version(s)
Parcel 2.3.2
Node v14.19.0
npm/Yarn yarn v1.22.17
Operating System Linux
@ArthurMelin
Copy link
Author

ArthurMelin commented Mar 16, 2022

For anyone else reading this issue having a similar problem, here is the hacky temporary solution I came up with:

I made this patch:

diff --git a/node_modules/@parcel/transformer-webextension/lib/WebExtensionTransformer.js b/node_modules/@parcel/transformer-webextension/lib/WebExtensionTransformer.js
index 53cf1e0..1b015ad 100644
--- a/node_modules/@parcel/transformer-webextension/lib/WebExtensionTransformer.js
+++ b/node_modules/@parcel/transformer-webextension/lib/WebExtensionTransformer.js
@@ -195,6 +195,10 @@ async function collectDependencies(asset, program, ptrs, hot) {
     let war = [];
 
     for (let i = 0; i < program.web_accessible_resources.length; ++i) {
+      if (program.web_accessible_resources[i].startsWith('<generated>')) {
+        war.push(program.web_accessible_resources[i].substring(11));
+        continue;
+      }
       // TODO: this doesn't support Parcel resolution
       const globFiles = (await (0, _utils().glob)(_path().default.join(_path().default.dirname(filePath), program.web_accessible_resources[i]), fs, {})).map(fp => asset.addURLDependency(_path().default.relative(_path().default.dirname(filePath), fp), {
         needsStableName: true,

and I prefix the path of my resource with <generated> in the manifest.

@fregante
Copy link
Contributor

fregante commented Mar 21, 2022

I think that since this is a file that Parcel generated from an entry point (content.js), it should automatically added next to the content.js injection.

This is "easy" if the entry point is just the manifest:

// Parcel should apply:
{

    "content_scripts": [
        {,
+			"css": ["content.css"],
            "js": ["content.js"],
            "matches": ["*://*/*"]
        }
    ]
}

but less easy if the injection is made via chrome.tabs.executeScript (which isn't supported). In that case currently the user can just add an extra chrome.tabs.insertCSS call.

The non-completely-correct-but-easiest alternative would be to:

  1. keep the CSS in the JS file
  2. have the JS file inline the CSS normally via document.head.append(<style etc/>)

… however it doesn't seem to be natively supported, we'd need the equivalent of Webpack’s "style-loader":

@fregante
Copy link
Contributor

fregante commented Mar 21, 2022

Possible solutions for users

Untested

  • Ignore "content.css" so that Parcel doesn't attempt to resolve it Ignore certain link targets in HTML href #1186
  • move content.js to some-other-folder/content.js and then add "some-other-folder/*" to web_accessible_resources; Parcel should preserve the * option without throwing.

@101arrowz
Copy link
Member

101arrowz commented Mar 24, 2022

This will now be fixed by #7050. In fact you shouldn't even need to reference the CSS in content_scripts, Parcel will add it for you automagically :)

@fregante
Copy link
Contributor

fregante commented Mar 24, 2022

Good to hear that fixes it for scripts loaded via manifest.json but, as mentioned, anything injected via executeScript would have to be followed by a new insertCSS

  chrome.tabs.executeScript('content.js');
+ chrome.tabs.insertCSS('content.css');

that's unrelated to web_accessible_resources however

@101arrowz
Copy link
Member

101arrowz commented Mar 24, 2022

anything injected via executeScript would have to be followed by a new insertCSS

A bit off topic, but since it's a generated file, it should be possible but will probably not be easy. Importing style:./myfile.vue will import the style from the Vue file, but since you want the CSS as a URL, you need url:./something.css, and you can't combine two pipelines. Maybe if the Vue transformer were refactored to use query parameters to access style vs. scripts vs. etc. (it was originally created before query parameters were added to Parcel), you could do import cssLink from 'url:./App.vue?style';

@ArthurMelin
Copy link
Author

ArthurMelin commented Mar 24, 2022

Great! Small precision regarding my own solution: I inject the CSS file into the page from the content script by manually adding a <link> tag using its asset URL. Would that work the same way?

@fregante
Copy link
Contributor

Extensions should inject CSS via the manifest or via the insertCSS() function. Adding a link tag is not ideal because it requires the file to appear in web_accessible_resources

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants