vite-plugin-fast-external
Advanced tools
Comparing version 1.2.0 to 1.3.0
import { Plugin as VitePlugin } from 'vite'; | ||
export declare function external(externals: Record<string, string>, options?: { | ||
/** | ||
* @default 'esm' | ||
* esm will generate code - const vue = window['Vue']; export { vue as default }; | ||
* cjs will generate code - const vue = window['Vue']; module.exports = vue; | ||
*/ | ||
export declare type Externals = Record<string, string | (() => string)>; | ||
export interface ExternalOptions { | ||
format: 'esm' | 'cjs'; | ||
}): VitePlugin; | ||
} | ||
export declare function external( | ||
/** | ||
* @example | ||
* export default defineConfig({ | ||
* plugins: [ | ||
* fastExternal({ | ||
* // use string | ||
* vue: 'Vue', | ||
* // custom external code by function | ||
* '@scope/name': () => `const Lib = window.LibraryName; export default Lib;`, | ||
* }) | ||
* ] | ||
* }) | ||
*/ | ||
externals: Externals, | ||
/** | ||
* @default 'esm' | ||
* @example | ||
* esm will generate code -> const vue = window['Vue']; export { vue as default }; | ||
* cjs will generate code -> const vue = window['Vue']; module.exports = vue; | ||
*/ | ||
options?: ExternalOptions): VitePlugin; | ||
export default external; |
@@ -9,6 +9,25 @@ "use strict"; | ||
const path_1 = __importDefault(require("path")); | ||
function external(externals, options) { | ||
const modCache = {}; | ||
const root = process.cwd(); | ||
const node_modules = path_1.default.join(root, 'node_modules'); | ||
function external( | ||
/** | ||
* @example | ||
* export default defineConfig({ | ||
* plugins: [ | ||
* fastExternal({ | ||
* // use string | ||
* vue: 'Vue', | ||
* // custom external code by function | ||
* '@scope/name': () => `const Lib = window.LibraryName; export default Lib;`, | ||
* }) | ||
* ] | ||
* }) | ||
*/ | ||
externals, | ||
/** | ||
* @default 'esm' | ||
* @example | ||
* esm will generate code -> const vue = window['Vue']; export { vue as default }; | ||
* cjs will generate code -> const vue = window['Vue']; module.exports = vue; | ||
*/ | ||
options) { | ||
let root = process.cwd(); | ||
const viteExternalId = '.vite-plugin-fast-external'; | ||
@@ -18,27 +37,12 @@ return { | ||
config(config) { | ||
// ensure viteExternal exist | ||
const externalDir = path_1.default.join(node_modules, viteExternalId); | ||
fs_1.default.existsSync(externalDir) || fs_1.default.mkdirSync(externalDir); | ||
// generate external module file. | ||
for (const [mod, iifeName] of Object.entries(externals)) { | ||
const modFilename = path_1.default.join(node_modules, viteExternalId, `${mod}.js`); | ||
if (!fs_1.default.existsSync(modFilename)) { | ||
// for '@scope/name' package | ||
ensureDir(path_1.default.parse(modFilename).dir); | ||
const modContent = (options === null || options === void 0 ? void 0 : options.format) === 'cjs' | ||
? `const ${iifeName} = window['${iifeName}']; module.exports = ${iifeName};` | ||
: `const ${iifeName} = window['${iifeName}']; export { ${iifeName} as default }`; | ||
fs_1.default.writeFileSync(modFilename, modContent); | ||
} | ||
// init root path | ||
if (config.root && path_1.default.isAbsolute(config.root)) { | ||
// TODO: config.root is relative path | ||
root = config.root; | ||
} | ||
}, | ||
load(id) { | ||
const url = cleanUrl(id); | ||
const parsed = path_1.default.parse(url); | ||
const external = Object.entries(externals).find(([name]) => url.includes('node_modules') && parsed.name === name); | ||
if (external) { | ||
const modFilename = path_1.default.join(node_modules, viteExternalId, parsed.base); | ||
return modCache[modFilename] || (modCache[modFilename] = fs_1.default.readFileSync(modFilename, 'utf8')); | ||
} | ||
}, | ||
// Step 1 | ||
generateExternalFile(root, externals, viteExternalId, (options === null || options === void 0 ? void 0 : options.format) || 'esm'); | ||
// Step 2 | ||
rewriteAlias(root, config, externals, viteExternalId); | ||
} | ||
}; | ||
@@ -56,7 +60,50 @@ } | ||
} | ||
function cleanUrl(url) { | ||
const queryRE = /\?.*$/s; | ||
const hashRE = /#.*$/s; | ||
return url.replace(hashRE, '').replace(queryRE, ''); | ||
function node_modules(root, count = 0) { | ||
const p = path_1.default.join(root, 'node_modules'); | ||
if (fs_1.default.existsSync(p)) { | ||
return p; | ||
} | ||
if (count >= 19) { | ||
throw new Error('Can not found node_modules directory.'); | ||
} | ||
return node_modules(path_1.default.join(root, '..'), count + 1); | ||
} | ||
function generateExternalFile(root, externals, viteExternalId, format) { | ||
// ensure {viteExternal} directory existed | ||
const externalDir = path_1.default.join(node_modules(root), viteExternalId); | ||
fs_1.default.existsSync(externalDir) || fs_1.default.mkdirSync(externalDir); | ||
// generate external module file. | ||
for (const [module, strOrFn] of Object.entries(externals)) { | ||
const modFilename = path_1.default.join(node_modules(root), viteExternalId, `${module}.js`); | ||
if (!fs_1.default.existsSync(modFilename)) { | ||
// for '@scope/name' package | ||
ensureDir(path_1.default.parse(modFilename).dir); | ||
let moduleContent; | ||
if (typeof strOrFn === 'string') { | ||
const iifeName = strOrFn; | ||
moduleContent = format === 'cjs' | ||
? `const ${iifeName} = window['${iifeName}']; module.exports = ${iifeName};` | ||
: `const ${iifeName} = window['${iifeName}']; export { ${iifeName} as default }`; | ||
} | ||
else { | ||
moduleContent = strOrFn(); | ||
} | ||
fs_1.default.writeFileSync(modFilename, moduleContent); | ||
} | ||
} | ||
} | ||
function rewriteAlias(root, config, external, viteExternalId) { | ||
if (!config.resolve) { | ||
config.resolve = {}; | ||
} | ||
let alias = config.resolve.alias || {}; | ||
if (!Array.isArray(alias)) { | ||
alias = Object.entries(alias).map(([k, v]) => ({ find: k, replacement: v })); | ||
} | ||
Object.keys(external).forEach(k => { | ||
// redirect external module to `node_modules/.vite-plugin-fast-external` directory | ||
alias.push({ find: k, replacement: path_1.default.join(node_modules(root), viteExternalId, k) }); | ||
}); | ||
config.resolve.alias = alias; | ||
} | ||
exports.default = external; |
{ | ||
"name": "vite-plugin-fast-external", | ||
"version": "1.2.0", | ||
"version": "1.3.0", | ||
"description": "An tiny and fast external plugin for vite.", | ||
@@ -5,0 +5,0 @@ "main": "dist/index.js", |
@@ -13,3 +13,3 @@ # vite-plugin-fast-external | ||
```bash | ||
npm install vite-plugin-fast-external --save-dev | ||
npm i -D vite-plugin-fast-external | ||
``` | ||
@@ -25,13 +25,16 @@ | ||
fastExternal({ | ||
// use string | ||
vue: 'Vue', | ||
// custom external code by function | ||
'@scope/name': () => `const Lib = window.LibraryName; export default Lib;`, | ||
}) | ||
] | ||
}); | ||
}) | ||
``` | ||
## Definition | ||
## Options define | ||
```typescript | ||
export type fastExternal = ( | ||
externals: Record<string, string>, | ||
externals: Record<string, string | (() => string)>, | ||
options?: { | ||
@@ -50,26 +53,16 @@ /** | ||
- Generate ESModule code into `node_modules/.vite-plugin-fast-external/xxxx.js` - eg: | ||
1. External-module will be generated code into `node_modules/.vite-plugin-fast-external/xxxx.js` | ||
2. Append an external-module alias | ||
```js | ||
// source code | ||
import Vue from 'vue' | ||
// transformed | ||
const vue = window['Vue']; export { vue as default } | ||
``` | ||
- `node_modules/.vite-plugin-fast-external/xxxx.js` will be return when vite load hooks - eg: | ||
```js | ||
{ | ||
name: 'vite-plugin-fast-external', | ||
load(id) { | ||
if (id.includes('node_modules/.vite-plugin-fast-external')) { | ||
return fs.readFileSync(externalFilename, 'utf8') | ||
} | ||
resolve: { | ||
alias: [ | ||
{ | ||
find: 'vue', | ||
replacement: 'User/work-directory/node_modules/.vite-plugin-fast-external/vue.js', | ||
}, | ||
], | ||
}, | ||
}, | ||
} | ||
``` | ||
## TODO | ||
- [ ] Support multiple member import, such as `import { ref, watch } from '@vue/composition-api'` |
147
src/index.ts
import fs from 'fs' | ||
import path from 'path' | ||
import { Plugin as VitePlugin } from 'vite' | ||
import { Plugin as VitePlugin, UserConfig, Alias } from 'vite' | ||
export type Externals = Record<string, string | (() => string)> | ||
export interface ExternalOptions { | ||
format: 'esm' | 'cjs' | ||
} | ||
export function external( | ||
externals: Record<string, string>, | ||
options?: { | ||
/** | ||
* @default 'esm' | ||
* esm will generate code - const vue = window['Vue']; export { vue as default }; | ||
* cjs will generate code - const vue = window['Vue']; module.exports = vue; | ||
*/ | ||
format: 'esm' | 'cjs' | ||
}, | ||
/** | ||
* @example | ||
* export default defineConfig({ | ||
* plugins: [ | ||
* fastExternal({ | ||
* // use string | ||
* vue: 'Vue', | ||
* // custom external code by function | ||
* '@scope/name': () => `const Lib = window.LibraryName; export default Lib;`, | ||
* }) | ||
* ] | ||
* }) | ||
*/ | ||
externals: Externals, | ||
/** | ||
* @default 'esm' | ||
* @example | ||
* esm will generate code -> const vue = window['Vue']; export { vue as default }; | ||
* cjs will generate code -> const vue = window['Vue']; module.exports = vue; | ||
*/ | ||
options?: ExternalOptions, | ||
): VitePlugin { | ||
const modCache: Record<string, string> = {} | ||
const root = process.cwd() | ||
const node_modules = path.join(root, 'node_modules') | ||
let root = process.cwd() | ||
const viteExternalId = '.vite-plugin-fast-external' | ||
@@ -24,31 +39,14 @@ | ||
config(config) { | ||
// ensure viteExternal exist | ||
const externalDir = path.join(node_modules, viteExternalId) | ||
fs.existsSync(externalDir) || fs.mkdirSync(externalDir) | ||
// init root path | ||
if (config.root && path.isAbsolute(config.root)) { | ||
// TODO: config.root is relative path | ||
root = config.root | ||
} | ||
// generate external module file. | ||
for (const [mod, iifeName] of Object.entries(externals)) { | ||
const modFilename = path.join(node_modules, viteExternalId, `${mod}.js`) | ||
if (!fs.existsSync(modFilename)) { | ||
// for '@scope/name' package | ||
ensureDir(path.parse(modFilename).dir) | ||
// Step 1 | ||
generateExternalFile(root, externals, viteExternalId, options?.format || 'esm') | ||
const modContent = options?.format === 'cjs' | ||
? `const ${iifeName} = window['${iifeName}']; module.exports = ${iifeName};` | ||
: `const ${iifeName} = window['${iifeName}']; export { ${iifeName} as default }` | ||
fs.writeFileSync(modFilename, modContent) | ||
} | ||
} | ||
}, | ||
load(id) { | ||
const url = cleanUrl(id) | ||
const parsed = path.parse(url) | ||
const external = Object.entries(externals).find(([name]) => url.includes('node_modules') && parsed.name === name) | ||
if (external) { | ||
const modFilename = path.join(node_modules, viteExternalId, parsed.base) | ||
return modCache[modFilename] || (modCache[modFilename] = fs.readFileSync(modFilename, 'utf8')) | ||
} | ||
}, | ||
// Step 2 | ||
rewriteAlias(root, config, externals, viteExternalId) | ||
} | ||
} | ||
@@ -66,8 +64,69 @@ } | ||
function cleanUrl(url: string) { | ||
const queryRE = /\?.*$/s | ||
const hashRE = /#.*$/s | ||
return url.replace(hashRE, '').replace(queryRE, '') | ||
function node_modules(root: string, count = 0) { | ||
const p = path.join(root, 'node_modules') | ||
if (fs.existsSync(p)) { | ||
return p | ||
} | ||
if (count >= 19) { | ||
throw new Error('Can not found node_modules directory.') | ||
} | ||
return node_modules(path.join(root, '..'), count + 1) | ||
} | ||
function generateExternalFile( | ||
root: string, | ||
externals: Externals, | ||
viteExternalId: string, | ||
format: ExternalOptions['format'] | ||
) { | ||
// ensure {viteExternal} directory existed | ||
const externalDir = path.join(node_modules(root), viteExternalId) | ||
fs.existsSync(externalDir) || fs.mkdirSync(externalDir) | ||
// generate external module file. | ||
for (const [module, strOrFn] of Object.entries(externals)) { | ||
const modFilename = path.join(node_modules(root), viteExternalId, `${module}.js`) | ||
if (!fs.existsSync(modFilename)) { | ||
// for '@scope/name' package | ||
ensureDir(path.parse(modFilename).dir) | ||
let moduleContent: string | ||
if (typeof strOrFn === 'string') { | ||
const iifeName = strOrFn | ||
moduleContent = format === 'cjs' | ||
? `const ${iifeName} = window['${iifeName}']; module.exports = ${iifeName};` | ||
: `const ${iifeName} = window['${iifeName}']; export { ${iifeName} as default }` | ||
} else { | ||
moduleContent = strOrFn() | ||
} | ||
fs.writeFileSync(modFilename, moduleContent) | ||
} | ||
} | ||
} | ||
function rewriteAlias( | ||
root: string, | ||
config: UserConfig, | ||
external: Externals, | ||
viteExternalId: string | ||
) { | ||
if (!config.resolve) { | ||
config.resolve = {} | ||
} | ||
let alias = config.resolve.alias || {} | ||
if (!Array.isArray(alias)) { | ||
alias = Object.entries(alias).map(([k, v]) => ({ find: k, replacement: v })) | ||
} | ||
Object.keys(external).forEach(k => { | ||
// redirect external module to `node_modules/.vite-plugin-fast-external` directory | ||
(alias as Alias[]).push({ find: k, replacement: path.join(node_modules(root), viteExternalId, k) }) | ||
}) | ||
config.resolve.alias = alias | ||
} | ||
export default external |
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
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
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
10831
263
66
1