Skip to content
Merged
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: 5 additions & 0 deletions .changeset/webpack-symbolicate-absolute-paths.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@callstack/repack": patch
---

Fix the webpack compiler double-joining absolute paths in `getSource`. The dev server resolves symbolicated stack frames to absolute paths before asking the compiler for their source, but the webpack compiler joined them onto the project root a second time, so the lookup failed. This only affected the fallback used when a frame's source is not embedded in the source map, for example with `nosources-*` devtools, and now matches the Rspack compiler.
4 changes: 3 additions & 1 deletion packages/repack/src/commands/webpack/Compiler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -276,7 +276,9 @@ export class Compiler implements CompilerInterface {
}

try {
const filePath = path.join(this.rootDir, filename);
const filePath = path.isAbsolute(filename)
? filename
: path.join(this.rootDir, filename);
const source = await fs.promises.readFile(filePath, 'utf8');
return source;
} catch {
Expand Down
42 changes: 42 additions & 0 deletions packages/repack/src/commands/webpack/__tests__/Compiler.test.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
import type { EventEmitter } from 'node:events';
import { Worker } from 'node:worker_threads';
import { fs, vol } from 'memfs';
import type { Reporter } from '../../../logging/types.js';
import { Compiler } from '../Compiler.js';

jest.mock('node:fs', () => jest.requireActual('memfs').fs);

jest.mock('node:worker_threads', () => {
const { EventEmitter } =
jest.requireActual<typeof import('node:events')>('node:events');
Expand Down Expand Up @@ -70,3 +73,42 @@ test('terminates active workers when closed', async () => {

expect(worker.terminate).toHaveBeenCalledTimes(1);
});

describe('getSource', () => {
const reporter: Reporter = {
process: jest.fn(),
flush: jest.fn(),
stop: jest.fn(),
};

const createCompiler = () =>
new Compiler(['ios'], { host: '' }, reporter, '/project', '/react-native');

beforeEach(() => {
vol.reset();
});

afterEach(() => {
jest.restoreAllMocks();
});

test('reads an absolute filename as-is', async () => {
vol.fromJSON({ '/outside/project/file.js': 'absolute source' });
const readFile = jest.spyOn(fs.promises, 'readFile');

await expect(
createCompiler().getSource('/outside/project/file.js', 'ios')
).resolves.toBe('absolute source');
expect(readFile).toHaveBeenCalledWith('/outside/project/file.js', 'utf8');
});

test('resolves a relative filename against the project root', async () => {
vol.fromJSON({ '/project/src/index.js': 'source under the project root' });
const readFile = jest.spyOn(fs.promises, 'readFile');

await expect(
createCompiler().getSource('src/index.js', 'ios')
).resolves.toBe('source under the project root');
expect(readFile).toHaveBeenCalledWith('/project/src/index.js', 'utf8');
});
});
Loading