Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
76df629
feat: optimizeDeps.devStrategy, new 'dynamic-scan' strat
patak-dev Jun 30, 2022
48ae304
chore: merge main
patak-dev Jun 30, 2022
f3bb834
chore: update
patak-dev Jun 30, 2022
b6f2d04
fix: use urlWithoutBase
patak-dev Jun 30, 2022
fd46ccf
test: add example of full-reload with 'lazy' in preload playground
patak-dev Jun 30, 2022
562d479
chore: merge main
patak-dev Jul 1, 2022
cda64d2
refactor: dynamic-scan -> scan
patak-dev Jul 1, 2022
a7cf18f
feat: scan strategy, fix alias issue by making it the default
patak-dev Jul 2, 2022
d7da60e
chore: remove unneeded changes to scan.ts
patak-dev Jul 2, 2022
6d288fa
fix: use scanner during build time, remove devStrategy option
patak-dev Jul 2, 2022
39f9858
chore: update
patak-dev Jul 2, 2022
7ad4962
fix: preAliasPlugin during build
patak-dev Jul 2, 2022
89fef62
fix: restrict preAlias to aliased bareImports
patak-dev Jul 2, 2022
6eb114d
fix: post scan optimization
patak-dev Jul 2, 2022
387b18e
chore: try serialize esbuild
patak-dev Jul 2, 2022
80e7a4d
chore: serialize esbuild scan calls
patak-dev Jul 2, 2022
04f34b2
fix: await scanner before optimizing SSR deps
patak-dev Jul 2, 2022
aa58dd8
chore: revert 04f34b2939131edaae16b4f0c5a80978b6ff1210
patak-dev Jul 2, 2022
1ec2f5b
chore: update
patak-dev Jul 2, 2022
e491071
chore: test CI, await scanner and ssr deps optimization before server…
patak-dev Jul 2, 2022
9b33538
chore: sync set of depsOptimizer.scanning
patak-dev Jul 2, 2022
967dfd4
test: move SSR module error test to ssr-vue
patak-dev Jul 2, 2022
6c72736
test: avoid starting two servers concurrently in a test
patak-dev Jul 3, 2022
e814d41
fix: improve init logic
patak-dev Jul 3, 2022
0cb384b
chore: use hints for snapshots
patak-dev Jul 3, 2022
23df866
chore: remove optimizeDeps guard
patak-dev Jul 3, 2022
d81a855
fix: SSR deps external/noExternal optimization
patak-dev Jul 3, 2022
1a58e7d
fix: don't collide external/noExternal with optimizeDeps
patak-dev Jul 3, 2022
48b215e
fix: correct init server await
patak-dev Jul 4, 2022
96b9170
chore: reduce changeset
patak-dev Jul 4, 2022
81b3992
chore: reduce changeset
patak-dev Jul 4, 2022
8861550
chore: remove changes to SSR/optimizeDeps, TBD in another PR
patak-dev Jul 4, 2022
File filter

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
fix: use scanner during build time, remove devStrategy option
  • Loading branch information
patak-dev committed Jul 2, 2022
commit 6d288faf8b4e80e14bb8fac227f83d315982c709
4 changes: 0 additions & 4 deletions docs/guide/migration.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,10 +45,6 @@ Vite's default dev server port is now 5173. You can use [`server.port`](../confi

Vite's default dev server host is now `localhost`. You can use [`server.host`](../config/server-options.md#server-host) to set it to `127.0.0.1`.

Vite optimizes dependencies with esbuild to both convert CJS-only deps to ESM and to reduce the number of modules the browser needs to request. In v3, the default strategy to discover and batch dependencies has changed. Vite no longer pre-scans user code with esbuild to get an initial list of dependencies on cold start. Instead, it delays the first dependency optimization run until every imported user module on load is processed.

To get back the v2 strategy, you can use `optimizeDeps.devStrategy: 'pre-scan'`.

### Build Changes

In v3, Vite uses esbuild to optimize dependencies by default. Doing so, it removes one of the most significant differences between dev and prod present in v2. Because esbuild converts CJS-only dependencies to ESM, [`@rollupjs/plugin-commonjs`](https://github.com/rollup/plugins/tree/master/packages/commonjs) is no longer used.
Expand Down
1 change: 0 additions & 1 deletion packages/vite/src/node/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -610,7 +610,6 @@ export async function resolveConfig(
packageCache: new Map(),
createResolver,
optimizeDeps: {
devStrategy: 'scan',
...optimizeDeps,
esbuildOptions: {
preserveSymlinks: config.resolve?.preserveSymlinks,
Expand Down
19 changes: 0 additions & 19 deletions packages/vite/src/node/optimizer/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,6 @@ export interface DepsOptimizer {
isOptimizedDepFile: (id: string) => boolean
isOptimizedDepUrl: (url: string) => boolean
getOptimizedDepId: (depInfo: OptimizedDepInfo) => string
registerDynamicImport: (importInfo: { id: string; url: string }) => void
delayDepsOptimizerUntil: (id: string, done: () => Promise<any>) => void
registerWorkersSource: (id: string) => void
resetRegisteredIds: () => void
Expand All @@ -73,24 +72,6 @@ export interface DepsOptimizer {
}

export interface DepOptimizationOptions {
/**
* Defines the cold start strategy:
* 'scan': use esbuild to scan for deps in the background and optimize them.
* Await until the server is iddle so we also get the list of deps found while
* crawling static imports. Use the optimization result if every dep has already
* been optimized. If there are new dependencies, trigger a new optimization
* step discarding the previous optimization result.
* 'lazy': only static imports are crawled, leading to the fastest cold start
* experience with the tradeoff of possible full page reload when navigating
* to dynamic routes
* 'eager': both static and dynamic imports are processed on cold start
* completely removing the need for full page reloads at the expense of a
* slower cold start
*
* @default 'scan'
* @experimental
*/
devStrategy?: 'scan' | 'lazy' | 'eager'
/**
* By default, Vite will crawl your `index.html` to detect dependencies that
* need to be pre-bundled. If `build.rollupOptions.input` is specified, Vite
Expand Down
159 changes: 44 additions & 115 deletions packages/vite/src/node/optimizer/optimizer.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,6 @@
import path from 'node:path'
import colors from 'picocolors'
import _debug from 'debug'
import glob from 'fast-glob'
import micromatch from 'micromatch'
import { FS_PREFIX } from '../constants'
import { getHash } from '../utils'
import { preTransformRequest } from '../server/transformRequest'
import type { ResolvedConfig, ViteDevServer } from '..'

import {
Expand Down Expand Up @@ -75,9 +70,6 @@ async function createDepsOptimizer(
const { logger } = config
const isBuild = config.command === 'build'

const { devStrategy } = config.optimizeDeps
const scan = !isBuild && devStrategy === 'scan'

const sessionTimestamp = Date.now().toString()

const cachedMetadata = loadCachedDepOptimizationMetadata(config)
Expand All @@ -87,13 +79,6 @@ async function createDepsOptimizer(
let metadata =
cachedMetadata || initDepsOptimizerMetadata(config, sessionTimestamp)

const { entries } = config.optimizeDeps
const optOutEntries = (
entries ? (Array.isArray(entries) ? entries : [entries]) : []
)
.filter((rule) => rule.startsWith('!'))
.map((rule) => rule.slice(1))

const depsOptimizer: DepsOptimizer = {
metadata,
registerMissingImport,
Expand All @@ -106,19 +91,6 @@ async function createDepsOptimizer(
delayDepsOptimizerUntil,
resetRegisteredIds,
ensureFirstRun,
registerDynamicImport: ({ id, url }) => {
if (!firstRunCalled && server) {
// devStrategy === 'eager' process all dynamic imports with the real
// plugins during cold start
if (devStrategy === 'eager') {
if (!micromatch.isMatch(id, optOutEntries)) {
preTransformRequest(url, server, { ssr: false })
}
}
// devStrategy === 'lazy' ignores dynamic imports, giving a faster cold
// start with potential full page reloads
}
},
options: config.optimizeDeps
}

Expand All @@ -130,13 +102,10 @@ async function createDepsOptimizer(
let newDepsToLogHandle: NodeJS.Timeout | undefined
const logNewlyDiscoveredDeps = () => {
if (newDepsToLog.length) {
const depsString = depsLogString(newDepsToLog)
config.logger.info(
colors.green(
`✨ new dependencies optimized: ${depsLogString(newDepsToLog)}`
),
{
timestamp: true
}
colors.green(`✨ new dependencies optimized: ${depsString}`),
{ timestamp: true }
)
newDepsToLog = []
}
Expand All @@ -155,9 +124,6 @@ async function createDepsOptimizer(
let enqueuedRerun: (() => void) | undefined
let currentlyProcessing = false

// Only pretransform optimizeDeps.entries on cold start
let optimizeDepsEntriesVisited = !!cachedMetadata

// If there wasn't a cache or it is outdated, we need to prepare a first run
let firstRunCalled = !!cachedMetadata

Expand Down Expand Up @@ -185,44 +151,42 @@ async function createDepsOptimizer(
})
}

// For 'scan' dev, we run the scanner and the first optimization
// run on the background, but we wait until crawling has ended
// to decide if we send this result to the browser or we need to
// do another optimize step
if (scan) {
const scanPhaseProcessing = newDepOptimizationProcessing()
depsOptimizer.scanning = scanPhaseProcessing.promise

setTimeout(async () => {
try {
debug(colors.green(`scanning for dependencies...`))

const deps = await discoverProjectDependencies(config)

// Add these dependencies to the discovered list, as these are currently
// used by the preAliasPlugin to support aliased and optimized deps.
// This is also used by the CJS externalization heuristics in legacy mode
for (const id of Object.keys(deps)) {
if (!metadata.discovered[id]) {
addMissingDep(id, deps[id])
}
}
// TODO: We need the scan during build time, until preAliasPlugin
// is refactored to work without the scanned deps. We could skip
// this for build later.

const discoveredByScanner = toDiscoveredDependencies(
config,
deps,
sessionTimestamp
)
const scanPhaseProcessing = newDepOptimizationProcessing()
depsOptimizer.scanning = scanPhaseProcessing.promise

debug(
colors.green(
`dependencies found by scanner: ${depsLogString(
Object.keys(discoveredByScanner)
)}`
)
)
setTimeout(async () => {
try {
debug(colors.green(`scanning for dependencies...`))

const deps = await discoverProjectDependencies(config)

const depsString = depsLogString(Object.keys(deps))
debug(colors.green(`dependencies found by scanner: ${depsString}`))

// Add these dependencies to the discovered list, as these are currently
// used by the preAliasPlugin to support aliased and optimized deps.
// This is also used by the CJS externalization heuristics in legacy mode
for (const id of Object.keys(deps)) {
if (!metadata.discovered[id]) {
addMissingDep(id, deps[id])
}
}

if (!isBuild) {
// For dev, we run the scanner and the first optimization
// run on the background, but we wait until crawling has ended
// to decide if we send this result to the browser or we need to
// do another optimize step
setTimeout(() => {
const discoveredByScanner = toDiscoveredDependencies(
config,
deps,
sessionTimestamp
)
try {
postScanOptimizationResult = runOptimizeDeps(
config,
Expand All @@ -232,14 +196,14 @@ async function createDepsOptimizer(
logger.error(e.message)
}
}, 0)
} catch (e) {
logger.error(e.message)
} finally {
scanPhaseProcessing.resolve()
depsOptimizer.scanning = undefined
}
}, 0)
}
} catch (e) {
logger.error(e.message)
} finally {
scanPhaseProcessing.resolve()
depsOptimizer.scanning = undefined
}
}, 0)
}

async function startNextDiscoveredBatch() {
Expand Down Expand Up @@ -576,7 +540,7 @@ async function createDepsOptimizer(

currentlyProcessing = false

if (scan) {
if (!isBuild) {
// Await for the scan+optimize step running in the background
// It normally should be over by the time crawling of user code ended
await depsOptimizer.scanning
Expand Down Expand Up @@ -622,7 +586,7 @@ async function createDepsOptimizer(
runOptimizer(result)
}
} else {
// 'lazy' and 'eager', queue the first optimizer run
// queue the first optimizer run
debouncedProcessing(0)
}
}
Expand Down Expand Up @@ -674,10 +638,6 @@ async function createDepsOptimizer(
registeredIds.push({ id, done })
runOptimizerWhenIdle()
}
if (server && !optimizeDepsEntriesVisited) {
optimizeDepsEntriesVisited = true
preTransformOptimizeDepsEntries(server)
}
}

function runOptimizerWhenIdle() {
Expand Down Expand Up @@ -725,7 +685,6 @@ async function createDevSsrDepsOptimizer(
'Vite Internal Error: registerMissingImport is not supported in dev SSR'
)
},
registerDynamicImport: () => {},
// noop, there is no scanning during dev SSR
// the optimizer blocks the server start
run: () => {},
Expand All @@ -738,36 +697,6 @@ async function createDevSsrDepsOptimizer(
devSsrDepsOptimizerMap.set(config, depsOptimizer)
}

export async function preTransformOptimizeDepsEntries(
server: ViteDevServer
): Promise<void> {
const { config } = server
const { entries } = config.optimizeDeps
if (entries) {
const explicitEntries = await globExplicitEntries(entries, config)
// TODO: should we restrict the entries to JS and HTML like the
// scanner did? I think we can let the user chose any entry
for (const entry of explicitEntries) {
const url = entry.startsWith(config.root + '/')
? entry.slice(config.root.length)
: path.posix.join(FS_PREFIX + entry)

preTransformRequest(url, server, { ssr: false })
}
}
}

async function globExplicitEntries(
entries: string | string[],
config: ResolvedConfig
): Promise<string[]> {
return await glob(entries, {
cwd: config.root,
ignore: ['**/node_modules/**', `**/${config.build.outDir}/**`],
absolute: true
})
}

function findInteropMismatches(
discovered: Record<string, OptimizedDepInfo>,
optimized: Record<string, OptimizedDepInfo>
Expand Down
2 changes: 0 additions & 2 deletions packages/vite/src/node/plugins/importAnalysis.ts
Original file line number Diff line number Diff line change
Expand Up @@ -536,8 +536,6 @@ export function importAnalysisPlugin(config: ResolvedConfig): Plugin {
}
if (!isDynamicImport) {
importedUrlsToPreTransform.add(importedUrl)
} else {
depsOptimizer?.registerDynamicImport(importedUrl)
}
} else if (!importer.startsWith(clientDir) && !ssr) {
// check @vite-ignore which suppresses dynamic import warning
Expand Down