@typed/vite-plugin 0.0.11 → 0.0.12
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/index.d.ts +0 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +0 -2
- package/dist/index.js.map +1 -1
- package/dist/vite-plugin.d.ts +25 -8
- package/dist/vite-plugin.d.ts.map +1 -1
- package/dist/vite-plugin.js +287 -87
- package/dist/vite-plugin.js.map +1 -1
- package/package.json +8 -7
- package/src/index.ts +0 -3
- package/src/vite-plugin.ts +422 -105
- package/tsconfig.build.tsbuildinfo +1 -1
- package/tsconfig.json +0 -3
- package/src/browser.ts +0 -4
- package/src/server.ts +0 -4
- package/src/virtual-modules.d.ts +0 -39
package/src/vite-plugin.ts
CHANGED
|
@@ -1,164 +1,481 @@
|
|
|
1
1
|
import { existsSync } from 'fs'
|
|
2
|
-
import {
|
|
2
|
+
import { readFile } from 'fs/promises'
|
|
3
|
+
import { basename, dirname, join, relative, resolve } from 'path'
|
|
3
4
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
5
|
+
import {
|
|
6
|
+
setupTsProject,
|
|
7
|
+
makeBrowserModule,
|
|
8
|
+
makeHtmlModule,
|
|
9
|
+
makeRuntimeModule,
|
|
10
|
+
readDirectory,
|
|
11
|
+
readModules,
|
|
12
|
+
} from '@typed/compiler'
|
|
13
|
+
import glob from 'fast-glob'
|
|
14
|
+
import { Project, SourceFile, ts } from 'ts-morph'
|
|
15
|
+
// @ts-expect-error Unable to resolve types w/ NodeNext
|
|
16
|
+
import vavite from 'vavite'
|
|
17
|
+
import { ConfigEnv, Plugin, PluginOption, UserConfig, ViteDevServer } from 'vite'
|
|
18
|
+
import compression from 'vite-plugin-compression'
|
|
12
19
|
import tsconfigPaths from 'vite-tsconfig-paths'
|
|
13
20
|
|
|
21
|
+
/**
|
|
22
|
+
* The Configuration for the Typed Plugin. All file paths can be relative to sourceDirectory or
|
|
23
|
+
* can be absolute, path.resolve is used to stitch things together.
|
|
24
|
+
*/
|
|
14
25
|
export interface PluginOptions {
|
|
15
26
|
/**
|
|
16
|
-
* The directory in which you have your
|
|
27
|
+
* The directory in which you have your application.
|
|
28
|
+
* This can be relative to the current working directory or absolute.
|
|
29
|
+
*/
|
|
30
|
+
readonly sourceDirectory: string
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* The file path to your tsconfig.json file.
|
|
34
|
+
*/
|
|
35
|
+
readonly tsConfig?: string
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* The file path to your server entry file
|
|
39
|
+
*/
|
|
40
|
+
readonly serverFilePath?: string
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* The output directory for your client code
|
|
17
44
|
*/
|
|
18
|
-
readonly
|
|
45
|
+
readonly clientOutputDirectory?: string
|
|
46
|
+
|
|
19
47
|
/**
|
|
20
|
-
* The
|
|
48
|
+
* The output directory for your server code
|
|
21
49
|
*/
|
|
22
|
-
readonly
|
|
50
|
+
readonly serverOutputDirectory?: string
|
|
51
|
+
|
|
23
52
|
/**
|
|
24
|
-
* File globs to
|
|
53
|
+
* File globs to use to look for your HTML entry points.
|
|
25
54
|
*/
|
|
26
|
-
readonly
|
|
55
|
+
readonly htmlFileGlobs?: readonly string[]
|
|
27
56
|
}
|
|
28
57
|
|
|
29
58
|
const cwd = process.cwd()
|
|
30
59
|
|
|
31
60
|
const PLUGIN_NAME = '@typed/vite-plugin'
|
|
32
|
-
const BROWSER_VIRTUAL_ENTRYPOINT = 'virtual:browser-entry'
|
|
33
|
-
const SERVER_VIRTUAL_ENTRYPOINT = 'virtual:server-entry'
|
|
34
61
|
|
|
35
|
-
|
|
62
|
+
const RUNTIME_VIRTUAL_ENTRYPOINT_PREFIX = 'runtime'
|
|
63
|
+
const BROWSER_VIRTUAL_ENTRYPOINT_PREFIX = 'browser'
|
|
64
|
+
const HTML_VIRTUAL_ENTRYPOINT_PREFIX = 'html'
|
|
65
|
+
|
|
66
|
+
const VIRTUAL_ID_PREFIX = '\0'
|
|
67
|
+
|
|
68
|
+
export default function makePlugin({
|
|
69
|
+
sourceDirectory: directory,
|
|
70
|
+
tsConfig,
|
|
71
|
+
serverFilePath,
|
|
72
|
+
clientOutputDirectory,
|
|
73
|
+
serverOutputDirectory,
|
|
74
|
+
htmlFileGlobs,
|
|
75
|
+
}: PluginOptions): PluginOption[] {
|
|
76
|
+
// Resolved options
|
|
36
77
|
const sourceDirectory = resolve(cwd, directory)
|
|
37
|
-
const tsConfigFilePath = resolve(sourceDirectory, tsConfig)
|
|
78
|
+
const tsConfigFilePath = resolve(sourceDirectory, tsConfig ?? 'tsconfig.json')
|
|
79
|
+
const resolvedServerFilePath = resolve(sourceDirectory, serverFilePath ?? 'server.ts')
|
|
80
|
+
const resolvedServerOutputDirectory = resolve(
|
|
81
|
+
sourceDirectory,
|
|
82
|
+
serverOutputDirectory ?? 'dist/server',
|
|
83
|
+
)
|
|
84
|
+
const resolvedClientOutputDirectory = resolve(
|
|
85
|
+
sourceDirectory,
|
|
86
|
+
clientOutputDirectory ?? 'dist/client',
|
|
87
|
+
)
|
|
38
88
|
|
|
39
|
-
console.
|
|
40
|
-
|
|
89
|
+
console.log(
|
|
90
|
+
sourceDirectory,
|
|
91
|
+
tsConfigFilePath,
|
|
92
|
+
resolvedServerFilePath,
|
|
93
|
+
resolvedServerOutputDirectory,
|
|
94
|
+
resolvedClientOutputDirectory,
|
|
95
|
+
)
|
|
96
|
+
|
|
97
|
+
const virtualIds = new Set<string>()
|
|
98
|
+
const dependentsMap = new Map<string, Set<string>>()
|
|
99
|
+
const sourceFilePathToVirtualId = new Map<string, string>()
|
|
100
|
+
let devServer: ViteDevServer
|
|
101
|
+
let project: Project
|
|
41
102
|
|
|
42
|
-
const
|
|
43
|
-
|
|
103
|
+
const serverExists = existsSync(resolvedServerFilePath)
|
|
104
|
+
|
|
105
|
+
const plugins: PluginOption[] = [
|
|
106
|
+
tsconfigPaths({
|
|
107
|
+
projects: [join(sourceDirectory, 'tsconfig.json')],
|
|
108
|
+
}),
|
|
109
|
+
...(serverExists
|
|
110
|
+
? [
|
|
111
|
+
vavite({
|
|
112
|
+
serverEntry: resolvedServerFilePath,
|
|
113
|
+
serveClientAssetsInDev: true,
|
|
114
|
+
}),
|
|
115
|
+
]
|
|
116
|
+
: []),
|
|
117
|
+
]
|
|
44
118
|
|
|
45
|
-
const
|
|
119
|
+
const setupProject = () => {
|
|
120
|
+
info(`Setting up TypeScript project...`)
|
|
121
|
+
const project = setupTsProject(tsConfigFilePath)
|
|
122
|
+
info(`Setup TypeScript project.`)
|
|
46
123
|
|
|
47
|
-
|
|
48
|
-
throw new Error(`[${PLUGIN_NAME}]: Could not find index.html file at ${indexHtmlFilePath}`)
|
|
124
|
+
return project
|
|
49
125
|
}
|
|
50
126
|
|
|
51
|
-
const
|
|
52
|
-
|
|
127
|
+
const handleFileChange = async (path: string, event: 'create' | 'update' | 'delete') => {
|
|
128
|
+
if (/\.tsx?$/.test(path)) {
|
|
129
|
+
switch (event) {
|
|
130
|
+
case 'create': {
|
|
131
|
+
project.addSourceFileAtPath(path)
|
|
132
|
+
break
|
|
133
|
+
}
|
|
134
|
+
case 'update': {
|
|
135
|
+
const sourceFile = project.getSourceFile(path)
|
|
53
136
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
137
|
+
if (sourceFile) {
|
|
138
|
+
sourceFile.refreshFromFileSystemSync()
|
|
139
|
+
} else {
|
|
140
|
+
project.addSourceFileAtPath(path)
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
if (devServer) {
|
|
144
|
+
const dependents = dependentsMap.get(path.replace(/.ts(x)?/, '.js$1'))
|
|
145
|
+
|
|
146
|
+
for (const dependent of dependents ?? []) {
|
|
147
|
+
const id = sourceFilePathToVirtualId.get(dependent) ?? dependent
|
|
148
|
+
const mod = devServer.moduleGraph.getModuleById(id)
|
|
149
|
+
|
|
150
|
+
if (mod) {
|
|
151
|
+
info(`reloading ${id}`)
|
|
152
|
+
|
|
153
|
+
await devServer.reloadModule(mod)
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
break
|
|
159
|
+
}
|
|
160
|
+
case 'delete': {
|
|
161
|
+
await project.getSourceFile(path)?.deleteImmediately()
|
|
162
|
+
break
|
|
163
|
+
}
|
|
59
164
|
}
|
|
165
|
+
}
|
|
166
|
+
}
|
|
60
167
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
)
|
|
168
|
+
const virtualModulePlugin = {
|
|
169
|
+
name: PLUGIN_NAME,
|
|
170
|
+
|
|
171
|
+
config(config: UserConfig, env: ConfigEnv) {
|
|
172
|
+
// Configure Build steps when running with vavite
|
|
173
|
+
if (env.mode === 'multibuild') {
|
|
174
|
+
const clientBuild: UserConfig['build'] = {
|
|
175
|
+
outDir: resolvedClientOutputDirectory,
|
|
176
|
+
rollupOptions: {
|
|
177
|
+
input: buildClientInput(findHtmlFiles(sourceDirectory, htmlFileGlobs)),
|
|
178
|
+
},
|
|
179
|
+
}
|
|
74
180
|
|
|
75
|
-
|
|
181
|
+
const serverBuild: UserConfig['build'] = {
|
|
182
|
+
ssr: true,
|
|
183
|
+
outDir: resolvedServerOutputDirectory,
|
|
184
|
+
rollupOptions: {
|
|
185
|
+
input: resolvedServerFilePath,
|
|
186
|
+
},
|
|
187
|
+
}
|
|
76
188
|
|
|
77
|
-
if (serverExists && !(config as any).buildSteps) {
|
|
78
189
|
;(config as any).buildSteps = [
|
|
79
190
|
{
|
|
80
191
|
name: 'client',
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
outDir: 'dist/client',
|
|
84
|
-
rollupOptions: { input: resolve(sourceDirectory, 'index.html') },
|
|
85
|
-
},
|
|
86
|
-
},
|
|
87
|
-
},
|
|
88
|
-
{
|
|
89
|
-
name: 'server',
|
|
90
|
-
config: {
|
|
91
|
-
build: {
|
|
92
|
-
ssr: true,
|
|
93
|
-
outDir: 'dist/server',
|
|
94
|
-
rollupOptions: { input: serverFilePath },
|
|
95
|
-
},
|
|
96
|
-
},
|
|
192
|
+
// @ts-expect-error Unable to resolve types w/ NodeNext
|
|
193
|
+
config: { build: clientBuild, plugins: [compression()] },
|
|
97
194
|
},
|
|
195
|
+
...(serverExists
|
|
196
|
+
? [
|
|
197
|
+
{
|
|
198
|
+
name: 'server',
|
|
199
|
+
config: { build: serverBuild },
|
|
200
|
+
},
|
|
201
|
+
]
|
|
202
|
+
: []),
|
|
98
203
|
]
|
|
204
|
+
|
|
205
|
+
return
|
|
206
|
+
}
|
|
207
|
+
},
|
|
208
|
+
|
|
209
|
+
configureServer(server) {
|
|
210
|
+
devServer = server
|
|
211
|
+
|
|
212
|
+
server.watcher.on('all', (event, path) => {
|
|
213
|
+
if (event === 'change') {
|
|
214
|
+
handleFileChange(path, 'update')
|
|
215
|
+
} else if (event === 'add') {
|
|
216
|
+
handleFileChange(path, 'create')
|
|
217
|
+
} else if (event === 'unlink') {
|
|
218
|
+
handleFileChange(path, 'delete')
|
|
219
|
+
}
|
|
220
|
+
})
|
|
221
|
+
},
|
|
222
|
+
|
|
223
|
+
async watchChange(path, { event }) {
|
|
224
|
+
handleFileChange(path, event)
|
|
225
|
+
},
|
|
226
|
+
|
|
227
|
+
closeBundle() {
|
|
228
|
+
if (project) {
|
|
229
|
+
const diagnostics = project.getPreEmitDiagnostics()
|
|
230
|
+
|
|
231
|
+
if (diagnostics.length > 0) {
|
|
232
|
+
this.error(project.formatDiagnosticsWithColorAndContext(diagnostics))
|
|
233
|
+
}
|
|
99
234
|
}
|
|
100
235
|
},
|
|
101
236
|
|
|
102
|
-
async resolveId(id, importer) {
|
|
103
|
-
if (id
|
|
104
|
-
|
|
237
|
+
async resolveId(id: string, importer?: string) {
|
|
238
|
+
if (id.startsWith(RUNTIME_VIRTUAL_ENTRYPOINT_PREFIX)) {
|
|
239
|
+
const virtualId =
|
|
240
|
+
VIRTUAL_ID_PREFIX + `${importer}?modules=${parseModulesFromId(id, importer)}`
|
|
241
|
+
|
|
242
|
+
virtualIds.add(virtualId)
|
|
243
|
+
|
|
244
|
+
return virtualId
|
|
105
245
|
}
|
|
106
246
|
|
|
107
|
-
if (id
|
|
108
|
-
|
|
247
|
+
if (id.startsWith(BROWSER_VIRTUAL_ENTRYPOINT_PREFIX)) {
|
|
248
|
+
const virtualId =
|
|
249
|
+
VIRTUAL_ID_PREFIX + `${importer}?modules=${parseModulesFromId(id, importer)}&browser`
|
|
250
|
+
|
|
251
|
+
virtualIds.add(virtualId)
|
|
252
|
+
|
|
253
|
+
return virtualId
|
|
109
254
|
}
|
|
110
255
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
// If a relative path, attempt to match to a source .ts(x) file
|
|
115
|
-
if (id.startsWith('.')) {
|
|
116
|
-
const tsPath = resolve(sourceDirectory, id.replace(/.js(x)?$/, '.ts$1'))
|
|
256
|
+
if (id.startsWith(HTML_VIRTUAL_ENTRYPOINT_PREFIX)) {
|
|
257
|
+
const virtualId =
|
|
258
|
+
VIRTUAL_ID_PREFIX + `${importer}?source=${parseModulesFromId(id, importer)}`
|
|
117
259
|
|
|
118
|
-
|
|
119
|
-
return tsPath
|
|
120
|
-
}
|
|
260
|
+
virtualIds.add(virtualId)
|
|
121
261
|
|
|
122
|
-
|
|
262
|
+
return virtualId
|
|
263
|
+
}
|
|
123
264
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
265
|
+
// Virtual modules have problems with resolving relative paths due to not
|
|
266
|
+
// having a real directory to work with thus the need to resolve them manually.
|
|
267
|
+
if (importer?.startsWith(VIRTUAL_ID_PREFIX) && id.startsWith('.')) {
|
|
268
|
+
return findRelativeFile(importer, id)
|
|
128
269
|
}
|
|
129
270
|
},
|
|
130
271
|
|
|
131
|
-
load(id) {
|
|
132
|
-
if (id
|
|
133
|
-
|
|
134
|
-
|
|
272
|
+
async load(id: string) {
|
|
273
|
+
if (virtualIds.has(id)) {
|
|
274
|
+
// Setup the TypeScript project if it hasn't been already
|
|
275
|
+
if (!project) {
|
|
276
|
+
project = setupProject()
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
// Build our virtual module as a SourceFile
|
|
280
|
+
const sourceFile: SourceFile = await buildVirtualModule(
|
|
281
|
+
project,
|
|
282
|
+
id,
|
|
283
|
+
sourceDirectory,
|
|
284
|
+
resolvedServerOutputDirectory,
|
|
285
|
+
resolvedClientOutputDirectory,
|
|
286
|
+
devServer,
|
|
287
|
+
)
|
|
288
|
+
const filePath = sourceFile.getFilePath()
|
|
135
289
|
|
|
136
|
-
|
|
137
|
-
|
|
290
|
+
sourceFilePathToVirtualId.set(filePath, id)
|
|
291
|
+
|
|
292
|
+
// If we're in a development evnironment, we need to track the dependencies of
|
|
293
|
+
// our virtual module so we can reload them when they change.
|
|
294
|
+
if (devServer) {
|
|
295
|
+
const importModuleSpecifiers = await Promise.all(
|
|
296
|
+
sourceFile.getLiteralsReferencingOtherSourceFiles().map((l) => l.getLiteralText()),
|
|
297
|
+
)
|
|
298
|
+
|
|
299
|
+
for (const specifier of importModuleSpecifiers) {
|
|
300
|
+
let resolved =
|
|
301
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
302
|
+
(await virtualModulePlugin.resolveId!.apply(this, [specifier, filePath])) || specifier
|
|
303
|
+
|
|
304
|
+
if (resolved.startsWith('.')) {
|
|
305
|
+
resolved = resolve(dirname(filePath), resolved)
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
const current = dependentsMap.get(resolved) ?? new Set()
|
|
309
|
+
|
|
310
|
+
current.add(filePath)
|
|
311
|
+
dependentsMap.set(resolved, current)
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
const diagnostics = sourceFile.getPreEmitDiagnostics()
|
|
316
|
+
const relativeFilePath = relative(sourceDirectory, filePath)
|
|
317
|
+
|
|
318
|
+
if (diagnostics.length > 0) {
|
|
319
|
+
info(project.formatDiagnosticsWithColorAndContext(diagnostics))
|
|
320
|
+
info(sourceFile.getFullText())
|
|
321
|
+
} else {
|
|
322
|
+
info(`${relativeFilePath} virtual module successfuly typed-checked.`)
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
const output = ts.transpileModule(sourceFile.getFullText(), {
|
|
326
|
+
compilerOptions: project.getCompilerOptions(),
|
|
327
|
+
})
|
|
328
|
+
|
|
329
|
+
return {
|
|
330
|
+
code: output.outputText,
|
|
331
|
+
map: output.sourceMapText,
|
|
332
|
+
moduleSideEffects: false,
|
|
333
|
+
}
|
|
138
334
|
}
|
|
139
335
|
},
|
|
140
|
-
}
|
|
336
|
+
} satisfies Plugin
|
|
337
|
+
|
|
338
|
+
plugins.push(virtualModulePlugin)
|
|
339
|
+
|
|
340
|
+
return plugins
|
|
141
341
|
}
|
|
142
342
|
|
|
143
|
-
function
|
|
144
|
-
dir: string,
|
|
145
|
-
pages: readonly string[],
|
|
343
|
+
async function buildVirtualModule(
|
|
146
344
|
project: Project,
|
|
147
|
-
|
|
345
|
+
id: string,
|
|
346
|
+
sourceDirectory: string,
|
|
347
|
+
serverOutputDirectory: string,
|
|
348
|
+
clientOutputDirectory: string,
|
|
349
|
+
devServer?: ViteDevServer,
|
|
148
350
|
) {
|
|
149
|
-
|
|
150
|
-
|
|
351
|
+
// Parse our virtual ID into the original importer and whatever query was passed to it
|
|
352
|
+
const [importer, query] = id.split(VIRTUAL_ID_PREFIX)[1].split('?')
|
|
353
|
+
|
|
354
|
+
// If the query is for a runtime module, read the directory and transform it into a module.
|
|
355
|
+
if (query.includes('modules=')) {
|
|
356
|
+
const moduleDirectory = resolve(dirname(importer), query.split('modules=')[1].split('&')[0])
|
|
357
|
+
const relativeDirectory = relative(sourceDirectory, moduleDirectory)
|
|
358
|
+
const directory = await readDirectory(moduleDirectory)
|
|
359
|
+
const moduleTree = readModules(project, directory)
|
|
360
|
+
const isBrowser = query.includes('&browser')
|
|
361
|
+
|
|
362
|
+
info(`Building ${isBrowser ? 'browser' : 'runtime'} module for ${relativeDirectory}...`)
|
|
363
|
+
|
|
364
|
+
const mod = isBrowser
|
|
365
|
+
? makeBrowserModule(project, moduleTree, importer)
|
|
366
|
+
: makeRuntimeModule(project, moduleTree, importer)
|
|
367
|
+
|
|
368
|
+
info(`Built ${isBrowser ? 'browser' : 'runtime'} module for ${relativeDirectory}.`)
|
|
369
|
+
|
|
370
|
+
return mod
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
// If the query is for an HTML file, read the file and transform it into a module.
|
|
374
|
+
|
|
375
|
+
const htmlFile = query.split('source=')[1]
|
|
376
|
+
const htmlFilePath = resolve(dirname(importer), htmlFile + '.html')
|
|
377
|
+
const relativeHtmlFilePath = relative(sourceDirectory, htmlFilePath)
|
|
378
|
+
let html = ''
|
|
379
|
+
|
|
380
|
+
info(`Building html module for ${relativeHtmlFilePath}...`)
|
|
381
|
+
|
|
382
|
+
// If there's a dev server, use it to transform the HTML for development
|
|
383
|
+
if (devServer) {
|
|
384
|
+
html = (await readFile(htmlFilePath, 'utf-8')).toString()
|
|
385
|
+
html = await devServer.transformIndexHtml(getRelativePath(sourceDirectory, htmlFilePath), html)
|
|
386
|
+
} else {
|
|
387
|
+
// Otherwise, read the already transformed file from the output directory.
|
|
388
|
+
html = (
|
|
389
|
+
await readFile(
|
|
390
|
+
resolve(clientOutputDirectory, relative(sourceDirectory, htmlFilePath)),
|
|
391
|
+
'utf-8',
|
|
392
|
+
)
|
|
393
|
+
).toString()
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
const module = await makeHtmlModule({
|
|
151
397
|
project,
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
398
|
+
filePath: htmlFilePath,
|
|
399
|
+
html,
|
|
400
|
+
importer,
|
|
401
|
+
serverOutputDirectory,
|
|
402
|
+
clientOutputDirectory,
|
|
403
|
+
devServer,
|
|
158
404
|
})
|
|
159
405
|
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
406
|
+
info(`Built html module for ${relativeHtmlFilePath}.`)
|
|
407
|
+
|
|
408
|
+
return module
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
function findRelativeFile(importer: string, id: string) {
|
|
412
|
+
const dir = getVirtualSourceDirectory(importer)
|
|
413
|
+
const tsPath = resolve(dir, id.replace(/.js(x)?$/, '.ts$1'))
|
|
414
|
+
|
|
415
|
+
if (existsSync(tsPath)) {
|
|
416
|
+
return tsPath
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
const jsPath = resolve(dir, id)
|
|
420
|
+
|
|
421
|
+
if (existsSync(jsPath)) {
|
|
422
|
+
return tsPath
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
function getVirtualSourceDirectory(id: string) {
|
|
427
|
+
return dirname(id.split(VIRTUAL_ID_PREFIX)[1].split('?')[0])
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
function parseModulesFromId(id: string, importer: string | undefined): string {
|
|
431
|
+
const pages = id
|
|
432
|
+
.replace(RUNTIME_VIRTUAL_ENTRYPOINT_PREFIX + ':', '')
|
|
433
|
+
.replace(BROWSER_VIRTUAL_ENTRYPOINT_PREFIX + ':', '')
|
|
434
|
+
.replace(HTML_VIRTUAL_ENTRYPOINT_PREFIX + ':', '')
|
|
435
|
+
|
|
436
|
+
if (pages === '') {
|
|
437
|
+
throw new Error(`[${PLUGIN_NAME}]: No pages were specified from ${importer}`)
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
return pages
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
function findHtmlFiles(directory: string, htmlFileGlobs?: readonly string[]): readonly string[] {
|
|
444
|
+
if (htmlFileGlobs) {
|
|
445
|
+
// eslint-disable-next-line import/no-named-as-default-member
|
|
446
|
+
return glob.sync([...htmlFileGlobs], { cwd: directory })
|
|
163
447
|
}
|
|
448
|
+
|
|
449
|
+
// eslint-disable-next-line import/no-named-as-default-member
|
|
450
|
+
return glob.sync(['**/*.html', '!' + '**/node_modules/**', '!' + '**/dist/**'], {
|
|
451
|
+
cwd: directory,
|
|
452
|
+
})
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
function buildClientInput(htmlFilePaths: readonly string[]) {
|
|
456
|
+
const input: Record<string, string> = {}
|
|
457
|
+
|
|
458
|
+
for (const htmlFilePath of htmlFilePaths) {
|
|
459
|
+
const htmlFile = basename(htmlFilePath, '.html')
|
|
460
|
+
|
|
461
|
+
input[htmlFile] = htmlFilePath
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
return input
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
function getRelativePath(from: string, to: string) {
|
|
468
|
+
const path = relative(from, to)
|
|
469
|
+
|
|
470
|
+
if (!path.startsWith('.')) {
|
|
471
|
+
return './' + path
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
return path
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
function info(message: string) {
|
|
478
|
+
const date = new Date()
|
|
479
|
+
|
|
480
|
+
console.info(`[${PLUGIN_NAME}] ${date.toISOString()};`, `${message}`)
|
|
164
481
|
}
|