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
51 changes: 51 additions & 0 deletions src/entries/vite-plugin.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import { beforeEach, describe, expect, it, vi } from 'vitest';

const mocks = vi.hoisted(() => ({
cpSync: vi.fn(),
createRequire: vi.fn(),
existsSync: vi.fn(),
mkdirSync: vi.fn(),
readFileSync: vi.fn(),
}));

vi.mock('node:fs', () => ({
cpSync: mocks.cpSync,
existsSync: mocks.existsSync,
mkdirSync: mocks.mkdirSync,
readFileSync: mocks.readFileSync,
}));
vi.mock('node:module', () => ({ createRequire: mocks.createRequire }));

import { datadogVitePlugin } from './vite-plugin';

describe('datadogVitePlugin', () => {
beforeEach(() => {
vi.resetAllMocks();
});

it('resolves transitive dependencies from their parent package', () => {
const rootResolve = vi.fn((pkg: string) => {
if (pkg === 'dd-trace') return '/packages/dd-trace/index.js';
if (pkg === '@datadog/electron-sdk') return '/packages/electron-sdk/index.js';
throw new Error(`Cannot resolve ${pkg}`);
});
const ddTraceResolve = vi.fn(() => '/packages/nested-package/index.js');

mocks.createRequire.mockImplementation((path: string) => ({
resolve: path === '/packages/dd-trace/package.json' ? ddTraceResolve : rootResolve,
}));
mocks.existsSync.mockImplementation((path: string) =>
path.startsWith('/packages/') ? path.endsWith('/package.json') : false
);
mocks.readFileSync.mockImplementation((path: string) =>
JSON.stringify({ dependencies: path === '/packages/dd-trace/package.json' ? { 'nested-package': '1.0.0' } : {} })
);

datadogVitePlugin().writeBundle?.({ dir: '/output' });

expect(ddTraceResolve).toHaveBeenCalledWith('nested-package');
expect(mocks.cpSync).toHaveBeenCalledWith('/packages/nested-package', '/output/node_modules/nested-package', {
recursive: true,
});
});
});
7 changes: 4 additions & 3 deletions src/entries/vite-plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,13 +77,13 @@ export function datadogVitePlugin(): VitePlugin {
const destModules = join(outDir, 'node_modules');
const visited = new Set<string>();

function copyPackageTree(pkg: string): void {
function copyPackageTree(pkg: string, resolveFrom = _require): void {
if (visited.has(pkg)) return;
visited.add(pkg);

try {
// Resolve the package's main entry, then walk up to find the root
const entryPath = _require.resolve(pkg);
const entryPath = resolveFrom.resolve(pkg);
let pkgDir = dirname(entryPath);
while (pkgDir !== dirname(pkgDir) && !existsSync(join(pkgDir, 'package.json'))) {
pkgDir = dirname(pkgDir);
Expand All @@ -99,8 +99,9 @@ export function datadogVitePlugin(): VitePlugin {
const pkgJson = JSON.parse(readFileSync(join(pkgDir, 'package.json'), 'utf8')) as {
dependencies?: Record<string, string>;
};
const packageRequire = createRequire(join(pkgDir, 'package.json'));
for (const dep of Object.keys(pkgJson.dependencies ?? {})) {
copyPackageTree(dep);
copyPackageTree(dep, packageRequire);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Preserve nested versions when copying package trees

In pnpm/non-hoisted Vite builds with duplicate transitive package names, this call resolves the second parent's dependency with the right packageRequire but still feeds only the package name into the global visited set and flat output/node_modules/<pkg> destination. The current dd-trace tree already has node-gyp-build v3 for @datadog/native-* and v4 for @datadog/pprof/wasm-js-rewriter in yarn.lock, so whichever one is copied first makes the other parent skip its own version and later resolve the wrong package in the packaged app. Preserve the resolved path/version in the key or copy dependencies under the requiring package's node_modules.

Useful? React with 👍 / 👎.

}
} catch {
console.warn(`[datadog] Failed to copy package '${pkg}' to build output`);
Expand Down