vite-plugin-resolve
Advanced tools
Comparing version 1.8.0 to 2.0.0
@@ -1,47 +0,12 @@ | ||
import { Plugin, UserConfig } from 'vite'; | ||
import { Plugin } from 'vite'; | ||
export default resolve; | ||
declare const resolve: VitePluginResolve; | ||
export default resolve; | ||
export interface ResolveArgs { | ||
/** Generated file cache directory */ | ||
dir: string; | ||
} | ||
export interface Resolves { | ||
[moduleId: string]: | ||
| string | ||
| ((args: ResolveArgs) => | ||
| string | ||
| Promise<string | void> | ||
| void) | ||
| void; | ||
} | ||
export interface ResolveOptions { | ||
/** | ||
* Absolute path or relative path | ||
* @default ".vite-plugin-resolve" | ||
*/ | ||
dir?: string; | ||
} | ||
export interface VitePluginResolve { | ||
(resolves: Resolves, options?: ResolveOptions): Plugin; | ||
(entries: { | ||
[moduleId: string]: | ||
| ReturnType<Plugin['load']> | ||
| ((...args: Parameters<Plugin['load']>) => ReturnType<Plugin['load']>) | ||
}): Plugin[]; | ||
} | ||
// --------- utils --------- | ||
export interface GenerateESModule { | ||
(dir: string, resolves: Resolves): Promise<void>; | ||
} | ||
export interface ModifyAlias { | ||
( | ||
config: UserConfig, | ||
aliaList: { [moduleId: string]: string; }[], | ||
): void; | ||
} | ||
export interface ModifyOptimizeDepsExclude { | ||
(config: UserConfig, exclude: string[]): void; | ||
} |
129
index.js
@@ -1,99 +0,44 @@ | ||
const fs = require('fs'); | ||
const path = require('path'); | ||
/** | ||
* @type {import('.').VitePluginResolve} | ||
*/ | ||
module.exports = function resolve(resolves = {}, options = {}) { | ||
let { dir = '.vite-plugin-resolve' } = options; | ||
let root = process.cwd(); | ||
module.exports = function resolve(resolves) { | ||
const prefix = '\0'; | ||
const resolveKeys = Object.keys(resolves); | ||
const resolveKeysWithPrefix = resolveKeys.map(key => prefix + key); | ||
return { | ||
name: 'vite-plugin-resolve', | ||
async config(config) { | ||
if (!path.isAbsolute(dir)) dir = path.join(node_modules(root), dir); | ||
if (config.root) root = path.resolve(config.root); | ||
return [ | ||
{ | ||
name: 'vite-plugin-resolve:resolveId', | ||
// run before the builtin 'vite:resolve' of Vite | ||
enforce: 'pre', | ||
resolveId(source) { | ||
if (resolveKeys.includes(source)) { | ||
// https://vitejs.dev/guide/api-plugin.html#virtual-modules-convention | ||
return prefix + source; | ||
} | ||
}, | ||
}, | ||
{ | ||
name: 'vite-plugin-resolve', | ||
config(config) { | ||
if (!config.optimizeDeps) config.optimizeDeps = {}; | ||
if (!config.optimizeDeps.exclude) config.optimizeDeps.exclude = []; | ||
modifyOptimizeDepsExclude(config, Object.keys(resolves)); | ||
modifyAlias( | ||
config, | ||
Object.keys(resolves).map(moduleId => ({ [moduleId]: path.join(dir, moduleId) })), | ||
); | ||
let keys = resolveKeys; | ||
if (config.optimizeDeps.include) { | ||
keys = resolveKeys.filter(key => !config.optimizeDeps.include.includes(key)); | ||
} | ||
await generateESModule(dir, resolves); | ||
config.optimizeDeps.exclude.push(...keys); | ||
}, | ||
async load(id, opts) { | ||
if (resolveKeysWithPrefix.includes(id)) { | ||
const stringOrFunction = resolves[id.replace(prefix, '')]; | ||
return typeof stringOrFunction === 'function' | ||
? await stringOrFunction(id, opts) | ||
: stringOrFunction; | ||
} | ||
}, | ||
}, | ||
} | ||
} | ||
/** | ||
* @type {import('.').GenerateESModule} | ||
*/ | ||
async function generateESModule(dir, resolves) { | ||
// generate custom-resolve module file | ||
for (const [module, strOrFn] of Object.entries(resolves)) { | ||
const moduleId = path.join(dir, module + '.js'); | ||
const moduleContent = await (typeof strOrFn === 'function' ? strOrFn({ dir }) : strOrFn); | ||
if (moduleContent == null) continue; | ||
// supported nest moduleId ('@scope/name') | ||
ensureDir(path.parse(moduleId).dir); | ||
// write custom-resolve | ||
fs.writeFileSync(moduleId, moduleContent); | ||
} | ||
} | ||
/** | ||
* @type {import('.').ModifyAlias} | ||
*/ | ||
function modifyAlias(config, aliaList) { | ||
if (!config.resolve) config.resolve = {}; | ||
let alias = config.resolve.alias || []; | ||
if (!Array.isArray(alias)) { | ||
// keep the the original alias | ||
alias = Object.entries(alias).map(([k, v]) => ({ find: k, replacement: v })); | ||
} | ||
// redirect resolve-module to `node_modules/.vite-plugin-resolve` | ||
alias.push(...aliaList.map(item => { | ||
const [find, replacement] = Object.entries(item)[0]; | ||
return { find, replacement }; | ||
})); | ||
config.resolve.alias = alias; | ||
} | ||
/** | ||
* @type {import('.').ModifyOptimizeDepsExclude} | ||
*/ | ||
function modifyOptimizeDepsExclude(config, exclude) { | ||
if (!config.optimizeDeps) config.optimizeDeps = {}; | ||
if (!config.optimizeDeps.exclude) config.optimizeDeps.exclude = []; | ||
if (config.optimizeDeps.include) { | ||
exclude = exclude.filter(e => !config.optimizeDeps.include.includes(e)); | ||
} | ||
config.optimizeDeps.exclude.push(...exclude); | ||
} | ||
// --------- utils --------- | ||
function ensureDir(dir) { | ||
if (!(fs.existsSync(dir) && fs.statSync(dir).isDirectory())) { | ||
fs.mkdirSync(dir, { recursive: true }); | ||
} | ||
return dir; | ||
} | ||
function node_modules(root, count = 0) { | ||
if (node_modules.p) { | ||
return node_modules.p; | ||
} | ||
const p = path.join(root, 'node_modules'); | ||
if (fs.existsSync(p)) { | ||
return node_modules.p = p; | ||
} | ||
if (count >= 19) { | ||
throw new Error('Can not found node_modules directory.'); | ||
} | ||
return node_modules(path.join(root, '..'), count + 1); | ||
} | ||
]; | ||
}; |
{ | ||
"name": "vite-plugin-resolve", | ||
"version": "1.8.0", | ||
"version": "2.0.0", | ||
"description": "Custom resolve module content.", | ||
@@ -11,3 +11,3 @@ "main": "index.js", | ||
"devDependencies": { | ||
"vite": "^2.6.13" | ||
"vite": "^2.x" | ||
}, | ||
@@ -14,0 +14,0 @@ "keywords": [ |
133
README.md
@@ -8,4 +8,3 @@ # vite-plugin-resolve [![NPM version](https://img.shields.io/npm/v/vite-plugin-resolve.svg)](https://npmjs.org/package/vite-plugin-resolve) [![awesome-vite](https://awesome.re/badge.svg)](https://github.com/vitejs/awesome-vite) | ||
- Compatible Browser, Node.js and Electron | ||
- You can think of it as an enhanced Vite external plugin | ||
- You can think of it as manually [Pre-Bundling](https://vitejs.dev/guide/dep-pre-bundling.html) | ||
- You can think of this as the implementation of the official tutorial 👉 [Virtual Modules Convention](https://vitejs.dev/guide/api-plugin.html#virtual-modules-convention) | ||
@@ -41,3 +40,3 @@ ## Install | ||
// Support return Promise | ||
'@scope/name': async () => await require('fs').promises.readFile('path', 'utf-8'), | ||
'@scope/name': () => require('fs').promises.readFile('path', 'utf-8'), | ||
}) | ||
@@ -55,131 +54,23 @@ ``` | ||
#### Resolve an ES module as an CommonJs module for Node.js | ||
Such as [execa](https://www.npmjs.com/package/execa), [node-fetch](https://www.npmjs.com/package/node-fetch) | ||
Here, Vite is used as the build tool | ||
You can also choose other tools, such as [rollup](https://rollupjs.org), [webpack](https://webpack.js.org), [esbuild](https://esbuild.github.io), [swc](https://swc.rs) and so on | ||
```ts | ||
import { builtinModules } from 'module' | ||
import { defineConfig, build } from 'vite' | ||
import resolve from 'vite-plugin-resolve' | ||
export default defineConfig({ | ||
plugins: [ | ||
resolve({ | ||
async execa(args) { | ||
// Transpile execa as an CommonJs module | ||
await build({ | ||
plugins: [ | ||
{ | ||
name: 'vite-plugin[node:mod-to-mod]', | ||
enforce: 'pre', | ||
// Replace `import fs from "node:fs"` with `import fs from "fs"` | ||
resolveId(source) { | ||
if (source.startsWith('node:')) { | ||
return source.replace('node:', '') | ||
} | ||
}, | ||
} | ||
], | ||
// Build execa.js into cache directory | ||
build: { | ||
outDir: args.dir, | ||
minify: false, | ||
emptyOutDir: false, | ||
lib: { | ||
entry: require.resolve('execa'), | ||
formats: ['cjs'], | ||
fileName: () => `execa.js`, | ||
}, | ||
rollupOptions: { | ||
external: [ | ||
...builtinModules, | ||
], | ||
}, | ||
}, | ||
}) | ||
}, | ||
}) | ||
] | ||
}) | ||
``` | ||
## API | ||
### resolve(resolves[, options]) | ||
#### resolve(entries) | ||
##### resolves | ||
**entries** | ||
```ts | ||
export interface Resolves { | ||
{ | ||
[moduleId: string]: | ||
| string | ||
| ((args: ResolveArgs) => | ||
| string | ||
| Promise<string | void> | ||
| void) | ||
| void; | ||
| ReturnType<Plugin['load']> | ||
| ((...args: Parameters<Plugin['load']>) => ReturnType<Plugin['load']>) | ||
} | ||
export interface ResolveArgs { | ||
/** Generated file cache directory */ | ||
dir: string; | ||
} | ||
``` | ||
##### options | ||
You can see the return value type definition here [rollup/types.d.ts#L272](https://github.com/rollup/rollup/blob/b8315e03f9790d610a413316fbf6d565f9340cab/src/rollup/types.d.ts#L272) | ||
```ts | ||
export interface ResolveOptions { | ||
/** | ||
* Absolute path or relative path | ||
* @default ".vite-plugin-resolve" | ||
*/ | ||
dir: string; | ||
} | ||
``` | ||
## What's different from the official Demo? | ||
## How to work | ||
There are two main differences | ||
#### Let's use Vue as an example | ||
```js | ||
resolve({ | ||
vue: `const vue = window.Vue; export { vue as default }`, | ||
}) | ||
``` | ||
1. Create `node_modules/.vite-plugin-resolve/vue.js` and contains the following code | ||
```js | ||
const vue = window.Vue; export { vue as default } | ||
``` | ||
2. Create a `vue` alias item and add it to `resolve.alias` | ||
```js | ||
{ | ||
resolve: { | ||
alias: [ | ||
{ | ||
find: 'vue', | ||
replacement: 'User/work-directory/node_modules/.vite-plugin-resolve/vue.js', | ||
}, | ||
], | ||
}, | ||
} | ||
``` | ||
3. Add `vue` to the `optimizeDeps.exclude` by default. | ||
You can avoid it through `optimizeDeps.include` | ||
```js | ||
export default { | ||
optimizeDeps: { | ||
exclude: ['vue'], | ||
}, | ||
} | ||
``` | ||
1. Bypass the builtin `vite:resolve` plugin | ||
2. Reasonably avoid [Pre-Bundling](https://vitejs.dev/guide/dep-pre-bundling.html) treatment |
@@ -8,4 +8,3 @@ # vite-plugin-resolve [![NPM version](https://img.shields.io/npm/v/vite-plugin-resolve.svg)](https://npmjs.org/package/vite-plugin-resolve) [![awesome-vite](https://awesome.re/badge.svg)](https://github.com/vitejs/awesome-vite) | ||
- 兼容 Browser, Node.js and Electron | ||
- 你可以认为它是一个加强版的 Vite external 插件 | ||
- 你可以认为它是手动版的 Vite 预构建 [Pre-Bundling](https://vitejs.dev/guide/dep-pre-bundling.html) | ||
- 你可以认为它是官方教程的一个实现 👉 [Virtual Modules Convention](https://vitejs.dev/guide/api-plugin.html#virtual-modules-convention) | ||
@@ -54,131 +53,23 @@ ## 安装 | ||
#### 将 ES 模块转换成 CommonJs 模块供 Node.js 使用 | ||
例如 [execa](https://www.npmjs.com/package/execa), [node-fetch](https://www.npmjs.com/package/node-fetch) | ||
这里使用 "vite" 作为构建工具 | ||
你也可以选用其他的工具,比如 [rollup](https://rollupjs.org), [webpack](https://webpack.js.org), [esbuild](https://esbuild.github.io), [swc](https://swc.rs) 等等 | ||
```ts | ||
import { builtinModules } from 'module' | ||
import { defineConfig, build } from 'vite' | ||
import resolve from 'vite-plugin-resolve' | ||
export default defineConfig({ | ||
plugins: [ | ||
resolve({ | ||
async execa(args) { | ||
// 将 execa 构建成 CommonJs 模块 | ||
await build({ | ||
plugins: [ | ||
{ | ||
name: 'vite-plugin[node:mod-to-mod]', | ||
enforce: 'pre', | ||
// 将 import fs from "node:fs" 替换为 import fs from "fs" | ||
resolveId(source) { | ||
if (source.startsWith('node:')) { | ||
return source.replace('node:', '') | ||
} | ||
}, | ||
} | ||
], | ||
// 将 execa.js 写入到缓存目录 | ||
build: { | ||
outDir: args.dir, | ||
minify: false, | ||
emptyOutDir: false, | ||
lib: { | ||
entry: require.resolve('execa'), | ||
formats: ['cjs'], | ||
fileName: () => `execa.js`, | ||
}, | ||
rollupOptions: { | ||
external: [ | ||
...builtinModules, | ||
], | ||
}, | ||
}, | ||
}) | ||
}, | ||
}) | ||
] | ||
}) | ||
``` | ||
## API | ||
### resolve(resolves[, options]) | ||
#### resolve(entries) | ||
##### resolves | ||
**entries** | ||
```ts | ||
export interface Resolves { | ||
{ | ||
[moduleId: string]: | ||
| string | ||
| ((args: ResolveArgs) => | ||
| string | ||
| Promise<string | void> | ||
| void) | ||
| void; | ||
| ReturnType<Plugin['load']> | ||
| ((...args: Parameters<Plugin['load']>) => ReturnType<Plugin['load']>) | ||
} | ||
export interface ResolveArgs { | ||
/** 生成缓存文件夹 */ | ||
dir: string; | ||
} | ||
``` | ||
##### options | ||
详细的返回值类型看这里 [rollup/types.d.ts#L272](https://github.com/rollup/rollup/blob/b8315e03f9790d610a413316fbf6d565f9340cab/src/rollup/types.d.ts#L272) | ||
```ts | ||
export interface ResolveOptions { | ||
/** | ||
* 相对或绝对路径 | ||
* @default ".vite-plugin-resolve" | ||
*/ | ||
dir: string; | ||
} | ||
``` | ||
## 这与官方的 Demo 有何异同? | ||
## 工作原理 | ||
主要有两点不一样 | ||
#### 用 Vue 来举个 🌰 | ||
```js | ||
viteResolve({ | ||
vue: `const vue = window.Vue; export { vue as default }`, | ||
}) | ||
``` | ||
1. 创建 `node_modules/.vite-plugin-resolve/vue.js` 文件并包含下面的代码 | ||
```js | ||
const vue = window.Vue; export { vue as default } | ||
``` | ||
2. 创建一个 `vue` 的别名项,并且添加到 `resolve.alias` | ||
```js | ||
{ | ||
resolve: { | ||
alias: [ | ||
{ | ||
find: 'vue', | ||
replacement: 'User/work-directory/node_modules/.vite-plugin-resolve/vue.js', | ||
}, | ||
], | ||
}, | ||
} | ||
``` | ||
3. 默认会将 `vue` 添加到 `optimizeDeps.exclude` 中 | ||
你可以通过 `optimizeDeps.include` 绕开 | ||
```js | ||
export default { | ||
optimizeDeps: { | ||
exclude: ['vue'], | ||
}, | ||
} | ||
``` | ||
1. 绕过内置的 `vite:resolve` 插件 | ||
2. 合理的避开 [Pre-Bundling](https://vitejs.dev/guide/dep-pre-bundling.html) |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
1
5828
51
74