Skip to content

Commit

Permalink
fix: fix theme chunking logic causing out-of-order styles (#3403)
Browse files Browse the repository at this point in the history
  • Loading branch information
brc-dd committed Jan 3, 2024
1 parent 1407baf commit a6cd891
Show file tree
Hide file tree
Showing 4 changed files with 48 additions and 22 deletions.
11 changes: 4 additions & 7 deletions src/client/theme-default/components/VPLocalSearchBox.vue
Expand Up @@ -28,6 +28,7 @@ import {
} from 'vue'
import type { ModalTranslations } from '../../../../types/local-search'
import { pathToFile } from '../../app/utils'
import { escapeRegExp } from '../../shared'
import { useData } from '../composables/data'
import { LRUCache } from '../support/lru'
import { createSearchTranslate } from '../support/translation'
Expand Down Expand Up @@ -146,8 +147,8 @@ const cache = new LRUCache<string, Map<string, string>>(16) // 16 files
debouncedWatch(
() => [searchIndex.value, filterText.value, showDetailedList.value] as const,
async ([index, filterTextValue, showDetailedListValue], old, onCleanup) => {
if (old?.[0] !== index) { // in case of hmr
if (old?.[0] !== index) {
// in case of hmr
cache.clear()
}
Expand Down Expand Up @@ -396,11 +397,7 @@ function formMarkRegex(terms: Set<string>) {
return new RegExp(
[...terms]
.sort((a, b) => b.length - a.length)
.map((term) => {
return `(${term
.replace(/[|\\{}()[\]^$+*?.]/g, '\\$&')
.replace(/-/g, '\\x2d')})`
})
.map((term) => `(${escapeRegExp(term)})`)
.join('|'),
'gi'
)
Expand Down
3 changes: 0 additions & 3 deletions src/client/theme-default/without-fonts.ts
Expand Up @@ -11,9 +11,6 @@ import type { Theme } from 'vitepress'
import VPBadge from './components/VPBadge.vue'
import Layout from './Layout.vue'

// Note: if we add more optional components here, i.e. components that are not
// used in the theme by default unless the user imports them, make sure to update
// the `lazyDefaultThemeComponentsRE` regex in src/node/build/bundle.ts.
export { default as VPImage } from './components/VPImage.vue'
export { default as VPButton } from './components/VPButton.vue'
export { default as VPHomeHero } from './components/VPHomeHero.vue'
Expand Down
51 changes: 39 additions & 12 deletions src/node/build/bundle.ts
Expand Up @@ -11,18 +11,29 @@ import {
import { APP_PATH } from '../alias'
import type { SiteConfig } from '../config'
import { createVitePressPlugin } from '../plugin'
import { sanitizeFileName, slash } from '../shared'
import { escapeRegExp, sanitizeFileName, slash } from '../shared'
import { task } from '../utils/task'
import { buildMPAClient } from './buildMPAClient'

// A list of default theme components that should only be loaded on demand.
const lazyDefaultThemeComponentsRE =
/VP(HomeSponsors|DocAsideSponsors|TeamPage|TeamMembers|LocalSearchBox|AlgoliaSearchBox|CarbonAds|DocAsideCarbonAds|Sponsors)/
// https://github.com/vitejs/vite/blob/d2aa0969ee316000d3b957d7e879f001e85e369e/packages/vite/src/node/plugins/splitVendorChunk.ts#L14
const CSS_LANGS_RE =
/\.(css|less|sass|scss|styl|stylus|pcss|postcss|sss)(?:$|\?)/

const clientDir = normalizePath(
path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../client')
)

// these deps are also being used in the client code (outside of the theme)
// exclude them from the theme chunk so there is no circular dependency
const excludedModules = [
'/@siteData',
'node_modules/@vueuse/core/',
'node_modules/@vueuse/shared/',
'node_modules/vue/',
'node_modules/vue-demi/',
clientDir
]

// bundles the VitePress app for both client AND server.
export async function bundle(
config: SiteConfig,
Expand All @@ -47,6 +58,12 @@ export async function bundle(
input[slash(alias).replace(/\//g, '_')] = path.resolve(config.srcDir, file)
})

const themeEntryRE = new RegExp(
`^${escapeRegExp(
path.resolve(config.themeDir, 'index.js').replace(/\\/g, '/')
).slice(0, -2)}m?(j|t)s`
)

// resolve options to pass to vite
const { rollupOptions } = options

Expand Down Expand Up @@ -109,12 +126,6 @@ export async function bundle(
: `${config.assetsDir}/chunks/[name].[hash].js`
},
manualChunks(id, ctx) {
if (lazyDefaultThemeComponentsRE.test(id)) {
return
}
if (id.startsWith(`${clientDir}/theme-default`)) {
return 'theme'
}
// move known framework code into a stable chunk so that
// custom theme changes do not invalidate hash for all pages
if (id.startsWith('\0vite')) {
Expand All @@ -135,6 +146,19 @@ export async function bundle(
) {
return 'framework'
}

if (
(id.startsWith(`${clientDir}/theme-default`) ||
!excludedModules.some((i) => id.includes(i))) &&
staticImportedByEntry(
id,
ctx.getModuleInfo,
cacheTheme,
themeEntryRE
)
) {
return 'theme'
}
}
})
}
Expand Down Expand Up @@ -182,14 +206,15 @@ export async function bundle(
}

const cache = new Map<string, boolean>()
const cacheTheme = new Map<string, boolean>()

/**
* Check if a module is statically imported by at least one entry.
*/
function isEagerChunk(id: string, getModuleInfo: Rollup.GetModuleInfo) {
if (
id.includes('node_modules') &&
!/\.css($|\\?)/.test(id) &&
!CSS_LANGS_RE.test(id) &&
staticImportedByEntry(id, getModuleInfo, cache)
) {
return true
Expand All @@ -200,6 +225,7 @@ function staticImportedByEntry(
id: string,
getModuleInfo: Rollup.GetModuleInfo,
cache: Map<string, boolean>,
entryRE: RegExp | null = null,
importStack: string[] = []
): boolean {
if (cache.has(id)) {
Expand All @@ -216,7 +242,7 @@ function staticImportedByEntry(
return false
}

if (mod.isEntry) {
if (entryRE ? entryRE.test(id) : mod.isEntry) {
cache.set(id, true)
return true
}
Expand All @@ -225,6 +251,7 @@ function staticImportedByEntry(
importer,
getModuleInfo,
cache,
entryRE,
importStack.concat(id)
)
)
Expand Down
5 changes: 5 additions & 0 deletions src/shared/shared.ts
Expand Up @@ -195,3 +195,8 @@ export function treatAsHtml(filename: string): boolean {

return ext == null || !KNOWN_EXTENSIONS.has(ext.toLowerCase())
}

// https://github.com/sindresorhus/escape-string-regexp/blob/ba9a4473850cb367936417e97f1f2191b7cc67dd/index.js
export function escapeRegExp(str: string) {
return str.replace(/[|\\{}()[\]^$+*?.]/g, '\\$&').replace(/-/g, '\\x2d')
}

0 comments on commit a6cd891

Please sign in to comment.