Skip to content
Open
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
import { mkdtemp, mkdir, rm, writeFile } from 'node:fs/promises';
import { tmpdir } from 'node:os';
import { join } from 'node:path';
import { afterEach, describe, expect, it } from 'vitest';
import { resolveVirtualModules } from '../resolveVirtualModules';
import { fakeResolvedConfig } from '../../../../utils/testing/fake-objects';

const tempDirs: string[] = [];

afterEach(async () => {
await Promise.all(
tempDirs.splice(0).map((dir) => rm(dir, { recursive: true, force: true })),
);
});

describe('resolveVirtualModules', () => {
it.each([
`import definition from 'virtual:user-background-entrypoint';`,
`import definition from "virtual:user-background-entrypoint";`,
])(
'should escape input paths with apostrophes when encountering: %s',
async (template) => {
const wxtModuleDir = await mkdtemp(join(tmpdir(), 'wxt-test-'));
tempDirs.push(wxtModuleDir);

const filePath = join(
wxtModuleDir,
'dist/virtual/background-entrypoint.mjs',
);
await mkdir(join(wxtModuleDir, 'dist/virtual'), { recursive: true });
await writeFile(filePath, template);

const plugin = resolveVirtualModules(
fakeResolvedConfig({ wxtModuleDir }),
).find(
(plugin) => plugin.name === 'wxt:resolve-virtual-background-entrypoint',
);

expect(plugin).toBeDefined();

const inputPath = `/tmp/foo'bar/background.ts`;
const code = await plugin!.load!.handler!(
'\0virtual:wxt-background-entrypoint?' + inputPath,
);

expect(code).toBe(
`import definition from "file:///tmp/foo'bar/background.ts";`,
);
},
);

it.each([
`import definition from 'virtual:user-background-entrypoint';`,
`import definition from "virtual:user-background-entrypoint";`,
])(
'should escape input paths with double quotes when encountering: %s',
async (template) => {
const wxtModuleDir = await mkdtemp(join(tmpdir(), 'wxt-test-'));
tempDirs.push(wxtModuleDir);

const filePath = join(
wxtModuleDir,
'dist/virtual/background-entrypoint.mjs',
);
await mkdir(join(wxtModuleDir, 'dist/virtual'), { recursive: true });
await writeFile(filePath, template);

const plugin = resolveVirtualModules(
fakeResolvedConfig({ wxtModuleDir }),
).find(
(plugin) => plugin.name === 'wxt:resolve-virtual-background-entrypoint',
);

expect(plugin).toBeDefined();

const inputPath = `/tmp/foo"bar/background.ts`;
const code = await plugin!.load!.handler!(
'\0virtual:wxt-background-entrypoint?' + inputPath,
);

expect(code).toBe(
`import definition from "file:///tmp/foo%22bar/background.ts";`,
);
},
);
});
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { readFile } from 'node:fs/promises';
import { pathToFileURL } from 'node:url';
import { resolve } from 'path';
import type { Plugin } from 'vite';
import { ResolvedConfig } from '../../../../types';
Expand All @@ -15,6 +16,7 @@ import {
export function resolveVirtualModules(config: ResolvedConfig): Plugin[] {
return virtualModuleNames.map((name) => {
const virtualId: `${VirtualModuleId}?` = `virtual:wxt-${name}?`;
const userVirtualId = `virtual:user-${name}`;
const resolvedVirtualId = '\0' + virtualId;

return {
Expand All @@ -40,7 +42,16 @@ export function resolveVirtualModules(config: ResolvedConfig): Plugin[] {
resolve(config.wxtModuleDir, `dist/virtual/${name}.mjs`),
'utf-8',
);
return template.replace(`virtual:user-${name}`, inputPath);
const escapedPath = pathToFileURL(inputPath).href;
const code = template
.replace(`'${userVirtualId}'`, `"${escapedPath}"`)
.replace(`"${userVirtualId}"`, `"${escapedPath}"`);
if (code === template) {
throw Error(
`Failed to resolve virtual module "${name}": expected template import "${userVirtualId}"`,
);
}
return code;
},
},
};
Expand Down