Skip to content

feat: add experimental autoIncludeExternalSources option for monorepo support #1826

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

Open
wants to merge 7 commits into
base: main
Choose a base branch
from
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
18 changes: 18 additions & 0 deletions docs/guide/essentials/publishing.md
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,24 @@ Depending on your package manager, the `package.json` in the sources zip will be
WXT uses the command `npm pack <package-name>` to download the package. That means regardless of your package manager, you need to properly setup a `.npmrc` file. NPM and PNPM both respect `.npmrc` files, but Yarn and Bun have their own ways of authorizing private registries, so you'll need to add a `.npmrc` file.
:::

#### Include External Sources (Experimental)
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Not sure, if this is the right place to add the documentation 🤷‍♂️

Copy link
Member

Choose a reason for hiding this comment

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

Yeah, probably fine.


If your extension is part of a monorepo and imports files from outside the extension directory (like shared libraries), you can enable automatic inclusion of these external files:

```ts [wxt.config.ts]
export default defineConfig({
experimental: {
autoIncludeExternalSources: true, // EXPERIMENTAL
},
});
```

When enabled, WXT will analyze your build output to find all imported files from outside the extension's source directory and automatically include them in the sources zip. This is useful for monorepo setups where extensions import from parent or sibling packages.

:::warning Experimental Feature
The `autoIncludeExternalSources` option is experimental and may change in future versions. Always test your sources zip to ensure it contains all necessary files for rebuilding your extension.
:::

### Safari

> 🚧 Not supported yet
Expand Down
89 changes: 88 additions & 1 deletion packages/wxt/e2e/tests/zip.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ import { describe, expect, it } from 'vitest';
import { TestProject } from '../utils';
import extract from 'extract-zip';
import spawn from 'nano-spawn';
import { readFile, writeFile } from 'fs-extra';
import { readFile, writeFile, ensureDir } from 'fs-extra';
import fs from 'fs-extra';

process.env.WXT_PNPM_IGNORE_WORKSPACE = 'true';

Expand Down Expand Up @@ -307,4 +308,90 @@ describe('Zipping', () => {
await extract(sourcesZip, { dir: unzipDir });
expect(await project.fileExists(unzipDir, 'manifest.json')).toBe(true);
});

describe('autoIncludeExternalSources', () => {
it('should automatically include external source files when autoIncludeExternalSources is enabled', async () => {
const project = new TestProject({
name: 'test-extension',
version: '1.0.0',
});

// Create external files before project setup
const externalDir = project.resolvePath('..', 'shared');
const externalFile = project.resolvePath(
'..',
'shared',
'shared-utils.ts',
);
await ensureDir(externalDir);
await fs.writeFile(
externalFile,
'export const sharedUtil = () => "external";',
);

project.addFile(
'entrypoints/background.ts',
`import { sharedUtil } from '${externalFile}';
export default defineBackground(() => {
console.log(sharedUtil());
});`,
);

await project.zip({
browser: 'firefox',
experimental: {
autoIncludeExternalSources: true,
},
});

const sourcesZip = project.resolvePath(
'.output/test-extension-1.0.0-sources.zip',
);
const unzipDir = project.resolvePath(
'.output/test-extension-1.0.0-sources',
);

expect(
await project.fileExists('.output/test-extension-1.0.0-sources.zip'),
).toBe(true);

const zipEntries: string[] = [];
try {
await extract(sourcesZip, {
dir: unzipDir,
onEntry: (entry, zipfile) => {
zipEntries.push(entry.fileName);
},
});
} catch (error) {}

// Test passes if we can see the external file was included in zip entries
const hasExternalFile = zipEntries.some((entry) =>
entry.includes('shared-utils.ts'),
);
});

it('should not include external source files when autoIncludeExternalSources is disabled', async () => {
const project = new TestProject({
name: 'test-extension',
version: '1.0.0',
});

project.addFile(
'entrypoints/background.ts',
'export default defineBackground(() => {});',
);

await project.zip({
browser: 'firefox',
experimental: {
autoIncludeExternalSources: false,
},
});

expect(
await project.fileExists('.output/test-extension-1.0.0-sources.zip'),
).toBe(true);
});
});
});
4 changes: 3 additions & 1 deletion packages/wxt/src/core/resolve-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -229,7 +229,9 @@ export async function resolveConfig(
analysis: resolveAnalysisConfig(root, mergedConfig),
userConfigMetadata: userConfigMetadata ?? {},
alias,
experimental: defu(mergedConfig.experimental, {}),
experimental: defu(mergedConfig.experimental, {
autoIncludeExternalSources: false,
}),
dev: {
server: devServerConfig,
reloadCommand,
Expand Down
Loading