Skip to content

Commit

Permalink
Fix missing "inputs" in the report created by the esbuild plugin.
Browse files Browse the repository at this point in the history
  • Loading branch information
filipsobol committed Oct 7, 2024
1 parent 7b3a78f commit d6d1b61
Show file tree
Hide file tree
Showing 6 changed files with 86 additions and 41 deletions.
5 changes: 5 additions & 0 deletions .changeset/witty-humans-pump.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"sonda": patch
---

Fix missing "inputs" in the report created by the esbuild plugin.
1 change: 1 addition & 0 deletions packages/sonda/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
},
"dependencies": {
"@ampproject/remapping": "^2.3.0",
"@jridgewell/sourcemap-codec": "^1.5.0",
"open": "^10.1.0"
},
"devDependencies": {
Expand Down
20 changes: 19 additions & 1 deletion packages/sonda/src/bundlers/esbuild.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import { resolve } from 'path';
import { normalizeOptions } from '../utils';
import { generateReportFromAssets } from '../report/generate';
import type { Plugin } from 'esbuild';
import type { Options, JsonReport } from '../types';
import { addSourcesToInputs } from '../sourcemap/map';

export function SondaEsbuildPlugin( options?: Partial<Options> ): Plugin {
return {
Expand All @@ -14,17 +16,33 @@ export function SondaEsbuildPlugin( options?: Partial<Options> ): Plugin {
return console.error( 'Metafile is required for SondaEsbuildPlugin to work.' );
}

const cwd = process.cwd();
const normalizedOptions = normalizeOptions( options );

// Esbuild already reads the existing source maps, so there's no need to do it again
normalizedOptions.detailed = false;

const inputs = Object
.entries( result.metafile.inputs )
.reduce( ( acc, [ path, data ] ) => {

acc[ path ] = {
bytes: data.bytes,
format: data.format ?? 'unknown',
imports: data.imports.map( data => data.path ),
belongsTo: null,
};

/**
* Because esbuild already reads the existing source maps, there may be
* cases where some report "outputs" include "inputs" don't exist in the
* main "inputs" object. To avoid this, we parse each esbuild input and
* add its sources to the "inputs" object.
*/
addSourcesToInputs(
resolve( cwd, path ),
acc
);

return acc;
}, {} as JsonReport[ 'inputs' ] );

Expand Down
5 changes: 4 additions & 1 deletion packages/sonda/src/report.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { dirname, resolve } from 'path';
import { fileURLToPath } from 'url';
import { readFileSync } from 'fs';
import { loadCodeAndMap } from 'load-source-map';
import { decode } from '@jridgewell/sourcemap-codec';
import { mapSourceMap } from './sourcemap/map.js';
import { getBytesPerSource, getSizes } from './sourcemap/bytes.js';
import type {
Expand Down Expand Up @@ -62,7 +63,9 @@ function processAsset(
}

const { code, map } = maybeCodeMap;
const mapped = mapSourceMap( map, dirname( asset ), inputs, options );
const mapped = options.detailed
? mapSourceMap( map, dirname( asset ), inputs )
: { ...map, mappings: decode( map.mappings ) };

mapped.sources = mapped.sources.map( source => normalizePath( source! ) );

Expand Down
68 changes: 41 additions & 27 deletions packages/sonda/src/sourcemap/map.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,12 @@ import { default as remapping, type DecodedSourceMap, type EncodedSourceMap } fr
import { loadCodeAndMap } from 'load-source-map';
import { resolve } from 'path';
import { normalizePath } from '../utils';
import type { Options, ReportInput } from '../types';
import type { CodeMap, ReportInput } from '../types';

export function mapSourceMap(
map: EncodedSourceMap,
dirPath: string,
inputs: Record<string, ReportInput>,
options: Options
inputs: Record<string, ReportInput>
): DecodedSourceMap {
const alreadyRemapped = new Set<string>();
const remapped = remapping( map, ( file, ctx ) => {
Expand All @@ -18,40 +17,55 @@ export function mapSourceMap(

alreadyRemapped.add( file );

const codeMap = loadCodeAndMap( resolve( dirPath, file ) );
const codeMap = addSourcesToInputs(
resolve( dirPath, file ),
inputs
);

if ( !codeMap ) {
return;
}

if ( !options.detailed ) {
return null;
}
ctx.content ??= codeMap.code;

const parentPath = normalizePath( file );
const format = inputs[ parentPath ]?.format ?? 'unknown';
return codeMap.map;
}, { decodedMappings: true } );

codeMap.map?.sources
.filter( source => source !== null )
.forEach( ( source, index ) => {
const normalizedPath = normalizePath( source );
return remapped as DecodedSourceMap;
}

if ( parentPath === normalizedPath ) {
return;
}
/**
* Loads the source map of a given file and adds its "sources" to the given inputs object.
*/
export function addSourcesToInputs(
path: string,
inputs: Record<string, ReportInput>
): CodeMap | null {
const codeMap = loadCodeAndMap( path );

inputs[ normalizedPath ] = {
bytes: Buffer.byteLength( codeMap.map!.sourcesContent?.[ index ] ?? '' ),
format,
imports: [],
belongsTo: parentPath
};
} );
if ( !codeMap ) {
return null;
}

ctx.content ??= codeMap.code;
const parentPath = normalizePath( path );
const format = inputs[ parentPath ]?.format ?? 'unknown';

return codeMap.map;
}, { decodedMappings: true } );
codeMap.map?.sources
.filter( source => source !== null )
.forEach( ( source, index ) => {
const normalizedPath = normalizePath( source );

return remapped as DecodedSourceMap;
if ( parentPath === normalizedPath ) {
return;
}

inputs[ normalizedPath ] = {
bytes: Buffer.byteLength( codeMap.map!.sourcesContent?.[ index ] ?? '' ),
format,
imports: [],
belongsTo: parentPath
};
} );

return codeMap;
}
28 changes: 16 additions & 12 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit d6d1b61

Please sign in to comment.