Skip to content

Commit

Permalink
feat: chunkMap for legacy
Browse files Browse the repository at this point in the history
  • Loading branch information
bhbs committed Apr 27, 2024
1 parent 5ab5397 commit 22f8d74
Show file tree
Hide file tree
Showing 2 changed files with 80 additions and 5 deletions.
81 changes: 79 additions & 2 deletions packages/plugin-legacy/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import type {
import type {
NormalizedOutputOptions,
OutputBundle,
OutputChunk,
OutputOptions,
PreRenderedChunk,
RenderedChunk,
Expand Down Expand Up @@ -122,6 +123,51 @@ const _require = createRequire(import.meta.url)
const nonLeadingHashInFileNameRE = /[^/]+\[hash(?::\d+)?\]/
const prefixedHashInFileNameRE = /\W?\[hash(:\d+)?\]/

const hashPlaceholderLeft = '!~{'
const hashPlaceholderRight = '}~'
const hashPlaceholderOverhead =
hashPlaceholderLeft.length + hashPlaceholderRight.length
const maxHashSize = 22
// from https://github.com/rollup/rollup/blob/fbc25afcc2e494b562358479524a88ab8fe0f1bf/src/utils/hashPlaceholders.ts#L41-L46
const REPLACER_REGEX = new RegExp(
// eslint-disable-next-line regexp/strict, regexp/prefer-w
`${hashPlaceholderLeft}[0-9a-zA-Z_$]{1,${
maxHashSize - hashPlaceholderOverhead
}}${hashPlaceholderRight}`,
'g',
)

const hashPlaceholderToFacadeModuleIdHashMap: Map<string, string> = new Map()

function augmentFacadeModuleIdHash(name: string): string {
return name.replace(
REPLACER_REGEX,
(match) => hashPlaceholderToFacadeModuleIdHashMap.get(match) ?? match,
)
}

function createChunkMap(
bundle: OutputBundle,
base: string,
): Record<string, string> {
return Object.fromEntries(
Object.values(bundle)
.filter((chunk): chunk is OutputChunk => chunk.type === 'chunk')
.map((output) => {
return [
base + augmentFacadeModuleIdHash(output.preliminaryFileName),
base + output.fileName,
]
}),
)
}

export function getHash(text: Buffer | string, length = 8): string {
const h = createHash('sha256').update(text).digest('hex').substring(0, length)
if (length <= 64) return h
return h.padEnd(length, '_')
}

function viteLegacyPlugin(options: Options = {}): Plugin[] {
let config: ResolvedConfig
let targets: Options['targets']
Expand Down Expand Up @@ -153,6 +199,7 @@ function viteLegacyPlugin(options: Options = {}): Plugin[] {
const isDebug =
debugFlags.includes('vite:*') || debugFlags.includes('vite:legacy')

const chunkMap = new Map()
const facadeToLegacyChunkMap = new Map()
const facadeToLegacyPolyfillMap = new Map()
const facadeToModernPolyfillMap = new Map()
Expand Down Expand Up @@ -405,7 +452,7 @@ function viteLegacyPlugin(options: Options = {}): Plugin[] {
}
},

async renderChunk(raw, chunk, opts) {
async renderChunk(raw, chunk, opts, meta) {
if (config.build.ssr) {
return null
}
Expand Down Expand Up @@ -450,6 +497,17 @@ function viteLegacyPlugin(options: Options = {}): Plugin[] {
}
}

Object.values(meta.chunks).forEach((chunk) => {
const hashPlaceholder = chunk.fileName.match(REPLACER_REGEX)?.[0]
if (!hashPlaceholder) return
if (hashPlaceholderToFacadeModuleIdHashMap.get(hashPlaceholder)) return

hashPlaceholderToFacadeModuleIdHashMap.set(
hashPlaceholder,
getHash(chunk.facadeModuleId ?? chunk.fileName),
)
})

if (!genLegacy) {
return null
}
Expand Down Expand Up @@ -505,13 +563,21 @@ function viteLegacyPlugin(options: Options = {}): Plugin[] {
return null
},

transformIndexHtml(html, { chunk }) {
transformIndexHtml(html, { chunk, filename, bundle }) {
if (config.build.ssr) return
if (!chunk) return
if (chunk.fileName.includes('-legacy')) {
// The legacy bundle is built first, and its index.html isn't actually emitted if
// modern bundle will be generated. Here we simply record its corresponding legacy chunk.
facadeToLegacyChunkMap.set(chunk.facadeModuleId, chunk.fileName)

const relativeUrlPath = path.posix.relative(
config.root,
normalizePath(filename),
)
const assetsBase = getBaseInHTML(relativeUrlPath, config)
chunkMap.set(chunk.facadeModuleId, createChunkMap(bundle!, assetsBase))

if (genModern) {
return
}
Expand Down Expand Up @@ -634,6 +700,17 @@ function viteLegacyPlugin(options: Options = {}): Plugin[] {
})
}

if (chunkMap.get(chunk.facadeModuleId)) {
tags.push({
tag: 'script',
attrs: { type: 'systemjs-importmap' },
children: JSON.stringify({
imports: chunkMap.get(chunk.facadeModuleId),
}),
injectTo: 'head-prepend',
})
}

return {
html,
tags,
Expand Down
4 changes: 1 addition & 3 deletions packages/vite/src/node/build.ts
Original file line number Diff line number Diff line change
Expand Up @@ -448,9 +448,7 @@ export async function resolveBuildPlugins(config: ResolvedConfig): Promise<{
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
// TODO: Change to an opt-in option (temporarily disable only for VitePress)
!config.vitepress &&
// TODO: Legacy support
config.plugins.every((plugin) => !plugin.name.includes('vite:legacy'))
!config.vitepress
? [chunkMapPlugin()]
: []),
],
Expand Down

0 comments on commit 22f8d74

Please sign in to comment.