-
-
Notifications
You must be signed in to change notification settings - Fork 246
Expand file tree
/
Copy pathcjs.ts
More file actions
84 lines (76 loc) · 2.55 KB
/
cjs.ts
File metadata and controls
84 lines (76 loc) · 2.55 KB
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
import { parseAstAsync, type Plugin } from 'vite'
import { findClosestPkgJsonPath } from 'vitefu'
import path from 'node:path'
import fs from 'node:fs'
import * as esModuleLexer from 'es-module-lexer'
import { transformCjsToEsm } from '../transforms/cjs'
import { createDebug } from '@hiogawa/utils'
import { parseIdQuery } from './shared'
const debug = createDebug('vite-rsc:cjs')
export function cjsModuleRunnerPlugin(): Plugin[] {
const warnedPackages = new Set<string>()
return [
{
name: 'cjs-module-runner-transform',
apply: 'serve',
applyToEnvironment: (env) => env.config.dev.moduleRunnerTransform,
async transform(code, id) {
if (
id.includes('/node_modules/') &&
!id.startsWith(this.environment.config.cacheDir) &&
/\b(require|exports)\b/.test(code)
) {
id = parseIdQuery(id).filename
if (!/\.[cm]?js$/.test(id)) return
// skip genuine esm
if (id.endsWith('.mjs')) return
if (id.endsWith('.js')) {
const pkgJsonPath = await findClosestPkgJsonPath(path.dirname(id))
if (pkgJsonPath) {
const pkgJson = JSON.parse(
fs.readFileSync(pkgJsonPath, 'utf-8'),
) as { type?: string }
if (pkgJson.type === 'module') return
}
}
// skip faux esm (e.g. from "module" field)
const [, , , hasModuleSyntax] = esModuleLexer.parse(code)
if (hasModuleSyntax) return
// warning once per package
const packageKey = extractPackageKey(id)
if (!warnedPackages.has(packageKey)) {
debug(
`non-optimized CJS dependency in '${this.environment.name}' environment: ${id}`,
)
warnedPackages.add(packageKey)
}
const ast = await parseAstAsync(code)
const result = transformCjsToEsm(code, ast)
const output = result.output
return {
code: output.toString(),
map: output.generateMap({ hires: 'boundary' }),
}
}
},
},
]
}
function extractPackageKey(id: string): string {
// .../.yarn/cache/abc/... => abc
const yarnMatch = id.match(/\/.yarn\/cache\/([^/]+)/)
if (yarnMatch) {
return yarnMatch[1]!
}
// .../node_modules/@x/y/... => @x/y
// .../node_modules/x/... => x
if (id.includes('/node_modules')) {
id = id.split('/node_modules/').at(-1)!
let [x, y] = id.split('/')
if (x!.startsWith('@')) {
return `${x}/${y}`
}
return x!
}
return id
}