Skip to content

Commit

Permalink
fix: properly cascade asset hash change
Browse files Browse the repository at this point in the history
  • Loading branch information
yyx990803 committed Feb 2, 2021
1 parent ae50e38 commit f8e4eeb
Show file tree
Hide file tree
Showing 3 changed files with 56 additions and 15 deletions.
55 changes: 45 additions & 10 deletions packages/vite/src/node/plugins/asset.ts
Expand Up @@ -8,6 +8,7 @@ import { cleanUrl } from '../utils'
import { FS_PREFIX } from '../constants'
import { PluginContext, RenderedChunk } from 'rollup'
import MagicString from 'magic-string'
import { createHash } from 'crypto'

export const assetUrlRE = /__VITE_ASSET__([a-z\d]{8})__(?:(.*?)__)?/g

Expand Down Expand Up @@ -63,8 +64,10 @@ export function assetPlugin(config: ResolvedConfig): Plugin {
let s
while ((match = assetUrlQuotedRE.exec(code))) {
s = s || (s = new MagicString(code))
const [full, fileHandle, postfix = ''] = match
const file = this.getFileName(fileHandle)
const [full, hash, postfix = ''] = match
// some internal plugins may still need to emit chunks (e.g. worker) so
// fallback to this.getFileName for that.
const file = getAssetFilename(hash, config) || this.getFileName(hash)
registerAssetToChunk(chunk, file)
const outputFilepath = config.base + file + postfix
s.overwrite(
Expand Down Expand Up @@ -155,6 +158,15 @@ export function fileToDevUrl(id: string, config: ResolvedConfig) {

const assetCache = new WeakMap<ResolvedConfig, Map<string, string>>()

const assetHashToFilenameMap = new WeakMap<
ResolvedConfig,
Map<string, string>
>()

export function getAssetFilename(hash: string, config: ResolvedConfig) {
return assetHashToFilenameMap.get(config)?.get(hash)
}

/**
* Register an asset to be emitted as part of the bundle (if necessary)
* and returns the resolved public URL
Expand Down Expand Up @@ -196,20 +208,43 @@ async function fileToBuiltUrl(
// emit as asset
// rollup supports `import.meta.ROLLUP_FILE_URL_*`, but it generates code
// that uses runtime url sniffing and it can be verbose when targeting
// non-module format. For consistency, generate a marker here and replace
// with resolved url strings in renderChunk.
const fileId = pluginContext.emitFile({
name: path.basename(file),
type: 'asset',
source: content
})
url = `__VITE_ASSET__${fileId}__${postfix ? `${postfix}__` : ``}`
// non-module format. It also fails to cascade the asset content change
// into the chunk's hash, so we have to do our own content hashing here.
// https://bundlers.tooling.report/hashing/asset-cascade/
// https://github.com/rollup/rollup/issues/3415
let map = assetHashToFilenameMap.get(config)
if (!map) {
map = new Map()
assetHashToFilenameMap.set(config, map)
}

const contentHash = getAssetHash(content)
if (!map.has(contentHash)) {
const basename = path.basename(file)
const ext = path.extname(basename)
const fileName = path.posix.join(
config.build.assetsDir,
`${basename.slice(0, -ext.length)}.${contentHash}${ext}`
)
map.set(contentHash, fileName)
pluginContext.emitFile({
fileName,
type: 'asset',
source: content
})
}

url = `__VITE_ASSET__${contentHash}__${postfix ? `${postfix}__` : ``}`
}

cache.set(id, url)
return url
}

function getAssetHash(content: Buffer) {
return createHash('sha256').update(content).digest('hex').slice(0, 8)
}

export async function urlToBuiltUrl(
url: string,
importer: string,
Expand Down
5 changes: 3 additions & 2 deletions packages/vite/src/node/plugins/css.ts
Expand Up @@ -31,6 +31,7 @@ import {
} from 'postcss'
import { ResolveFn, ViteDevServer } from '../'
import {
getAssetFilename,
assetUrlRE,
fileToDevUrl,
registerAssetToChunk,
Expand Down Expand Up @@ -273,8 +274,8 @@ export function cssPostPlugin(config: ResolvedConfig): Plugin {
) => {
// replace asset url references with resolved url.
const isRelativeBase = config.base === '' || config.base.startsWith('.')
css = css.replace(assetUrlRE, (_, fileId, postfix = '') => {
const filename = this.getFileName(fileId) + postfix
css = css.replace(assetUrlRE, (_, fileHash, postfix = '') => {
const filename = getAssetFilename(fileHash, config) + postfix
registerAssetToChunk(chunk, filename)
if (!isRelativeBase || inlined) {
// absoulte base or relative base but inlined (injected as style tag into
Expand Down
11 changes: 8 additions & 3 deletions packages/vite/src/node/plugins/html.ts
Expand Up @@ -7,7 +7,12 @@ import { cleanUrl, isExternalUrl, isDataUrl, generateCodeFrame } from '../utils'
import { ResolvedConfig } from '../config'
import slash from 'slash'
import MagicString from 'magic-string'
import { checkPublicFile, assetUrlRE, urlToBuiltUrl } from './asset'
import {
checkPublicFile,
assetUrlRE,
urlToBuiltUrl,
getAssetFilename
} from './asset'
import { isCSSRequest, chunkToEmittedCssFileMap } from './css'
import { polyfillId } from './dynamicImportPolyfill'
import {
Expand Down Expand Up @@ -280,8 +285,8 @@ export function buildHtmlPlugin(config: ResolvedConfig): Plugin {

for (const [id, html] of processedHtml) {
// resolve asset url references
let result = html.replace(assetUrlRE, (_, fileId, postfix = '') => {
return config.base + this.getFileName(fileId) + postfix
let result = html.replace(assetUrlRE, (_, fileHash, postfix = '') => {
return config.base + getAssetFilename(fileHash, config) + postfix
})

// find corresponding entry chunk
Expand Down

0 comments on commit f8e4eeb

Please sign in to comment.