Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 2 additions & 3 deletions packages/wxt/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -58,11 +58,10 @@
"publish-browser-extension": "^2.3.0 || ^3.0.2",
"scule": "^1.3.0",
"unimport": "^3.13.1 || ^4.0.0 || ^5.0.0",
"vite-node": "^2.1.4 || ^3.1.2",
"web-ext-run": "^0.2.4"
},
"peerDependencies": {
"vite": "^5.4.19 || ^6.3.4 || ^7.0.0"
"vite": "^6.3.4 || ^7.0.0"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perfect, was gonna call this out.

},
"devDependencies": {
"@aklinker1/check": "^2.1.0",
Expand All @@ -79,7 +78,7 @@
"publint": "^0.3.12",
"typescript": "^5.9.2",
"unbuild": "^3.6.1",
"vite": "^6.3.5",
"vite": "^7.1.12",
"vitest": "^3.2.4",
"vitest-plugin-random-seed": "^1.1.1"
},
Expand Down
117 changes: 66 additions & 51 deletions packages/wxt/src/core/builders/vite/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,6 @@ import {
import { Hookable } from 'hookable';
import { toArray } from '../../utils/arrays';
import { safeVarName } from '../../utils/strings';
import { ViteNodeServer } from 'vite-node/server';
import { ViteNodeRunner } from 'vite-node/client';
import { installSourcemapsSupport } from 'vite-node/source-map';
import { createExtensionEnvironment } from '../../utils/environments';
import { dirname, extname, join, relative } from 'node:path';
import fs from 'fs-extra';
Expand Down Expand Up @@ -71,7 +68,6 @@ export async function createViteBuilder(

// TODO: Remove once https://github.com/wxt-dev/wxt/pull/1411 is merged
config.legacy ??= {};
// @ts-ignore: Untyped option:
config.legacy.skipWebSocketTokenCheck = true;

const server = getWxtDevServer?.();
Expand All @@ -90,8 +86,9 @@ export async function createViteBuilder(
wxtPlugins.resolveAppConfig(wxtConfig),
);
if (
// TODO: Should this be migrated to use perEnvironmentState?
wxtConfig.analysis.enabled &&
// If included, vite-node entrypoint loader will increment the
// If included, entrypoint loader will increment the
// bundleAnalysis's internal build index tracker, which we don't want
!baseConfigOptions?.excludeAnalysisPlugin
) {
Expand Down Expand Up @@ -224,8 +221,7 @@ export async function createViteBuilder(
},
};
};

const createViteNodeImporter = async (paths: string[]) => {
const createImporterEnvironment = async (paths: string[]) => {
const baseConfig = await getBaseConfig({
excludeAnalysisPlugin: true,
});
Expand All @@ -238,33 +234,47 @@ export async function createViteBuilder(
wxtPlugins.removeEntrypointMainFunction(wxtConfig, path),
),
};
const config = vite.mergeConfig(baseConfig, envConfig);
const server = await vite.createServer(config);
await server.pluginContainer.buildStart({});
const node = new ViteNodeServer(
// @ts-ignore: Some weird type error...
server,
const importerConfig = vite.mergeConfig(baseConfig, envConfig);

const config = await vite.resolveConfig(
vite.mergeConfig(importerConfig || {}, {
configFile: false,
envDir: false,
cacheDir: process.cwd(),
environments: {
inline: {
consumer: 'server',
dev: {
moduleRunnerTransform: true,
},
resolve: {
external: true,
mainFields: [],
conditions: ['node'],
},
},
},
} satisfies vite.InlineConfig),
'serve',
);
installSourcemapsSupport({
getSourceMap: (source) => node.getSourceMap(source),
});
const runner = new ViteNodeRunner({
root: server.config.root,
base: server.config.base,
// when having the server and runner in a different context,
// you will need to handle the communication between them
// and pass to this function
fetchModule(id) {
return node.fetchModule(id);
},
resolveId(id, importer) {
return node.resolveId(id, importer);

const environment = vite.createRunnableDevEnvironment('inline', config, {
runnerOptions: {
hmr: {
logger: false,
},
},
hot: false,
});
return { runner, server };
await environment.init();

return environment;
};

const requireDefaultExport = (path: string, mod: any) => {
function requireDefaultExport(
path: string,
mod: any,
): asserts mod is { default: unknown } {
const relativePath = relative(wxtConfig.root, path);
if (mod?.default == null) {
const defineFn = relativePath.includes('.content')
Expand All @@ -277,36 +287,37 @@ export async function createViteBuilder(
`${relativePath}: Default export not found, did you forget to call "export default ${defineFn}(...)"?`,
);
}
};
}

return {
name: 'Vite',
version: vite.version,
async importEntrypoint(path) {
const env = createExtensionEnvironment();
const { runner, server } = await createViteNodeImporter([path]);
const res = await env.run(() => runner.executeFile(path));
await server.close();
requireDefaultExport(path, res);
return res.default;
const [module] = await this.importEntrypoints([path]);

return module as any;
},
async importEntrypoints(paths) {
const env = createExtensionEnvironment();
const { runner, server } = await createViteNodeImporter(paths);
const res = await env.run(() =>
Promise.all(
paths.map(async (path) => {
const mod = await runner.executeFile(path);
requireDefaultExport(path, mod);
return mod.default;
}),
),
);
await server.close();
return res;
const context = createExtensionEnvironment();
const environment = await createImporterEnvironment(paths);

try {
return await context.run(
async () =>
await Promise.all(
paths.map(async (path) => {
const module = await environment.runner.import(path);
requireDefaultExport(path, module);
return module.default as any;
}),
),
);
} finally {
await environment.close();
}
},
async build(group) {
let entryConfig;
let entryConfig: vite.InlineConfig;
if (Array.isArray(group)) entryConfig = getMultiPageConfig(group);
else if (
group.type === 'content-script-style' ||
Expand All @@ -315,12 +326,16 @@ export async function createViteBuilder(
entryConfig = getCssConfig(group);
else entryConfig = getLibModeConfig(group);

const buildConfig = vite.mergeConfig(await getBaseConfig(), entryConfig);
const buildConfig: vite.InlineConfig = vite.mergeConfig(
await getBaseConfig(),
entryConfig,
);
await hooks.callHook(
'vite:build:extendConfig',
toArray(group),
buildConfig,
);

const result = await vite.build(buildConfig);
const chunks = getBuildOutputChunks(result);
return {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ export function removeEntrypointMainFunction(
handler(code, id) {
if (id === absPath) {
const newCode = removeMainFunctionCode(code);
config.logger.debug('vite-node transformed entrypoint', path);
config.logger.debug('transformed entrypoint', path);
config.logger.debug(`Original:\n---\n${code}\n---`);
config.logger.debug(`Transformed:\n---\n${newCode.code}\n---`);
return newCode;
Expand Down
2 changes: 1 addition & 1 deletion packages/wxt/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1029,7 +1029,7 @@ export interface WxtBuilder {
/**
* Import a JS entrypoint file, returning the default export containing the options.
*/
importEntrypoint<T>(path: string): Promise<T>;
importEntrypoint<T>(this: WxtBuilder, path: string): Promise<T>;
/**
* Import a list of JS entrypoint files, returning their options.
*/
Expand Down
Loading