Skip to content

Commit

Permalink
refactor: use faster custom node resolve
Browse files Browse the repository at this point in the history
  • Loading branch information
yyx990803 committed Dec 16, 2020
1 parent 7405cbf commit e9df34c
Show file tree
Hide file tree
Showing 9 changed files with 141 additions and 766 deletions.
2 changes: 2 additions & 0 deletions .eslintrc.js
Expand Up @@ -17,6 +17,8 @@ module.exports = {
'node/no-missing-require': [
'error',
{
// for try-catching yarn pnp
allowModules: ['pnpapi'],
tryExtensions: ['.ts', '.js']
}
],
Expand Down
4 changes: 1 addition & 3 deletions package.json
Expand Up @@ -5,8 +5,7 @@
"packages/*"
],
"scripts": {
"lint": "eslint --ext .ts packages/*/src/**",
"postinstall": "patch-package"
"lint": "eslint --ext .ts packages/*/src/**"
},
"devDependencies": {
"@types/node": "^14.14.10",
Expand All @@ -18,7 +17,6 @@
"lint-staged": "^10.5.3",
"minimist": "^1.2.5",
"npm-run-all": "^4.1.5",
"patch-package": "^6.2.2",
"prettier": "^2.2.1",
"rimraf": "^3.0.2",
"semver": "^7.3.4",
Expand Down
27 changes: 10 additions & 17 deletions packages/playground/vite.config.ts
Expand Up @@ -3,8 +3,6 @@ import vue from 'rollup-plugin-vue'
import reactRefresh from '@vitejs/plugin-react-refresh'

export default defineConfig({
// @ts-ignore (when linked locally the types of different rollup installations
// conflicts, but for end user this will work properly)
plugins: [
// reactRefresh,
vue({
Expand All @@ -15,11 +13,6 @@ export default defineConfig({
alias: {
react: '@pika/react/source.development.js',
'react-dom': '@pika/react-dom/source.development.js'
// vue: '/Users/evan/Vue/vite/node_modules/vue/dist/vue.runtime.esm-bundler.js',
// '@vue/runtime-dom': '/Users/evan/Vue/vite/node_modules/@vue/runtime-dom/dist/runtime-dom.esm-bundler.js',
// '@vue/runtime-core': '/Users/evan/Vue/vite/node_modules/@vue/runtime-core/dist/runtime-core.esm-bundler.js',
// '@vue/reactivity': '/Users/evan/Vue/vite/node_modules/@vue/reactivity/dist/reactivity.esm-bundler.js',
// '@vue/shared': '/Users/evan/Vue/vite/node_modules/@vue/shared/dist/shared.esm-bundler.js'
},
define: {
__DEV__: true,
Expand All @@ -31,15 +24,15 @@ export default defineConfig({
// jsxFragment: 'Fragment'
},
server: {
proxy: {
'/api': {
target: 'http://jsonplaceholder.typicode.com',
changeOrigin: true,
rewrite: (path) => path.replace(/^\/api/, '')
}
}
},
optimizeDeps: {
auto: false
// proxy: {
// '/api': {
// target: 'http://jsonplaceholder.typicode.com',
// changeOrigin: true,
// rewrite: (path) => path.replace(/^\/api/, '')
// }
// }
}
// optimizeDeps: {
// auto: false
// }
})
3 changes: 2 additions & 1 deletion packages/vite/package.json
Expand Up @@ -57,13 +57,13 @@
"@rollup/plugin-alias": "^3.1.1",
"@rollup/plugin-commonjs": "^17.0.0",
"@rollup/plugin-json": "^4.1.0",
"@rollup/plugin-node-resolve": "^11.0.0",
"@rollup/plugin-typescript": "^8.0.0",
"@rollup/pluginutils": "^4.1.0",
"@types/debug": "^4.1.5",
"@types/es-module-lexer": "^0.3.0",
"@types/etag": "^1.8.0",
"@types/node": "^14.14.10",
"@types/resolve": "^1.17.1",
"@types/ws": "^7.4.0",
"acorn": "^8.0.4",
"acorn-class-fields": "^0.3.7",
Expand All @@ -88,6 +88,7 @@
"postcss-import": "^13.0.0",
"postcss-load-config": "^3.0.0",
"postcss-modules": "^4.0.0",
"resolve": "^1.19.0",
"rollup-plugin-terser": "^7.0.2",
"selfsigned": "^1.10.8",
"sirv": "^1.0.10",
Expand Down
9 changes: 5 additions & 4 deletions packages/vite/src/node/config.ts
Expand Up @@ -12,9 +12,9 @@ import { esbuildPlugin } from './plugins/esbuild'
import { TransformOptions as ESbuildTransformOptions } from 'esbuild'
import dotenv from 'dotenv'
import dotenvExpand from 'dotenv-expand'
import { nodeResolve } from '@rollup/plugin-node-resolve'
import { Alias, AliasOptions } from 'types/alias'
import { CLIENT_DIR } from './constants'
import { resolvePlugin } from './plugins/resolve'

const debug = createDebugger('vite:config')

Expand Down Expand Up @@ -254,9 +254,10 @@ async function loadConfigFromFile(
plugins: [
// use esbuild + node-resolve to support .ts files
esbuildPlugin({ target: 'es2019' }),
nodeResolve({
extensions: ['.mjs', '.js', '.ts', '.json']
})
resolvePlugin(
path.dirname(resolvedPath),
false /* disallow url resolves */
)
]
})

Expand Down
11 changes: 2 additions & 9 deletions packages/vite/src/node/plugins/index.ts
@@ -1,8 +1,7 @@
import { Plugin, ResolvedConfig } from '..'
import aliasPlugin from '@rollup/plugin-alias'
import jsonPlugin from '@rollup/plugin-json'
import { nodeResolve } from '@rollup/plugin-node-resolve'
import { resolvePlugin, supportedExts } from './resolve'
import { resolvePlugin } from './resolve'
import { esbuildPlugin } from './esbuild'
import { importAnalysisPlugin } from './importsAnalysis'
import { cssPlugin, cssPostPlugin } from './css'
Expand All @@ -22,7 +21,7 @@ export function resolvePlugins(
return [
aliasPlugin({ entries: config.alias }),
...prePlugins,
resolvePlugin(config),
resolvePlugin(config.root),
htmlPlugin(),
cssPlugin(config, isBuild),
esbuildPlugin(config.esbuild || {}),
Expand All @@ -31,12 +30,6 @@ export function resolvePlugins(
...normalPlugins,
...postPlugins,
cssPostPlugin(config, isBuild),
// node-resolve is slow, so we want to only fallback to it after all other
// resolvers have run.
nodeResolve({
extensions: supportedExts,
mainFields: ['module', 'jsnext', 'jsnext:main', 'browser', 'main']
}),
// internal server-only plugins are always applied after everything else
...(isBuild
? []
Expand Down
119 changes: 113 additions & 6 deletions packages/vite/src/node/plugins/resolve.ts
@@ -1,20 +1,23 @@
import fs from 'fs'
import path from 'path'
import resolve from 'resolve'
import { createDebugger } from '../utils'
import { Plugin, ResolvedConfig } from '..'
import { Plugin } from '..'
import chalk from 'chalk'
import { FILE_PREFIX } from '../constants'
import { isCSSProxy } from './css'

export const supportedExts = ['.mjs', '.js', '.ts', '.jsx', '.tsx', '.json']
export const FAILED_RESOLVE = `__vite_failed_resolve__`

const supportedExts = ['.mjs', '.js', '.ts', '.jsx', '.tsx', '.json']
const mainFields = ['module', 'jsnext', 'jsnext:main', 'browser', 'main']

const isDebug = process.env.DEBUG
const debug = createDebugger('vite:resolve-details', {
onlyWhenFocused: true
})

export function resolvePlugin({ root }: ResolvedConfig): Plugin {
export function resolvePlugin(root: string, allowUrls = true): Plugin {
return {
name: 'vite:resolve',
resolveId(id, importer) {
Expand All @@ -26,7 +29,7 @@ export function resolvePlugin({ root }: ResolvedConfig): Plugin {
isCSSProxyId ? res + '.js' : res

let res
if (id.startsWith(FILE_PREFIX)) {
if (allowUrls && id.startsWith(FILE_PREFIX)) {
// explicit fs paths that starts with /@fs/*
// these are injected by the rewrite plugin so that the file can work
// in the browser
Expand All @@ -41,7 +44,7 @@ export function resolvePlugin({ root }: ResolvedConfig): Plugin {

// URL
// /foo -> /fs-root/foo
if (id.startsWith('/')) {
if (allowUrls && id.startsWith('/')) {
const fsPath = path.resolve(root, id.slice(1))
if ((res = tryFsResolve(fsPath))) {
isDebug && debug(`[url] ${chalk.cyan(id)} -> ${chalk.dim(res)}`)
Expand All @@ -64,6 +67,14 @@ export function resolvePlugin({ root }: ResolvedConfig): Plugin {
return restoreCSSProxy(res)
}

// bare package imports, perform node resolve
if (
/^[\w@]/.test(id) &&
(res = tryNodeResolve(id, importer ? path.dirname(importer) : root))
) {
return restoreCSSProxy(res)
}

isDebug && debug(`[fallthrough] ${chalk.dim(id)}`)
return this.resolve(id, importer, {
skipSelf: true
Expand All @@ -74,7 +85,7 @@ export function resolvePlugin({ root }: ResolvedConfig): Plugin {
}
}

export function tryFsResolve(fsPath: string) {
function tryFsResolve(fsPath: string) {
const [file, q] = fsPath.split(`?`)
const query = q ? `?${q}` : ``
if (fs.existsSync(file)) {
Expand All @@ -86,3 +97,99 @@ export function tryFsResolve(fsPath: string) {
}
}
}

const deepImportRE = /^([^@][^/]*)\/|^(@[^/]+\/[^/]+)\//

let isRunningWithYarnPnp: boolean
try {
isRunningWithYarnPnp = Boolean(require('pnpapi'))
} catch {}

function tryNodeResolve(id: string, basedir: string): string | undefined {
let result: string | undefined
const isDeep = deepImportRE.test(id)
const resolveTarget = isDeep ? id : `${id}/package.json`

try {
result = resolve.sync(resolveTarget, {
basedir,
extensions: supportedExts,
// necessary to work with pnpm
preserveSymlinks: isRunningWithYarnPnp || false
})
} catch (e) {
isDebug && debug(`${chalk.red(`[failed node resolve]`)} ${id}`)
}

if (result) {
if (isDeep) {
// deep import, return as-is
isDebug &&
debug(`[node/deep-import] ${chalk.cyan(id)} -> ${chalk.dim(result)}`)
return result
} else {
// resolve package entry
return resolvePackageEntry(id, result)
}
}
}

function resolvePackageEntry(id: string, pkgPath: string): string | undefined {
let pkg
try {
pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf-8'))
} catch (e) {
isDebug && debug(`${chalk.red(`[failed pkg read]`)} ${pkgPath}`)
return
}

let entryPoint: string = 'index.js'

for (const field of mainFields) {
if (typeof pkg[field] === 'string') {
entryPoint = pkg[field]
break
}
}

// resolve object browser field in package.json
// https://github.com/defunctzombie/package-browser-field-spec
const { browser: browserField } = pkg
if (browserField && typeof browserField === 'object') {
entryPoint = mapWithBrowserField(entryPoint, browserField)
}

entryPoint = path.resolve(path.dirname(pkgPath), entryPoint)
const resolvedEntryPont = tryFsResolve(entryPoint)

if (resolvedEntryPont) {
isDebug &&
debug(
`[package entry] ${chalk.cyan(id)} -> ${chalk.dim(resolvedEntryPont)}`
)
return resolvedEntryPont
} else {
isDebug && debug(`${chalk.red(`[missing pkg entry]`)} ${id}`)
}
}

const normalize = path.posix.normalize

/**
* given a relative path in pkg dir,
* return a relative path in pkg dir,
* mapped with the "map" object
*/
function mapWithBrowserField(
relativePathInPkgDir: string,
map: Record<string, string>
) {
const normalized = normalize(relativePathInPkgDir)
const foundEntry = Object.entries(map).find(
([from]) => normalize(from) === normalized
)
if (!foundEntry) {
return normalized
}
return normalize(foundEntry[1])
}
10 changes: 0 additions & 10 deletions patches/@rollup+plugin-node-resolve+11.0.0.patch

This file was deleted.

0 comments on commit e9df34c

Please sign in to comment.