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

Does wxt support manifest.json dynamic variable injection? #443

Open
ddeisadze opened this issue Feb 14, 2024 · 13 comments
Open

Does wxt support manifest.json dynamic variable injection? #443

ddeisadze opened this issue Feb 14, 2024 · 13 comments
Labels
Milestone

Comments

@ddeisadze
Copy link

In my current setup, for certain urls in manifest.json I am replacing them with webpack during buildtime (prod/dev/test). Does wxt support this behavior OR is there anyway to define custom webpack rules?

Thanks!

@ddeisadze
Copy link
Author

I just saw it in the defineConfig interface: https://wxt.dev/api/wxt/interfaces/InlineConfig.html#transformmanifest

@aklinker1
Copy link
Collaborator

WXT uses vite internally, not webpack. You can configure vite here: https://wxt.dev/api/wxt/interfaces/InlineConfig.html#vite

I didn't really understand what you're asking, so that's the best response I can give you. Could you provide an example of what you're trying to replace?

@ddeisadze
Copy link
Author

@aklinker1 this is what i do in webpack: I have a dev manifest (for testing) and a prod manifest. For dev my nextjs server is localhost and for prod a different URL, so I inject a login content content script to detect auth on a login page. see this code fragment:

"content_scripts": [
      {
          "matches": [
              "<all_urls>"
          ],
          "js": [
              "job_description_content.js"
          ],
          "run_at": "document_end"
      },
      {
          "matches": [
              "$FRONTEND_APP_DOMAIN/*/login*",

@aklinker1
Copy link
Collaborator

OK, yes, I would recommend transforming the manifest for this. transformManifest is being deprecated, use hooks.build.manifestGenerated to modify the manifest going forward.

@ddeisadze
Copy link
Author

Yep that works perfect, thanks @aklinker1!

@ddeisadze
Copy link
Author

ddeisadze commented Feb 15, 2024

@aklinker1 can I use environemtn variables loaded using vite config in content script matches?

Content script definition using environment variable:

export default defineContentScript({
	matches: [
		`${import.meta.env.SA_FRONTEND_APP_DOMAIN}/*/login/*`,
		`${import.meta.env.SA_FRONTEND_APP_DOMAIN}/login*`,

		`${import.meta.env.SA_FRONTEND_APP_DOMAIN}/*/signup*`,
		`${import.meta.env.SA_FRONTEND_APP_DOMAIN}/signup*`,
	],

Environment variable definition in defineConfig

export default defineConfig({
	vite: () => ({
		plugins: [react()],
		envDir: 'env',
		envPrefix: 'SA',
	}),

@aklinker1
Copy link
Collaborator

aklinker1 commented Feb 15, 2024

When entrypoints are loaded during the build to extract their matches array, they are not loaded with Vite. They're loaded with jiti. So adding env to Vite won't help.

This issue is kinda related to #336.

For now, I'd recommend an approach like this:

// entrypoints/content.ts
export default defineContentScript({
  matches: ["*://$FRONTEND_APP_DOMAIN/*/login*"],
  
  main(ctx) {
    // ...
  }
})
// wxt.config.ts
export default defineConfig({
  // ...
  hooks: {
    'build:manifestGenerated': (wxt, manifest) => {
      const replacements = {
        "$FRONTEND_APP_DOMAIN": wxt.config.mode === "development" ? "dev.mydomain.com" : "mydomain.com",
      }
      manifest.content_scripts?.forEach((contentScript) => {
        contentScript.matches = replaceMatches(
          contentScript.matches,
          replacements,
        );
      });
    },
  },
});

function replaceMatches(
  matches: string[],
  replacements: Record<string, string>,
) {
  return matches.map((pattern) =>
    Object.entries(replacements).reduce<string>(
      (pattern, [find, replace]) => pattern.replace(find, replace),
      pattern,
    ),
  );
}

@aklinker1 aklinker1 added feature wontfix This will not be worked on labels Feb 15, 2024
@aklinker1 aklinker1 closed this as not planned Won't fix, can't repro, duplicate, stale Feb 15, 2024
@ddeisadze
Copy link
Author

@aklinker1 thanks for that! Just did that, now running into a bug, none of the content scripts are loading. This is the error I see in service worker log:

image

My setup is like this for content script:

export default defineContentScript({
	matches: [
		'$FRONTEND_APP_DOMAIN/*/login*',
		'$FRONTEND_APP_DOMAIN/*/signup*',
		'$FRONTEND_APP_DOMAIN/login*',
		'$FRONTEND_APP_DOMAIN/signup*',
		'http://localhost/login*',
	],

And using your code to replace the variable:

hooks: {
		'build:manifestGenerated': (wxt, manifest) => {
			// Modify the manifest object
			const replacements = {
				$FRONTEND_APP_DOMAIN:
					wxt.config.mode === 'development'
						? 'http://localhost'
						: 'https://app.scoutahead.work',
			};
			manifest.content_scripts?.forEach((contentScript) => {
				contentScript.matches = replaceMatches(
					contentScript.matches,
					replacements
				);

				console.log('contentScript.matches', contentScript.matches);
			});

			manifest.host_permissions = replaceMatches(
				manifest?.host_permissions ?? [],
				replacements
			);
		},
	},

@aklinker1
Copy link
Collaborator

Ah, duh, my bad. You have replaced it in the manifest, but during development it loads them from runtime separately.

So that isn't gonna work, like you're seeing. Let me do a little bit of research and get back to you.

In the meantime... Just comment them out when you want to test against the other lol.

@ddeisadze
Copy link
Author

ddeisadze commented Feb 15, 2024 via email

@aklinker1 aklinker1 removed the wontfix This will not be worked on label Feb 15, 2024
@aklinker1 aklinker1 reopened this Feb 15, 2024
@aklinker1 aklinker1 added this to the v1.1 milestone Mar 12, 2024
@tsukkee
Copy link

tsukkee commented Apr 3, 2024

I also want to import some variables on .env files into manifest.json.
In my use case, I want to change API endpoint called from my extension by mode, and the API endpoints should be specified in permissions and host_permissions field in manifest.json.

For example, I would be happy if I could use a function like Vite's loadEnv() in wxt.config.ts.
https://vitejs.dev/config/#using-environment-variables-in-config

@dirablue
Copy link

dirablue commented Apr 29, 2024

@tsukkee

I was also looking for env sample and found it.
How about this?

import react from '@vitejs/plugin-react'
import { defineConfig } from 'wxt'
import { loadEnv } from 'vite'

export default defineConfig({
  vite: () => ({
    plugins: [react()],
  }),
  manifest: ({ browser, manifestVersion, mode, command }) => {
    const env = loadEnv(mode, process.cwd(), '')
    console.log('env', env)
    return {
      manifest_version: 3,
      permissions: ['storage', 'tabs', 'identity'],
      oauth2: {
        client_id: env.VITE_APP_GOOGLE_CLIENT_ID,
        scopes: ["openid", "email", "profile"]
      },
    }
  }
})

@tsukkee
Copy link

tsukkee commented May 8, 2024

@dirablue Thank you!!
I didn't notice manifest can be function and it has mode as its argument.
Your code also works well for me! It helps me a lot 😄

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

No branches or pull requests

4 participants