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.
- package/CHANGELOG.md +66 -0
- package/LICENSE.md +161 -3011
- package/bin/vite.js +2 -1
- package/dist/node/chunks/{dep-91aa74e8.js → dep-1e0a75a8.js} +58 -32
- package/dist/node/chunks/dep-1e0a75a8.js.map +1 -0
- package/dist/node/chunks/{dep-e36486f6.js → dep-ac1b4bf9.js} +1 -1
- package/dist/node/chunks/dep-ac1b4bf9.js.map +1 -0
- package/dist/node/chunks/{dep-c7e510f9.js → dep-ba6b30a0.js} +27538 -4953
- package/dist/node/chunks/dep-ba6b30a0.js.map +1 -0
- package/dist/node/chunks/{dep-11213a75.js → dep-c4cf6e92.js} +19 -6
- package/dist/node/chunks/dep-c4cf6e92.js.map +1 -0
- package/dist/node/chunks/{dep-eb6ef720.js → dep-d574094c.js} +18 -5
- package/dist/node/chunks/dep-d574094c.js.map +1 -0
- package/dist/node/chunks/{dep-0d2f9464.js → dep-e39b05d6.js} +18 -5
- package/dist/node/chunks/dep-e39b05d6.js.map +1 -0
- package/dist/node/cli.js +60 -23992
- package/dist/node/cli.js.map +1 -1
- package/dist/node/index.d.ts +26 -8
- package/dist/node/index.js +18 -15
- package/dist/node/index.js.map +1 -1
- package/dist/node/terser.js +102 -55
- package/package.json +28 -13
- package/types/package.json +3 -0
- package/api-extractor.json +0 -54
- package/dist/node/chunks/dep-0d2f9464.js.map +0 -1
- package/dist/node/chunks/dep-11213a75.js.map +0 -1
- package/dist/node/chunks/dep-91aa74e8.js.map +0 -1
- package/dist/node/chunks/dep-c7e510f9.js.map +0 -1
- package/dist/node/chunks/dep-e36486f6.js.map +0 -1
- package/dist/node/chunks/dep-eb6ef720.js.map +0 -1
- package/dist/node/terser.js.map +0 -1
- package/rollup.config.js +0 -389
- package/scripts/patchTypes.js +0 -70
- package/src/node/__tests__/asset.spec.ts +0 -156
- package/src/node/__tests__/build.spec.ts +0 -67
- package/src/node/__tests__/config.spec.ts +0 -166
- package/src/node/__tests__/packages/name/package.json +0 -3
- package/src/node/__tests__/packages/noname/package.json +0 -1
- package/src/node/__tests__/plugins/css.spec.ts +0 -116
- package/src/node/__tests__/scan.spec.ts +0 -118
- package/src/node/__tests__/utils.spec.ts +0 -40
- package/src/node/build.ts +0 -783
- package/src/node/cli.ts +0 -239
- package/src/node/config.ts +0 -1033
- package/src/node/constants.ts +0 -87
- package/src/node/importGlob.ts +0 -173
- package/src/node/index.ts +0 -88
- package/src/node/logger.ts +0 -167
- package/src/node/optimizer/esbuildDepPlugin.ts +0 -216
- package/src/node/optimizer/index.ts +0 -410
- package/src/node/optimizer/registerMissing.ts +0 -102
- package/src/node/optimizer/scan.ts +0 -457
- package/src/node/plugin.ts +0 -138
- package/src/node/plugins/asset.ts +0 -365
- package/src/node/plugins/assetImportMetaUrl.ts +0 -99
- package/src/node/plugins/clientInjections.ts +0 -72
- package/src/node/plugins/css.ts +0 -1279
- package/src/node/plugins/dataUri.ts +0 -64
- package/src/node/plugins/define.ts +0 -107
- package/src/node/plugins/esbuild.ts +0 -280
- package/src/node/plugins/html.ts +0 -673
- package/src/node/plugins/importAnalysis.ts +0 -614
- package/src/node/plugins/importAnalysisBuild.ts +0 -334
- package/src/node/plugins/index.ts +0 -69
- package/src/node/plugins/json.ts +0 -75
- package/src/node/plugins/loadFallback.ts +0 -19
- package/src/node/plugins/manifest.ts +0 -123
- package/src/node/plugins/modulePreloadPolyfill.ts +0 -100
- package/src/node/plugins/preAlias.ts +0 -22
- package/src/node/plugins/reporter.ts +0 -244
- package/src/node/plugins/resolve.ts +0 -925
- package/src/node/plugins/terser.ts +0 -40
- package/src/node/plugins/wasm.ts +0 -72
- package/src/node/plugins/worker.ts +0 -117
- package/src/node/preview.ts +0 -82
- package/src/node/server/__tests__/fixtures/none/nested/package.json +0 -3
- package/src/node/server/__tests__/fixtures/pnpm/nested/package.json +0 -3
- package/src/node/server/__tests__/fixtures/pnpm/package.json +0 -3
- package/src/node/server/__tests__/fixtures/pnpm/pnpm-workspace.yaml +0 -0
- package/src/node/server/__tests__/fixtures/yarn/nested/package.json +0 -3
- package/src/node/server/__tests__/fixtures/yarn/package.json +0 -6
- package/src/node/server/__tests__/search-root.spec.ts +0 -31
- package/src/node/server/hmr.ts +0 -489
- package/src/node/server/http.ts +0 -198
- package/src/node/server/index.ts +0 -705
- package/src/node/server/middlewares/base.ts +0 -52
- package/src/node/server/middlewares/error.ts +0 -98
- package/src/node/server/middlewares/indexHtml.ts +0 -170
- package/src/node/server/middlewares/proxy.ts +0 -124
- package/src/node/server/middlewares/spaFallback.ts +0 -32
- package/src/node/server/middlewares/static.ts +0 -153
- package/src/node/server/middlewares/time.ts +0 -18
- package/src/node/server/middlewares/transform.ts +0 -196
- package/src/node/server/moduleGraph.ts +0 -200
- package/src/node/server/openBrowser.ts +0 -101
- package/src/node/server/pluginContainer.ts +0 -546
- package/src/node/server/searchRoot.ts +0 -70
- package/src/node/server/send.ts +0 -54
- package/src/node/server/sourcemap.ts +0 -54
- package/src/node/server/transformRequest.ts +0 -168
- package/src/node/server/ws.ts +0 -131
- package/src/node/ssr/__tests__/ssrTransform.spec.ts +0 -309
- package/src/node/ssr/ssrExternal.ts +0 -161
- package/src/node/ssr/ssrManifestPlugin.ts +0 -53
- package/src/node/ssr/ssrModuleLoader.ts +0 -214
- package/src/node/ssr/ssrStacktrace.ts +0 -75
- package/src/node/ssr/ssrTransform.ts +0 -452
- package/src/node/tsconfig.json +0 -14
- package/src/node/utils.ts +0 -565
- package/tsconfig.base.json +0 -11
package/src/node/plugins/html.ts
DELETED
|
@@ -1,673 +0,0 @@
|
|
|
1
|
-
import fs from 'fs'
|
|
2
|
-
import path from 'path'
|
|
3
|
-
import { Plugin } from '../plugin'
|
|
4
|
-
import { ViteDevServer } from '../server'
|
|
5
|
-
import { OutputAsset, OutputBundle, OutputChunk } from 'rollup'
|
|
6
|
-
import {
|
|
7
|
-
slash,
|
|
8
|
-
cleanUrl,
|
|
9
|
-
isExternalUrl,
|
|
10
|
-
isDataUrl,
|
|
11
|
-
generateCodeFrame,
|
|
12
|
-
processSrcSet
|
|
13
|
-
} from '../utils'
|
|
14
|
-
import { ResolvedConfig } from '../config'
|
|
15
|
-
import MagicString from 'magic-string'
|
|
16
|
-
import {
|
|
17
|
-
checkPublicFile,
|
|
18
|
-
assetUrlRE,
|
|
19
|
-
urlToBuiltUrl,
|
|
20
|
-
getAssetFilename
|
|
21
|
-
} from './asset'
|
|
22
|
-
import { isCSSRequest, chunkToEmittedCssFileMap } from './css'
|
|
23
|
-
import { modulePreloadPolyfillId } from './modulePreloadPolyfill'
|
|
24
|
-
import {
|
|
25
|
-
AttributeNode,
|
|
26
|
-
NodeTransform,
|
|
27
|
-
NodeTypes,
|
|
28
|
-
ElementNode
|
|
29
|
-
} from '@vue/compiler-dom'
|
|
30
|
-
|
|
31
|
-
const htmlProxyRE = /\?html-proxy&index=(\d+)\.js$/
|
|
32
|
-
export const isHTMLProxy = (id: string): boolean => htmlProxyRE.test(id)
|
|
33
|
-
|
|
34
|
-
const htmlCommentRE = /<!--[\s\S]*?-->/g
|
|
35
|
-
const scriptModuleRE =
|
|
36
|
-
/(<script\b[^>]*type\s*=\s*(?:"module"|'module')[^>]*>)(.*?)<\/script>/gims
|
|
37
|
-
|
|
38
|
-
export function htmlInlineScriptProxyPlugin(): Plugin {
|
|
39
|
-
return {
|
|
40
|
-
name: 'vite:html',
|
|
41
|
-
|
|
42
|
-
resolveId(id) {
|
|
43
|
-
if (htmlProxyRE.test(id)) {
|
|
44
|
-
return id
|
|
45
|
-
}
|
|
46
|
-
},
|
|
47
|
-
|
|
48
|
-
load(id) {
|
|
49
|
-
const proxyMatch = id.match(htmlProxyRE)
|
|
50
|
-
if (proxyMatch) {
|
|
51
|
-
const index = Number(proxyMatch[1])
|
|
52
|
-
const file = cleanUrl(id)
|
|
53
|
-
const html = fs.readFileSync(file, 'utf-8').replace(htmlCommentRE, '')
|
|
54
|
-
let match: RegExpExecArray | null | undefined
|
|
55
|
-
scriptModuleRE.lastIndex = 0
|
|
56
|
-
for (let i = 0; i <= index; i++) {
|
|
57
|
-
match = scriptModuleRE.exec(html)
|
|
58
|
-
}
|
|
59
|
-
if (match) {
|
|
60
|
-
return match[2]
|
|
61
|
-
} else {
|
|
62
|
-
throw new Error(`No matching html proxy module found from ${id}`)
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
// this extends the config in @vue/compiler-sfc with <link href>
|
|
70
|
-
export const assetAttrsConfig: Record<string, string[]> = {
|
|
71
|
-
link: ['href'],
|
|
72
|
-
video: ['src', 'poster'],
|
|
73
|
-
source: ['src', 'srcset'],
|
|
74
|
-
img: ['src', 'srcset'],
|
|
75
|
-
image: ['xlink:href', 'href'],
|
|
76
|
-
use: ['xlink:href', 'href']
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
export const isAsyncScriptMap = new WeakMap<
|
|
80
|
-
ResolvedConfig,
|
|
81
|
-
Map<string, boolean>
|
|
82
|
-
>()
|
|
83
|
-
|
|
84
|
-
export async function traverseHtml(
|
|
85
|
-
html: string,
|
|
86
|
-
filePath: string,
|
|
87
|
-
visitor: NodeTransform
|
|
88
|
-
): Promise<void> {
|
|
89
|
-
// lazy load compiler
|
|
90
|
-
const { parse, transform } = await import('@vue/compiler-dom')
|
|
91
|
-
// @vue/compiler-core doesn't like lowercase doctypes
|
|
92
|
-
html = html.replace(/<!doctype\s/i, '<!DOCTYPE ')
|
|
93
|
-
try {
|
|
94
|
-
const ast = parse(html, { comments: true })
|
|
95
|
-
transform(ast, {
|
|
96
|
-
nodeTransforms: [visitor]
|
|
97
|
-
})
|
|
98
|
-
} catch (e) {
|
|
99
|
-
const parseError = {
|
|
100
|
-
loc: filePath,
|
|
101
|
-
frame: '',
|
|
102
|
-
...formatParseError(e, filePath, html)
|
|
103
|
-
}
|
|
104
|
-
throw new Error(
|
|
105
|
-
`Unable to parse ${JSON.stringify(parseError.loc)}\n${parseError.frame}`
|
|
106
|
-
)
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
export function getScriptInfo(node: ElementNode): {
|
|
111
|
-
src: AttributeNode | undefined
|
|
112
|
-
isModule: boolean
|
|
113
|
-
isAsync: boolean
|
|
114
|
-
} {
|
|
115
|
-
let src: AttributeNode | undefined
|
|
116
|
-
let isModule = false
|
|
117
|
-
let isAsync = false
|
|
118
|
-
for (let i = 0; i < node.props.length; i++) {
|
|
119
|
-
const p = node.props[i]
|
|
120
|
-
if (p.type === NodeTypes.ATTRIBUTE) {
|
|
121
|
-
if (p.name === 'src') {
|
|
122
|
-
src = p
|
|
123
|
-
} else if (p.name === 'type' && p.value && p.value.content === 'module') {
|
|
124
|
-
isModule = true
|
|
125
|
-
} else if (p.name === 'async') {
|
|
126
|
-
isAsync = true
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
return { src, isModule, isAsync }
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
function formatParseError(e: any, id: string, html: string): Error {
|
|
134
|
-
// normalize the error to rollup format
|
|
135
|
-
if (e.loc) {
|
|
136
|
-
e.frame = generateCodeFrame(html, e.loc.start.offset)
|
|
137
|
-
e.loc = {
|
|
138
|
-
file: id,
|
|
139
|
-
line: e.loc.start.line,
|
|
140
|
-
column: e.loc.start.column
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
return e
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
/**
|
|
147
|
-
* Compiles index.html into an entry js module
|
|
148
|
-
*/
|
|
149
|
-
export function buildHtmlPlugin(config: ResolvedConfig): Plugin {
|
|
150
|
-
const [preHooks, postHooks] = resolveHtmlTransforms(config.plugins)
|
|
151
|
-
const processedHtml = new Map<string, string>()
|
|
152
|
-
const isExcludedUrl = (url: string) =>
|
|
153
|
-
url.startsWith('#') ||
|
|
154
|
-
isExternalUrl(url) ||
|
|
155
|
-
isDataUrl(url) ||
|
|
156
|
-
checkPublicFile(url, config)
|
|
157
|
-
|
|
158
|
-
return {
|
|
159
|
-
name: 'vite:build-html',
|
|
160
|
-
|
|
161
|
-
buildStart() {
|
|
162
|
-
isAsyncScriptMap.set(config, new Map())
|
|
163
|
-
},
|
|
164
|
-
|
|
165
|
-
async transform(html, id) {
|
|
166
|
-
if (id.endsWith('.html')) {
|
|
167
|
-
const publicPath = `/${slash(path.relative(config.root, id))}`
|
|
168
|
-
// pre-transform
|
|
169
|
-
html = await applyHtmlTransforms(html, preHooks, {
|
|
170
|
-
path: publicPath,
|
|
171
|
-
filename: id
|
|
172
|
-
})
|
|
173
|
-
|
|
174
|
-
let js = ''
|
|
175
|
-
const s = new MagicString(html)
|
|
176
|
-
const assetUrls: AttributeNode[] = []
|
|
177
|
-
let inlineModuleIndex = -1
|
|
178
|
-
|
|
179
|
-
let everyScriptIsAsync = true
|
|
180
|
-
let someScriptsAreAsync = false
|
|
181
|
-
let someScriptsAreDefer = false
|
|
182
|
-
|
|
183
|
-
await traverseHtml(html, id, (node) => {
|
|
184
|
-
if (node.type !== NodeTypes.ELEMENT) {
|
|
185
|
-
return
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
let shouldRemove = false
|
|
189
|
-
|
|
190
|
-
// script tags
|
|
191
|
-
if (node.tag === 'script') {
|
|
192
|
-
const { src, isModule, isAsync } = getScriptInfo(node)
|
|
193
|
-
|
|
194
|
-
const url = src && src.value && src.value.content
|
|
195
|
-
if (url && checkPublicFile(url, config)) {
|
|
196
|
-
// referencing public dir url, prefix with base
|
|
197
|
-
s.overwrite(
|
|
198
|
-
src!.value!.loc.start.offset,
|
|
199
|
-
src!.value!.loc.end.offset,
|
|
200
|
-
`"${config.base + url.slice(1)}"`
|
|
201
|
-
)
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
if (isModule) {
|
|
205
|
-
inlineModuleIndex++
|
|
206
|
-
if (url && !isExcludedUrl(url)) {
|
|
207
|
-
// <script type="module" src="..."/>
|
|
208
|
-
// add it as an import
|
|
209
|
-
js += `\nimport ${JSON.stringify(url)}`
|
|
210
|
-
shouldRemove = true
|
|
211
|
-
} else if (node.children.length) {
|
|
212
|
-
// <script type="module">...</script>
|
|
213
|
-
js += `\nimport "${id}?html-proxy&index=${inlineModuleIndex}.js"`
|
|
214
|
-
shouldRemove = true
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
everyScriptIsAsync &&= isAsync
|
|
218
|
-
someScriptsAreAsync ||= isAsync
|
|
219
|
-
someScriptsAreDefer ||= !isAsync
|
|
220
|
-
}
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
// For asset references in index.html, also generate an import
|
|
224
|
-
// statement for each - this will be handled by the asset plugin
|
|
225
|
-
const assetAttrs = assetAttrsConfig[node.tag]
|
|
226
|
-
if (assetAttrs) {
|
|
227
|
-
for (const p of node.props) {
|
|
228
|
-
if (
|
|
229
|
-
p.type === NodeTypes.ATTRIBUTE &&
|
|
230
|
-
p.value &&
|
|
231
|
-
assetAttrs.includes(p.name)
|
|
232
|
-
) {
|
|
233
|
-
const url = p.value.content
|
|
234
|
-
if (!isExcludedUrl(url)) {
|
|
235
|
-
if (node.tag === 'link' && isCSSRequest(url)) {
|
|
236
|
-
// CSS references, convert to import
|
|
237
|
-
js += `\nimport ${JSON.stringify(url)}`
|
|
238
|
-
shouldRemove = true
|
|
239
|
-
} else {
|
|
240
|
-
assetUrls.push(p)
|
|
241
|
-
}
|
|
242
|
-
} else if (checkPublicFile(url, config)) {
|
|
243
|
-
s.overwrite(
|
|
244
|
-
p.value.loc.start.offset,
|
|
245
|
-
p.value.loc.end.offset,
|
|
246
|
-
`"${config.base + url.slice(1)}"`
|
|
247
|
-
)
|
|
248
|
-
}
|
|
249
|
-
}
|
|
250
|
-
}
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
if (shouldRemove) {
|
|
254
|
-
// remove the script tag from the html. we are going to inject new
|
|
255
|
-
// ones in the end.
|
|
256
|
-
s.remove(node.loc.start.offset, node.loc.end.offset)
|
|
257
|
-
}
|
|
258
|
-
})
|
|
259
|
-
|
|
260
|
-
isAsyncScriptMap.get(config)!.set(id, everyScriptIsAsync)
|
|
261
|
-
|
|
262
|
-
if (someScriptsAreAsync && someScriptsAreDefer) {
|
|
263
|
-
config.logger.warn(
|
|
264
|
-
`\nMixed async and defer script modules in ${id}, output script will fallback to defer. Every script, including inline ones, need to be marked as async for your output script to be async.`
|
|
265
|
-
)
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
// for each encountered asset url, rewrite original html so that it
|
|
269
|
-
// references the post-build location.
|
|
270
|
-
for (const attr of assetUrls) {
|
|
271
|
-
const value = attr.value!
|
|
272
|
-
try {
|
|
273
|
-
const url =
|
|
274
|
-
attr.name === 'srcset'
|
|
275
|
-
? await processSrcSet(value.content, ({ url }) =>
|
|
276
|
-
urlToBuiltUrl(url, id, config, this)
|
|
277
|
-
)
|
|
278
|
-
: await urlToBuiltUrl(value.content, id, config, this)
|
|
279
|
-
|
|
280
|
-
s.overwrite(
|
|
281
|
-
value.loc.start.offset,
|
|
282
|
-
value.loc.end.offset,
|
|
283
|
-
`"${url}"`
|
|
284
|
-
)
|
|
285
|
-
} catch (e) {
|
|
286
|
-
// #1885 preload may be pointing to urls that do not exist
|
|
287
|
-
// locally on disk
|
|
288
|
-
if (e.code !== 'ENOENT') {
|
|
289
|
-
throw e
|
|
290
|
-
}
|
|
291
|
-
}
|
|
292
|
-
}
|
|
293
|
-
|
|
294
|
-
processedHtml.set(id, s.toString())
|
|
295
|
-
|
|
296
|
-
// inject module preload polyfill
|
|
297
|
-
if (config.build.polyfillModulePreload) {
|
|
298
|
-
js = `import "${modulePreloadPolyfillId}";\n${js}`
|
|
299
|
-
}
|
|
300
|
-
|
|
301
|
-
return js
|
|
302
|
-
}
|
|
303
|
-
},
|
|
304
|
-
|
|
305
|
-
async generateBundle(options, bundle) {
|
|
306
|
-
const analyzedChunk: Map<OutputChunk, number> = new Map()
|
|
307
|
-
const getImportedChunks = (
|
|
308
|
-
chunk: OutputChunk,
|
|
309
|
-
seen: Set<string> = new Set()
|
|
310
|
-
): OutputChunk[] => {
|
|
311
|
-
const chunks: OutputChunk[] = []
|
|
312
|
-
chunk.imports.forEach((file) => {
|
|
313
|
-
const importee = bundle[file]
|
|
314
|
-
if (importee?.type === 'chunk' && !seen.has(file)) {
|
|
315
|
-
seen.add(file)
|
|
316
|
-
|
|
317
|
-
// post-order traversal
|
|
318
|
-
chunks.push(...getImportedChunks(importee, seen))
|
|
319
|
-
chunks.push(importee)
|
|
320
|
-
}
|
|
321
|
-
})
|
|
322
|
-
return chunks
|
|
323
|
-
}
|
|
324
|
-
|
|
325
|
-
const toScriptTag = (
|
|
326
|
-
chunk: OutputChunk,
|
|
327
|
-
isAsync: boolean
|
|
328
|
-
): HtmlTagDescriptor => ({
|
|
329
|
-
tag: 'script',
|
|
330
|
-
attrs: {
|
|
331
|
-
...(isAsync ? { async: true } : {}),
|
|
332
|
-
type: 'module',
|
|
333
|
-
crossorigin: true,
|
|
334
|
-
src: toPublicPath(chunk.fileName, config)
|
|
335
|
-
}
|
|
336
|
-
})
|
|
337
|
-
|
|
338
|
-
const toPreloadTag = (chunk: OutputChunk): HtmlTagDescriptor => ({
|
|
339
|
-
tag: 'link',
|
|
340
|
-
attrs: {
|
|
341
|
-
rel: 'modulepreload',
|
|
342
|
-
href: toPublicPath(chunk.fileName, config)
|
|
343
|
-
}
|
|
344
|
-
})
|
|
345
|
-
|
|
346
|
-
const getCssTagsForChunk = (
|
|
347
|
-
chunk: OutputChunk,
|
|
348
|
-
seen: Set<string> = new Set()
|
|
349
|
-
): HtmlTagDescriptor[] => {
|
|
350
|
-
const tags: HtmlTagDescriptor[] = []
|
|
351
|
-
if (!analyzedChunk.has(chunk)) {
|
|
352
|
-
analyzedChunk.set(chunk, 1)
|
|
353
|
-
chunk.imports.forEach((file) => {
|
|
354
|
-
const importee = bundle[file]
|
|
355
|
-
if (importee?.type === 'chunk') {
|
|
356
|
-
tags.push(...getCssTagsForChunk(importee, seen))
|
|
357
|
-
}
|
|
358
|
-
})
|
|
359
|
-
}
|
|
360
|
-
|
|
361
|
-
const cssFiles = chunkToEmittedCssFileMap.get(chunk)
|
|
362
|
-
if (cssFiles) {
|
|
363
|
-
cssFiles.forEach((file) => {
|
|
364
|
-
if (!seen.has(file)) {
|
|
365
|
-
seen.add(file)
|
|
366
|
-
tags.push({
|
|
367
|
-
tag: 'link',
|
|
368
|
-
attrs: {
|
|
369
|
-
rel: 'stylesheet',
|
|
370
|
-
href: toPublicPath(file, config)
|
|
371
|
-
}
|
|
372
|
-
})
|
|
373
|
-
}
|
|
374
|
-
})
|
|
375
|
-
}
|
|
376
|
-
return tags
|
|
377
|
-
}
|
|
378
|
-
|
|
379
|
-
for (const [id, html] of processedHtml) {
|
|
380
|
-
const isAsync = isAsyncScriptMap.get(config)!.get(id)!
|
|
381
|
-
|
|
382
|
-
// resolve asset url references
|
|
383
|
-
let result = html.replace(assetUrlRE, (_, fileHash, postfix = '') => {
|
|
384
|
-
return config.base + getAssetFilename(fileHash, config) + postfix
|
|
385
|
-
})
|
|
386
|
-
|
|
387
|
-
// find corresponding entry chunk
|
|
388
|
-
const chunk = Object.values(bundle).find(
|
|
389
|
-
(chunk) =>
|
|
390
|
-
chunk.type === 'chunk' &&
|
|
391
|
-
chunk.isEntry &&
|
|
392
|
-
chunk.facadeModuleId === id
|
|
393
|
-
) as OutputChunk | undefined
|
|
394
|
-
let canInlineEntry = false
|
|
395
|
-
|
|
396
|
-
// inject chunk asset links
|
|
397
|
-
if (chunk) {
|
|
398
|
-
// an entry chunk can be inlined if
|
|
399
|
-
// - it's an ES module (e.g. not generated by the legacy plugin)
|
|
400
|
-
// - it contains no meaningful code other than import statments
|
|
401
|
-
if (options.format === 'es' && isEntirelyImport(chunk.code)) {
|
|
402
|
-
canInlineEntry = true
|
|
403
|
-
}
|
|
404
|
-
|
|
405
|
-
// when not inlined, inject <script> for entry and modulepreload its dependencies
|
|
406
|
-
// when inlined, discard entry chunk and inject <script> for everything in post-order
|
|
407
|
-
const imports = getImportedChunks(chunk)
|
|
408
|
-
const assetTags = canInlineEntry
|
|
409
|
-
? imports.map((chunk) => toScriptTag(chunk, isAsync))
|
|
410
|
-
: [toScriptTag(chunk, isAsync), ...imports.map(toPreloadTag)]
|
|
411
|
-
|
|
412
|
-
assetTags.push(...getCssTagsForChunk(chunk))
|
|
413
|
-
|
|
414
|
-
result = injectToHead(result, assetTags)
|
|
415
|
-
}
|
|
416
|
-
|
|
417
|
-
// inject css link when cssCodeSplit is false
|
|
418
|
-
if (!config.build.cssCodeSplit) {
|
|
419
|
-
const cssChunk = Object.values(bundle).find(
|
|
420
|
-
(chunk) => chunk.type === 'asset' && chunk.name === 'style.css'
|
|
421
|
-
) as OutputAsset | undefined
|
|
422
|
-
if (cssChunk) {
|
|
423
|
-
result = injectToHead(result, [
|
|
424
|
-
{
|
|
425
|
-
tag: 'link',
|
|
426
|
-
attrs: {
|
|
427
|
-
rel: 'stylesheet',
|
|
428
|
-
href: toPublicPath(cssChunk.fileName, config)
|
|
429
|
-
}
|
|
430
|
-
}
|
|
431
|
-
])
|
|
432
|
-
}
|
|
433
|
-
}
|
|
434
|
-
|
|
435
|
-
const shortEmitName = path.posix.relative(config.root, id)
|
|
436
|
-
result = await applyHtmlTransforms(result, postHooks, {
|
|
437
|
-
path: '/' + shortEmitName,
|
|
438
|
-
filename: id,
|
|
439
|
-
bundle,
|
|
440
|
-
chunk
|
|
441
|
-
})
|
|
442
|
-
|
|
443
|
-
if (chunk && canInlineEntry) {
|
|
444
|
-
// all imports from entry have been inlined to html, prevent rollup from outputting it
|
|
445
|
-
delete bundle[chunk.fileName]
|
|
446
|
-
}
|
|
447
|
-
|
|
448
|
-
this.emitFile({
|
|
449
|
-
type: 'asset',
|
|
450
|
-
fileName: shortEmitName,
|
|
451
|
-
source: result
|
|
452
|
-
})
|
|
453
|
-
}
|
|
454
|
-
}
|
|
455
|
-
}
|
|
456
|
-
}
|
|
457
|
-
|
|
458
|
-
export interface HtmlTagDescriptor {
|
|
459
|
-
tag: string
|
|
460
|
-
attrs?: Record<string, string | boolean | undefined>
|
|
461
|
-
children?: string | HtmlTagDescriptor[]
|
|
462
|
-
/**
|
|
463
|
-
* default: 'head-prepend'
|
|
464
|
-
*/
|
|
465
|
-
injectTo?: 'head' | 'body' | 'head-prepend' | 'body-prepend'
|
|
466
|
-
}
|
|
467
|
-
|
|
468
|
-
export type IndexHtmlTransformResult =
|
|
469
|
-
| string
|
|
470
|
-
| HtmlTagDescriptor[]
|
|
471
|
-
| {
|
|
472
|
-
html: string
|
|
473
|
-
tags: HtmlTagDescriptor[]
|
|
474
|
-
}
|
|
475
|
-
|
|
476
|
-
export interface IndexHtmlTransformContext {
|
|
477
|
-
/**
|
|
478
|
-
* public path when served
|
|
479
|
-
*/
|
|
480
|
-
path: string
|
|
481
|
-
/**
|
|
482
|
-
* filename on disk
|
|
483
|
-
*/
|
|
484
|
-
filename: string
|
|
485
|
-
server?: ViteDevServer
|
|
486
|
-
bundle?: OutputBundle
|
|
487
|
-
chunk?: OutputChunk
|
|
488
|
-
originalUrl?: string
|
|
489
|
-
}
|
|
490
|
-
|
|
491
|
-
export type IndexHtmlTransformHook = (
|
|
492
|
-
html: string,
|
|
493
|
-
ctx: IndexHtmlTransformContext
|
|
494
|
-
) => IndexHtmlTransformResult | void | Promise<IndexHtmlTransformResult | void>
|
|
495
|
-
|
|
496
|
-
export type IndexHtmlTransform =
|
|
497
|
-
| IndexHtmlTransformHook
|
|
498
|
-
| {
|
|
499
|
-
enforce?: 'pre' | 'post'
|
|
500
|
-
transform: IndexHtmlTransformHook
|
|
501
|
-
}
|
|
502
|
-
|
|
503
|
-
export function resolveHtmlTransforms(
|
|
504
|
-
plugins: readonly Plugin[]
|
|
505
|
-
): [IndexHtmlTransformHook[], IndexHtmlTransformHook[]] {
|
|
506
|
-
const preHooks: IndexHtmlTransformHook[] = []
|
|
507
|
-
const postHooks: IndexHtmlTransformHook[] = []
|
|
508
|
-
|
|
509
|
-
for (const plugin of plugins) {
|
|
510
|
-
const hook = plugin.transformIndexHtml
|
|
511
|
-
if (hook) {
|
|
512
|
-
if (typeof hook === 'function') {
|
|
513
|
-
postHooks.push(hook)
|
|
514
|
-
} else if (hook.enforce === 'pre') {
|
|
515
|
-
preHooks.push(hook.transform)
|
|
516
|
-
} else {
|
|
517
|
-
postHooks.push(hook.transform)
|
|
518
|
-
}
|
|
519
|
-
}
|
|
520
|
-
}
|
|
521
|
-
|
|
522
|
-
return [preHooks, postHooks]
|
|
523
|
-
}
|
|
524
|
-
|
|
525
|
-
export async function applyHtmlTransforms(
|
|
526
|
-
html: string,
|
|
527
|
-
hooks: IndexHtmlTransformHook[],
|
|
528
|
-
ctx: IndexHtmlTransformContext
|
|
529
|
-
): Promise<string> {
|
|
530
|
-
const headTags: HtmlTagDescriptor[] = []
|
|
531
|
-
const headPrependTags: HtmlTagDescriptor[] = []
|
|
532
|
-
const bodyTags: HtmlTagDescriptor[] = []
|
|
533
|
-
const bodyPrependTags: HtmlTagDescriptor[] = []
|
|
534
|
-
|
|
535
|
-
for (const hook of hooks) {
|
|
536
|
-
const res = await hook(html, ctx)
|
|
537
|
-
if (!res) {
|
|
538
|
-
continue
|
|
539
|
-
}
|
|
540
|
-
if (typeof res === 'string') {
|
|
541
|
-
html = res
|
|
542
|
-
} else {
|
|
543
|
-
let tags: HtmlTagDescriptor[]
|
|
544
|
-
if (Array.isArray(res)) {
|
|
545
|
-
tags = res
|
|
546
|
-
} else {
|
|
547
|
-
html = res.html || html
|
|
548
|
-
tags = res.tags
|
|
549
|
-
}
|
|
550
|
-
for (const tag of tags) {
|
|
551
|
-
if (tag.injectTo === 'body') {
|
|
552
|
-
bodyTags.push(tag)
|
|
553
|
-
} else if (tag.injectTo === 'body-prepend') {
|
|
554
|
-
bodyPrependTags.push(tag)
|
|
555
|
-
} else if (tag.injectTo === 'head') {
|
|
556
|
-
headTags.push(tag)
|
|
557
|
-
} else {
|
|
558
|
-
headPrependTags.push(tag)
|
|
559
|
-
}
|
|
560
|
-
}
|
|
561
|
-
}
|
|
562
|
-
}
|
|
563
|
-
|
|
564
|
-
// inject tags
|
|
565
|
-
if (headPrependTags.length) {
|
|
566
|
-
html = injectToHead(html, headPrependTags, true)
|
|
567
|
-
}
|
|
568
|
-
if (headTags.length) {
|
|
569
|
-
html = injectToHead(html, headTags)
|
|
570
|
-
}
|
|
571
|
-
if (bodyPrependTags.length) {
|
|
572
|
-
html = injectToBody(html, bodyPrependTags, true)
|
|
573
|
-
}
|
|
574
|
-
if (bodyTags.length) {
|
|
575
|
-
html = injectToBody(html, bodyTags)
|
|
576
|
-
}
|
|
577
|
-
|
|
578
|
-
return html
|
|
579
|
-
}
|
|
580
|
-
|
|
581
|
-
const importRE = /\bimport\s*("[^"]*[^\\]"|'[^']*[^\\]');*/g
|
|
582
|
-
const commentRE = /\/\*[\s\S]*?\*\/|\/\/.*$/gm
|
|
583
|
-
function isEntirelyImport(code: string) {
|
|
584
|
-
// only consider "side-effect" imports, which match <script type=module> semantics exactly
|
|
585
|
-
// the regexes will remove too little in some exotic cases, but false-negatives are alright
|
|
586
|
-
return !code.replace(importRE, '').replace(commentRE, '').trim().length
|
|
587
|
-
}
|
|
588
|
-
|
|
589
|
-
function toPublicPath(filename: string, config: ResolvedConfig) {
|
|
590
|
-
return isExternalUrl(filename) ? filename : config.base + filename
|
|
591
|
-
}
|
|
592
|
-
|
|
593
|
-
const headInjectRE = /<\/head>/
|
|
594
|
-
const headPrependInjectRE = [/<head>/, /<!doctype html>/i]
|
|
595
|
-
function injectToHead(
|
|
596
|
-
html: string,
|
|
597
|
-
tags: HtmlTagDescriptor[],
|
|
598
|
-
prepend = false
|
|
599
|
-
) {
|
|
600
|
-
const tagsHtml = serializeTags(tags)
|
|
601
|
-
if (prepend) {
|
|
602
|
-
// inject after head or doctype
|
|
603
|
-
for (const re of headPrependInjectRE) {
|
|
604
|
-
if (re.test(html)) {
|
|
605
|
-
return html.replace(re, `$&\n${tagsHtml}`)
|
|
606
|
-
}
|
|
607
|
-
}
|
|
608
|
-
} else {
|
|
609
|
-
// inject before head close
|
|
610
|
-
if (headInjectRE.test(html)) {
|
|
611
|
-
return html.replace(headInjectRE, `${tagsHtml}\n $&`)
|
|
612
|
-
}
|
|
613
|
-
}
|
|
614
|
-
// if no <head> tag is present, just prepend
|
|
615
|
-
return tagsHtml + `\n` + html
|
|
616
|
-
}
|
|
617
|
-
|
|
618
|
-
const bodyInjectRE = /<\/body>/
|
|
619
|
-
const bodyPrependInjectRE = /<body[^>]*>/
|
|
620
|
-
function injectToBody(
|
|
621
|
-
html: string,
|
|
622
|
-
tags: HtmlTagDescriptor[],
|
|
623
|
-
prepend = false
|
|
624
|
-
) {
|
|
625
|
-
if (prepend) {
|
|
626
|
-
// inject after body open
|
|
627
|
-
const tagsHtml = `\n` + serializeTags(tags)
|
|
628
|
-
if (bodyPrependInjectRE.test(html)) {
|
|
629
|
-
return html.replace(bodyPrependInjectRE, `$&\n${tagsHtml}`)
|
|
630
|
-
}
|
|
631
|
-
// if no body, prepend
|
|
632
|
-
return tagsHtml + `\n` + html
|
|
633
|
-
} else {
|
|
634
|
-
// inject before body close
|
|
635
|
-
const tagsHtml = `\n` + serializeTags(tags)
|
|
636
|
-
if (bodyInjectRE.test(html)) {
|
|
637
|
-
return html.replace(bodyInjectRE, `${tagsHtml}\n$&`)
|
|
638
|
-
}
|
|
639
|
-
// if no body, append
|
|
640
|
-
return html + `\n` + tagsHtml
|
|
641
|
-
}
|
|
642
|
-
}
|
|
643
|
-
|
|
644
|
-
const unaryTags = new Set(['link', 'meta', 'base'])
|
|
645
|
-
|
|
646
|
-
function serializeTag({ tag, attrs, children }: HtmlTagDescriptor): string {
|
|
647
|
-
if (unaryTags.has(tag)) {
|
|
648
|
-
return `<${tag}${serializeAttrs(attrs)}>`
|
|
649
|
-
} else {
|
|
650
|
-
return `<${tag}${serializeAttrs(attrs)}>${serializeTags(children)}</${tag}>`
|
|
651
|
-
}
|
|
652
|
-
}
|
|
653
|
-
|
|
654
|
-
function serializeTags(tags: HtmlTagDescriptor['children']): string {
|
|
655
|
-
if (typeof tags === 'string') {
|
|
656
|
-
return tags
|
|
657
|
-
} else if (tags) {
|
|
658
|
-
return ` ${tags.map(serializeTag).join('\n ')}`
|
|
659
|
-
}
|
|
660
|
-
return ''
|
|
661
|
-
}
|
|
662
|
-
|
|
663
|
-
function serializeAttrs(attrs: HtmlTagDescriptor['attrs']): string {
|
|
664
|
-
let res = ''
|
|
665
|
-
for (const key in attrs) {
|
|
666
|
-
if (typeof attrs[key] === 'boolean') {
|
|
667
|
-
res += attrs[key] ? ` ${key}` : ``
|
|
668
|
-
} else {
|
|
669
|
-
res += ` ${key}=${JSON.stringify(attrs[key])}`
|
|
670
|
-
}
|
|
671
|
-
}
|
|
672
|
-
return res
|
|
673
|
-
}
|