parcel-plugin-externals
Advanced tools
Comparing version 0.2.0 to 0.3.0-pre.20191112.1
# parcel-plugin-externals Changelog | ||
## 0.3.0 | ||
- Implemented a way to dynamically choose what (and how) to externalize (#4) | ||
- Fixed exception on browser property set to false (#6) | ||
## 0.2.0 | ||
@@ -4,0 +9,0 @@ |
{ | ||
"name": "parcel-plugin-externals", | ||
"version": "0.2.0", | ||
"version": "0.3.0-pre.20191112.1", | ||
"description": "A plugin for Parcel to omit declared externals from being included in the emitted bundles.", | ||
@@ -5,0 +5,0 @@ "main": "index.js", |
@@ -78,2 +78,34 @@ # parcel-plugin-externals | ||
### Dynamic Dependency Resolution | ||
Sometimes you want to externalize a whole set of dependencies, potentially by a given rule, e.g., `react-*` or similar. For such cases you can also refer to a module that does the replacement rule determination: | ||
```json | ||
{ | ||
"externals": "./tools/ruleFactory.js" | ||
} | ||
``` | ||
The rule factory module is just a simple Node.js module that exports a function: | ||
```js | ||
const rx = /node_modules\/react-(.*?)\//; | ||
module.exports = function(path) { | ||
const result = rx.exec(path); | ||
if (result) { | ||
const suffix = result[1]; | ||
const name = suffix[0].toUpperCase() + suffix.substr(1); | ||
return `react-${suffix} => React${name}`; | ||
} | ||
return undefined; | ||
}; | ||
``` | ||
What you need to return is either `undefined` (i.e., the module will not be externalized) or the replacement rule. | ||
**Remark**: If the rule does not contain the forward `=>` slash it will be interpreted as `returnValue => require('returnValue')`, where `returnValue` is the part returned from the function. | ||
## Changelog | ||
@@ -80,0 +112,0 @@ |
118
utils.js
@@ -17,7 +17,9 @@ const { readFileSync, existsSync } = require("fs"); | ||
if (typeof moduleDefinition.browser === "string") { | ||
return { | ||
name, | ||
rule, | ||
path: resolve(moduleRoot, moduleDefinition.browser) | ||
}; | ||
return [ | ||
{ | ||
name, | ||
rule, | ||
path: resolve(moduleRoot, moduleDefinition.browser) | ||
} | ||
]; | ||
} | ||
@@ -28,6 +30,9 @@ | ||
const desired = moduleDefinition.browser[repl]; | ||
replacements[resolve(moduleRoot, repl)] = resolve( | ||
moduleRoot, | ||
desired | ||
); | ||
if (desired) { | ||
replacements[resolve(moduleRoot, repl)] = resolve( | ||
moduleRoot, | ||
desired | ||
); | ||
} | ||
}); | ||
@@ -38,7 +43,9 @@ } | ||
const modulePath = resolve(moduleRoot, moduleDefinition.module); | ||
return { | ||
name, | ||
rule, | ||
path: replacements[modulePath] || modulePath | ||
}; | ||
return [ | ||
{ | ||
name, | ||
rule, | ||
path: replacements[modulePath] || modulePath | ||
} | ||
]; | ||
} | ||
@@ -50,10 +57,18 @@ } | ||
}); | ||
return { | ||
name, | ||
rule, | ||
path: replacements[directPath] || directPath | ||
}; | ||
return [ | ||
...Object.keys(replacements).map(r => ({ | ||
name, | ||
rule, | ||
path: replacements[r] | ||
})), | ||
{ | ||
name, | ||
rule, | ||
path: directPath | ||
} | ||
]; | ||
} catch (ex) { | ||
console.warn(`Could not find module ${name}.`); | ||
return undefined; | ||
return []; | ||
} | ||
@@ -66,8 +81,23 @@ } | ||
function provideSupportForExternals(proto, externalNames, targetDir) { | ||
const externals = externalNames | ||
.map(name => resolveModule(name, targetDir)) | ||
.filter(m => !!m); | ||
const ra = proto.getLoadedAsset; | ||
proto.getLoadedAsset = function(path) { | ||
function wrapFactory(ruleFactory) { | ||
return path => { | ||
const rule = ruleFactory(path); | ||
if (rule !== undefined) { | ||
return `/${rule}.${extension}`; | ||
} | ||
return path; | ||
}; | ||
} | ||
function makeResolver(targetDir, externalNames) { | ||
const externals = []; | ||
for (const name of externalNames) { | ||
const modules = resolveModule(name, targetDir); | ||
externals.push(...modules); | ||
} | ||
return path => { | ||
const [external] = externals.filter(m => m.path === path); | ||
@@ -79,6 +109,14 @@ | ||
return ra.call(this, path); | ||
return path; | ||
}; | ||
} | ||
function provideSupportForExternals(proto, resolver) { | ||
const ra = proto.getLoadedAsset; | ||
proto.getLoadedAsset = function(path) { | ||
const result = resolver(path); | ||
return ra.call(this, result); | ||
}; | ||
} | ||
function retrieveExternals(rootDir) { | ||
@@ -95,8 +133,28 @@ const path = resolvePackage(rootDir); | ||
if (Array.isArray(externals)) { | ||
return externals.concat(plain); | ||
const values = externals.concat(plain); | ||
return makeResolver(rootDir, values); | ||
} else if (typeof externals === "object") { | ||
return Object.keys(externals) | ||
.filter(name => typeof externals[name] === 'string') | ||
const values = Object.keys(externals) | ||
.filter(name => typeof externals[name] === "string") | ||
.map(name => `${name} => ${externals[name]}`) | ||
.concat(plain); | ||
return makeResolver(rootDir, values); | ||
} else if (typeof externals === "string") { | ||
const externalPath = resolve(rootDir, externals); | ||
if (!existsSync(externalPath)) { | ||
console.warn( | ||
`Could not find "${externals}". Looked in "${externalPath}".` | ||
); | ||
} else { | ||
const resolver = require(externalPath); | ||
if (typeof resolver === "function") { | ||
return wrapFactory(resolver); | ||
} | ||
console.warn( | ||
`Did not find a function. Expected to find something like "module.exports = function() {}".` | ||
); | ||
} | ||
} | ||
@@ -103,0 +161,0 @@ |
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
12953
226
119
5