vite 2.6.0-beta.0 → 2.6.0-beta.4

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.

Potentially problematic release.


This version of vite might be problematic. Click here for more details.

Files changed (110) hide show
  1. package/CHANGELOG.md +66 -0
  2. package/LICENSE.md +161 -3011
  3. package/bin/vite.js +2 -1
  4. package/dist/node/chunks/{dep-91aa74e8.js → dep-1e0a75a8.js} +58 -32
  5. package/dist/node/chunks/dep-1e0a75a8.js.map +1 -0
  6. package/dist/node/chunks/{dep-e36486f6.js → dep-ac1b4bf9.js} +1 -1
  7. package/dist/node/chunks/dep-ac1b4bf9.js.map +1 -0
  8. package/dist/node/chunks/{dep-c7e510f9.js → dep-ba6b30a0.js} +27538 -4953
  9. package/dist/node/chunks/dep-ba6b30a0.js.map +1 -0
  10. package/dist/node/chunks/{dep-11213a75.js → dep-c4cf6e92.js} +19 -6
  11. package/dist/node/chunks/dep-c4cf6e92.js.map +1 -0
  12. package/dist/node/chunks/{dep-eb6ef720.js → dep-d574094c.js} +18 -5
  13. package/dist/node/chunks/dep-d574094c.js.map +1 -0
  14. package/dist/node/chunks/{dep-0d2f9464.js → dep-e39b05d6.js} +18 -5
  15. package/dist/node/chunks/dep-e39b05d6.js.map +1 -0
  16. package/dist/node/cli.js +60 -23992
  17. package/dist/node/cli.js.map +1 -1
  18. package/dist/node/index.d.ts +26 -8
  19. package/dist/node/index.js +18 -15
  20. package/dist/node/index.js.map +1 -1
  21. package/dist/node/terser.js +102 -55
  22. package/package.json +28 -13
  23. package/types/package.json +3 -0
  24. package/api-extractor.json +0 -54
  25. package/dist/node/chunks/dep-0d2f9464.js.map +0 -1
  26. package/dist/node/chunks/dep-11213a75.js.map +0 -1
  27. package/dist/node/chunks/dep-91aa74e8.js.map +0 -1
  28. package/dist/node/chunks/dep-c7e510f9.js.map +0 -1
  29. package/dist/node/chunks/dep-e36486f6.js.map +0 -1
  30. package/dist/node/chunks/dep-eb6ef720.js.map +0 -1
  31. package/dist/node/terser.js.map +0 -1
  32. package/rollup.config.js +0 -389
  33. package/scripts/patchTypes.js +0 -70
  34. package/src/node/__tests__/asset.spec.ts +0 -156
  35. package/src/node/__tests__/build.spec.ts +0 -67
  36. package/src/node/__tests__/config.spec.ts +0 -166
  37. package/src/node/__tests__/packages/name/package.json +0 -3
  38. package/src/node/__tests__/packages/noname/package.json +0 -1
  39. package/src/node/__tests__/plugins/css.spec.ts +0 -116
  40. package/src/node/__tests__/scan.spec.ts +0 -118
  41. package/src/node/__tests__/utils.spec.ts +0 -40
  42. package/src/node/build.ts +0 -783
  43. package/src/node/cli.ts +0 -239
  44. package/src/node/config.ts +0 -1033
  45. package/src/node/constants.ts +0 -87
  46. package/src/node/importGlob.ts +0 -173
  47. package/src/node/index.ts +0 -88
  48. package/src/node/logger.ts +0 -167
  49. package/src/node/optimizer/esbuildDepPlugin.ts +0 -216
  50. package/src/node/optimizer/index.ts +0 -410
  51. package/src/node/optimizer/registerMissing.ts +0 -102
  52. package/src/node/optimizer/scan.ts +0 -457
  53. package/src/node/plugin.ts +0 -138
  54. package/src/node/plugins/asset.ts +0 -365
  55. package/src/node/plugins/assetImportMetaUrl.ts +0 -99
  56. package/src/node/plugins/clientInjections.ts +0 -72
  57. package/src/node/plugins/css.ts +0 -1279
  58. package/src/node/plugins/dataUri.ts +0 -64
  59. package/src/node/plugins/define.ts +0 -107
  60. package/src/node/plugins/esbuild.ts +0 -280
  61. package/src/node/plugins/html.ts +0 -673
  62. package/src/node/plugins/importAnalysis.ts +0 -614
  63. package/src/node/plugins/importAnalysisBuild.ts +0 -334
  64. package/src/node/plugins/index.ts +0 -69
  65. package/src/node/plugins/json.ts +0 -75
  66. package/src/node/plugins/loadFallback.ts +0 -19
  67. package/src/node/plugins/manifest.ts +0 -123
  68. package/src/node/plugins/modulePreloadPolyfill.ts +0 -100
  69. package/src/node/plugins/preAlias.ts +0 -22
  70. package/src/node/plugins/reporter.ts +0 -244
  71. package/src/node/plugins/resolve.ts +0 -925
  72. package/src/node/plugins/terser.ts +0 -40
  73. package/src/node/plugins/wasm.ts +0 -72
  74. package/src/node/plugins/worker.ts +0 -117
  75. package/src/node/preview.ts +0 -82
  76. package/src/node/server/__tests__/fixtures/none/nested/package.json +0 -3
  77. package/src/node/server/__tests__/fixtures/pnpm/nested/package.json +0 -3
  78. package/src/node/server/__tests__/fixtures/pnpm/package.json +0 -3
  79. package/src/node/server/__tests__/fixtures/pnpm/pnpm-workspace.yaml +0 -0
  80. package/src/node/server/__tests__/fixtures/yarn/nested/package.json +0 -3
  81. package/src/node/server/__tests__/fixtures/yarn/package.json +0 -6
  82. package/src/node/server/__tests__/search-root.spec.ts +0 -31
  83. package/src/node/server/hmr.ts +0 -489
  84. package/src/node/server/http.ts +0 -198
  85. package/src/node/server/index.ts +0 -705
  86. package/src/node/server/middlewares/base.ts +0 -52
  87. package/src/node/server/middlewares/error.ts +0 -98
  88. package/src/node/server/middlewares/indexHtml.ts +0 -170
  89. package/src/node/server/middlewares/proxy.ts +0 -124
  90. package/src/node/server/middlewares/spaFallback.ts +0 -32
  91. package/src/node/server/middlewares/static.ts +0 -153
  92. package/src/node/server/middlewares/time.ts +0 -18
  93. package/src/node/server/middlewares/transform.ts +0 -196
  94. package/src/node/server/moduleGraph.ts +0 -200
  95. package/src/node/server/openBrowser.ts +0 -101
  96. package/src/node/server/pluginContainer.ts +0 -546
  97. package/src/node/server/searchRoot.ts +0 -70
  98. package/src/node/server/send.ts +0 -54
  99. package/src/node/server/sourcemap.ts +0 -54
  100. package/src/node/server/transformRequest.ts +0 -168
  101. package/src/node/server/ws.ts +0 -131
  102. package/src/node/ssr/__tests__/ssrTransform.spec.ts +0 -309
  103. package/src/node/ssr/ssrExternal.ts +0 -161
  104. package/src/node/ssr/ssrManifestPlugin.ts +0 -53
  105. package/src/node/ssr/ssrModuleLoader.ts +0 -214
  106. package/src/node/ssr/ssrStacktrace.ts +0 -75
  107. package/src/node/ssr/ssrTransform.ts +0 -452
  108. package/src/node/tsconfig.json +0 -14
  109. package/src/node/utils.ts +0 -565
  110. package/tsconfig.base.json +0 -11
@@ -1,489 +0,0 @@
1
- import fs from 'fs'
2
- import path from 'path'
3
- import chalk from 'chalk'
4
- import { createServer, ViteDevServer } from '..'
5
- import { createDebugger, normalizePath } from '../utils'
6
- import { ModuleNode } from './moduleGraph'
7
- import { Update } from 'types/hmrPayload'
8
- import { CLIENT_DIR } from '../constants'
9
- import { RollupError } from 'rollup'
10
- import match from 'minimatch'
11
- import { Server } from 'http'
12
- import { isCSSRequest } from '../plugins/css'
13
-
14
- export const debugHmr = createDebugger('vite:hmr')
15
-
16
- const normalizedClientDir = normalizePath(CLIENT_DIR)
17
-
18
- export interface HmrOptions {
19
- protocol?: string
20
- host?: string
21
- port?: number
22
- clientPort?: number
23
- path?: string
24
- timeout?: number
25
- overlay?: boolean
26
- server?: Server
27
- }
28
-
29
- export interface HmrContext {
30
- file: string
31
- timestamp: number
32
- modules: Array<ModuleNode>
33
- read: () => string | Promise<string>
34
- server: ViteDevServer
35
- }
36
-
37
- function getShortName(file: string, root: string) {
38
- return file.startsWith(root + '/') ? path.posix.relative(root, file) : file
39
- }
40
-
41
- export async function handleHMRUpdate(
42
- file: string,
43
- server: ViteDevServer
44
- ): Promise<any> {
45
- const { ws, config, moduleGraph } = server
46
- const shortFile = getShortName(file, config.root)
47
-
48
- const isConfig = file === config.configFile
49
- const isConfigDependency = config.configFileDependencies.some(
50
- (name) => file === path.resolve(name)
51
- )
52
- const isEnv = config.inlineConfig.envFile !== false && file.endsWith('.env')
53
- if (isConfig || isConfigDependency || isEnv) {
54
- // auto restart server
55
- debugHmr(`[config change] ${chalk.dim(shortFile)}`)
56
- config.logger.info(
57
- chalk.green(
58
- `${path.relative(process.cwd(), file)} changed, restarting server...`
59
- ),
60
- { clear: true, timestamp: true }
61
- )
62
- await restartServer(server)
63
- return
64
- }
65
-
66
- debugHmr(`[file change] ${chalk.dim(shortFile)}`)
67
-
68
- // (dev only) the client itself cannot be hot updated.
69
- if (file.startsWith(normalizedClientDir)) {
70
- ws.send({
71
- type: 'full-reload',
72
- path: '*'
73
- })
74
- return
75
- }
76
-
77
- const mods = moduleGraph.getModulesByFile(file)
78
-
79
- // check if any plugin wants to perform custom HMR handling
80
- const timestamp = Date.now()
81
- const hmrContext: HmrContext = {
82
- file,
83
- timestamp,
84
- modules: mods ? [...mods] : [],
85
- read: () => readModifiedFile(file),
86
- server
87
- }
88
-
89
- for (const plugin of config.plugins) {
90
- if (plugin.handleHotUpdate) {
91
- const filteredModules = await plugin.handleHotUpdate(hmrContext)
92
- if (filteredModules) {
93
- hmrContext.modules = filteredModules
94
- break
95
- }
96
- }
97
- }
98
-
99
- if (!hmrContext.modules.length) {
100
- // html file cannot be hot updated
101
- if (file.endsWith('.html')) {
102
- config.logger.info(chalk.green(`page reload `) + chalk.dim(shortFile), {
103
- clear: true,
104
- timestamp: true
105
- })
106
- ws.send({
107
- type: 'full-reload',
108
- path: config.server.middlewareMode
109
- ? '*'
110
- : '/' + normalizePath(path.relative(config.root, file))
111
- })
112
- } else {
113
- // loaded but not in the module graph, probably not js
114
- debugHmr(`[no modules matched] ${chalk.dim(shortFile)}`)
115
- }
116
- return
117
- }
118
-
119
- updateModules(shortFile, hmrContext.modules, timestamp, server)
120
- }
121
-
122
- function updateModules(
123
- file: string,
124
- modules: ModuleNode[],
125
- timestamp: number,
126
- { config, ws }: ViteDevServer
127
- ) {
128
- const updates: Update[] = []
129
- const invalidatedModules = new Set<ModuleNode>()
130
- let needFullReload = false
131
-
132
- for (const mod of modules) {
133
- invalidate(mod, timestamp, invalidatedModules)
134
- if (needFullReload) {
135
- continue
136
- }
137
-
138
- const boundaries = new Set<{
139
- boundary: ModuleNode
140
- acceptedVia: ModuleNode
141
- }>()
142
- const hasDeadEnd = propagateUpdate(mod, boundaries)
143
- if (hasDeadEnd) {
144
- needFullReload = true
145
- continue
146
- }
147
-
148
- updates.push(
149
- ...[...boundaries].map(({ boundary, acceptedVia }) => ({
150
- type: `${boundary.type}-update` as Update['type'],
151
- timestamp,
152
- path: boundary.url,
153
- acceptedPath: acceptedVia.url
154
- }))
155
- )
156
- }
157
-
158
- if (needFullReload) {
159
- config.logger.info(chalk.green(`page reload `) + chalk.dim(file), {
160
- clear: true,
161
- timestamp: true
162
- })
163
- ws.send({
164
- type: 'full-reload'
165
- })
166
- } else {
167
- config.logger.info(
168
- updates
169
- .map(({ path }) => chalk.green(`hmr update `) + chalk.dim(path))
170
- .join('\n'),
171
- { clear: true, timestamp: true }
172
- )
173
- ws.send({
174
- type: 'update',
175
- updates
176
- })
177
- }
178
- }
179
-
180
- export async function handleFileAddUnlink(
181
- file: string,
182
- server: ViteDevServer,
183
- isUnlink = false
184
- ): Promise<void> {
185
- const modules = [...(server.moduleGraph.getModulesByFile(file) ?? [])]
186
- if (isUnlink && file in server._globImporters) {
187
- delete server._globImporters[file]
188
- } else {
189
- for (const i in server._globImporters) {
190
- const { module, importGlobs } = server._globImporters[i]
191
- for (const { base, pattern } of importGlobs) {
192
- if (match(file, pattern) || match(path.relative(base, file), pattern)) {
193
- modules.push(module)
194
- // We use `onFileChange` to invalidate `module.file` so that subsequent `ssrLoadModule()`
195
- // calls get fresh glob import results with(out) the newly added(/removed) `file`.
196
- server.moduleGraph.onFileChange(module.file!)
197
- break
198
- }
199
- }
200
- }
201
- }
202
- if (modules.length > 0) {
203
- updateModules(
204
- getShortName(file, server.config.root),
205
- modules,
206
- Date.now(),
207
- server
208
- )
209
- }
210
- }
211
-
212
- function propagateUpdate(
213
- node: ModuleNode,
214
- boundaries: Set<{
215
- boundary: ModuleNode
216
- acceptedVia: ModuleNode
217
- }>,
218
- currentChain: ModuleNode[] = [node]
219
- ): boolean /* hasDeadEnd */ {
220
- if (node.isSelfAccepting) {
221
- boundaries.add({
222
- boundary: node,
223
- acceptedVia: node
224
- })
225
-
226
- // additionally check for CSS importers, since a PostCSS plugin like
227
- // Tailwind JIT may register any file as a dependency to a CSS file.
228
- for (const importer of node.importers) {
229
- if (isCSSRequest(importer.url) && !currentChain.includes(importer)) {
230
- propagateUpdate(importer, boundaries, currentChain.concat(importer))
231
- }
232
- }
233
-
234
- return false
235
- }
236
-
237
- if (!node.importers.size) {
238
- return true
239
- }
240
-
241
- // #3716, #3913
242
- // For a non-CSS file, if all of its importers are CSS files (registered via
243
- // PostCSS plugins) it should be considered a dead end and force full reload.
244
- if (
245
- !isCSSRequest(node.url) &&
246
- [...node.importers].every((i) => isCSSRequest(i.url))
247
- ) {
248
- return true
249
- }
250
-
251
- for (const importer of node.importers) {
252
- const subChain = currentChain.concat(importer)
253
- if (importer.acceptedHmrDeps.has(node)) {
254
- boundaries.add({
255
- boundary: importer,
256
- acceptedVia: node
257
- })
258
- continue
259
- }
260
-
261
- if (currentChain.includes(importer)) {
262
- // circular deps is considered dead end
263
- return true
264
- }
265
-
266
- if (propagateUpdate(importer, boundaries, subChain)) {
267
- return true
268
- }
269
- }
270
- return false
271
- }
272
-
273
- function invalidate(mod: ModuleNode, timestamp: number, seen: Set<ModuleNode>) {
274
- if (seen.has(mod)) {
275
- return
276
- }
277
- seen.add(mod)
278
- mod.lastHMRTimestamp = timestamp
279
- mod.transformResult = null
280
- mod.ssrModule = null
281
- mod.ssrTransformResult = null
282
- mod.importers.forEach((importer) => {
283
- if (!importer.acceptedHmrDeps.has(mod)) {
284
- invalidate(importer, timestamp, seen)
285
- }
286
- })
287
- }
288
-
289
- export function handlePrunedModules(
290
- mods: Set<ModuleNode>,
291
- { ws }: ViteDevServer
292
- ): void {
293
- // update the disposed modules' hmr timestamp
294
- // since if it's re-imported, it should re-apply side effects
295
- // and without the timestamp the browser will not re-import it!
296
- const t = Date.now()
297
- mods.forEach((mod) => {
298
- mod.lastHMRTimestamp = t
299
- debugHmr(`[dispose] ${chalk.dim(mod.file)}`)
300
- })
301
- ws.send({
302
- type: 'prune',
303
- paths: [...mods].map((m) => m.url)
304
- })
305
- }
306
-
307
- const enum LexerState {
308
- inCall,
309
- inSingleQuoteString,
310
- inDoubleQuoteString,
311
- inTemplateString,
312
- inArray
313
- }
314
-
315
- /**
316
- * Lex import.meta.hot.accept() for accepted deps.
317
- * Since hot.accept() can only accept string literals or array of string
318
- * literals, we don't really need a heavy @babel/parse call on the entire source.
319
- *
320
- * @returns selfAccepts
321
- */
322
- export function lexAcceptedHmrDeps(
323
- code: string,
324
- start: number,
325
- urls: Set<{ url: string; start: number; end: number }>
326
- ): boolean {
327
- let state: LexerState = LexerState.inCall
328
- // the state can only be 2 levels deep so no need for a stack
329
- let prevState: LexerState = LexerState.inCall
330
- let currentDep: string = ''
331
-
332
- function addDep(index: number) {
333
- urls.add({
334
- url: currentDep,
335
- start: index - currentDep.length - 1,
336
- end: index + 1
337
- })
338
- currentDep = ''
339
- }
340
-
341
- for (let i = start; i < code.length; i++) {
342
- const char = code.charAt(i)
343
- switch (state) {
344
- case LexerState.inCall:
345
- case LexerState.inArray:
346
- if (char === `'`) {
347
- prevState = state
348
- state = LexerState.inSingleQuoteString
349
- } else if (char === `"`) {
350
- prevState = state
351
- state = LexerState.inDoubleQuoteString
352
- } else if (char === '`') {
353
- prevState = state
354
- state = LexerState.inTemplateString
355
- } else if (/\s/.test(char)) {
356
- continue
357
- } else {
358
- if (state === LexerState.inCall) {
359
- if (char === `[`) {
360
- state = LexerState.inArray
361
- } else {
362
- // reaching here means the first arg is neither a string literal
363
- // nor an Array literal (direct callback) or there is no arg
364
- // in both case this indicates a self-accepting module
365
- return true // done
366
- }
367
- } else if (state === LexerState.inArray) {
368
- if (char === `]`) {
369
- return false // done
370
- } else if (char === ',') {
371
- continue
372
- } else {
373
- error(i)
374
- }
375
- }
376
- }
377
- break
378
- case LexerState.inSingleQuoteString:
379
- if (char === `'`) {
380
- addDep(i)
381
- if (prevState === LexerState.inCall) {
382
- // accept('foo', ...)
383
- return false
384
- } else {
385
- state = prevState
386
- }
387
- } else {
388
- currentDep += char
389
- }
390
- break
391
- case LexerState.inDoubleQuoteString:
392
- if (char === `"`) {
393
- addDep(i)
394
- if (prevState === LexerState.inCall) {
395
- // accept('foo', ...)
396
- return false
397
- } else {
398
- state = prevState
399
- }
400
- } else {
401
- currentDep += char
402
- }
403
- break
404
- case LexerState.inTemplateString:
405
- if (char === '`') {
406
- addDep(i)
407
- if (prevState === LexerState.inCall) {
408
- // accept('foo', ...)
409
- return false
410
- } else {
411
- state = prevState
412
- }
413
- } else if (char === '$' && code.charAt(i + 1) === '{') {
414
- error(i)
415
- } else {
416
- currentDep += char
417
- }
418
- break
419
- default:
420
- throw new Error('unknown import.meta.hot lexer state')
421
- }
422
- }
423
- return false
424
- }
425
-
426
- function error(pos: number) {
427
- const err = new Error(
428
- `import.meta.accept() can only accept string literals or an ` +
429
- `Array of string literals.`
430
- ) as RollupError
431
- err.pos = pos
432
- throw err
433
- }
434
-
435
- // vitejs/vite#610 when hot-reloading Vue files, we read immediately on file
436
- // change event and sometimes this can be too early and get an empty buffer.
437
- // Poll until the file's modified time has changed before reading again.
438
- async function readModifiedFile(file: string): Promise<string> {
439
- const content = fs.readFileSync(file, 'utf-8')
440
- if (!content) {
441
- const mtime = fs.statSync(file).mtimeMs
442
- await new Promise((r) => {
443
- let n = 0
444
- const poll = async () => {
445
- n++
446
- const newMtime = fs.statSync(file).mtimeMs
447
- if (newMtime !== mtime || n > 10) {
448
- r(0)
449
- } else {
450
- setTimeout(poll, 10)
451
- }
452
- }
453
- setTimeout(poll, 10)
454
- })
455
- return fs.readFileSync(file, 'utf-8')
456
- } else {
457
- return content
458
- }
459
- }
460
-
461
- async function restartServer(server: ViteDevServer) {
462
- // @ts-ignore
463
- global.__vite_start_time = Date.now()
464
- const { port } = server.config.server
465
-
466
- await server.close()
467
-
468
- let newServer = null
469
- try {
470
- newServer = await createServer(server.config.inlineConfig)
471
- } catch (err: any) {
472
- server.config.logger.error(err.message, {
473
- timestamp: true
474
- })
475
- return
476
- }
477
-
478
- for (const key in newServer) {
479
- if (key !== 'app') {
480
- // @ts-ignore
481
- server[key] = newServer[key]
482
- }
483
- }
484
- if (!server.config.server.middlewareMode) {
485
- await server.listen(port, true)
486
- } else {
487
- server.config.logger.info('server restarted.', { timestamp: true })
488
- }
489
- }
@@ -1,198 +0,0 @@
1
- import fs, { promises as fsp } from 'fs'
2
- import path from 'path'
3
- import { Server as HttpServer } from 'http'
4
- import { ServerOptions as HttpsServerOptions } from 'https'
5
- import { ResolvedConfig, ServerOptions } from '..'
6
- import { isObject } from '../utils'
7
- import { Connect } from 'types/connect'
8
- import { Logger } from '../logger'
9
-
10
- export async function resolveHttpServer(
11
- { proxy }: ServerOptions,
12
- app: Connect.Server,
13
- httpsOptions?: HttpsServerOptions
14
- ): Promise<HttpServer> {
15
- if (!httpsOptions) {
16
- return require('http').createServer(app)
17
- }
18
-
19
- if (proxy) {
20
- // #484 fallback to http1 when proxy is needed.
21
- return require('https').createServer(httpsOptions, app)
22
- } else {
23
- return require('http2').createSecureServer(
24
- {
25
- ...httpsOptions,
26
- allowHTTP1: true
27
- },
28
- app
29
- )
30
- }
31
- }
32
-
33
- export async function resolveHttpsConfig(
34
- config: ResolvedConfig
35
- ): Promise<HttpsServerOptions | undefined> {
36
- if (!config.server.https) return undefined
37
-
38
- const httpsOption = isObject(config.server.https) ? config.server.https : {}
39
-
40
- const { ca, cert, key, pfx } = httpsOption
41
- Object.assign(httpsOption, {
42
- ca: readFileIfExists(ca),
43
- cert: readFileIfExists(cert),
44
- key: readFileIfExists(key),
45
- pfx: readFileIfExists(pfx)
46
- })
47
- if (!httpsOption.key || !httpsOption.cert) {
48
- httpsOption.cert = httpsOption.key = await getCertificate(config)
49
- }
50
- return httpsOption
51
- }
52
-
53
- function readFileIfExists(value?: string | Buffer | any[]) {
54
- if (typeof value === 'string') {
55
- try {
56
- return fs.readFileSync(path.resolve(value as string))
57
- } catch (e) {
58
- return value
59
- }
60
- }
61
- return value
62
- }
63
-
64
- /**
65
- * https://github.com/webpack/webpack-dev-server/blob/master/lib/utils/createCertificate.js
66
- *
67
- * Copyright JS Foundation and other contributors
68
- * This source code is licensed under the MIT license found in the
69
- * LICENSE file at
70
- * https://github.com/webpack/webpack-dev-server/blob/master/LICENSE
71
- */
72
- async function createCertificate() {
73
- const { generate } = await import('selfsigned')
74
- const pems = generate(null, {
75
- algorithm: 'sha256',
76
- days: 30,
77
- keySize: 2048,
78
- extensions: [
79
- // {
80
- // name: 'basicConstraints',
81
- // cA: true,
82
- // },
83
- {
84
- name: 'keyUsage',
85
- keyCertSign: true,
86
- digitalSignature: true,
87
- nonRepudiation: true,
88
- keyEncipherment: true,
89
- dataEncipherment: true
90
- },
91
- {
92
- name: 'extKeyUsage',
93
- serverAuth: true,
94
- clientAuth: true,
95
- codeSigning: true,
96
- timeStamping: true
97
- },
98
- {
99
- name: 'subjectAltName',
100
- altNames: [
101
- {
102
- // type 2 is DNS
103
- type: 2,
104
- value: 'localhost'
105
- },
106
- {
107
- type: 2,
108
- value: 'localhost.localdomain'
109
- },
110
- {
111
- type: 2,
112
- value: 'lvh.me'
113
- },
114
- {
115
- type: 2,
116
- value: '*.lvh.me'
117
- },
118
- {
119
- type: 2,
120
- value: '[::1]'
121
- },
122
- {
123
- // type 7 is IP
124
- type: 7,
125
- ip: '127.0.0.1'
126
- },
127
- {
128
- type: 7,
129
- ip: 'fe80::1'
130
- }
131
- ]
132
- }
133
- ]
134
- })
135
- return pems.private + pems.cert
136
- }
137
-
138
- async function getCertificate(config: ResolvedConfig) {
139
- if (!config.cacheDir) return await createCertificate()
140
-
141
- const cachePath = path.join(config.cacheDir, '_cert.pem')
142
-
143
- try {
144
- const [stat, content] = await Promise.all([
145
- fsp.stat(cachePath),
146
- fsp.readFile(cachePath, 'utf8')
147
- ])
148
-
149
- if (Date.now() - stat.ctime.valueOf() > 30 * 24 * 60 * 60 * 1000) {
150
- throw new Error('cache is outdated.')
151
- }
152
-
153
- return content
154
- } catch {
155
- const content = await createCertificate()
156
- fsp
157
- .mkdir(config.cacheDir, { recursive: true })
158
- .then(() => fsp.writeFile(cachePath, content))
159
- .catch(() => {})
160
- return content
161
- }
162
- }
163
-
164
- export async function httpServerStart(
165
- httpServer: HttpServer,
166
- serverOptions: {
167
- port: number
168
- strictPort: boolean | undefined
169
- host: string | undefined
170
- logger: Logger
171
- }
172
- ): Promise<number> {
173
- return new Promise((resolve, reject) => {
174
- let { port, strictPort, host, logger } = serverOptions
175
-
176
- const onError = (e: Error & { code?: string }) => {
177
- if (e.code === 'EADDRINUSE') {
178
- if (strictPort) {
179
- httpServer.removeListener('error', onError)
180
- reject(new Error(`Port ${port} is already in use`))
181
- } else {
182
- logger.info(`Port ${port} is in use, trying another one...`)
183
- httpServer.listen(++port, host)
184
- }
185
- } else {
186
- httpServer.removeListener('error', onError)
187
- reject(e)
188
- }
189
- }
190
-
191
- httpServer.on('error', onError)
192
-
193
- httpServer.listen(port, host, () => {
194
- httpServer.removeListener('error', onError)
195
- resolve(port)
196
- })
197
- })
198
- }