Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 10 additions & 39 deletions packages/vite/src/node/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,6 @@ import {
type EnvironmentResolveOptions,
type InternalResolveOptions,
type ResolveOptions,
tryNodeResolve,
} from './plugins/resolve'
import type { LogLevel, Logger } from './logger'
import { createLogger } from './logger'
Expand All @@ -110,6 +109,7 @@ import {
BasicMinimalPluginContext,
basePluginContextMeta,
} from './server/pluginContainer'
import { nodeResolveWithVite } from './nodeResolve'

const debug = createDebugger('vite:config', { depth: 10 })
const promisifiedRealpath = promisify(fs.realpath)
Expand Down Expand Up @@ -1921,12 +1921,11 @@ async function bundleConfigFile(
fileName: string,
isESM: boolean,
): Promise<{ code: string; dependencies: string[] }> {
const isModuleSyncConditionEnabled = (await import('#module-sync-enabled'))
.default

const root = path.dirname(fileName)
const dirnameVarName = '__vite_injected_original_dirname'
const filenameVarName = '__vite_injected_original_filename'
const importMetaUrlVarName = '__vite_injected_original_import_meta_url'

const result = await build({
absWorkingDir: process.cwd(),
entryPoints: [fileName],
Expand All @@ -1952,35 +1951,6 @@ async function bundleConfigFile(
{
name: 'externalize-deps',
setup(build) {
const packageCache = new Map()
const resolveByViteResolver = (
id: string,
importer: string,
isRequire: boolean,
) => {
return tryNodeResolve(id, importer, {
root: path.dirname(fileName),
isBuild: true,
isProduction: true,
preferRelative: false,
tryIndex: true,
mainFields: [],
conditions: [
'node',
...(isModuleSyncConditionEnabled ? ['module-sync'] : []),
],
externalConditions: [],
external: [],
noExternal: [],
dedupe: [],
extensions: configDefaults.resolve.extensions,
preserveSymlinks: false,
packageCache,
isRequire,
builtins: nodeLikeBuiltins,
})?.id
}

// externalize bare imports
build.onResolve(
{ filter: /^[^.#].*/ },
Expand All @@ -2003,16 +1973,17 @@ async function bundleConfigFile(
const isImport = isESM || kind === 'dynamic-import'
let idFsPath: string | undefined
try {
idFsPath = resolveByViteResolver(id, importer, !isImport)
idFsPath = nodeResolveWithVite(id, importer, {
root,
isRequire: !isImport,
})
} catch (e) {
if (!isImport) {
let canResolveWithImport = false
try {
canResolveWithImport = !!resolveByViteResolver(
id,
importer,
false,
)
canResolveWithImport = !!nodeResolveWithVite(id, importer, {
root,
})
} catch {}
if (canResolveWithImport) {
throw new Error(
Expand Down
41 changes: 41 additions & 0 deletions packages/vite/src/node/nodeResolve.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import isModuleSyncConditionEnabled from '#module-sync-enabled'
import { configDefaults } from './config'
import { tryNodeResolve } from './plugins/resolve'
import { nodeLikeBuiltins } from './utils'

export interface NodeResolveWithViteOptions {
root: string
isRequire?: boolean
}

/**
* Resolve like Node.js using Vite's resolution algorithm with preconfigured options.
*/
export function nodeResolveWithVite(
id: string,
importer: string | undefined,
options: NodeResolveWithViteOptions,
): string | undefined {
return tryNodeResolve(id, importer, {
root: options.root,
isBuild: true,
isProduction: true,
preferRelative: false,
tryIndex: true,
mainFields: [],
conditions: [
'node',
...(isModuleSyncConditionEnabled ? ['module-sync'] : []),
],
externalConditions: [],
external: [],
noExternal: [],
dedupe: [],
extensions: configDefaults.resolve.extensions,
preserveSymlinks: false,
// Intentionally disable package cache for now as consumers don't need it
packageCache: undefined,
isRequire: options.isRequire,
builtins: nodeLikeBuiltins,
})?.id
}
76 changes: 34 additions & 42 deletions packages/vite/src/node/plugins/css.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import fs from 'node:fs'
import fsp from 'node:fs/promises'
import path from 'node:path'
import { createRequire } from 'node:module'
import { fileURLToPath, pathToFileURL } from 'node:url'
import postcssrc from 'postcss-load-config'
import type {
Expand Down Expand Up @@ -57,6 +56,7 @@ import type { ResolvedConfig } from '../config'
import type { Plugin } from '../plugin'
import { checkPublicFile } from '../publicDir'
import {
_dirname,
arraify,
asyncReplace,
combineSourcemaps,
Expand All @@ -79,7 +79,6 @@ import {
processSrcSet,
removeDirectQuery,
removeUrlQuery,
requireResolveFromRootWithFallback,
stripBomTag,
urlRE,
} from '../utils'
Expand All @@ -94,6 +93,7 @@ import { searchForWorkspaceRoot } from '../server/searchRoot'
import { type DevEnvironment } from '..'
import type { PackageCache } from '../packages'
import { findNearestMainPackageData } from '../packages'
import { nodeResolveWithVite } from '../nodeResolve'
import { addToHTMLProxyTransformResult } from './html'
import {
assetUrlRE,
Expand Down Expand Up @@ -1562,7 +1562,7 @@ async function compilePostCSS(

const postcssOptions = postcssConfig?.options ?? {}
const postcssParser =
lang === 'sss' ? loadSss(config.root) : postcssOptions.parser
lang === 'sss' ? await loadSss(config.root) : postcssOptions.parser

if (!postcssPlugins.length && !postcssParser) {
return
Expand All @@ -1588,11 +1588,12 @@ async function transformSugarSS(
const { config } = environment
const { devSourcemap } = config.css

const sssParser = await loadSss(config.root)
const result = await runPostCSS(
id,
code,
[],
{ parser: loadSss(config.root) },
{ parser: sssParser },
undefined,
environment.logger,
devSourcemap,
Expand Down Expand Up @@ -2323,23 +2324,18 @@ function loadPreprocessorPath(
if (cached) {
return cached
}
try {
const resolved = requireResolveFromRootWithFallback(root, lang)
return (loadedPreprocessorPath[lang] = resolved)
} catch (e) {
if (e.code === 'MODULE_NOT_FOUND') {
const installCommand = getPackageManagerCommand('install')
throw new Error(
`Preprocessor dependency "${lang}" not found. Did you install it? Try \`${installCommand} -D ${lang}\`.`,
)
} else {
const message = new Error(
`Preprocessor dependency "${lang}" failed to load:\n${e.message}`,
)
message.stack = e.stack + '\n' + message.stack
throw message
}
}

// Try resolve from project root first, then the current vite installation path
const resolved =
nodeResolveWithVite(lang, undefined, { root }) ??
nodeResolveWithVite(lang, _dirname, { root })
if (resolved) return (loadedPreprocessorPath[lang] = resolved)

// Error if we can't find the preprocessor
const installCommand = getPackageManagerCommand('install')
throw new Error(
`Preprocessor dependency "${lang}" not found. Did you install it? Try \`${installCommand} -D ${lang}\`.`,
)
}

function loadSassPackage(root: string): {
Expand All @@ -2360,12 +2356,15 @@ function loadSassPackage(root: string): {
}
}

let cachedSss: PostCSS.Syntax
function loadSss(root: string): PostCSS.Syntax {
if (cachedSss) return cachedSss

const sssPath = loadPreprocessorPath(PostCssDialectLang.sss, root)
cachedSss = createRequire(/** #__KEEP__ */ import.meta.url)(sssPath)
let cachedSss: PostCSS.Syntax | Promise<PostCSS.Syntax>
async function loadSss(root: string): Promise<PostCSS.Syntax> {
if (!cachedSss) {
cachedSss = (async () => {
const sssPath = loadPreprocessorPath(PostCssDialectLang.sss, root)
const resolved = (await import(pathToFileURL(sssPath).href)).default
return (cachedSss = resolved)
})()
}
return cachedSss
}

Expand Down Expand Up @@ -2415,10 +2414,7 @@ const makeScssWorker = (

const worker: WorkerType = {
async run(sassPath, data, options) {
// need pathToFileURL for windows since import("D:...") fails
// https://github.com/nodejs/node/issues/31710
const sass: typeof Sass = (await import(pathToFileURL(sassPath).href))
.default
const sass: typeof Sass = await import(sassPath)
compilerPromise ??= sass.initAsyncCompiler()
const compiler = await compilerPromise

Expand Down Expand Up @@ -2535,7 +2531,7 @@ const scssProcessor = (
}
try {
const result = await worker.run(
sassPackage.path,
pathToFileURL(sassPackage.path).href,
data,
optionsWithoutAdditionalData,
)
Expand Down Expand Up @@ -2796,9 +2792,7 @@ const lessProcessor = (
worker?.stop()
},
async process(environment, source, root, options, resolvers) {
const lessPath = pathToFileURL(
loadPreprocessorPath(PreprocessLang.less, root),
).href
const lessPath = loadPreprocessorPath(PreprocessLang.less, root)
worker ??= makeLessWorker(environment, resolvers, maxWorkers)

const { content, map: additionalMap } = await getSource(
Expand All @@ -2815,7 +2809,7 @@ const lessProcessor = (
}
try {
result = await worker.run(
lessPath,
pathToFileURL(lessPath).href,
content,
optionsWithoutAdditionalData,
)
Expand Down Expand Up @@ -2864,9 +2858,9 @@ const makeStylWorker = (maxWorkers: number | undefined) => {
additionalData: undefined
},
) => {
const nodeStylus: typeof Stylus = (await import(stylusPath)).default
const stylus: typeof Stylus = (await import(stylusPath)).default

const ref = nodeStylus(content, {
const ref = stylus(content, {
// support @import from node dependencies by default
paths: ['node_modules'],
...options,
Expand Down Expand Up @@ -2917,9 +2911,7 @@ const stylProcessor = (
worker?.stop()
},
async process(_environment, source, root, options, _resolvers) {
const stylusPath = pathToFileURL(
loadPreprocessorPath(PreprocessLang.stylus, root),
).href
const stylusPath = loadPreprocessorPath(PreprocessLang.stylus, root)
worker ??= makeStylWorker(maxWorkers)

// Get source with preprocessor options.additionalData. Make sure a new line separator
Expand All @@ -2942,7 +2934,7 @@ const stylProcessor = (
}
try {
const { code, map, deps } = await worker.run(
stylusPath,
pathToFileURL(stylusPath).href,
content,
root,
optionsWithoutAdditionalData,
Expand Down
33 changes: 15 additions & 18 deletions packages/vite/src/node/plugins/terser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ import type {
import { WorkerWithFallback } from 'artichokie'
import type { Plugin } from '../plugin'
import type { ResolvedConfig } from '..'
import { generateCodeFrame, requireResolveFromRootWithFallback } from '../utils'
import { _dirname, generateCodeFrame } from '../utils'
import { nodeResolveWithVite } from '../nodeResolve'

export interface TerserOptions extends TerserMinifyOptions {
/**
Expand All @@ -19,22 +20,19 @@ export interface TerserOptions extends TerserMinifyOptions {
}

let terserPath: string | undefined
const loadTerserPath = (root: string) => {
function loadTerserPath(root: string) {
if (terserPath) return terserPath
try {
terserPath = requireResolveFromRootWithFallback(root, 'terser')
} catch (e) {
if (e.code === 'MODULE_NOT_FOUND') {
throw new Error(
'terser not found. Since Vite v3, terser has become an optional dependency. You need to install it.',
)
} else {
const message = new Error(`terser failed to load:\n${e.message}`)
message.stack = e.stack + '\n' + message.stack
throw message
}
}
return terserPath

// Try resolve from project root first, then the current vite installation path
const resolved =
nodeResolveWithVite('terser', undefined, { root }) ??
nodeResolveWithVite('terser', _dirname, { root })
if (resolved) return (terserPath = resolved)

// Error if we can't find the package
throw new Error(
'terser not found. Since Vite v3, terser has become an optional dependency. You need to install it.',
)
}

export function terserPlugin(config: ResolvedConfig): Plugin {
Expand All @@ -48,8 +46,7 @@ export function terserPlugin(config: ResolvedConfig): Plugin {
code: string,
options: TerserMinifyOptions,
) => {
const terser: typeof import('terser') = (await import(terserPath))
.default
const terser: typeof import('terser') = await import(terserPath)
try {
return (await terser.minify(code, options)) as TerserMinifyOutput
} catch (e) {
Expand Down
Loading
Loading