Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add importedCss and importedAssets properties to RenderedChunk type #6629

Merged
merged 6 commits into from Mar 3, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
9 changes: 9 additions & 0 deletions packages/vite/src/node/index.ts
Expand Up @@ -58,6 +58,7 @@ export type {
HtmlTagDescriptor
} from './plugins/html'
export type { CSSOptions, CSSModulesOptions } from './plugins/css'
export type { ChunkMetadata } from './plugins/metadata'
export type { JsonOptions } from './plugins/json'
export type { TransformOptions as EsbuildTransformOptions } from 'esbuild'
export type { ESBuildOptions, ESBuildTransformResult } from './plugins/esbuild'
Expand Down Expand Up @@ -91,3 +92,11 @@ export type { Terser } from 'types/terser'
export type { RollupCommonJSOptions } from 'types/commonjs'
export type { RollupDynamicImportVarsOptions } from 'types/dynamicImportVars'
export type { Matcher, AnymatchPattern, AnymatchFn } from 'types/anymatch'

import type { ChunkMetadata } from './plugins/metadata'

declare module 'rollup' {
export interface RenderedChunk {
viteMetadata: ChunkMetadata
}
}
15 changes: 2 additions & 13 deletions packages/vite/src/node/plugins/asset.ts
Expand Up @@ -6,7 +6,7 @@ import type { Plugin } from '../plugin'
import type { ResolvedConfig } from '../config'
import { cleanUrl } from '../utils'
import { FS_PREFIX } from '../constants'
import type { OutputOptions, PluginContext, RenderedChunk } from 'rollup'
import type { OutputOptions, PluginContext } from 'rollup'
import MagicString from 'magic-string'
import { createHash } from 'crypto'
import { normalizePath } from '../utils'
Expand All @@ -16,8 +16,6 @@ export const assetUrlRE = /__VITE_ASSET__([a-z\d]{8})__(?:\$_(.*?)__)?/g
const rawRE = /(\?|&)raw(?:&|$)/
const urlRE = /(\?|&)url(?:&|$)/

export const chunkToEmittedAssetsMap = new WeakMap<RenderedChunk, Set<string>>()

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

const assetHashToFilenameMap = new WeakMap<
Expand Down Expand Up @@ -96,7 +94,7 @@ export function assetPlugin(config: ResolvedConfig): Plugin {
// 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)
chunk.viteMetadata.importedAssets.add(cleanUrl(file))
const outputFilepath = config.base + file + postfix
s.overwrite(match.index, match.index + full.length, outputFilepath)
}
Expand Down Expand Up @@ -127,15 +125,6 @@ export function assetPlugin(config: ResolvedConfig): Plugin {
}
}

export function registerAssetToChunk(chunk: RenderedChunk, file: string): void {
let emitted = chunkToEmittedAssetsMap.get(chunk)
if (!emitted) {
emitted = new Set()
chunkToEmittedAssetsMap.set(chunk, emitted)
}
emitted.add(cleanUrl(file))
}

export function checkPublicFile(
url: string,
{ publicDir }: ResolvedConfig
Expand Down
28 changes: 7 additions & 21 deletions packages/vite/src/node/plugins/css.ts
Expand Up @@ -30,7 +30,6 @@ import type { ResolveFn, ViteDevServer } from '../'
import {
getAssetFilename,
assetUrlRE,
registerAssetToChunk,
fileToUrl,
checkPublicFile
} from './asset'
Expand Down Expand Up @@ -120,11 +119,6 @@ const cssModulesCache = new WeakMap<
Map<string, Record<string, string>>
>()

export const chunkToEmittedCssFileMap = new WeakMap<
RenderedChunk,
Set<string>
>()

export const removedPureCssFilesCache = new WeakMap<
ResolvedConfig,
Map<string, RenderedChunk>
Expand Down Expand Up @@ -390,7 +384,7 @@ export function cssPostPlugin(config: ResolvedConfig): Plugin {
const isRelativeBase = config.base === '' || config.base.startsWith('.')
css = css.replace(assetUrlRE, (_, fileHash, postfix = '') => {
const filename = getAssetFilename(fileHash, config) + postfix
registerAssetToChunk(chunk, filename)
chunk.viteMetadata.importedAssets.add(cleanUrl(filename))
if (!isRelativeBase || inlined) {
// absolute base or relative base but inlined (injected as style tag into
// index.html) use the base as-is
Expand Down Expand Up @@ -427,10 +421,7 @@ export function cssPostPlugin(config: ResolvedConfig): Plugin {
type: 'asset',
source: chunkCSS
})
chunkToEmittedCssFileMap.set(
chunk,
new Set([this.getFileName(fileHandle)])
)
chunk.viteMetadata.importedCss.add(this.getFileName(fileHandle))
} else if (!config.build.ssr) {
// legacy build, inline css
chunkCSS = await processChunkCSS(chunkCSS, {
Expand Down Expand Up @@ -488,17 +479,12 @@ export function cssPostPlugin(config: ResolvedConfig): Plugin {
// chunks instead.
chunk.imports = chunk.imports.filter((file) => {
if (pureCssChunks.has(file)) {
const css = chunkToEmittedCssFileMap.get(
bundle[file] as OutputChunk
const {
viteMetadata: { importedCss }
} = bundle[file] as OutputChunk
importedCss.forEach((file) =>
chunk.viteMetadata.importedCss.add(file)
)
if (css) {
let existing = chunkToEmittedCssFileMap.get(chunk)
if (!existing) {
existing = new Set()
}
css.forEach((file) => existing!.add(file))
chunkToEmittedCssFileMap.set(chunk, existing)
}
return false
}
return true
Expand Down
30 changes: 14 additions & 16 deletions packages/vite/src/node/plugins/html.ts
Expand Up @@ -24,7 +24,7 @@ import {
urlToBuiltUrl,
getAssetFilename
} from './asset'
import { isCSSRequest, chunkToEmittedCssFileMap } from './css'
import { isCSSRequest } from './css'
import { modulePreloadPolyfillId } from './modulePreloadPolyfill'
import type {
AttributeNode,
Expand Down Expand Up @@ -532,21 +532,19 @@ export function buildHtmlPlugin(config: ResolvedConfig): Plugin {
})
}

const cssFiles = chunkToEmittedCssFileMap.get(chunk)
if (cssFiles) {
cssFiles.forEach((file) => {
if (!seen.has(file)) {
seen.add(file)
tags.push({
tag: 'link',
attrs: {
rel: 'stylesheet',
href: toPublicPath(file, config)
}
})
}
})
}
chunk.viteMetadata.importedCss.forEach((file) => {
if (!seen.has(file)) {
seen.add(file)
tags.push({
tag: 'link',
attrs: {
rel: 'stylesheet',
href: toPublicPath(file, config)
}
})
}
})

return tags
}

Expand Down
20 changes: 6 additions & 14 deletions packages/vite/src/node/plugins/importAnalysisBuild.ts
Expand Up @@ -5,11 +5,7 @@ import MagicString from 'magic-string'
import type { ImportSpecifier } from 'es-module-lexer'
import { init, parse as parseImports } from 'es-module-lexer'
import type { OutputChunk } from 'rollup'
import {
chunkToEmittedCssFileMap,
isCSSRequest,
removedPureCssFilesCache
} from './css'
import { isCSSRequest, removedPureCssFilesCache } from './css'
import { transformImportGlob } from '../importGlob'
import { bareImportRE } from '../utils'

Expand Down Expand Up @@ -281,21 +277,17 @@ export function buildImportAnalysisPlugin(config: ResolvedConfig): Plugin {
const chunk = bundle[filename] as OutputChunk | undefined
if (chunk) {
deps.add(chunk.fileName)
const cssFiles = chunkToEmittedCssFileMap.get(chunk)
if (cssFiles) {
cssFiles.forEach((file) => {
deps.add(file)
})
}
chunk.viteMetadata.importedCss.forEach((file) => {
deps.add(file)
})
chunk.imports.forEach(addDeps)
} else {
const removedPureCssFiles =
removedPureCssFilesCache.get(config)!
const chunk = removedPureCssFiles.get(filename)
if (chunk) {
const cssFiles = chunkToEmittedCssFileMap.get(chunk)
if (cssFiles && cssFiles.size > 0) {
cssFiles.forEach((file) => {
if (chunk.viteMetadata.importedCss.size) {
chunk.viteMetadata.importedCss.forEach((file) => {
deps.add(file)
})
hasRemovedPureCssChunk = true
Expand Down
2 changes: 2 additions & 0 deletions packages/vite/src/node/plugins/index.ts
Expand Up @@ -16,6 +16,7 @@ import { preAliasPlugin } from './preAlias'
import { definePlugin } from './define'
import { ssrRequireHookPlugin } from './ssrRequireHook'
import { workerImportMetaUrlPlugin } from './workerImportMetaUrl'
import { metadataPlugin } from './metadata'

export async function resolvePlugins(
config: ResolvedConfig,
Expand All @@ -30,6 +31,7 @@ export async function resolvePlugins(
: { pre: [], post: [] }

return [
isBuild ? metadataPlugin() : null,
isBuild ? null : preAliasPlugin(),
aliasPlugin({ entries: config.resolve.alias }),
...prePlugins,
Expand Down
13 changes: 5 additions & 8 deletions packages/vite/src/node/plugins/manifest.ts
Expand Up @@ -2,8 +2,6 @@ import path from 'path'
import type { OutputChunk } from 'rollup'
import type { ResolvedConfig } from '..'
import type { Plugin } from '../plugin'
import { chunkToEmittedCssFileMap } from './css'
import { chunkToEmittedAssetsMap } from './asset'
import { normalizePath } from '../utils'

export type Manifest = Record<string, ManifestChunk>
Expand Down Expand Up @@ -90,13 +88,12 @@ export function manifestPlugin(config: ResolvedConfig): Plugin {
}
}

const cssFiles = chunkToEmittedCssFileMap.get(chunk)
if (cssFiles) {
manifestChunk.css = [...cssFiles]
if (chunk.viteMetadata.importedCss.size) {
manifestChunk.css = [...chunk.viteMetadata.importedCss]
}
if (chunk.viteMetadata.importedAssets.size) {
manifestChunk.assets = [...chunk.viteMetadata.importedAssets]
}

const assets = chunkToEmittedAssetsMap.get(chunk)
if (assets) [(manifestChunk.assets = [...assets])]

return manifestChunk
}
Expand Down
23 changes: 23 additions & 0 deletions packages/vite/src/node/plugins/metadata.ts
@@ -0,0 +1,23 @@
import type { Plugin } from '../plugin'

export interface ChunkMetadata {
importedAssets: Set<string>
importedCss: Set<string>
}

/**
* Prepares the rendered chunks to contain additional metadata during build.
*/
export function metadataPlugin(): Plugin {
return {
name: 'vite:build-metadata',

async renderChunk(_code, chunk) {
chunk.viteMetadata = {
importedAssets: new Set(),
importedCss: new Set()
}
return null
}
}
}
31 changes: 9 additions & 22 deletions packages/vite/src/node/ssr/ssrManifestPlugin.ts
Expand Up @@ -4,8 +4,6 @@ import type { ImportSpecifier } from 'es-module-lexer'
import type { OutputChunk } from 'rollup'
import type { ResolvedConfig } from '..'
import type { Plugin } from '../plugin'
import { chunkToEmittedCssFileMap } from '../plugins/css'
import { chunkToEmittedAssetsMap } from '../plugins/asset'
import { preloadMethod } from '../plugins/importAnalysisBuild'
import { normalizePath } from '../utils'

Expand All @@ -20,29 +18,21 @@ export function ssrManifestPlugin(config: ResolvedConfig): Plugin {
for (const file in bundle) {
const chunk = bundle[file]
if (chunk.type === 'chunk') {
// links for certain entry chunks are already generated in static HTML
// in those cases we only need to record info for non-entry chunks
const cssFiles = chunk.isEntry
? null
: chunkToEmittedCssFileMap.get(chunk)
const assetFiles = chunkToEmittedAssetsMap.get(chunk)
for (const id in chunk.modules) {
const normalizedId = normalizePath(relative(config.root, id))
const mappedChunks =
ssrManifest[normalizedId] || (ssrManifest[normalizedId] = [])
if (!chunk.isEntry) {
mappedChunks.push(base + chunk.fileName)
}
if (cssFiles) {
cssFiles.forEach((file) => {
mappedChunks.push(base + file)
})
}
if (assetFiles) {
assetFiles.forEach((file) => {
// <link> tags for entry chunks are already generated in static HTML,
// so we only need to record info for non-entry chunks.
chunk.viteMetadata.importedCss.forEach((file) => {
mappedChunks.push(base + file)
})
}
chunk.viteMetadata.importedAssets.forEach((file) => {
mappedChunks.push(base + file)
})
}
if (chunk.code.includes(preloadMethod)) {
// generate css deps map
Expand Down Expand Up @@ -74,12 +64,9 @@ export function ssrManifestPlugin(config: ResolvedConfig): Plugin {
analyzed.add(filename)
const chunk = bundle[filename] as OutputChunk | undefined
if (chunk) {
const cssFiles = chunkToEmittedCssFileMap.get(chunk)
if (cssFiles) {
cssFiles.forEach((file) => {
deps.push(`/${file}`)
})
}
chunk.viteMetadata.importedCss.forEach((file) => {
deps.push(`/${file}`)
})
chunk.imports.forEach(addDeps)
}
}
Expand Down