@typed/vite-plugin 0.0.19 → 0.0.21
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 +185 -58
- package/dist/vite-plugin.js.map +1 -1
- package/package.json +8 -4
- package/src/vite-plugin.ts +331 -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,6 @@ export default function makePlugin({
|
|
|
133
248
|
tsconfigPaths({
|
|
134
249
|
projects: [tsConfigFilePath],
|
|
135
250
|
}),
|
|
136
|
-
...(serverExists
|
|
137
|
-
? [
|
|
138
|
-
vavite({
|
|
139
|
-
serverEntry: resolvedServerFilePath,
|
|
140
|
-
serveClientAssetsInDev: true,
|
|
141
|
-
}),
|
|
142
|
-
]
|
|
143
|
-
: []),
|
|
144
251
|
]
|
|
145
252
|
|
|
146
253
|
const setupProject = () => {
|
|
@@ -148,9 +255,9 @@ export default function makePlugin({
|
|
|
148
255
|
return
|
|
149
256
|
}
|
|
150
257
|
|
|
151
|
-
info(`Setting up TypeScript project
|
|
258
|
+
info(`Setting up TypeScript project...`, logger)
|
|
152
259
|
project = setupTsProject(tsConfigFilePath)
|
|
153
|
-
info(`Setup TypeScript project
|
|
260
|
+
info(`Setup TypeScript project.`, logger)
|
|
154
261
|
|
|
155
262
|
// Setup transformer for virtual modules.
|
|
156
263
|
transformers = {
|
|
@@ -169,7 +276,9 @@ export default function makePlugin({
|
|
|
169
276
|
|
|
170
277
|
return {
|
|
171
278
|
...project.getCompilerOptions(),
|
|
172
|
-
|
|
279
|
+
inlineSourceMap: false,
|
|
280
|
+
inlineSources: saveGeneratedModules,
|
|
281
|
+
sourceMap: true,
|
|
173
282
|
}
|
|
174
283
|
}
|
|
175
284
|
|
|
@@ -196,7 +305,7 @@ export default function makePlugin({
|
|
|
196
305
|
const mod = devServer.moduleGraph.getModuleById(dependent)
|
|
197
306
|
|
|
198
307
|
if (mod) {
|
|
199
|
-
info(`reloading ${dependent}
|
|
308
|
+
info(`reloading ${dependent}`, logger)
|
|
200
309
|
|
|
201
310
|
await devServer.reloadModule(mod)
|
|
202
311
|
}
|
|
@@ -213,24 +322,32 @@ export default function makePlugin({
|
|
|
213
322
|
}
|
|
214
323
|
}
|
|
215
324
|
|
|
216
|
-
const
|
|
325
|
+
const buildRuntimeModule = async (importer: string, id: string) => {
|
|
217
326
|
const moduleDirectory = resolve(dirname(importer), parseModulesFromId(id, importer))
|
|
218
327
|
const relativeDirectory = relative(sourceDirectory, moduleDirectory)
|
|
219
328
|
const isBrowser = id.startsWith(BROWSER_VIRTUAL_ENTRYPOINT_PREFIX)
|
|
220
329
|
const moduleType = isBrowser ? 'browser' : 'runtime'
|
|
221
330
|
const filePath = `${moduleDirectory}.${moduleType}.__generated__.ts`
|
|
222
|
-
|
|
223
|
-
info(`Building ${moduleType} module for ${relativeDirectory}...`)
|
|
224
|
-
|
|
225
331
|
const directory = await readDirectory(moduleDirectory)
|
|
226
332
|
const moduleTree = readModules(project, directory)
|
|
227
333
|
|
|
334
|
+
addManifestEntry(
|
|
335
|
+
{
|
|
336
|
+
type: moduleType,
|
|
337
|
+
...moduleTreeToJson(sourceDirectory, moduleTree),
|
|
338
|
+
},
|
|
339
|
+
relative(sourceDirectory, importer),
|
|
340
|
+
id,
|
|
341
|
+
)
|
|
342
|
+
|
|
228
343
|
// Setup the TypeScript project if it hasn't been already
|
|
229
344
|
setupProject()
|
|
230
345
|
|
|
231
346
|
const sourceFile = makeRuntimeModule(project, moduleTree, importer, filePath, isBrowser)
|
|
232
347
|
|
|
233
|
-
|
|
348
|
+
addDependents(sourceFile)
|
|
349
|
+
|
|
350
|
+
info(`Built ${moduleType} module for ${relativeDirectory}.`, logger)
|
|
234
351
|
|
|
235
352
|
filePathToModule.set(filePath, sourceFile)
|
|
236
353
|
|
|
@@ -247,10 +364,8 @@ export default function makePlugin({
|
|
|
247
364
|
const relativeHtmlFilePath = relative(sourceDirectory, htmlFilePath)
|
|
248
365
|
let html = ''
|
|
249
366
|
|
|
250
|
-
info(`Building html module for ${relativeHtmlFilePath}...`)
|
|
251
|
-
|
|
252
367
|
// If there's a dev server, use it to transform the HTML for development
|
|
253
|
-
if (devServer) {
|
|
368
|
+
if (!isStaticBuild && devServer) {
|
|
254
369
|
html = (await readFile(htmlFilePath, 'utf-8')).toString()
|
|
255
370
|
html = await devServer.transformIndexHtml(
|
|
256
371
|
getRelativePath(sourceDirectory, htmlFilePath),
|
|
@@ -271,9 +386,21 @@ export default function makePlugin({
|
|
|
271
386
|
serverOutputDirectory: resolvedServerOutputDirectory,
|
|
272
387
|
clientOutputDirectory: resolvedClientOutputDirectory,
|
|
273
388
|
devServer,
|
|
389
|
+
isStaticBuild,
|
|
274
390
|
})
|
|
275
391
|
|
|
276
|
-
|
|
392
|
+
addManifestEntry(
|
|
393
|
+
{
|
|
394
|
+
type: 'html',
|
|
395
|
+
filePath: relativeHtmlFilePath,
|
|
396
|
+
},
|
|
397
|
+
relative(sourceDirectory, importer),
|
|
398
|
+
id,
|
|
399
|
+
)
|
|
400
|
+
|
|
401
|
+
addDependents(sourceFile)
|
|
402
|
+
|
|
403
|
+
info(`Built html module for ${relativeHtmlFilePath}.`, logger)
|
|
277
404
|
|
|
278
405
|
const filePath = sourceFile.getFilePath()
|
|
279
406
|
|
|
@@ -291,10 +418,7 @@ export default function makePlugin({
|
|
|
291
418
|
const moduleName = parseModulesFromId(id, importer)
|
|
292
419
|
const moduleDirectory = resolve(importDirectory, moduleName)
|
|
293
420
|
const relativeDirectory = relative(sourceDirectory, moduleDirectory)
|
|
294
|
-
const moduleType = id.startsWith(EXPRESS_VIRTUAL_ENTRYPOINT_PREFIX) ? 'express' : '
|
|
295
|
-
|
|
296
|
-
info(`Building ${moduleType} module for ${relativeDirectory}...`)
|
|
297
|
-
|
|
421
|
+
const moduleType = id.startsWith(EXPRESS_VIRTUAL_ENTRYPOINT_PREFIX) ? 'express' : 'api'
|
|
298
422
|
const directory = await readDirectory(moduleDirectory)
|
|
299
423
|
const moduleTree = readApiModules(project, directory)
|
|
300
424
|
const filePath = `${importDirectory}/${basename(
|
|
@@ -309,7 +433,18 @@ export default function makePlugin({
|
|
|
309
433
|
id.startsWith(EXPRESS_VIRTUAL_ENTRYPOINT_PREFIX),
|
|
310
434
|
)
|
|
311
435
|
|
|
312
|
-
|
|
436
|
+
addManifestEntry(
|
|
437
|
+
{
|
|
438
|
+
type: moduleType,
|
|
439
|
+
...apiModuleTreeToJson(sourceDirectory, moduleTree),
|
|
440
|
+
},
|
|
441
|
+
relative(sourceDirectory, importer),
|
|
442
|
+
id,
|
|
443
|
+
)
|
|
444
|
+
|
|
445
|
+
addDependents(sourceFile)
|
|
446
|
+
|
|
447
|
+
info(`Built ${moduleType} module for ${relativeDirectory}.`, logger)
|
|
313
448
|
|
|
314
449
|
filePathToModule.set(filePath, sourceFile)
|
|
315
450
|
|
|
@@ -320,17 +455,32 @@ export default function makePlugin({
|
|
|
320
455
|
return filePath
|
|
321
456
|
}
|
|
322
457
|
|
|
323
|
-
const
|
|
458
|
+
const addDependents = (sourceFile: SourceFile) => {
|
|
459
|
+
const importer = sourceFile.getFilePath()
|
|
460
|
+
const imports = sourceFile
|
|
461
|
+
.getLiteralsReferencingOtherSourceFiles()
|
|
462
|
+
.map((i) => i.getLiteralValue())
|
|
463
|
+
|
|
464
|
+
for (const i of imports) {
|
|
465
|
+
const dependents = dependentsMap.get(i) ?? new Set()
|
|
466
|
+
|
|
467
|
+
dependents.add(importer)
|
|
468
|
+
dependentsMap.set(i, dependents)
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
const virtualModulePlugin: TypedVitePlugin = {
|
|
324
473
|
name: PLUGIN_NAME,
|
|
474
|
+
resolvedOptions,
|
|
325
475
|
config(config: UserConfig, env: ConfigEnv) {
|
|
476
|
+
isSsr = env.ssrBuild ?? false
|
|
477
|
+
|
|
326
478
|
// Configure Build steps when running with vavite
|
|
327
479
|
if (env.mode === 'multibuild') {
|
|
328
480
|
const clientBuild: UserConfig['build'] = {
|
|
329
481
|
outDir: resolvedClientOutputDirectory,
|
|
330
482
|
rollupOptions: {
|
|
331
|
-
input: buildClientInput(
|
|
332
|
-
findHtmlFiles(sourceDirectory, htmlFileGlobs).map((p) => resolve(sourceDirectory, p)),
|
|
333
|
-
),
|
|
483
|
+
input: buildClientInput(resolvedOptions.htmlFiles),
|
|
334
484
|
},
|
|
335
485
|
}
|
|
336
486
|
|
|
@@ -338,7 +488,9 @@ export default function makePlugin({
|
|
|
338
488
|
ssr: true,
|
|
339
489
|
outDir: resolvedServerOutputDirectory,
|
|
340
490
|
rollupOptions: {
|
|
341
|
-
input:
|
|
491
|
+
input: {
|
|
492
|
+
index: resolvedServerFilePath,
|
|
493
|
+
},
|
|
342
494
|
},
|
|
343
495
|
}
|
|
344
496
|
|
|
@@ -360,6 +512,35 @@ export default function makePlugin({
|
|
|
360
512
|
|
|
361
513
|
return
|
|
362
514
|
}
|
|
515
|
+
|
|
516
|
+
if (serverExists) {
|
|
517
|
+
config.plugins?.push(
|
|
518
|
+
vavite({
|
|
519
|
+
serverEntry: resolvedServerFilePath,
|
|
520
|
+
serveClientAssetsInDev: true,
|
|
521
|
+
}),
|
|
522
|
+
)
|
|
523
|
+
} else {
|
|
524
|
+
// TODO: Add vavite plugins without reloader
|
|
525
|
+
}
|
|
526
|
+
},
|
|
527
|
+
|
|
528
|
+
configResolved(resolvedConfig) {
|
|
529
|
+
logger = resolvedConfig.logger
|
|
530
|
+
|
|
531
|
+
const input = resolvedConfig.build.rollupOptions.input
|
|
532
|
+
|
|
533
|
+
if (!input) return
|
|
534
|
+
|
|
535
|
+
if (typeof input === 'string') {
|
|
536
|
+
manifest.entryFiles.push(parseEntryFile(sourceDirectory, input))
|
|
537
|
+
} else if (Array.isArray(input)) {
|
|
538
|
+
manifest.entryFiles.push(...input.map((i) => parseEntryFile(sourceDirectory, i)))
|
|
539
|
+
} else {
|
|
540
|
+
manifest.entryFiles.push(
|
|
541
|
+
...Object.values(input).map((i) => parseEntryFile(sourceDirectory, i)),
|
|
542
|
+
)
|
|
543
|
+
}
|
|
363
544
|
},
|
|
364
545
|
|
|
365
546
|
configureServer(server) {
|
|
@@ -380,7 +561,7 @@ export default function makePlugin({
|
|
|
380
561
|
handleFileChange(path, event)
|
|
381
562
|
},
|
|
382
563
|
|
|
383
|
-
closeBundle() {
|
|
564
|
+
async closeBundle() {
|
|
384
565
|
if (project) {
|
|
385
566
|
const diagnostics = project.getPreEmitDiagnostics()
|
|
386
567
|
|
|
@@ -388,6 +569,16 @@ export default function makePlugin({
|
|
|
388
569
|
this.error(project.formatDiagnosticsWithColorAndContext(diagnostics))
|
|
389
570
|
}
|
|
390
571
|
}
|
|
572
|
+
|
|
573
|
+
if (Object.keys(manifest).length > 0) {
|
|
574
|
+
writeFileSync(
|
|
575
|
+
resolve(
|
|
576
|
+
isSsr ? resolvedServerOutputDirectory : resolvedClientOutputDirectory,
|
|
577
|
+
'typed-manifest.json',
|
|
578
|
+
),
|
|
579
|
+
JSON.stringify(manifest, null, 2) + EOL,
|
|
580
|
+
)
|
|
581
|
+
}
|
|
391
582
|
},
|
|
392
583
|
|
|
393
584
|
async resolveId(id: string, importer?: string) {
|
|
@@ -401,13 +592,17 @@ export default function makePlugin({
|
|
|
401
592
|
) {
|
|
402
593
|
setupProject()
|
|
403
594
|
|
|
404
|
-
|
|
595
|
+
const virtualId = VIRTUAL_ID_PREFIX + (await buildRuntimeModule(importer, id))
|
|
596
|
+
|
|
597
|
+
return virtualId
|
|
405
598
|
}
|
|
406
599
|
|
|
407
600
|
if (id.startsWith(HTML_VIRTUAL_ENTRYPOINT_PREFIX)) {
|
|
408
601
|
setupProject()
|
|
409
602
|
|
|
410
|
-
|
|
603
|
+
const virtualId = VIRTUAL_ID_PREFIX + (await buildHtmlModule(importer, id))
|
|
604
|
+
|
|
605
|
+
return virtualId
|
|
411
606
|
}
|
|
412
607
|
|
|
413
608
|
if (
|
|
@@ -416,7 +611,13 @@ export default function makePlugin({
|
|
|
416
611
|
) {
|
|
417
612
|
setupProject()
|
|
418
613
|
|
|
419
|
-
|
|
614
|
+
const virtualId = VIRTUAL_ID_PREFIX + (await buildApiModule(importer, id))
|
|
615
|
+
|
|
616
|
+
return virtualId
|
|
617
|
+
}
|
|
618
|
+
|
|
619
|
+
if (id === TYPED_CONFIG_IMPORT) {
|
|
620
|
+
return VIRTUAL_ID_PREFIX + TYPED_CONFIG_IMPORT
|
|
420
621
|
}
|
|
421
622
|
|
|
422
623
|
importer = importer.replace(VIRTUAL_ID_PREFIX, '')
|
|
@@ -434,24 +635,24 @@ export default function makePlugin({
|
|
|
434
635
|
const sourceFile = filePathToModule.get(id) ?? project?.getSourceFile(id)
|
|
435
636
|
|
|
436
637
|
if (sourceFile) {
|
|
437
|
-
logDiagnostics(project, sourceFile, sourceDirectory, id)
|
|
638
|
+
logDiagnostics(project, sourceFile, sourceDirectory, id, logger)
|
|
438
639
|
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
transformers,
|
|
444
|
-
})
|
|
640
|
+
return {
|
|
641
|
+
code: sourceFile.getFullText(),
|
|
642
|
+
}
|
|
643
|
+
}
|
|
445
644
|
|
|
645
|
+
if (id === TYPED_CONFIG_IMPORT) {
|
|
446
646
|
return {
|
|
447
|
-
code:
|
|
448
|
-
|
|
647
|
+
code: Object.entries(resolvedOptions)
|
|
648
|
+
.map(([key, value]) => `export const ${key} = ${JSON.stringify(value)}`)
|
|
649
|
+
.join(EOL),
|
|
449
650
|
}
|
|
450
651
|
}
|
|
451
652
|
},
|
|
452
653
|
|
|
453
654
|
transform(text: string, id: string) {
|
|
454
|
-
if (/.
|
|
655
|
+
if (/.[c|m]?tsx?$/.test(id)) {
|
|
455
656
|
const output = ts.transpileModule(text, {
|
|
456
657
|
fileName: id,
|
|
457
658
|
compilerOptions: transpilerCompilerOptions(),
|
|
@@ -464,7 +665,7 @@ export default function makePlugin({
|
|
|
464
665
|
}
|
|
465
666
|
}
|
|
466
667
|
},
|
|
467
|
-
}
|
|
668
|
+
}
|
|
468
669
|
|
|
469
670
|
plugins.push(virtualModulePlugin)
|
|
470
671
|
|
|
@@ -476,21 +677,21 @@ function logDiagnostics(
|
|
|
476
677
|
sourceFile: SourceFile,
|
|
477
678
|
sourceDirectory: string,
|
|
478
679
|
filePath: string,
|
|
680
|
+
logger: Logger | undefined,
|
|
479
681
|
) {
|
|
480
682
|
const diagnostics = sourceFile.getPreEmitDiagnostics()
|
|
481
683
|
const relativeFilePath = relative(sourceDirectory, filePath)
|
|
482
684
|
|
|
483
685
|
if (diagnostics.length > 0) {
|
|
484
|
-
info(
|
|
485
|
-
info(
|
|
486
|
-
|
|
487
|
-
info(`${relativeFilePath} module successfuly typed-checked.`)
|
|
686
|
+
info(`Type-checking errors found at ${relativeFilePath}`, logger)
|
|
687
|
+
info(`Source:` + EOL + sourceFile.getFullText(), logger)
|
|
688
|
+
info(project.formatDiagnosticsWithColorAndContext(diagnostics), logger)
|
|
488
689
|
}
|
|
489
690
|
}
|
|
490
691
|
|
|
491
692
|
function findRelativeFile(importer: string, id: string) {
|
|
492
693
|
const dir = dirname(importer)
|
|
493
|
-
const tsPath = resolve(dir, id.replace(/.js(x)?$/, '
|
|
694
|
+
const tsPath = resolve(dir, id.replace(/.([c|m])?js(x)?$/, '.$1ts$2'))
|
|
494
695
|
|
|
495
696
|
if (existsSync(tsPath)) {
|
|
496
697
|
return tsPath
|
|
@@ -530,15 +731,10 @@ function findHtmlFiles(directory: string, htmlFileGlobs?: readonly string[]): re
|
|
|
530
731
|
}
|
|
531
732
|
|
|
532
733
|
function buildClientInput(htmlFilePaths: readonly string[]) {
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
input[htmlFile] = htmlFilePath
|
|
539
|
-
}
|
|
540
|
-
|
|
541
|
-
return input
|
|
734
|
+
return htmlFilePaths.reduce(
|
|
735
|
+
(acc, htmlFilePath) => ({ ...acc, [basename(htmlFilePath, '.html')]: htmlFilePath }),
|
|
736
|
+
{},
|
|
737
|
+
)
|
|
542
738
|
}
|
|
543
739
|
|
|
544
740
|
function getRelativePath(from: string, to: string) {
|
|
@@ -551,8 +747,76 @@ function getRelativePath(from: string, to: string) {
|
|
|
551
747
|
return path
|
|
552
748
|
}
|
|
553
749
|
|
|
554
|
-
function info(message: string) {
|
|
555
|
-
|
|
750
|
+
function info(message: string, logger: Logger | undefined) {
|
|
751
|
+
if (logger) {
|
|
752
|
+
logger.info(`[${PLUGIN_NAME}]: ${message}`)
|
|
753
|
+
} else {
|
|
754
|
+
console.info(`[${PLUGIN_NAME}]:`, `${message}`)
|
|
755
|
+
}
|
|
756
|
+
}
|
|
757
|
+
|
|
758
|
+
function parseEntryFile(sourceDirectory: string, filePath: string): EntryFile {
|
|
759
|
+
if (filePath.endsWith('.html')) {
|
|
760
|
+
return parseHtmlEntryFile(sourceDirectory, filePath)
|
|
761
|
+
}
|
|
762
|
+
|
|
763
|
+
return parseTsEntryFile(sourceDirectory, filePath)
|
|
764
|
+
}
|
|
765
|
+
|
|
766
|
+
function parseHtmlEntryFile(sourceDirectory: string, filePath: string): EntryFile {
|
|
767
|
+
const content = readFileSync(filePath, 'utf-8').toString()
|
|
768
|
+
|
|
769
|
+
return {
|
|
770
|
+
type: 'html',
|
|
771
|
+
filePath: relative(sourceDirectory, filePath),
|
|
772
|
+
imports: parseHtmlImports(sourceDirectory, content),
|
|
773
|
+
basePath: parseBasePath(content),
|
|
774
|
+
}
|
|
775
|
+
}
|
|
776
|
+
|
|
777
|
+
function parseHtmlImports(sourceDirectory: string, content: string) {
|
|
778
|
+
const imports: string[] = []
|
|
779
|
+
|
|
780
|
+
const matches = content.match(/<script[^>]*src="([^"]*)"[^>]*>/g)
|
|
781
|
+
|
|
782
|
+
if (matches) {
|
|
783
|
+
for (const match of matches) {
|
|
784
|
+
// If script is not type=module then skip
|
|
785
|
+
if (!match.includes('type="module"')) {
|
|
786
|
+
continue
|
|
787
|
+
}
|
|
556
788
|
|
|
557
|
-
|
|
789
|
+
const src = match.match(/src="([^"]*)"/)?.[1]
|
|
790
|
+
|
|
791
|
+
if (src) {
|
|
792
|
+
const fullPath = join(sourceDirectory, src)
|
|
793
|
+
const relativePath = relative(sourceDirectory, fullPath)
|
|
794
|
+
|
|
795
|
+
imports.push(relativePath)
|
|
796
|
+
}
|
|
797
|
+
}
|
|
798
|
+
}
|
|
799
|
+
|
|
800
|
+
return imports
|
|
801
|
+
}
|
|
802
|
+
|
|
803
|
+
function parseBasePath(content: string) {
|
|
804
|
+
const baseTag = content.match(/<base[^>]*>/)?.[0]
|
|
805
|
+
|
|
806
|
+
if (baseTag) {
|
|
807
|
+
const href = baseTag.match(/href="([^"]*)"/)?.[1]
|
|
808
|
+
|
|
809
|
+
if (href) {
|
|
810
|
+
return href
|
|
811
|
+
}
|
|
812
|
+
}
|
|
813
|
+
|
|
814
|
+
return '/'
|
|
815
|
+
}
|
|
816
|
+
|
|
817
|
+
function parseTsEntryFile(sourceDirectory: string, filePath: string): EntryFile {
|
|
818
|
+
return {
|
|
819
|
+
type: 'ts',
|
|
820
|
+
filePath: relative(sourceDirectory, filePath),
|
|
821
|
+
}
|
|
558
822
|
}
|