From aa4b6754305bc331f5927459b489593a240174e7 Mon Sep 17 00:00:00 2001 From: ygj6 Date: Tue, 24 Aug 2021 21:58:59 +0800 Subject: [PATCH 1/5] feat: add resolve.preserveSymlinks option --- docs/config/index.md | 10 ++++++++ packages/vite/src/node/config.ts | 1 + packages/vite/src/node/plugins/resolve.ts | 12 ++++++--- packages/vite/src/node/ssr/ssrExternal.ts | 4 ++- packages/vite/src/node/ssr/ssrModuleLoader.ts | 25 +++++++++++++++---- packages/vite/src/node/utils.ts | 9 +++++-- 6 files changed, 50 insertions(+), 11 deletions(-) diff --git a/docs/config/index.md b/docs/config/index.md index e7043a5145cc30..840d5740062169 100644 --- a/docs/config/index.md +++ b/docs/config/index.md @@ -206,6 +206,16 @@ export default defineConfig(async ({ command, mode }) => { List of file extensions to try for imports that omit extensions. Note it is **NOT** recommended to omit extensions for custom import types (e.g. `.vue`) since it can interfere with IDE and type support. +### resolve.preserveSymlinks + +- **Type:** `boolean` +- **Default:** `false` + + Enabling this setting causes vite to determine file identity by the original file path (i.e. the path without following symlinks) instead of the real file path (i.e. the path after following symlinks). + +- **Related:** [esbuild#preserve-symlinks](https://esbuild.github.io/api/#preserve-symlinks), [webpack#resolve.symlinks + ](https://webpack.js.org/configuration/resolve/#resolvesymlinks) + ### css.modules - **Type:** diff --git a/packages/vite/src/node/config.ts b/packages/vite/src/node/config.ts index 5d04918ed48f42..a676fc41e509ee 100644 --- a/packages/vite/src/node/config.ts +++ b/packages/vite/src/node/config.ts @@ -432,6 +432,7 @@ export async function resolveConfig( ...config.optimizeDeps, esbuildOptions: { keepNames: config.optimizeDeps?.keepNames, + preserveSymlinks: config.resolve?.preserveSymlinks, ...config.optimizeDeps?.esbuildOptions } } diff --git a/packages/vite/src/node/plugins/resolve.ts b/packages/vite/src/node/plugins/resolve.ts index dfaa270e79050f..27c13338dcba2e 100644 --- a/packages/vite/src/node/plugins/resolve.ts +++ b/packages/vite/src/node/plugins/resolve.ts @@ -44,6 +44,7 @@ export interface ResolveOptions { conditions?: string[] extensions?: string[] dedupe?: string[] + preserveSymlinks?: boolean } export interface InternalResolveOptions extends ResolveOptions { @@ -405,7 +406,11 @@ export function tryNodeResolve( basedir = root } - const pkg = resolvePackageData(pkgId, basedir) + const pkg = resolvePackageData( + pkgId, + basedir, + !!server?.config.resolve.preserveSymlinks + ) if (!pkg) { return @@ -504,14 +509,15 @@ const packageCache = new Map() export function resolvePackageData( id: string, - basedir: string + basedir: string, + preserveSymlinks = false ): PackageData | undefined { const cacheKey = id + basedir if (packageCache.has(cacheKey)) { return packageCache.get(cacheKey) } try { - const pkgPath = resolveFrom(`${id}/package.json`, basedir) + const pkgPath = resolveFrom(`${id}/package.json`, basedir, preserveSymlinks) return loadPackageData(pkgPath, cacheKey) } catch (e) { isDebug && debug(`${chalk.red(`[failed loading package.json]`)} ${id}`) diff --git a/packages/vite/src/node/ssr/ssrExternal.ts b/packages/vite/src/node/ssr/ssrExternal.ts index 4c3b40e1915a9a..2c4214ad9e751b 100644 --- a/packages/vite/src/node/ssr/ssrExternal.ts +++ b/packages/vite/src/node/ssr/ssrExternal.ts @@ -96,7 +96,9 @@ export function resolveSSRExternal( } for (const id of depsToTrace) { - const depRoot = path.dirname(resolveFrom(`${id}/package.json`, root)) + const depRoot = path.dirname( + resolveFrom(`${id}/package.json`, root, !!config.resolve.preserveSymlinks) + ) resolveSSRExternal( { ...config, diff --git a/packages/vite/src/node/ssr/ssrModuleLoader.ts b/packages/vite/src/node/ssr/ssrModuleLoader.ts index 6a64d6a0fdaca9..24f005bd22aac8 100644 --- a/packages/vite/src/node/ssr/ssrModuleLoader.ts +++ b/packages/vite/src/node/ssr/ssrModuleLoader.ts @@ -91,7 +91,12 @@ async function instantiateModule( const ssrImport = async (dep: string) => { if (dep[0] !== '.' && dep[0] !== '/') { - return nodeRequire(dep, mod.file, server.config.root) + return nodeRequire( + dep, + mod.file, + server.config.root, + !!server.config.resolve.preserveSymlinks + ) } dep = unwrapId(dep) if (!isCircular(dep) && !pendingImports.get(dep)?.some(isCircular)) { @@ -169,8 +174,13 @@ async function instantiateModule( return Object.freeze(ssrModule) } -function nodeRequire(id: string, importer: string | null, root: string) { - const mod = require(resolve(id, importer, root)) +function nodeRequire( + id: string, + importer: string | null, + root: string, + preserveSymlinks: boolean +) { + const mod = require(resolve(id, importer, root, preserveSymlinks)) const defaultExport = mod.__esModule ? mod.default : mod // rollup-style default import interop for cjs return new Proxy(mod, { @@ -183,7 +193,12 @@ function nodeRequire(id: string, importer: string | null, root: string) { const resolveCache = new Map() -function resolve(id: string, importer: string | null, root: string) { +function resolve( + id: string, + importer: string | null, + root: string, + preserveSymlinks: boolean +) { const key = id + importer + root const cached = resolveCache.get(key) if (cached) { @@ -193,7 +208,7 @@ function resolve(id: string, importer: string | null, root: string) { importer && fs.existsSync(cleanUrl(importer)) ? path.dirname(importer) : root - const resolved = resolveFrom(id, resolveDir, true) + const resolved = resolveFrom(id, resolveDir, preserveSymlinks, true) resolveCache.set(key, resolved) return resolved } diff --git a/packages/vite/src/node/utils.ts b/packages/vite/src/node/utils.ts index 305e08ce37796a..bd82a72233aa10 100644 --- a/packages/vite/src/node/utils.ts +++ b/packages/vite/src/node/utils.ts @@ -40,12 +40,17 @@ try { const ssrExtensions = ['.js', '.json', '.node'] -export function resolveFrom(id: string, basedir: string, ssr = false): string { +export function resolveFrom( + id: string, + basedir: string, + preserveSymlinks = false, + ssr = false +): string { return resolve.sync(id, { basedir, extensions: ssr ? ssrExtensions : DEFAULT_EXTENSIONS, // necessary to work with pnpm - preserveSymlinks: isRunningWithYarnPnp || false + preserveSymlinks: preserveSymlinks || isRunningWithYarnPnp || false }) } From ac4f64e615acc1524729a62c7f97bddaeea9563b Mon Sep 17 00:00:00 2001 From: ygj6 Date: Tue, 24 Aug 2021 22:15:17 +0800 Subject: [PATCH 2/5] feat: properly resolve symbolic links that depend on imports --- packages/vite/src/node/plugins/resolve.ts | 97 ++++++++++++++++++----- 1 file changed, 75 insertions(+), 22 deletions(-) diff --git a/packages/vite/src/node/plugins/resolve.ts b/packages/vite/src/node/plugins/resolve.ts index 27c13338dcba2e..7c0c52c9c07552 100644 --- a/packages/vite/src/node/plugins/resolve.ts +++ b/packages/vite/src/node/plugins/resolve.ts @@ -109,12 +109,14 @@ export function resolvePlugin(baseOptions: InternalResolveOptions): Plugin { const options = isRequire ? requireOptions : baseOptions + const preserveSymlinks = !!server?.config.resolve.preserveSymlinks + let res: string | PartialResolvedId | undefined // explicit fs paths that starts with /@fs/* if (asSrc && id.startsWith(FS_PREFIX)) { const fsPath = fsPathFromId(id) - res = tryFsResolve(fsPath, options) + res = tryFsResolve(fsPath, options, preserveSymlinks) isDebug && debug(`[@fs] ${chalk.cyan(id)} -> ${chalk.dim(res)}`) // always return here even if res doesn't exist since /@fs/ is explicit // if the file doesn't exist it should be a 404 @@ -125,7 +127,7 @@ export function resolvePlugin(baseOptions: InternalResolveOptions): Plugin { // /foo -> /fs-root/foo if (asSrc && id.startsWith('/')) { const fsPath = path.resolve(root, id.slice(1)) - if ((res = tryFsResolve(fsPath, options))) { + if ((res = tryFsResolve(fsPath, options, preserveSymlinks))) { isDebug && debug(`[url] ${chalk.cyan(id)} -> ${chalk.dim(res)}`) return res } @@ -160,12 +162,18 @@ export function resolvePlugin(baseOptions: InternalResolveOptions): Plugin { if ( targetWeb && - (res = tryResolveBrowserMapping(fsPath, importer, options, true)) + (res = tryResolveBrowserMapping( + fsPath, + importer, + options, + true, + preserveSymlinks + )) ) { return res } - if ((res = tryFsResolve(fsPath, options))) { + if ((res = tryFsResolve(fsPath, options, preserveSymlinks))) { isDebug && debug(`[relative] ${chalk.cyan(id)} -> ${chalk.dim(res)}`) const pkg = importer != null && idToPkgMap.get(importer) if (pkg) { @@ -180,7 +188,10 @@ export function resolvePlugin(baseOptions: InternalResolveOptions): Plugin { } // absolute fs paths - if (path.isAbsolute(id) && (res = tryFsResolve(id, options))) { + if ( + path.isAbsolute(id) && + (res = tryFsResolve(id, options, preserveSymlinks)) + ) { isDebug && debug(`[fs] ${chalk.cyan(id)} -> ${chalk.dim(res)}`) return res } @@ -212,7 +223,13 @@ export function resolvePlugin(baseOptions: InternalResolveOptions): Plugin { if ( targetWeb && - (res = tryResolveBrowserMapping(id, importer, options, false)) + (res = tryResolveBrowserMapping( + id, + importer, + options, + false, + preserveSymlinks + )) ) { return res } @@ -279,6 +296,7 @@ export function resolvePlugin(baseOptions: InternalResolveOptions): Plugin { function tryFsResolve( fsPath: string, options: InternalResolveOptions, + preserveSymlinks: boolean, tryIndex = true, targetWeb = true ): string | undefined { @@ -302,6 +320,7 @@ function tryFsResolve( options, false, targetWeb, + preserveSymlinks, options.tryPrefix, options.skipPackageJson )) @@ -317,6 +336,7 @@ function tryFsResolve( options, false, targetWeb, + preserveSymlinks, options.tryPrefix, options.skipPackageJson )) @@ -332,6 +352,7 @@ function tryFsResolve( options, tryIndex, targetWeb, + preserveSymlinks, options.tryPrefix, options.skipPackageJson )) @@ -346,6 +367,7 @@ function tryResolveFile( options: InternalResolveOptions, tryIndex: boolean, targetWeb: boolean, + preserveSymlinks: boolean, tryPrefix?: string, skipPackageJson?: boolean ): string | undefined { @@ -366,16 +388,30 @@ function tryResolveFile( if (fs.existsSync(pkgPath)) { // path points to a node package const pkg = loadPackageData(pkgPath) - return resolvePackageEntry(file, pkg, options, targetWeb) + const resolved = resolvePackageEntry( + file, + pkg, + options, + targetWeb, + preserveSymlinks + ) + return resolved ? getRealPath(resolved, preserveSymlinks) : resolved } } - const index = tryFsResolve(file + '/index', options) + const index = tryFsResolve(file + '/index', options, preserveSymlinks) if (index) return index + postfix } } if (tryPrefix) { const prefixed = `${path.dirname(file)}/${tryPrefix}${path.basename(file)}` - return tryResolveFile(prefixed, postfix, options, tryIndex, targetWeb) + return tryResolveFile( + prefixed, + postfix, + options, + tryIndex, + targetWeb, + preserveSymlinks + ) } } @@ -406,22 +442,23 @@ export function tryNodeResolve( basedir = root } - const pkg = resolvePackageData( - pkgId, - basedir, - !!server?.config.resolve.preserveSymlinks - ) + const preserveSymlinks = !!server?.config.resolve.preserveSymlinks + + const pkg = resolvePackageData(pkgId, basedir, preserveSymlinks) if (!pkg) { return } let resolved = deepMatch - ? resolveDeepImport(id, pkg, options, targetWeb) - : resolvePackageEntry(id, pkg, options, targetWeb) + ? resolveDeepImport(id, pkg, options, targetWeb, preserveSymlinks) + : resolvePackageEntry(id, pkg, options, targetWeb, preserveSymlinks) if (!resolved) { return } + + resolved = getRealPath(resolved, preserveSymlinks) + // link id to pkg for browser field mapping check idToPkgMap.set(resolved, pkg) if (isBuild) { @@ -566,7 +603,8 @@ export function resolvePackageEntry( id: string, { dir, data, setResolvedCache, getResolvedCache }: PackageData, options: InternalResolveOptions, - targetWeb: boolean + targetWeb: boolean, + preserveSymlinks = false ): string | undefined { const cached = getResolvedCache('.', targetWeb) if (cached) { @@ -603,7 +641,8 @@ export function resolvePackageEntry( // instead; Otherwise, assume it's ESM and use it. const resolvedBrowserEntry = tryFsResolve( path.join(dir, browserEntry), - options + options, + preserveSymlinks ) if (resolvedBrowserEntry) { const content = fs.readFileSync(resolvedBrowserEntry, 'utf-8') @@ -649,7 +688,11 @@ export function resolvePackageEntry( } entryPoint = path.join(dir, entryPoint) - const resolvedEntryPoint = tryFsResolve(entryPoint, options) + const resolvedEntryPoint = tryFsResolve( + entryPoint, + options, + preserveSymlinks + ) if (resolvedEntryPoint) { isDebug && @@ -706,7 +749,8 @@ function resolveDeepImport( data }: PackageData, options: InternalResolveOptions, - targetWeb: boolean + targetWeb: boolean, + preserveSymlinks: boolean ): string | undefined { id = '.' + id.slice(data.name.length) const cache = getResolvedCache(id, targetWeb) @@ -744,6 +788,7 @@ function resolveDeepImport( const resolved = tryFsResolve( path.join(dir, relativeId), options, + preserveSymlinks, !exportsField, // try index only if no exports field targetWeb ) @@ -760,7 +805,8 @@ function tryResolveBrowserMapping( id: string, importer: string | undefined, options: InternalResolveOptions, - isFilePath: boolean + isFilePath: boolean, + preserveSymlinks: boolean ) { let res: string | undefined const pkg = importer && idToPkgMap.get(importer) @@ -769,7 +815,7 @@ function tryResolveBrowserMapping( const browserMappedPath = mapWithBrowserField(mapId, pkg.data.browser) if (browserMappedPath) { const fsPath = path.join(pkg.dir, browserMappedPath) - if ((res = tryFsResolve(fsPath, options))) { + if ((res = tryFsResolve(fsPath, options, preserveSymlinks))) { isDebug && debug(`[browser mapped] ${chalk.cyan(id)} -> ${chalk.dim(res)}`) idToPkgMap.set(res, pkg) @@ -813,3 +859,10 @@ function mapWithBrowserField( function equalWithoutSuffix(path: string, key: string, suffix: string) { return key.endsWith(suffix) && key.slice(0, -suffix.length) === path } + +function getRealPath(resolved: string, preserveSymlinks?: boolean): string { + if (!preserveSymlinks && browserExternalId !== resolved) { + return (resolved = normalizePath(fs.realpathSync(resolved))) + } + return resolved +} From deca9fbcfd0cdd62d67cb4c02af62f6612cdb746 Mon Sep 17 00:00:00 2001 From: ygj6 Date: Wed, 25 Aug 2021 21:39:18 +0800 Subject: [PATCH 3/5] feat: add test cases --- .../__tests__/preload.spec.ts | 9 ++ .../preserve-symlinks/__tests__/serve.js | 108 ++++++++++++++++++ .../playground/preserve-symlinks/index.html | 13 +++ .../preserve-symlinks/moduleA/package.json | 17 +++ .../preserve-symlinks/moduleA/src/data.js | 3 + .../preserve-symlinks/moduleA/src/index.js | 5 + .../playground/preserve-symlinks/package.json | 13 +++ .../playground/preserve-symlinks/src/main.js | 3 + .../preserve-symlinks/vite.config.js | 6 + 9 files changed, 177 insertions(+) create mode 100644 packages/playground/preserve-symlinks/__tests__/preload.spec.ts create mode 100644 packages/playground/preserve-symlinks/__tests__/serve.js create mode 100644 packages/playground/preserve-symlinks/index.html create mode 100644 packages/playground/preserve-symlinks/moduleA/package.json create mode 100644 packages/playground/preserve-symlinks/moduleA/src/data.js create mode 100644 packages/playground/preserve-symlinks/moduleA/src/index.js create mode 100644 packages/playground/preserve-symlinks/package.json create mode 100644 packages/playground/preserve-symlinks/src/main.js create mode 100644 packages/playground/preserve-symlinks/vite.config.js diff --git a/packages/playground/preserve-symlinks/__tests__/preload.spec.ts b/packages/playground/preserve-symlinks/__tests__/preload.spec.ts new file mode 100644 index 00000000000000..7e0b546d7dbdbb --- /dev/null +++ b/packages/playground/preserve-symlinks/__tests__/preload.spec.ts @@ -0,0 +1,9 @@ +test('should have no 404s', () => { + browserLogs.forEach((msg) => { + expect(msg).not.toMatch('404') + }) +}) + +test('not-preserve-symlinks', async () => { + expect(await page.textContent('#root')).toBe('hello vite') +}) diff --git a/packages/playground/preserve-symlinks/__tests__/serve.js b/packages/playground/preserve-symlinks/__tests__/serve.js new file mode 100644 index 00000000000000..94d19390dbd6c0 --- /dev/null +++ b/packages/playground/preserve-symlinks/__tests__/serve.js @@ -0,0 +1,108 @@ +// @ts-check +// this is automtically detected by scripts/jestPerTestSetup.ts and will replace +// the default e2e test serve behavior + +const path = require('path') +const http = require('http') +const sirv = require('sirv') +const fs = require('fs') + +const port = (exports.port = 9527) + +/** + * @param {string} root + * @param {boolean} isBuildTest + */ +exports.serve = async function serve(root, isBuildTest) { + const testDist = path.resolve(__dirname, '../moduleA/dist') + + if (fs.existsSync(testDist)) { + emptyDir(testDist) + } else { + fs.mkdirSync(testDist, { recursive: true }) + } + + fs.symlinkSync( + path.resolve(testDist, '../src/index.js'), + path.resolve(testDist, 'symlinks-moduleA.esm.js') + ) + + if (!isBuildTest) { + const { createServer } = require('vite') + process.env.VITE_INLINE = 'inline-serve' + let viteServer = await ( + await createServer({ + root: root, + logLevel: 'silent', + server: { + watch: { + usePolling: true, + interval: 100 + }, + host: true, + fs: { + strict: !isBuildTest + } + }, + build: { + target: 'esnext' + } + }) + ).listen() + // use resolved port/base from server + const base = viteServer.config.base === '/' ? '' : viteServer.config.base + const url = + (global.viteTestUrl = `http://localhost:${viteServer.config.server.port}${base}`) + await page.goto(url) + + return viteServer + } else { + const { build } = require('vite') + await build({ + root, + logLevel: 'silent', + configFile: path.resolve(__dirname, '../vite.config.js') + }) + + // start static file server + const serve = sirv(path.resolve(root, 'dist')) + const httpServer = http.createServer((req, res) => { + if (req.url === '/ping') { + res.statusCode = 200 + res.end('pong') + } else { + serve(req, res) + } + }) + + return new Promise((resolve, reject) => { + try { + const server = httpServer.listen(port, async () => { + await page.goto(`http://localhost:${port}`) + resolve({ + // for test teardown + async close() { + await new Promise((resolve) => { + server.close(resolve) + }) + } + }) + }) + } catch (e) { + reject(e) + } + }) + } +} + +function emptyDir(dir) { + for (const file of fs.readdirSync(dir)) { + const abs = path.resolve(dir, file) + if (fs.lstatSync(abs).isDirectory()) { + emptyDir(abs) + fs.rmdirSync(abs) + } else { + fs.unlinkSync(abs) + } + } +} diff --git a/packages/playground/preserve-symlinks/index.html b/packages/playground/preserve-symlinks/index.html new file mode 100644 index 00000000000000..07f82cb05c3eec --- /dev/null +++ b/packages/playground/preserve-symlinks/index.html @@ -0,0 +1,13 @@ + + + + + + + Vite App + + +
+ + + diff --git a/packages/playground/preserve-symlinks/moduleA/package.json b/packages/playground/preserve-symlinks/moduleA/package.json new file mode 100644 index 00000000000000..cb535e54edeeeb --- /dev/null +++ b/packages/playground/preserve-symlinks/moduleA/package.json @@ -0,0 +1,17 @@ +{ + "name": "@symlinks/moduleA", + "version": "0.0.0", + "module": "dist/symlinks-moduleA.esm.js", + "main": "dist/symlinks-moduleA.cjs.js", + "preconstruct": { + "entrypoints": [ + "index.js" + ] + }, + "scripts": { + "dev": "preconstruct dev" + }, + "devDependencies": { + "@preconstruct/cli": "^2.0.6" + } +} diff --git a/packages/playground/preserve-symlinks/moduleA/src/data.js b/packages/playground/preserve-symlinks/moduleA/src/data.js new file mode 100644 index 00000000000000..e1bc98ec67da12 --- /dev/null +++ b/packages/playground/preserve-symlinks/moduleA/src/data.js @@ -0,0 +1,3 @@ +export const data = { + msg: 'hello vite' +} diff --git a/packages/playground/preserve-symlinks/moduleA/src/index.js b/packages/playground/preserve-symlinks/moduleA/src/index.js new file mode 100644 index 00000000000000..b564d013e6b5e8 --- /dev/null +++ b/packages/playground/preserve-symlinks/moduleA/src/index.js @@ -0,0 +1,5 @@ +import { data } from './data' + +export function sayHi() { + return data +} diff --git a/packages/playground/preserve-symlinks/package.json b/packages/playground/preserve-symlinks/package.json new file mode 100644 index 00000000000000..a751bf639f0d40 --- /dev/null +++ b/packages/playground/preserve-symlinks/package.json @@ -0,0 +1,13 @@ +{ + "name": "preserveSymlinks", + "version": "0.0.0", + "scripts": { + "dev": "vite --force", + "build": "vite build", + "serve": "vite preview" + }, + "workspaces": {}, + "dependencies": { + "@symlinks/moduleA": "link:./moduleA" + } +} diff --git a/packages/playground/preserve-symlinks/src/main.js b/packages/playground/preserve-symlinks/src/main.js new file mode 100644 index 00000000000000..7257c44f1ba83f --- /dev/null +++ b/packages/playground/preserve-symlinks/src/main.js @@ -0,0 +1,3 @@ +import { sayHi } from '@symlinks/moduleA' + +document.getElementById('root').innerText = sayHi().msg diff --git a/packages/playground/preserve-symlinks/vite.config.js b/packages/playground/preserve-symlinks/vite.config.js new file mode 100644 index 00000000000000..0c9322b79f6f27 --- /dev/null +++ b/packages/playground/preserve-symlinks/vite.config.js @@ -0,0 +1,6 @@ +// https://vitejs.dev/config/ +module.exports = { + resolve: { + preserveSymlinks: false + } +} From 639ccf81c86d3d45d629e9a2fca100b22dbd255c Mon Sep 17 00:00:00 2001 From: ygj6 <7699524+ygj6@users.noreply.github.com> Date: Mon, 30 Aug 2021 08:57:44 +0800 Subject: [PATCH 4/5] Update packages/vite/src/node/plugins/resolve.ts Co-authored-by: patak --- packages/vite/src/node/plugins/resolve.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/vite/src/node/plugins/resolve.ts b/packages/vite/src/node/plugins/resolve.ts index 7c0c52c9c07552..1aab62b415786f 100644 --- a/packages/vite/src/node/plugins/resolve.ts +++ b/packages/vite/src/node/plugins/resolve.ts @@ -862,7 +862,7 @@ function equalWithoutSuffix(path: string, key: string, suffix: string) { function getRealPath(resolved: string, preserveSymlinks?: boolean): string { if (!preserveSymlinks && browserExternalId !== resolved) { - return (resolved = normalizePath(fs.realpathSync(resolved))) + return normalizePath(fs.realpathSync(resolved)) } return resolved } From 5b1554616ce7a65df5ae530fd5a8519b2f35ad3c Mon Sep 17 00:00:00 2001 From: ygj6 Date: Mon, 13 Sep 2021 16:02:12 +0800 Subject: [PATCH 5/5] fix: Supplement the "preserveSymlinks" parameter of the "nestedResolveFrom" function --- packages/vite/src/node/plugins/resolve.ts | 2 +- packages/vite/src/node/utils.ts | 12 +++++++++--- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/packages/vite/src/node/plugins/resolve.ts b/packages/vite/src/node/plugins/resolve.ts index 7498be338d1bc3..d101a87cc1262b 100644 --- a/packages/vite/src/node/plugins/resolve.ts +++ b/packages/vite/src/node/plugins/resolve.ts @@ -457,7 +457,7 @@ export function tryNodeResolve( // nested node module, step-by-step resolve to the basedir of the nestedPath if (nestedRoot) { - basedir = nestedResolveFrom(nestedRoot, basedir) + basedir = nestedResolveFrom(nestedRoot, basedir, preserveSymlinks) } const pkg = resolvePackageData(pkgId, basedir, preserveSymlinks) diff --git a/packages/vite/src/node/utils.ts b/packages/vite/src/node/utils.ts index ac0fdb2c4d63d8..9c8be23b590f58 100644 --- a/packages/vite/src/node/utils.ts +++ b/packages/vite/src/node/utils.ts @@ -68,11 +68,15 @@ export function resolveFrom( * like `resolveFrom` but supports resolving `>` path in `id`, * for example: `foo > bar > baz` */ -export function nestedResolveFrom(id: string, basedir: string): string { +export function nestedResolveFrom( + id: string, + basedir: string, + preserveSymlinks = false +): string { const pkgs = id.split('>').map((pkg) => pkg.trim()) try { for (const pkg of pkgs) { - basedir = resolveFrom(pkg, basedir) + basedir = resolveFrom(pkg, basedir, preserveSymlinks) } } catch {} return basedir @@ -296,7 +300,9 @@ export function numberToPos( ): { line: number; column: number } { if (typeof offset !== 'number') return offset if (offset > source.length) { - throw new Error(`offset is longer than source length! offset ${offset} > length ${source.length}`); + throw new Error( + `offset is longer than source length! offset ${offset} > length ${source.length}` + ) } const lines = source.split(splitRE) let counted = 0