@jk2908/cxx 0.2.4 → 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +18 -2
- package/dist/build.d.ts +46 -0
- package/dist/build.d.ts.map +1 -0
- package/dist/build.js +314 -0
- package/dist/build.js.map +13 -0
- package/dist/index.d.ts +3 -36
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +8 -188
- package/dist/index.js.map +4 -7
- package/dist/logger.d.ts +9 -11
- package/dist/logger.d.ts.map +1 -1
- package/dist/lru.d.ts +2 -2
- package/dist/next/cxx-loader.cjs +249 -152
- package/dist/next/cxx-loader.cjs.map +9 -9
- package/dist/next/index.d.ts +32 -11
- package/dist/next/index.d.ts.map +1 -1
- package/dist/next/index.js +278 -135
- package/dist/next/index.js.map +7 -7
- package/dist/types.d.ts +3 -3
- package/dist/types.d.ts.map +1 -1
- package/dist/utils.d.ts +16 -1
- package/dist/utils.d.ts.map +1 -1
- package/dist/vite/index.d.ts +14 -6
- package/dist/vite/index.d.ts.map +1 -1
- package/dist/vite/index.js +281 -129
- package/dist/vite/index.js.map +8 -8
- package/package.json +83 -75
- package/src/build.ts +373 -0
- package/src/index.ts +24 -210
- package/src/logger.ts +14 -22
- package/src/lru.ts +2 -2
- package/src/next/cxx-loader.js +1 -5
- package/src/next/index.ts +143 -100
- package/src/types.ts +5 -4
- package/src/utils.ts +72 -7
- package/src/vite/index.ts +110 -79
package/src/vite/index.ts
CHANGED
|
@@ -2,16 +2,18 @@ import { realpathSync } from 'node:fs'
|
|
|
2
2
|
import fs from 'node:fs/promises'
|
|
3
3
|
import path from 'node:path'
|
|
4
4
|
|
|
5
|
-
import { type Plugin, type ViteDevServer } from 'vite'
|
|
5
|
+
import { type Plugin, type ResolvedConfig, type ViteDevServer } from 'vite'
|
|
6
6
|
|
|
7
7
|
import type { BuildContext, PluginConfig } from '../types.js'
|
|
8
|
+
import { collect, flattenTags, isENOENT, writeTypes } from '../build.js'
|
|
8
9
|
import { GENERATED_DIR } from '../config.js'
|
|
9
|
-
import { collect, flattenTags, isENOENT, writeTypes } from '../index.js'
|
|
10
10
|
import { Logger } from '../logger.js'
|
|
11
|
-
import {
|
|
11
|
+
import { createBatcher } from '../utils.js'
|
|
12
12
|
|
|
13
13
|
const ACCEPTED_EXTENSIONS = new Set(['.js', '.jsx', '.ts', '.tsx'])
|
|
14
14
|
|
|
15
|
+
type WatchEvent = 'add' | 'change' | 'unlink'
|
|
16
|
+
|
|
15
17
|
function normaliseWatchPath(p: string) {
|
|
16
18
|
return p.replace(/\\/g, '/')
|
|
17
19
|
}
|
|
@@ -21,23 +23,11 @@ export default function cxx(pluginConfig: PluginConfig = {}) {
|
|
|
21
23
|
tagsByFile: new Map(),
|
|
22
24
|
} satisfies BuildContext
|
|
23
25
|
|
|
24
|
-
const logger = new Logger(
|
|
25
|
-
(pluginConfig?.logger?.level ?? process.env.NODE_ENV === 'production')
|
|
26
|
-
? 'error'
|
|
27
|
-
: 'debug',
|
|
28
|
-
)
|
|
29
|
-
|
|
30
|
-
// write generated files into a hidden folder at the project root
|
|
31
|
-
// keep the generated surface out of src
|
|
32
|
-
const watchRoot = normaliseWatchPath(realpathSync.native(process.cwd()))
|
|
33
|
-
const watchedRoots = [`${watchRoot}/`]
|
|
26
|
+
const logger = new Logger()
|
|
34
27
|
|
|
35
|
-
|
|
36
|
-
let
|
|
28
|
+
// resolved from Vite's root in `configResolved`, not from `process.cwd()`
|
|
29
|
+
let watchRoot = normaliseWatchPath(process.cwd())
|
|
37
30
|
|
|
38
|
-
// watcher events can arrive through symlinked paths like /var while cwd has
|
|
39
|
-
// already resolved to /private/var, so canonicalise the parent dir once and
|
|
40
|
-
// reattach the file name for stable prefix checks
|
|
41
31
|
function resolveWatchFile(filePath: string) {
|
|
42
32
|
const absolutePath = path.resolve(watchRoot, filePath)
|
|
43
33
|
const parentPath = path.dirname(absolutePath)
|
|
@@ -53,101 +43,142 @@ export default function cxx(pluginConfig: PluginConfig = {}) {
|
|
|
53
43
|
}
|
|
54
44
|
}
|
|
55
45
|
|
|
56
|
-
|
|
46
|
+
// returns the canonical, watchable path or null when the file is irrelevant
|
|
47
|
+
function watchedFile(filePath: string): string | null {
|
|
57
48
|
const resolvedPath = resolveWatchFile(filePath)
|
|
58
49
|
|
|
59
|
-
|
|
60
|
-
|
|
50
|
+
if (
|
|
51
|
+
resolvedPath.startsWith(`${watchRoot}/`) &&
|
|
61
52
|
!resolvedPath.includes(`/${GENERATED_DIR}/`) &&
|
|
62
53
|
ACCEPTED_EXTENSIONS.has(path.extname(resolvedPath))
|
|
63
|
-
)
|
|
64
|
-
|
|
54
|
+
) {
|
|
55
|
+
return resolvedPath
|
|
56
|
+
}
|
|
65
57
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
void (async () => {
|
|
69
|
-
// collapse bursts of file events into one active rebuild plus a single
|
|
70
|
-
// queued rerun when changes land mid-build
|
|
71
|
-
if (rebuildRunning) {
|
|
72
|
-
rebuildQueued = true
|
|
73
|
-
return
|
|
74
|
-
}
|
|
58
|
+
return null
|
|
59
|
+
}
|
|
75
60
|
|
|
76
|
-
|
|
61
|
+
async function onEvent(event: WatchEvent, file: string) {
|
|
62
|
+
const hadTags = buildContext.tagsByFile.has(file)
|
|
77
63
|
|
|
78
|
-
|
|
79
|
-
|
|
64
|
+
if (event === 'unlink') {
|
|
65
|
+
if (!hadTags) return
|
|
80
66
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
67
|
+
buildContext.tagsByFile.delete(file)
|
|
68
|
+
await writeTypes(flattenTags(buildContext.tagsByFile))
|
|
69
|
+
logger.info(`updated types from ${file}`)
|
|
84
70
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
} else {
|
|
88
|
-
const source = await fs.readFile(file, 'utf-8')
|
|
89
|
-
const { tags } = collect(source, file, pluginConfig)
|
|
71
|
+
return
|
|
72
|
+
}
|
|
90
73
|
|
|
91
|
-
|
|
74
|
+
let source: string
|
|
92
75
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
}
|
|
76
|
+
try {
|
|
77
|
+
source = await fs.readFile(file, 'utf-8')
|
|
78
|
+
} catch (err) {
|
|
79
|
+
if (!isENOENT(err)) throw err
|
|
80
|
+
if (!hadTags) return
|
|
99
81
|
|
|
100
|
-
|
|
82
|
+
buildContext.tagsByFile.delete(file)
|
|
83
|
+
await writeTypes(flattenTags(buildContext.tagsByFile))
|
|
84
|
+
logger.info(`updated types from ${file}`)
|
|
101
85
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
} catch (err) {
|
|
105
|
-
if (isENOENT(err)) {
|
|
106
|
-
if (!buildContext.tagsByFile.has(file)) continue
|
|
86
|
+
return
|
|
87
|
+
}
|
|
107
88
|
|
|
108
|
-
|
|
109
|
-
|
|
89
|
+
const { tags } = collect(source, file, pluginConfig)
|
|
90
|
+
const hasTags = tags.size > 0
|
|
110
91
|
|
|
111
|
-
|
|
92
|
+
if (hasTags) {
|
|
93
|
+
buildContext.tagsByFile.set(file, tags)
|
|
94
|
+
} else {
|
|
95
|
+
buildContext.tagsByFile.delete(file)
|
|
96
|
+
}
|
|
112
97
|
|
|
113
|
-
|
|
114
|
-
}
|
|
98
|
+
if (!hadTags && !hasTags) return
|
|
115
99
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
100
|
+
await writeTypes(flattenTags(buildContext.tagsByFile))
|
|
101
|
+
logger.info(`updated types from ${file}`)
|
|
102
|
+
}
|
|
119
103
|
|
|
120
|
-
|
|
121
|
-
|
|
104
|
+
// collect change events that arrive close together and handle each file once.
|
|
105
|
+
// The file path is the key, so changes to different files are all kept, and a
|
|
106
|
+
// change that arrives during a rebuild runs after that rebuild finishes.
|
|
107
|
+
const queue = createBatcher<string, WatchEvent>(75, async batch => {
|
|
108
|
+
for (const [file, event] of batch) {
|
|
109
|
+
try {
|
|
110
|
+
await onEvent(event, file)
|
|
111
|
+
} catch (err) {
|
|
112
|
+
logger.error(`failed to update types from ${file}`, err)
|
|
113
|
+
}
|
|
122
114
|
}
|
|
123
|
-
|
|
124
|
-
// ignore anything outside the watched content dirs
|
|
125
|
-
if (!watchedFile(filePath)) return
|
|
126
|
-
|
|
127
|
-
const file = resolveWatchFile(filePath)
|
|
128
|
-
queue()
|
|
129
|
-
}, 75)
|
|
115
|
+
})
|
|
130
116
|
|
|
131
117
|
return {
|
|
132
118
|
name: 'cxx',
|
|
133
119
|
enforce: 'pre',
|
|
120
|
+
config() {
|
|
121
|
+
const ignore = pluginConfig.watch?.ignore
|
|
122
|
+
if (!ignore?.length) return null
|
|
123
|
+
|
|
124
|
+
// Vite concatenates `server.watch.ignored`, so only return the additions
|
|
125
|
+
return {
|
|
126
|
+
server: {
|
|
127
|
+
watch: {
|
|
128
|
+
ignored: ignore,
|
|
129
|
+
},
|
|
130
|
+
},
|
|
131
|
+
}
|
|
132
|
+
},
|
|
133
|
+
configResolved(config: ResolvedConfig) {
|
|
134
|
+
const root = pluginConfig.watch?.root ?? config.root
|
|
135
|
+
|
|
136
|
+
try {
|
|
137
|
+
watchRoot = normaliseWatchPath(realpathSync.native(root))
|
|
138
|
+
} catch {
|
|
139
|
+
watchRoot = normaliseWatchPath(root)
|
|
140
|
+
}
|
|
141
|
+
},
|
|
134
142
|
transform(code, id) {
|
|
135
|
-
|
|
143
|
+
if (id.startsWith('\0') || id.includes('/node_modules/')) return null
|
|
144
|
+
// cheap bail-out before running the regex/lightningcss on every module
|
|
145
|
+
if (!code.includes('cxx')) return null
|
|
146
|
+
|
|
147
|
+
const cleanId = id.split('?')[0]
|
|
148
|
+
if (!ACCEPTED_EXTENSIONS.has(path.extname(cleanId))) return null
|
|
136
149
|
|
|
137
|
-
|
|
150
|
+
const { template, tags, map } = collect(code, cleanId, pluginConfig)
|
|
151
|
+
if (template === code) return null
|
|
152
|
+
|
|
153
|
+
const resolved = resolveWatchFile(cleanId)
|
|
154
|
+
|
|
155
|
+
if (tags.size) {
|
|
156
|
+
buildContext.tagsByFile.set(resolved, tags)
|
|
157
|
+
} else {
|
|
158
|
+
buildContext.tagsByFile.delete(resolved)
|
|
159
|
+
}
|
|
138
160
|
|
|
139
161
|
return {
|
|
140
162
|
code: template,
|
|
141
|
-
map
|
|
163
|
+
map,
|
|
142
164
|
}
|
|
143
165
|
},
|
|
144
166
|
configureServer(server: ViteDevServer) {
|
|
145
167
|
logger.info('Watching for changes...')
|
|
146
168
|
|
|
147
169
|
server.watcher
|
|
148
|
-
.on('add', (p: string) =>
|
|
149
|
-
|
|
150
|
-
|
|
170
|
+
.on('add', (p: string) => {
|
|
171
|
+
const file = watchedFile(p)
|
|
172
|
+
if (file) queue.add(file, 'add')
|
|
173
|
+
})
|
|
174
|
+
.on('change', (p: string) => {
|
|
175
|
+
const file = watchedFile(p)
|
|
176
|
+
if (file) queue.add(file, 'change')
|
|
177
|
+
})
|
|
178
|
+
.on('unlink', (p: string) => {
|
|
179
|
+
const file = watchedFile(p)
|
|
180
|
+
if (file) queue.add(file, 'unlink')
|
|
181
|
+
})
|
|
151
182
|
},
|
|
152
183
|
async writeBundle() {
|
|
153
184
|
await writeTypes(flattenTags(buildContext.tagsByFile))
|