Skip to content

Commit 9c0964a

Browse files
committed
feat: source map support of transform hook
1 parent 7dcb4a5 commit 9c0964a

File tree

3 files changed

+36
-30
lines changed

3 files changed

+36
-30
lines changed

playground/demo.ts

+20-1
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,26 @@ export function demoPlugin(): Plugin {
3535
const code = await readFile(fileURLToPath(id), 'utf8')
3636
const s = new MagicString(code)
3737
s.prepend('// header\n')
38-
const map = s.generateMap({ hires: 'boundary', includeContent: true })
38+
const map = s.generateMap({
39+
file: id,
40+
hires: 'boundary',
41+
includeContent: true,
42+
})
43+
return {
44+
code: s.toString(),
45+
map,
46+
}
47+
}
48+
},
49+
transform(code, id) {
50+
if (id.endsWith('trace.js') && typeof code === 'string') {
51+
const s = new MagicString(code)
52+
s.prepend('// header2\n')
53+
const map = s.generateMap({
54+
file: id,
55+
hires: 'boundary',
56+
includeContent: true,
57+
})
3958
return {
4059
code: s.toString(),
4160
map,

src/loader/index.ts

+11-4
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import process from 'node:process'
2+
import remapping from '@ampproject/remapping'
23
import type {
34
FalsyValue,
45
LoadResult,
@@ -110,6 +111,7 @@ export const load: LoadHook = async (url, context, nextLoad) => {
110111

111112
let result: LoadFnOutput | undefined
112113
const defaultFormat = context.format || 'module'
114+
const maps: any[] = []
113115

114116
// load hook
115117
for (const plugin of plugins) {
@@ -131,11 +133,9 @@ export const load: LoadHook = async (url, context, nextLoad) => {
131133
shortCircuit: true,
132134
}
133135
} else {
136+
if (loadResult.map) maps.unshift(loadResult.map)
134137
result = {
135-
source:
136-
typeof loadResult.code === 'string'
137-
? attachSourceMap(loadResult.map, loadResult.code)
138-
: loadResult.code,
138+
source: loadResult.code,
139139
format: loadResult.format || defaultFormat,
140140
shortCircuit: true,
141141
}
@@ -162,6 +162,7 @@ export const load: LoadHook = async (url, context, nextLoad) => {
162162
) {
163163
result = { ...result, source: transformResult }
164164
} else {
165+
if (transformResult.map) maps.unshift(transformResult.map)
165166
result = {
166167
...result,
167168
source: transformResult.code,
@@ -171,5 +172,11 @@ export const load: LoadHook = async (url, context, nextLoad) => {
171172
}
172173
}
173174

175+
if (maps.length && typeof result.source === 'string') {
176+
const map = remapping(maps, () => null)
177+
const code = attachSourceMap(map, result.source)
178+
result.source = code
179+
}
180+
174181
return result
175182
}

src/loader/map.ts

+5-25
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,15 @@
11
import { Buffer } from 'node:buffer'
2-
import type { EncodedSourceMap, SourceMap } from '@ampproject/remapping'
2+
import type { SourceMap } from '@ampproject/remapping'
33

4-
export function attachSourceMap(map: any, code: string): string {
4+
export function attachSourceMap(map: SourceMap, code: string): string {
55
if (map) {
66
if (!map.sourcesContent || map.sourcesContent.length === 0)
77
map.sourcesContent = [code]
8-
9-
map = fixSourceMap(map as EncodedSourceMap)
10-
code += `\n//# sourceMappingURL=${map.toUrl()}`
8+
code += `\n//# sourceMappingURL=${toUrl(map)}`
119
}
1210
return code
1311
}
1412

15-
// `load` and `transform` may return a sourcemap without toString and toUrl,
16-
// but esbuild needs them, we fix the two methods
17-
export function fixSourceMap(map: EncodedSourceMap): SourceMap {
18-
if (!Object.prototype.hasOwnProperty.call(map, 'toString')) {
19-
Object.defineProperty(map, 'toString', {
20-
enumerable: false,
21-
value: function toString() {
22-
return JSON.stringify(this)
23-
},
24-
})
25-
}
26-
if (!Object.prototype.hasOwnProperty.call(map, 'toUrl')) {
27-
Object.defineProperty(map, 'toUrl', {
28-
enumerable: false,
29-
value: function toUrl() {
30-
return `data:application/json;charset=utf-8;base64,${Buffer.from(this.toString()).toString('base64')}`
31-
},
32-
})
33-
}
34-
return map as SourceMap
13+
function toUrl(map: SourceMap) {
14+
return `data:application/json;charset=utf-8;base64,${Buffer.from(map.toString()).toString('base64')}`
3515
}

0 commit comments

Comments
 (0)