-
-
Notifications
You must be signed in to change notification settings - Fork 1
/
hooks.mts
130 lines (119 loc) · 3.82 KB
/
hooks.mts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
// hooks used by loader-legacy.mjs and loader.mjs
import { readFile } from 'node:fs/promises'
import { parse } from 'node:path'
import { fileURLToPath } from 'node:url'
import type { MessagePort } from 'node:worker_threads'
import { getExclude } from './get-exclude.js'
import { getImportMetaURL } from './get-import-meta-url.js'
import { fakeMains } from './get-main.js'
import {
getProcessInfo as _getProcessInfo,
reset as processInfoReset,
} from './get-process-info.js'
import { saveLineLengths } from './line-lengths.js'
import { likelyHasSourceMap } from './lookup-sources.js'
let getProcessInfo = _getProcessInfo
let PORT: undefined | MessagePort = undefined
const exclude = getExclude('_TAPJS_PROCESSINFO_EXCLUDE_', false)
const smMagicComment = /\/[*\/]#\s+sourceMappingURL=[^\s]+/
export const globalPreload = (context: { port?: MessagePort }) => {
// this will be something like path/to/dist/esm/lib/esm.mjs
// but we need path/to/dist/commonjs/cjs.js
const base = getImportMetaURL('../commonjs/[global preload].js')
const { port } = context || {}
PORT = port
return `
if (typeof port !== 'undefined') {
const { createRequire } = getBuiltin('module')
const { fileURLToPath } = getBuiltin('url')
const require = createRequire(${JSON.stringify(base)})
const { getProcessInfo } = require('./get-process-info.js')
const { saveLineLengths } = require('./line-lengths.js')
const { likelyHasSourceMap } = require('./lookup-sources.js')
// must be called eagerly here.
// this does all the registration as well.
const processInfo = getProcessInfo()
port.onmessage = (e) => {
const { filename, content, url } = e.data
processInfo.files.push(filename)
saveLineLengths(filename, content)
if (url) likelyHasSourceMap(url)
}
port.unref()
}
`
}
export const initialize = ({ port }: { port: MessagePort }) => {
PORT = port
}
const record = async (
url: string,
content?: string,
originSource?: string
) => {
const filename = url.startsWith('file://') ? fileURLToPath(url) : url
if (exclude.test(filename)) {
return
}
if (fakeMains.includes(filename)) {
return
}
let maybeSM = false
if (
originSource !== content ||
(content === undefined && url.startsWith('file://'))
) {
// try to read the file, fall back to the content we have, or ''
// if any source maps anywhere, flag it as possibly having one
originSource ??=
(await readFile(filename, 'utf8').catch(() => content)) ?? ''
}
maybeSM = smMagicComment.test(originSource as string)
if (PORT) {
PORT.postMessage({
filename,
content,
...(maybeSM && { url }),
})
} else {
// call lazily so we don't double-register
getProcessInfo().files.push(filename)
saveLineLengths(filename, content)
if (maybeSM) likelyHasSourceMap(url)
}
}
export const load = async (
url: string,
context: any,
nextLoad: Function
) => {
if (url.startsWith('file://')) {
const filename = fileURLToPath(url)
const { ext } = parse(filename)
// Package bins will sometimes have an extensionless bin script
// instead of just naming their extensioned file and letting npm
// symlink it for them. Don't blow up when this happens, just tell
// node that it's commonjs.
// TODO: should we just let this fail? It fails *without* the loader,
// after all.
if (!ext) {
await record(url)
return {
...context,
format: 'commonjs',
shortCircuit: true,
}
}
}
// get line lengths from final source
// if origin source doesn't match, check for possible source map
const originSource = context.source
const ret = await nextLoad(url, context)
await record(url, ret.source, originSource)
return ret
}
// just for testing purposes
export const reset = () => {
PORT = undefined
getProcessInfo = processInfoReset().getProcessInfo
}