@typed/vite-plugin 0.0.20 → 0.0.22
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/dist/prerender.d.ts +6 -0
- package/dist/prerender.d.ts.map +1 -0
- package/dist/prerender.js +44 -0
- package/dist/prerender.js.map +1 -0
- package/dist/staticHtmlPlugin.d.ts +2 -0
- package/dist/staticHtmlPlugin.d.ts.map +1 -0
- package/dist/staticHtmlPlugin.js +2 -0
- package/dist/staticHtmlPlugin.js.map +1 -0
- package/dist/vite-plugin.d.ts +63 -2
- package/dist/vite-plugin.d.ts.map +1 -1
- package/dist/vite-plugin.js +182 -58
- package/dist/vite-plugin.js.map +1 -1
- package/package.json +8 -4
- package/src/vite-plugin.ts +326 -67
- package/tsconfig.build.tsbuildinfo +1 -1
- package/tsconfig.json +3 -0
- package/dist/browser.d.ts +0 -3
- package/dist/browser.d.ts.map +0 -1
- package/dist/browser.js +0 -4
- package/dist/browser.js.map +0 -1
- package/dist/server.d.ts +0 -3
- package/dist/server.d.ts.map +0 -1
- package/dist/server.js +0 -4
- package/dist/server.js.map +0 -1
package/src/vite-plugin.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import { existsSync } from 'fs'
|
|
1
|
+
import { existsSync, readFileSync, writeFileSync } from 'fs'
|
|
2
2
|
import { readFile } from 'fs/promises'
|
|
3
|
-
import {
|
|
3
|
+
import { EOL } from 'os'
|
|
4
|
+
import { basename, dirname, join, relative, resolve } from 'path'
|
|
4
5
|
|
|
5
6
|
import effectTransformer from '@effect/language-service/transformer'
|
|
6
7
|
import {
|
|
@@ -11,12 +12,16 @@ import {
|
|
|
11
12
|
readModules,
|
|
12
13
|
readApiModules,
|
|
13
14
|
makeApiModule,
|
|
15
|
+
type ApiModuleTreeJson,
|
|
16
|
+
type ModuleTreeJsonWithFallback,
|
|
17
|
+
moduleTreeToJson,
|
|
18
|
+
apiModuleTreeToJson,
|
|
14
19
|
} from '@typed/compiler'
|
|
15
20
|
import glob from 'fast-glob'
|
|
16
21
|
import { Project, SourceFile, ts, type CompilerOptions } from 'ts-morph'
|
|
17
22
|
// @ts-expect-error Unable to resolve types w/ NodeNext
|
|
18
23
|
import vavite from 'vavite'
|
|
19
|
-
import type { ConfigEnv, Plugin, PluginOption, UserConfig, ViteDevServer } from 'vite'
|
|
24
|
+
import type { ConfigEnv, Logger, Plugin, PluginOption, UserConfig, ViteDevServer } from 'vite'
|
|
20
25
|
import compression from 'vite-plugin-compression'
|
|
21
26
|
import tsconfigPaths from 'vite-tsconfig-paths'
|
|
22
27
|
|
|
@@ -66,17 +71,28 @@ export interface PluginOptions {
|
|
|
66
71
|
* If true, will configure the plugin to save all the generated files to disk
|
|
67
72
|
*/
|
|
68
73
|
readonly saveGeneratedModules?: boolean
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* If true, will configure the plugin to operate in a static build mode.
|
|
77
|
+
*/
|
|
78
|
+
readonly isStaticBuild?: boolean
|
|
69
79
|
}
|
|
70
80
|
|
|
71
81
|
const cwd = process.cwd()
|
|
72
82
|
|
|
73
|
-
const PLUGIN_NAME = '@typed/vite-plugin'
|
|
83
|
+
export const PLUGIN_NAME = '@typed/vite-plugin'
|
|
84
|
+
|
|
85
|
+
export interface TypedVitePlugin extends Plugin {
|
|
86
|
+
readonly name: typeof PLUGIN_NAME
|
|
87
|
+
readonly resolvedOptions: ResolvedOptions
|
|
88
|
+
}
|
|
74
89
|
|
|
75
90
|
const RUNTIME_VIRTUAL_ENTRYPOINT_PREFIX = 'runtime'
|
|
76
91
|
const BROWSER_VIRTUAL_ENTRYPOINT_PREFIX = 'browser'
|
|
77
92
|
const HTML_VIRTUAL_ENTRYPOINT_PREFIX = 'html'
|
|
78
93
|
const API_VIRTUAL_ENTRYPOINT_PREFIX = 'api'
|
|
79
94
|
const EXPRESS_VIRTUAL_ENTRYPOINT_PREFIX = 'express'
|
|
95
|
+
const TYPED_CONFIG_IMPORT = 'typed:config'
|
|
80
96
|
|
|
81
97
|
const PREFIXES = [
|
|
82
98
|
RUNTIME_VIRTUAL_ENTRYPOINT_PREFIX,
|
|
@@ -88,6 +104,76 @@ const PREFIXES = [
|
|
|
88
104
|
|
|
89
105
|
const VIRTUAL_ID_PREFIX = '\0'
|
|
90
106
|
|
|
107
|
+
export interface Manifest {
|
|
108
|
+
readonly entryFiles: EntryFile[]
|
|
109
|
+
|
|
110
|
+
readonly modules: {
|
|
111
|
+
[importer: string]: Record<string, ManifestEntry>
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
export interface ClientManifest extends Manifest {
|
|
116
|
+
readonly entryFiles: HtmlEntryFile[]
|
|
117
|
+
|
|
118
|
+
readonly modules: {
|
|
119
|
+
[importer: string]: Record<string, ManifestEntry>
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
export type EntryFile = HtmlEntryFile | TsEntryFile
|
|
124
|
+
|
|
125
|
+
export interface HtmlEntryFile {
|
|
126
|
+
readonly type: 'html'
|
|
127
|
+
readonly filePath: string
|
|
128
|
+
readonly imports: string[]
|
|
129
|
+
readonly basePath: string
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
export interface TsEntryFile {
|
|
133
|
+
readonly type: 'ts'
|
|
134
|
+
readonly filePath: string
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
export type ManifestEntry =
|
|
138
|
+
| ApiManifestEntry
|
|
139
|
+
| ExpressManifestEntry
|
|
140
|
+
| HtmlManifestEntry
|
|
141
|
+
| RuntimeManifestEntry
|
|
142
|
+
| BrowserManifestEntry
|
|
143
|
+
|
|
144
|
+
export interface ApiManifestEntry extends ApiModuleTreeJson {
|
|
145
|
+
readonly type: 'api'
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
export interface ExpressManifestEntry extends ApiModuleTreeJson {
|
|
149
|
+
readonly type: 'express'
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
export interface HtmlManifestEntry {
|
|
153
|
+
readonly type: 'html'
|
|
154
|
+
readonly filePath: string
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
export interface BrowserManifestEntry extends ModuleTreeJsonWithFallback {
|
|
158
|
+
readonly type: 'browser'
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
export interface RuntimeManifestEntry extends ModuleTreeJsonWithFallback {
|
|
162
|
+
readonly type: 'runtime'
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
export interface ResolvedOptions {
|
|
166
|
+
readonly sourceDirectory: string
|
|
167
|
+
readonly tsConfig: string
|
|
168
|
+
readonly serverFilePath: string
|
|
169
|
+
readonly clientOutputDirectory: string
|
|
170
|
+
readonly serverOutputDirectory: string
|
|
171
|
+
readonly htmlFiles: readonly string[]
|
|
172
|
+
readonly debug: boolean
|
|
173
|
+
readonly saveGeneratedModules: boolean
|
|
174
|
+
readonly isStaticBuild: boolean
|
|
175
|
+
}
|
|
176
|
+
|
|
91
177
|
export default function makePlugin({
|
|
92
178
|
sourceDirectory: directory,
|
|
93
179
|
tsConfig,
|
|
@@ -97,6 +183,7 @@ export default function makePlugin({
|
|
|
97
183
|
htmlFileGlobs,
|
|
98
184
|
debug = false,
|
|
99
185
|
saveGeneratedModules = false,
|
|
186
|
+
isStaticBuild = false,
|
|
100
187
|
}: PluginOptions): PluginOption[] {
|
|
101
188
|
// Resolved options
|
|
102
189
|
const sourceDirectory = resolve(cwd, directory)
|
|
@@ -120,10 +207,38 @@ export default function makePlugin({
|
|
|
120
207
|
debug: debug ? defaultIncludeExcludeTs : {},
|
|
121
208
|
}
|
|
122
209
|
|
|
210
|
+
const resolvedOptions: ResolvedOptions = {
|
|
211
|
+
sourceDirectory,
|
|
212
|
+
tsConfig: tsConfigFilePath,
|
|
213
|
+
serverFilePath: resolvedServerFilePath,
|
|
214
|
+
serverOutputDirectory: resolvedServerOutputDirectory,
|
|
215
|
+
clientOutputDirectory: resolvedClientOutputDirectory,
|
|
216
|
+
htmlFiles: findHtmlFiles(sourceDirectory, htmlFileGlobs).map((p) =>
|
|
217
|
+
resolve(sourceDirectory, p),
|
|
218
|
+
),
|
|
219
|
+
debug,
|
|
220
|
+
saveGeneratedModules,
|
|
221
|
+
isStaticBuild,
|
|
222
|
+
}
|
|
223
|
+
|
|
123
224
|
const dependentsMap = new Map<string, Set<string>>()
|
|
124
225
|
const filePathToModule = new Map<string, SourceFile>()
|
|
226
|
+
const manifest: Manifest = {
|
|
227
|
+
entryFiles: [],
|
|
228
|
+
modules: {},
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
const addManifestEntry = (entry: ManifestEntry, importer: string, id: string) => {
|
|
232
|
+
if (!manifest.modules[importer]) {
|
|
233
|
+
manifest.modules[importer] = {}
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
manifest.modules[importer][id] = entry
|
|
237
|
+
}
|
|
125
238
|
|
|
126
239
|
let devServer: ViteDevServer
|
|
240
|
+
let logger: Logger
|
|
241
|
+
let isSsr = false
|
|
127
242
|
let project: Project
|
|
128
243
|
let transformers: ts.CustomTransformers
|
|
129
244
|
|
|
@@ -133,14 +248,12 @@ export default function makePlugin({
|
|
|
133
248
|
tsconfigPaths({
|
|
134
249
|
projects: [tsConfigFilePath],
|
|
135
250
|
}),
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
]
|
|
143
|
-
: []),
|
|
251
|
+
serverExists &&
|
|
252
|
+
!isStaticBuild &&
|
|
253
|
+
vavite({
|
|
254
|
+
serverEntry: resolvedServerFilePath,
|
|
255
|
+
serveClientAssetsInDev: true,
|
|
256
|
+
}),
|
|
144
257
|
]
|
|
145
258
|
|
|
146
259
|
const setupProject = () => {
|
|
@@ -148,9 +261,9 @@ export default function makePlugin({
|
|
|
148
261
|
return
|
|
149
262
|
}
|
|
150
263
|
|
|
151
|
-
info(`Setting up TypeScript project
|
|
264
|
+
info(`Setting up TypeScript project...`, logger)
|
|
152
265
|
project = setupTsProject(tsConfigFilePath)
|
|
153
|
-
info(`Setup TypeScript project
|
|
266
|
+
info(`Setup TypeScript project.`, logger)
|
|
154
267
|
|
|
155
268
|
// Setup transformer for virtual modules.
|
|
156
269
|
transformers = {
|
|
@@ -169,7 +282,9 @@ export default function makePlugin({
|
|
|
169
282
|
|
|
170
283
|
return {
|
|
171
284
|
...project.getCompilerOptions(),
|
|
172
|
-
|
|
285
|
+
inlineSourceMap: false,
|
|
286
|
+
inlineSources: saveGeneratedModules,
|
|
287
|
+
sourceMap: true,
|
|
173
288
|
}
|
|
174
289
|
}
|
|
175
290
|
|
|
@@ -196,7 +311,7 @@ export default function makePlugin({
|
|
|
196
311
|
const mod = devServer.moduleGraph.getModuleById(dependent)
|
|
197
312
|
|
|
198
313
|
if (mod) {
|
|
199
|
-
info(`reloading ${dependent}
|
|
314
|
+
info(`reloading ${dependent}`, logger)
|
|
200
315
|
|
|
201
316
|
await devServer.reloadModule(mod)
|
|
202
317
|
}
|
|
@@ -213,24 +328,32 @@ export default function makePlugin({
|
|
|
213
328
|
}
|
|
214
329
|
}
|
|
215
330
|
|
|
216
|
-
const
|
|
331
|
+
const buildRuntimeModule = async (importer: string, id: string) => {
|
|
217
332
|
const moduleDirectory = resolve(dirname(importer), parseModulesFromId(id, importer))
|
|
218
333
|
const relativeDirectory = relative(sourceDirectory, moduleDirectory)
|
|
219
334
|
const isBrowser = id.startsWith(BROWSER_VIRTUAL_ENTRYPOINT_PREFIX)
|
|
220
335
|
const moduleType = isBrowser ? 'browser' : 'runtime'
|
|
221
336
|
const filePath = `${moduleDirectory}.${moduleType}.__generated__.ts`
|
|
222
|
-
|
|
223
|
-
info(`Building ${moduleType} module for ${relativeDirectory}...`)
|
|
224
|
-
|
|
225
337
|
const directory = await readDirectory(moduleDirectory)
|
|
226
338
|
const moduleTree = readModules(project, directory)
|
|
227
339
|
|
|
340
|
+
addManifestEntry(
|
|
341
|
+
{
|
|
342
|
+
type: moduleType,
|
|
343
|
+
...moduleTreeToJson(sourceDirectory, moduleTree),
|
|
344
|
+
},
|
|
345
|
+
relative(sourceDirectory, importer),
|
|
346
|
+
id,
|
|
347
|
+
)
|
|
348
|
+
|
|
228
349
|
// Setup the TypeScript project if it hasn't been already
|
|
229
350
|
setupProject()
|
|
230
351
|
|
|
231
352
|
const sourceFile = makeRuntimeModule(project, moduleTree, importer, filePath, isBrowser)
|
|
232
353
|
|
|
233
|
-
|
|
354
|
+
addDependents(sourceFile)
|
|
355
|
+
|
|
356
|
+
info(`Built ${moduleType} module for ${relativeDirectory}.`, logger)
|
|
234
357
|
|
|
235
358
|
filePathToModule.set(filePath, sourceFile)
|
|
236
359
|
|
|
@@ -247,10 +370,8 @@ export default function makePlugin({
|
|
|
247
370
|
const relativeHtmlFilePath = relative(sourceDirectory, htmlFilePath)
|
|
248
371
|
let html = ''
|
|
249
372
|
|
|
250
|
-
info(`Building html module for ${relativeHtmlFilePath}...`)
|
|
251
|
-
|
|
252
373
|
// If there's a dev server, use it to transform the HTML for development
|
|
253
|
-
if (devServer) {
|
|
374
|
+
if (!isStaticBuild && devServer) {
|
|
254
375
|
html = (await readFile(htmlFilePath, 'utf-8')).toString()
|
|
255
376
|
html = await devServer.transformIndexHtml(
|
|
256
377
|
getRelativePath(sourceDirectory, htmlFilePath),
|
|
@@ -271,9 +392,21 @@ export default function makePlugin({
|
|
|
271
392
|
serverOutputDirectory: resolvedServerOutputDirectory,
|
|
272
393
|
clientOutputDirectory: resolvedClientOutputDirectory,
|
|
273
394
|
devServer,
|
|
395
|
+
isStaticBuild,
|
|
274
396
|
})
|
|
275
397
|
|
|
276
|
-
|
|
398
|
+
addManifestEntry(
|
|
399
|
+
{
|
|
400
|
+
type: 'html',
|
|
401
|
+
filePath: relativeHtmlFilePath,
|
|
402
|
+
},
|
|
403
|
+
relative(sourceDirectory, importer),
|
|
404
|
+
id,
|
|
405
|
+
)
|
|
406
|
+
|
|
407
|
+
addDependents(sourceFile)
|
|
408
|
+
|
|
409
|
+
info(`Built html module for ${relativeHtmlFilePath}.`, logger)
|
|
277
410
|
|
|
278
411
|
const filePath = sourceFile.getFilePath()
|
|
279
412
|
|
|
@@ -291,10 +424,7 @@ export default function makePlugin({
|
|
|
291
424
|
const moduleName = parseModulesFromId(id, importer)
|
|
292
425
|
const moduleDirectory = resolve(importDirectory, moduleName)
|
|
293
426
|
const relativeDirectory = relative(sourceDirectory, moduleDirectory)
|
|
294
|
-
const moduleType = id.startsWith(EXPRESS_VIRTUAL_ENTRYPOINT_PREFIX) ? 'express' : '
|
|
295
|
-
|
|
296
|
-
info(`Building ${moduleType} module for ${relativeDirectory}...`)
|
|
297
|
-
|
|
427
|
+
const moduleType = id.startsWith(EXPRESS_VIRTUAL_ENTRYPOINT_PREFIX) ? 'express' : 'api'
|
|
298
428
|
const directory = await readDirectory(moduleDirectory)
|
|
299
429
|
const moduleTree = readApiModules(project, directory)
|
|
300
430
|
const filePath = `${importDirectory}/${basename(
|
|
@@ -309,7 +439,18 @@ export default function makePlugin({
|
|
|
309
439
|
id.startsWith(EXPRESS_VIRTUAL_ENTRYPOINT_PREFIX),
|
|
310
440
|
)
|
|
311
441
|
|
|
312
|
-
|
|
442
|
+
addManifestEntry(
|
|
443
|
+
{
|
|
444
|
+
type: moduleType,
|
|
445
|
+
...apiModuleTreeToJson(sourceDirectory, moduleTree),
|
|
446
|
+
},
|
|
447
|
+
relative(sourceDirectory, importer),
|
|
448
|
+
id,
|
|
449
|
+
)
|
|
450
|
+
|
|
451
|
+
addDependents(sourceFile)
|
|
452
|
+
|
|
453
|
+
info(`Built ${moduleType} module for ${relativeDirectory}.`, logger)
|
|
313
454
|
|
|
314
455
|
filePathToModule.set(filePath, sourceFile)
|
|
315
456
|
|
|
@@ -320,17 +461,32 @@ export default function makePlugin({
|
|
|
320
461
|
return filePath
|
|
321
462
|
}
|
|
322
463
|
|
|
323
|
-
const
|
|
464
|
+
const addDependents = (sourceFile: SourceFile) => {
|
|
465
|
+
const importer = sourceFile.getFilePath()
|
|
466
|
+
const imports = sourceFile
|
|
467
|
+
.getLiteralsReferencingOtherSourceFiles()
|
|
468
|
+
.map((i) => i.getLiteralValue())
|
|
469
|
+
|
|
470
|
+
for (const i of imports) {
|
|
471
|
+
const dependents = dependentsMap.get(i) ?? new Set()
|
|
472
|
+
|
|
473
|
+
dependents.add(importer)
|
|
474
|
+
dependentsMap.set(i, dependents)
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
const virtualModulePlugin: TypedVitePlugin = {
|
|
324
479
|
name: PLUGIN_NAME,
|
|
480
|
+
resolvedOptions,
|
|
325
481
|
config(config: UserConfig, env: ConfigEnv) {
|
|
482
|
+
isSsr = env.ssrBuild ?? false
|
|
483
|
+
|
|
326
484
|
// Configure Build steps when running with vavite
|
|
327
485
|
if (env.mode === 'multibuild') {
|
|
328
486
|
const clientBuild: UserConfig['build'] = {
|
|
329
487
|
outDir: resolvedClientOutputDirectory,
|
|
330
488
|
rollupOptions: {
|
|
331
|
-
input: buildClientInput(
|
|
332
|
-
findHtmlFiles(sourceDirectory, htmlFileGlobs).map((p) => resolve(sourceDirectory, p)),
|
|
333
|
-
),
|
|
489
|
+
input: buildClientInput(resolvedOptions.htmlFiles),
|
|
334
490
|
},
|
|
335
491
|
}
|
|
336
492
|
|
|
@@ -338,7 +494,9 @@ export default function makePlugin({
|
|
|
338
494
|
ssr: true,
|
|
339
495
|
outDir: resolvedServerOutputDirectory,
|
|
340
496
|
rollupOptions: {
|
|
341
|
-
input:
|
|
497
|
+
input: {
|
|
498
|
+
index: resolvedServerFilePath,
|
|
499
|
+
},
|
|
342
500
|
},
|
|
343
501
|
}
|
|
344
502
|
|
|
@@ -362,6 +520,24 @@ export default function makePlugin({
|
|
|
362
520
|
}
|
|
363
521
|
},
|
|
364
522
|
|
|
523
|
+
configResolved(resolvedConfig) {
|
|
524
|
+
logger = resolvedConfig.logger
|
|
525
|
+
|
|
526
|
+
const input = resolvedConfig.build.rollupOptions.input
|
|
527
|
+
|
|
528
|
+
if (!input) return
|
|
529
|
+
|
|
530
|
+
if (typeof input === 'string') {
|
|
531
|
+
manifest.entryFiles.push(parseEntryFile(sourceDirectory, input))
|
|
532
|
+
} else if (Array.isArray(input)) {
|
|
533
|
+
manifest.entryFiles.push(...input.map((i) => parseEntryFile(sourceDirectory, i)))
|
|
534
|
+
} else {
|
|
535
|
+
manifest.entryFiles.push(
|
|
536
|
+
...Object.values(input).map((i) => parseEntryFile(sourceDirectory, i)),
|
|
537
|
+
)
|
|
538
|
+
}
|
|
539
|
+
},
|
|
540
|
+
|
|
365
541
|
configureServer(server) {
|
|
366
542
|
devServer = server
|
|
367
543
|
|
|
@@ -380,7 +556,7 @@ export default function makePlugin({
|
|
|
380
556
|
handleFileChange(path, event)
|
|
381
557
|
},
|
|
382
558
|
|
|
383
|
-
closeBundle() {
|
|
559
|
+
async closeBundle() {
|
|
384
560
|
if (project) {
|
|
385
561
|
const diagnostics = project.getPreEmitDiagnostics()
|
|
386
562
|
|
|
@@ -388,6 +564,16 @@ export default function makePlugin({
|
|
|
388
564
|
this.error(project.formatDiagnosticsWithColorAndContext(diagnostics))
|
|
389
565
|
}
|
|
390
566
|
}
|
|
567
|
+
|
|
568
|
+
if (Object.keys(manifest).length > 0) {
|
|
569
|
+
writeFileSync(
|
|
570
|
+
resolve(
|
|
571
|
+
isSsr ? resolvedServerOutputDirectory : resolvedClientOutputDirectory,
|
|
572
|
+
'typed-manifest.json',
|
|
573
|
+
),
|
|
574
|
+
JSON.stringify(manifest, null, 2) + EOL,
|
|
575
|
+
)
|
|
576
|
+
}
|
|
391
577
|
},
|
|
392
578
|
|
|
393
579
|
async resolveId(id: string, importer?: string) {
|
|
@@ -401,13 +587,17 @@ export default function makePlugin({
|
|
|
401
587
|
) {
|
|
402
588
|
setupProject()
|
|
403
589
|
|
|
404
|
-
|
|
590
|
+
const virtualId = VIRTUAL_ID_PREFIX + (await buildRuntimeModule(importer, id))
|
|
591
|
+
|
|
592
|
+
return virtualId
|
|
405
593
|
}
|
|
406
594
|
|
|
407
595
|
if (id.startsWith(HTML_VIRTUAL_ENTRYPOINT_PREFIX)) {
|
|
408
596
|
setupProject()
|
|
409
597
|
|
|
410
|
-
|
|
598
|
+
const virtualId = VIRTUAL_ID_PREFIX + (await buildHtmlModule(importer, id))
|
|
599
|
+
|
|
600
|
+
return virtualId
|
|
411
601
|
}
|
|
412
602
|
|
|
413
603
|
if (
|
|
@@ -416,7 +606,13 @@ export default function makePlugin({
|
|
|
416
606
|
) {
|
|
417
607
|
setupProject()
|
|
418
608
|
|
|
419
|
-
|
|
609
|
+
const virtualId = VIRTUAL_ID_PREFIX + (await buildApiModule(importer, id))
|
|
610
|
+
|
|
611
|
+
return virtualId
|
|
612
|
+
}
|
|
613
|
+
|
|
614
|
+
if (id === TYPED_CONFIG_IMPORT) {
|
|
615
|
+
return VIRTUAL_ID_PREFIX + TYPED_CONFIG_IMPORT
|
|
420
616
|
}
|
|
421
617
|
|
|
422
618
|
importer = importer.replace(VIRTUAL_ID_PREFIX, '')
|
|
@@ -434,24 +630,24 @@ export default function makePlugin({
|
|
|
434
630
|
const sourceFile = filePathToModule.get(id) ?? project?.getSourceFile(id)
|
|
435
631
|
|
|
436
632
|
if (sourceFile) {
|
|
437
|
-
logDiagnostics(project, sourceFile, sourceDirectory, id)
|
|
633
|
+
logDiagnostics(project, sourceFile, sourceDirectory, id, logger)
|
|
438
634
|
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
transformers,
|
|
444
|
-
})
|
|
635
|
+
return {
|
|
636
|
+
code: sourceFile.getFullText(),
|
|
637
|
+
}
|
|
638
|
+
}
|
|
445
639
|
|
|
640
|
+
if (id === TYPED_CONFIG_IMPORT) {
|
|
446
641
|
return {
|
|
447
|
-
code:
|
|
448
|
-
|
|
642
|
+
code: Object.entries(resolvedOptions)
|
|
643
|
+
.map(([key, value]) => `export const ${key} = ${JSON.stringify(value)}`)
|
|
644
|
+
.join(EOL),
|
|
449
645
|
}
|
|
450
646
|
}
|
|
451
647
|
},
|
|
452
648
|
|
|
453
649
|
transform(text: string, id: string) {
|
|
454
|
-
if (/.
|
|
650
|
+
if (/.[c|m]?tsx?$/.test(id)) {
|
|
455
651
|
const output = ts.transpileModule(text, {
|
|
456
652
|
fileName: id,
|
|
457
653
|
compilerOptions: transpilerCompilerOptions(),
|
|
@@ -464,7 +660,7 @@ export default function makePlugin({
|
|
|
464
660
|
}
|
|
465
661
|
}
|
|
466
662
|
},
|
|
467
|
-
}
|
|
663
|
+
}
|
|
468
664
|
|
|
469
665
|
plugins.push(virtualModulePlugin)
|
|
470
666
|
|
|
@@ -476,21 +672,21 @@ function logDiagnostics(
|
|
|
476
672
|
sourceFile: SourceFile,
|
|
477
673
|
sourceDirectory: string,
|
|
478
674
|
filePath: string,
|
|
675
|
+
logger: Logger | undefined,
|
|
479
676
|
) {
|
|
480
677
|
const diagnostics = sourceFile.getPreEmitDiagnostics()
|
|
481
678
|
const relativeFilePath = relative(sourceDirectory, filePath)
|
|
482
679
|
|
|
483
680
|
if (diagnostics.length > 0) {
|
|
484
|
-
info(
|
|
485
|
-
info(
|
|
486
|
-
|
|
487
|
-
info(`${relativeFilePath} module successfuly typed-checked.`)
|
|
681
|
+
info(`Type-checking errors found at ${relativeFilePath}`, logger)
|
|
682
|
+
info(`Source:` + EOL + sourceFile.getFullText(), logger)
|
|
683
|
+
info(project.formatDiagnosticsWithColorAndContext(diagnostics), logger)
|
|
488
684
|
}
|
|
489
685
|
}
|
|
490
686
|
|
|
491
687
|
function findRelativeFile(importer: string, id: string) {
|
|
492
688
|
const dir = dirname(importer)
|
|
493
|
-
const tsPath = resolve(dir, id.replace(/.js(x)?$/, '
|
|
689
|
+
const tsPath = resolve(dir, id.replace(/.([c|m])?js(x)?$/, '.$1ts$2'))
|
|
494
690
|
|
|
495
691
|
if (existsSync(tsPath)) {
|
|
496
692
|
return tsPath
|
|
@@ -530,15 +726,10 @@ function findHtmlFiles(directory: string, htmlFileGlobs?: readonly string[]): re
|
|
|
530
726
|
}
|
|
531
727
|
|
|
532
728
|
function buildClientInput(htmlFilePaths: readonly string[]) {
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
input[htmlFile] = htmlFilePath
|
|
539
|
-
}
|
|
540
|
-
|
|
541
|
-
return input
|
|
729
|
+
return htmlFilePaths.reduce(
|
|
730
|
+
(acc, htmlFilePath) => ({ ...acc, [basename(htmlFilePath, '.html')]: htmlFilePath }),
|
|
731
|
+
{},
|
|
732
|
+
)
|
|
542
733
|
}
|
|
543
734
|
|
|
544
735
|
function getRelativePath(from: string, to: string) {
|
|
@@ -551,8 +742,76 @@ function getRelativePath(from: string, to: string) {
|
|
|
551
742
|
return path
|
|
552
743
|
}
|
|
553
744
|
|
|
554
|
-
function info(message: string) {
|
|
555
|
-
|
|
745
|
+
function info(message: string, logger: Logger | undefined) {
|
|
746
|
+
if (logger) {
|
|
747
|
+
logger.info(`[${PLUGIN_NAME}]: ${message}`)
|
|
748
|
+
} else {
|
|
749
|
+
console.info(`[${PLUGIN_NAME}]:`, `${message}`)
|
|
750
|
+
}
|
|
751
|
+
}
|
|
752
|
+
|
|
753
|
+
function parseEntryFile(sourceDirectory: string, filePath: string): EntryFile {
|
|
754
|
+
if (filePath.endsWith('.html')) {
|
|
755
|
+
return parseHtmlEntryFile(sourceDirectory, filePath)
|
|
756
|
+
}
|
|
757
|
+
|
|
758
|
+
return parseTsEntryFile(sourceDirectory, filePath)
|
|
759
|
+
}
|
|
760
|
+
|
|
761
|
+
function parseHtmlEntryFile(sourceDirectory: string, filePath: string): EntryFile {
|
|
762
|
+
const content = readFileSync(filePath, 'utf-8').toString()
|
|
763
|
+
|
|
764
|
+
return {
|
|
765
|
+
type: 'html',
|
|
766
|
+
filePath: relative(sourceDirectory, filePath),
|
|
767
|
+
imports: parseHtmlImports(sourceDirectory, content),
|
|
768
|
+
basePath: parseBasePath(content),
|
|
769
|
+
}
|
|
770
|
+
}
|
|
771
|
+
|
|
772
|
+
function parseHtmlImports(sourceDirectory: string, content: string) {
|
|
773
|
+
const imports: string[] = []
|
|
774
|
+
|
|
775
|
+
const matches = content.match(/<script[^>]*src="([^"]*)"[^>]*>/g)
|
|
776
|
+
|
|
777
|
+
if (matches) {
|
|
778
|
+
for (const match of matches) {
|
|
779
|
+
// If script is not type=module then skip
|
|
780
|
+
if (!match.includes('type="module"')) {
|
|
781
|
+
continue
|
|
782
|
+
}
|
|
783
|
+
|
|
784
|
+
const src = match.match(/src="([^"]*)"/)?.[1]
|
|
556
785
|
|
|
557
|
-
|
|
786
|
+
if (src) {
|
|
787
|
+
const fullPath = join(sourceDirectory, src)
|
|
788
|
+
const relativePath = relative(sourceDirectory, fullPath)
|
|
789
|
+
|
|
790
|
+
imports.push(relativePath)
|
|
791
|
+
}
|
|
792
|
+
}
|
|
793
|
+
}
|
|
794
|
+
|
|
795
|
+
return imports
|
|
796
|
+
}
|
|
797
|
+
|
|
798
|
+
function parseBasePath(content: string) {
|
|
799
|
+
const baseTag = content.match(/<base[^>]*>/)?.[0]
|
|
800
|
+
|
|
801
|
+
if (baseTag) {
|
|
802
|
+
const href = baseTag.match(/href="([^"]*)"/)?.[1]
|
|
803
|
+
|
|
804
|
+
if (href) {
|
|
805
|
+
return href
|
|
806
|
+
}
|
|
807
|
+
}
|
|
808
|
+
|
|
809
|
+
return '/'
|
|
810
|
+
}
|
|
811
|
+
|
|
812
|
+
function parseTsEntryFile(sourceDirectory: string, filePath: string): EntryFile {
|
|
813
|
+
return {
|
|
814
|
+
type: 'ts',
|
|
815
|
+
filePath: relative(sourceDirectory, filePath),
|
|
816
|
+
}
|
|
558
817
|
}
|