Skip to content

Commit a87adc3

Browse files
authored
feat: Add basic polyfills (#5)
1 parent 47cd25d commit a87adc3

File tree

9 files changed

+138
-35
lines changed

9 files changed

+138
-35
lines changed

README.md

Lines changed: 30 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,32 @@
11
# javascript-debug-ids
22

3+
JavaScript Polyfills and Bundler Plugins for the TC39 [Debug ID proposal](https://github.com/tc39/source-map/blob/main/proposals/debug-id.md).
4+
5+
## Polyfills
6+
7+
### Browser
8+
9+
```ts
10+
import { getDebugIdForUrl } from "@sentry/debug-ids/browser";
11+
12+
const debugId = await getDebugIdForUrl("https://example.com/main.js");
13+
```
14+
15+
### Node.js
16+
17+
```ts
18+
import { getDebugIdForUrl } from "@sentry/debug-ids/node";
19+
20+
const debugId = await getDebugIdForUrl("./path/to/main.js");
21+
```
22+
23+
## Bundler Plugins
24+
325
Bundler plugins to inject [Debug
426
IDs](https://github.com/tc39/source-map/blob/main/proposals/debug-id.md) into
5-
both source and source-maps, making build artifacts self-identifying.
27+
both source and source-maps.
628

7-
## Rollup
29+
### Rollup
830

931
`rollup.config.mjs`
1032
```ts
@@ -21,7 +43,7 @@ export default {
2143
};
2244
```
2345

24-
## webpack
46+
### webpack
2547

2648
`webpack.config.mjs`
2749
```ts
@@ -39,7 +61,7 @@ export default {
3961
};
4062
```
4163

42-
## esbuild
64+
### esbuild
4365

4466
`build.mjs`
4567
```ts
@@ -57,7 +79,7 @@ await esbuild.build({
5779
});
5880
```
5981

60-
## vite
82+
### vite
6183

6284
`vite.config.mjs`
6385
```ts
@@ -74,7 +96,7 @@ export default {
7496
};
7597
```
7698

77-
## rspack
99+
### rspack
78100

79101
`rspack.config.mjs`
80102
```ts
@@ -92,7 +114,7 @@ export default {
92114
};
93115
```
94116

95-
## Rolldown
117+
### Rolldown
96118

97119
`rolldown.config.mjs`
98120
```ts
@@ -109,7 +131,7 @@ export default {
109131
};
110132
```
111133

112-
## Parcel
134+
### Parcel
113135

114136
`.parcelrc`
115137
```json

package.json

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,14 @@
3030
"parcel": {
3131
"require": "./dist/cjs/parcel.js",
3232
"import": "./dist/esm/parcel.js"
33+
},
34+
"node": {
35+
"require": "./dist/cjs/node.js",
36+
"import": "./dist/esm/node.js"
37+
},
38+
"browser": {
39+
"require": "./dist/cjs/browser.js",
40+
"import": "./dist/esm/browser.js"
3341
}
3442
},
3543
"scripts": {

rollup.config.mjs

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,23 +14,23 @@ const modulePackageJson = {
1414
},
1515
};
1616

17-
function transpileNode(format, input, outDir) {
17+
function transpile(format, input, outDir, preserveModules = true) {
1818
return {
1919
input,
2020
output: {
2121
sourcemap: true,
22-
strict: false,
2322
format,
2423
dir: outDir,
25-
preserveModules: true,
24+
preserveModules,
2625
},
2726
plugins: [typescript({ outDir, tsconfig: './tsconfig.json' }), format === 'esm' ? modulePackageJson : {}],
2827
external,
2928
};
3029
}
3130

32-
const inputs = [
31+
const nodeInputs = [
3332
'src/esbuild.ts',
33+
'src/node.ts',
3434
'src/parcel.ts',
3535
'src/rolldown.ts',
3636
'src/rollup.ts',
@@ -39,4 +39,9 @@ const inputs = [
3939
'src/webpack.ts',
4040
];
4141

42-
export default [transpileNode('cjs', inputs, 'dist/cjs'), transpileNode('esm', inputs, 'dist/esm')];
42+
export default [
43+
transpile('cjs', nodeInputs, 'dist/cjs'),
44+
transpile('esm', nodeInputs, 'dist/esm'),
45+
transpile('cjs', ['src/browser.ts'], 'dist/cjs', false),
46+
transpile('esm', ['src/browser.ts'], 'dist/esm', false),
47+
];

src/browser.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import { getDebugIdFromString } from './common';
2+
3+
export async function getDebugIdForUrl(url: string): Promise<string | undefined> {
4+
try {
5+
const text = await fetch(url, { cache: 'force-cache' }).then((res) => res.text());
6+
return getDebugIdFromString(text);
7+
} catch (_) {}
8+
9+
return;
10+
}

src/common.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,3 +34,10 @@ export function addDebugIdToSourcemap(input: string, debugId: string): string {
3434
sourceMapObj.debugId = debugId;
3535
return JSON.stringify(sourceMapObj);
3636
}
37+
38+
const DEBUG_ID_REGEX = /\/\/# debugId=([a-fA-F0-9-]+)(?![\s\S]*\/\/# debugId=)/m;
39+
40+
export function getDebugIdFromString(input: string): string | undefined {
41+
const match = input.match(DEBUG_ID_REGEX);
42+
return match ? match[1] : undefined;
43+
}

src/node.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import * as fs from 'fs/promises';
2+
import { getDebugIdFromString } from './common';
3+
4+
async function getLastBytesFromFile(path: string, bytesToRead = 1024) {
5+
let handle: fs.FileHandle | undefined;
6+
try {
7+
handle = await fs.open(path, 'r');
8+
const { size } = await handle.stat();
9+
const position = Math.max(0, size - bytesToRead);
10+
const { buffer } = await handle.read(Buffer.alloc(bytesToRead), 0, bytesToRead, position);
11+
return buffer;
12+
} finally {
13+
await handle?.close();
14+
}
15+
}
16+
17+
export async function getDebugIdForUrl(pathOrUrl: string): Promise<string | undefined> {
18+
const endOfFile = await getLastBytesFromFile(pathOrUrl);
19+
const eofString = endOfFile.toString('utf-8');
20+
return getDebugIdFromString(eofString);
21+
}

test/common/common.test.ts

Lines changed: 44 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { describe, expect, test } from 'vitest';
2-
import { addDebugIdToSource } from '../../src/common';
2+
import { addDebugIdToSource, getDebugIdFromString } from '../../src/common';
33

44
describe('common', () => {
55
describe('addDebugIdToSource', () => {
@@ -38,20 +38,50 @@ describe('common', () => {
3838
//# sourceMappingURL=main.js.map"
3939
`);
4040
});
41+
42+
test('adds debugId to source with sourceMapURL and existing debugId', () => {
43+
expect(
44+
addDebugIdToSource(
45+
`console.log('nothing');
46+
//# debugId=302a139c-0c62-4af7-bfd3-03d083925e5e
47+
//# sourceMappingURL=main.js.map`,
48+
'000-000-000-000',
49+
),
50+
).toMatchInlineSnapshot(`
51+
"console.log('nothing');
52+
//# debugId=000-000-000-000
53+
//# sourceMappingURL=main.js.map"
54+
`);
55+
});
4156
});
4257

43-
test('adds debugId to source with sourceMapURL and existing debugId', () => {
44-
expect(
45-
addDebugIdToSource(
46-
`console.log('nothing');
47-
//# debugId=302a139c-0c62-4af7-bfd3-03d083925e5e
48-
//# sourceMappingURL=main.js.map`,
49-
'000-000-000-000',
50-
),
51-
).toMatchInlineSnapshot(`
52-
"console.log('nothing');
53-
//# debugId=000-000-000-000
54-
//# sourceMappingURL=main.js.map"
55-
`);
58+
describe('getDebugIdFromString', () => {
59+
test('simple', () => {
60+
expect(
61+
getDebugIdFromString(`
62+
console.log('here')
63+
//# debugId=797b2e77-cda7-4d05-b93f-e4df1d24b5f6`),
64+
).toBe('797b2e77-cda7-4d05-b93f-e4df1d24b5f6');
65+
});
66+
67+
test('with sourcemap url', () => {
68+
expect(
69+
getDebugIdFromString(`
70+
console.log('here')
71+
//# debugId=b4b9bc99-7b69-4204-a399-e1899a41fc94
72+
//# sourceMappingURL=main.js.map`),
73+
).toBe('b4b9bc99-7b69-4204-a399-e1899a41fc94');
74+
});
75+
76+
test('only matches last occurrence', () => {
77+
expect(
78+
getDebugIdFromString(`
79+
console.log('here')
80+
//# debugId=797b2e77-cda7-4d05-b93f-e4df1d24b5f6
81+
console.log('here')
82+
//# debugId=b4b9bc99-7b69-4204-a399-e1899a41fc94
83+
//# sourceMappingURL=main.js.map`),
84+
).toBe('b4b9bc99-7b69-4204-a399-e1899a41fc94');
85+
});
5686
});
5787
});

test/esbuild/no-sourcemaps/build.mjs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
1-
import { join } from "path";
2-
import * as esbuild from "esbuild";
3-
import debugIds from "../../../dist/esm/esbuild.js";
1+
import { join } from 'path';
2+
import * as esbuild from 'esbuild';
3+
import debugIds from '../../../dist/esm/esbuild.js';
44

5-
const __dirname = new URL(".", import.meta.url).pathname;
5+
const __dirname = new URL('.', import.meta.url).pathname;
66

77
await esbuild.build({
8-
entryPoints: [join(__dirname, "src", "main.js")],
8+
entryPoints: [join(__dirname, 'src', 'main.js')],
99
bundle: true,
10-
format: "esm",
10+
format: 'esm',
1111
minify: true,
1212
sourcemap: false,
1313
plugins: [debugIds],
14-
outdir: join(__dirname, "dist"),
14+
outdir: join(__dirname, 'dist'),
1515
});

tsconfig.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
"include": ["src/**/*.ts"],
44
"exclude": ["node_modules"],
55
"compilerOptions": {
6-
"lib": ["ES2018"],
6+
"lib": ["ES2018", "DOM"],
77
"module": "ESNext",
88
"ignoreDeprecations": "5.0"
99
}

0 commit comments

Comments
 (0)