rollup-plugin-cjs-es
Advanced tools
Comparing version 0.4.0 to 0.5.0
266
index.js
@@ -5,15 +5,5 @@ const fs = require("fs"); | ||
const {transform: cjsEs} = require("cjs-es"); | ||
const mergeSourceMap = require("merge-source-map"); | ||
const {createFilter} = require("rollup-pluginutils"); | ||
const {analyze: esInfoAnalyze} = require("es-info"); | ||
const {wrapImport} = require("./lib/wrap-import"); | ||
const {unwrapImport} = require("./lib/unwrap-import"); | ||
function joinMaps(maps) { | ||
while (maps.length > 1) { | ||
maps[maps.length - 2] = mergeSourceMap(maps[maps.length - 2], maps.pop()); | ||
} | ||
return maps[0]; | ||
} | ||
function isEsModule(result) { | ||
@@ -26,36 +16,39 @@ return Object.keys(result.import).length || | ||
function factory(options = {}) { | ||
let isImportWrapped = false; | ||
let parse = null; | ||
function factory({ | ||
include = null, | ||
exclude = null, | ||
cache = ".cjsescache", | ||
sourceMap = true, | ||
nested = false, | ||
exportType = null, | ||
_fs = fs | ||
}) { | ||
const exportTypeCache = {}; | ||
const exportTable = {}; | ||
const exportCache = {}; | ||
const {_fs = fs} = options; | ||
const filter = createFilter(include, exclude); | ||
if (typeof options.exportType === "object") { | ||
if (exportType && typeof exportType === "object") { | ||
const newMap = {}; | ||
for (const key of Object.keys(options.exportType)) { | ||
for (const key of Object.keys(exportType)) { | ||
const newKey = path.resolve(key); | ||
newMap[newKey] = options.exportType[key]; | ||
newMap[newKey] = exportType[key]; | ||
} | ||
options.exportType = newMap; | ||
exportType = newMap; | ||
} | ||
if (options.sourceMap == null) { | ||
options.sourceMap = true; | ||
if (cache) { | ||
loadCjsEsCache(); | ||
} | ||
if (options.cache == null) { | ||
options.cache = true; | ||
} | ||
return { | ||
name: "rollup-plugin-cjs-es", | ||
transform, | ||
buildEnd | ||
}; | ||
const filter = createFilter(options.include, options.exclude); | ||
if (options.cache) { | ||
loadCjsEsCache(); | ||
} | ||
function loadCjsEsCache() { | ||
let data; | ||
try { | ||
data = _fs.readFileSync(".cjsescache", "utf8"); | ||
data = _fs.readFileSync(cache, "utf8"); | ||
} catch (err) { | ||
@@ -65,4 +58,5 @@ return; | ||
data = JSON.parse(data); | ||
for (const [id, type] of Object.entries(data)) { | ||
exportCache[path.resolve(id)] = type; | ||
for (const [id, expectBy] of Object.entries(data)) { | ||
exportCache[id[0] === "~" ? id.slice(1) : path.resolve(id)] = | ||
expectBy ? path.resolve(expectBy) : null; | ||
} | ||
@@ -72,28 +66,40 @@ } | ||
function writeCjsEsCache() { | ||
const data = Object.entries(exportTable).filter(e => e[1].trusted || e[1].external) | ||
const data = Object.entries(exportTable).filter(([, i]) => i.default && (i.trusted || i.external)) | ||
.sort((a, b) => a[0].localeCompare(b[0])) | ||
.reduce((output, [id, info]) => { | ||
id = path.relative(".", id).replace(/\\/g, "/"); | ||
output[id] = info.named ? "named" : "default"; | ||
.reduce((output, [id, {expectBy}]) => { | ||
if (expectBy === id) { | ||
expectBy = null; | ||
} else { | ||
expectBy = path.relative(".", expectBy).replace(/\\/g, "/"); | ||
} | ||
id = path.isAbsolute(id) ? path.relative(".", id).replace(/\\/g, "/") : `~${id}`; | ||
output[id] = expectBy; | ||
return output; | ||
}, {}); | ||
_fs.writeFileSync(".cjsescache", JSON.stringify(data, null, 2), "utf8"); | ||
_fs.writeFileSync(cache, JSON.stringify(data, null, 2), "utf8"); | ||
} | ||
function getExportTypeFromOptions(id) { | ||
if (!options.exportType) { | ||
if (!exportType) { | ||
return; | ||
} | ||
if (typeof options.exportType === "string") { | ||
return options.exportType; | ||
if (typeof exportType === "string") { | ||
return exportType; | ||
} | ||
return typeof options.exportType === "function" ? | ||
options.exportType(id) : options.exportType[id]; | ||
if (typeof exportType === "object") { | ||
return exportType[id]; | ||
} | ||
if (exportTypeCache.hasOwnProperty(id)) { | ||
return exportTypeCache[id]; | ||
} | ||
return Promise.resolve(exportType(id)) | ||
.then(result => { | ||
if (result) { | ||
exportTypeCache[id] = result; | ||
} | ||
return result; | ||
}); | ||
} | ||
function getExportType(id) { | ||
// get export type from trusted table | ||
if (exportTable[id] && exportTable[id].trusted) { | ||
return exportTable[id].named ? "named" : "default"; | ||
} | ||
function getExportType(id, importer = null) { | ||
// get export type from options | ||
@@ -105,12 +111,14 @@ return Promise.resolve(getExportTypeFromOptions(id)) | ||
} | ||
// get export type from guess table | ||
if (exportTable[id]) { | ||
// get export type from trusted table | ||
if (exportTable[id] && exportTable[id].trusted) { | ||
return exportTable[id].named ? "named" : "default"; | ||
} | ||
// get export type from cache | ||
return exportCache[id]; | ||
// check if id is in preferDefault cache | ||
if (exportCache.hasOwnProperty(id) && exportCache[id] !== importer) { | ||
return "default"; | ||
} | ||
}); | ||
} | ||
function updateExportTable({id, code, context, info}) { | ||
function updateExportTable({id, code, context, info, guessExportType}) { | ||
if (!info) { | ||
@@ -127,8 +135,11 @@ info = esInfoAnalyze(context.parse(code)); | ||
} | ||
exportTable[id] = { | ||
default: info.default, | ||
named: info.export.named.length > 0 || info.all, | ||
expectBy: id, | ||
trusted: true | ||
}; | ||
if (!exportTable[id] || !guessExportType.has(id)) { | ||
const exportInfo = info.export; | ||
exportTable[id] = { | ||
default: exportInfo.default, | ||
named: exportInfo.named.length > 0 || exportInfo.all, | ||
expectBy: id, | ||
trusted: !guessExportType.has(id) | ||
}; | ||
} | ||
return Promise.all(Object.entries(info.import).map(([name, importInfo]) => { | ||
@@ -149,12 +160,11 @@ return context.resolveId(name, id) | ||
} | ||
} else { | ||
const newGuess = { | ||
} | ||
if (!exportTable[importee] || !guessExportType.has(importee)) { | ||
exportTable[importee] = { | ||
default: importInfo.default, | ||
named: importInfo.named.length > 0 || importInfo.all, | ||
expectBy: id, | ||
external | ||
external, | ||
trusted: !guessExportType.has(importee) | ||
}; | ||
if (newGuess.default || newGuess.named) { | ||
exportTable[importee] = newGuess; | ||
} | ||
} | ||
@@ -178,94 +188,50 @@ }); | ||
return { | ||
name: "rollup-plugin-cjs-es", | ||
transform(code, id) { | ||
if (!filter(id)) { | ||
return; | ||
function transform(code, id) { | ||
if (!filter(id)) { | ||
return; | ||
} | ||
const ast = this.parse(code); | ||
const guessExportType = new Set; | ||
const info = esInfoAnalyze(ast); | ||
if (isEsModule(info)) { | ||
return updateExportTable({context: this, info, id, guessExportType}) | ||
.then(() => undefined); | ||
} | ||
return cjsEs({ | ||
code, | ||
ast, | ||
sourceMap, | ||
importStyle: requireId => | ||
this.resolveId(requireId, id) | ||
.then(newId => { | ||
guessExportType.add(newId || requireId); | ||
return getExportType(newId || requireId, id); | ||
}), | ||
exportStyle: () => { | ||
guessExportType.add(id); | ||
return getExportType(id); | ||
}, | ||
nested, | ||
warn: (message, pos) => { | ||
this.warn(message, pos); | ||
} | ||
parse = this.parse; | ||
let ast = parse(code); | ||
const info = esInfoAnalyze(ast); | ||
if (isEsModule(info)) { | ||
return updateExportTable({context: this, info, id}) | ||
.then(() => undefined); | ||
} | ||
const maps = []; | ||
let isTouched; | ||
if (options.splitCode) { | ||
const result = wrapImport({ | ||
code, | ||
parse, | ||
ast, | ||
shouldSplitCode: importee => { | ||
if (typeof options.splitCode === "function") { | ||
return options.splitCode(id, importee); | ||
} | ||
return false; | ||
} | ||
}); | ||
if (result.isTouched) { | ||
code = result.code; | ||
maps.push(result.map); | ||
isImportWrapped = true; | ||
isTouched = true; | ||
ast = null; | ||
}) | ||
.then(({code, map, isTouched}) => { | ||
if (isTouched) { | ||
return updateExportTable({context: this, code, id, guessExportType}) | ||
.then(() => ({ | ||
code, | ||
map | ||
})); | ||
} | ||
} | ||
return cjsEs({ | ||
code, | ||
parse, | ||
ast, | ||
sourceMap: options.sourceMap, | ||
importStyle: requireId => | ||
this.resolveId(requireId, id) | ||
.then(newId => getExportType(newId || requireId)), | ||
exportStyle: () => getExportTypeFromOptions(id), | ||
nested: options.nested, | ||
warn: (message, pos) => { | ||
this.warn(message, pos); | ||
} | ||
}) | ||
.then(result => { | ||
if (result.isTouched) { | ||
code = result.code; | ||
maps.push(result.map); | ||
isTouched = true; | ||
ast = null; | ||
} | ||
if (isTouched) { | ||
return updateExportTable({context: this, code, id}) | ||
.then(() => ({ | ||
code, | ||
map: options.sourceMap && maps.length && joinMaps(maps) | ||
})); | ||
} | ||
}); | ||
}, | ||
transformChunk(code, {format}) { | ||
if (!isImportWrapped) { | ||
return; | ||
} | ||
if (format !== "cjs") { | ||
throw new Error("`format` must be 'cjs'"); | ||
} | ||
const result = unwrapImport({ | ||
code, | ||
parse, | ||
sourceMap: options.sourceMap | ||
}); | ||
if (result.isTouched) { | ||
return { | ||
code: result.code, | ||
map: result.map | ||
}; | ||
} | ||
}, | ||
buildEnd() { | ||
if (options.cache) { | ||
writeCjsEsCache(); | ||
} | ||
} | ||
function buildEnd() { | ||
if (cache) { | ||
writeCjsEsCache(); | ||
} | ||
}; | ||
} | ||
} | ||
module.exports = factory; |
{ | ||
"name": "rollup-plugin-cjs-es", | ||
"version": "0.4.0", | ||
"version": "0.5.0", | ||
"description": "Convert CommonJS module into ES module", | ||
@@ -27,13 +27,15 @@ "keywords": [ | ||
"coveralls": "^3.0.1", | ||
"eslint": "^4.19.1", | ||
"endent": "^1.1.1", | ||
"eslint": "^5.0.1", | ||
"mocha": "^5.2.0", | ||
"nyc": "^12.0.2", | ||
"rollup": "^0.60.7" | ||
"rollup": "^0.62.0", | ||
"sinon": "^6.0.1", | ||
"tempdir-yaml": "^0.2.1" | ||
}, | ||
"dependencies": { | ||
"cjs-es": "^0.4.7", | ||
"cjs-es": "^0.4.9", | ||
"es-info": "^0.1.1", | ||
"estree-walker": "^0.5.2", | ||
"magic-string": "^0.25.0", | ||
"merge-source-map": "^1.1.0", | ||
"rollup-pluginutils": "^2.3.0" | ||
@@ -40,0 +42,0 @@ }, |
@@ -6,2 +6,3 @@ rollup-plugin-cjs-es | ||
[![Coverage Status](https://coveralls.io/repos/github/eight04/rollup-plugin-cjs-es/badge.svg?branch=master)](https://coveralls.io/github/eight04/rollup-plugin-cjs-es?branch=master) | ||
[![install size](https://packagephobia.now.sh/badge?p=rollup-plugin-cjs-es)](https://packagephobia.now.sh/result?p=rollup-plugin-cjs-es) | ||
@@ -20,5 +21,6 @@ Convert CommonJS module into ES module. Powered by [cjs-es](https://github.com/eight04/cjs-es). | ||
* Transform some cases and emit warnings for unconverted `require`s. | ||
* Transform typical cases. | ||
* Emit warnings for unconverted `require`s. | ||
* Use a cache file to solve export type conflicts instead of using proxy modules. | ||
* Split code with sync `require()` or async `Promise.resolve(require())`. | ||
* Split code with `Promise.resolve(require())`. | ||
@@ -29,3 +31,3 @@ Usage | ||
```js | ||
import cjsEs from "rollup-plugin-cjs-es" | ||
import cjs from "rollup-plugin-cjs-es"; | ||
@@ -39,3 +41,3 @@ export default { | ||
plugins: [ | ||
cjsEs({ | ||
cjs({ | ||
nested: true | ||
@@ -50,3 +52,3 @@ }) | ||
`cjs-es` can transform top-level `require`, `exports`, and `module.exports` statements. For those non-top-level statements, the transformer hoist them to top-level: | ||
`cjs-es` can transform top-level `require`, `exports`, and `module.exports` statements into `import` and `export`. For those non-top-level statements, the transformer hoist them to top-level: | ||
@@ -84,3 +86,3 @@ ```js | ||
These patterns are common in module loaders like UMD. I suggest using other plugin to unwrap the module back to normal CJS pattern. | ||
These patterns are common in module loaders like UMD. I suggest using other plugins to unwrap the module back to the normal CJS pattern. | ||
@@ -90,3 +92,3 @@ Lazy load and code splitting | ||
To lazy load an ES module, we can use `import()` function: | ||
To lazy load an ES module, we can use the `import()` function: | ||
@@ -129,3 +131,3 @@ *foo.js* | ||
With this plugin, you can use the same feature in CommonJS syntax, by writing the require statement inside a promise i.e. `Promise.resolve(require("..."))`: | ||
With this plugin, you can use the same feature with CommonJS syntax, by writing the require statement inside a promise: | ||
@@ -140,14 +142,4 @@ ```js | ||
Or, by adding a special comment `// split` if you can't use async function (must set `options.splitCode` to `true`): | ||
The plugin would transform it into the dynamic `import()`. | ||
```js | ||
module.exports = { | ||
foo: () => { | ||
return require("./bar"); // split | ||
} | ||
}; | ||
``` | ||
Note that in the later form, the result is a sync `require` function call, which means **the output format must be `cjs`**. | ||
Named import/export v.s. default import/export | ||
@@ -197,5 +189,6 @@ ---------------------------------------------- | ||
exportType: { | ||
"path/to/foo.js": "default" | ||
// the path would be resolved with the current directory. | ||
"foo.js": "default" | ||
} | ||
}) | ||
}) | ||
] | ||
@@ -330,38 +323,32 @@ } | ||
API reference | ||
------------- | ||
API | ||
---- | ||
This module exports a single function. | ||
### cjsEsFactory(options?: object): RollupPlugin object | ||
### cjsEsFactory | ||
```js | ||
cjsEsFactory(options?:Object) => rollupPlugin | ||
``` | ||
`options` may have following optional properties: | ||
`options` has following optional properties: | ||
* `include`: `Array<string>`. A list of minimatch pattern. Only matched files would be transformed. Match all files by default. | ||
* `exclude`: `Array<string>`. A list of minimatch pattern. Override `options.include`. Default: `[]`. | ||
* `cache`: `Boolean`. If true then read/write the cache file. Default: `true`. | ||
* `cache`: `String`. Path to the cache file. `false` to disable the cache. Default: `".cjsescache"`. | ||
* `sourceMap`: `boolean`. If true then generate the source map. Default: `true`. | ||
* `splitCode`: `boolean|function`. If true then enable code-splitting for require statements which are marked as `// split`. See [Lazy load and code splitting](#lazy-load-and-code-splitting) for details. | ||
* `nested`: `boolean`. If true then analyze the AST recursively, otherwise only top-level nodes are analyzed. Default: `false`. | ||
* `exportType`: `null|string|object|function`. Tell the plugin how to determine the export type. Valid export types are `"named"`, `"default"`. | ||
If `splitCode` is a function, it would receives 2 arguments: | ||
If `exportType` is a function, it has following signature: | ||
- `importer`: `string`. The module ID which is being transformed. It is usually an absolute path. | ||
- `importee`: `string`. The require ID inside `require()` function. | ||
```js | ||
(moduleId) => exportType:String|null|Promise<String|null> | ||
``` | ||
The return value should be a `boolean`. | ||
The return value should be the export type of `moduleId`. | ||
Default: `false` | ||
* `nested?`: `boolean`. If true then analyze the AST recursively, otherwise only top-level nodes are analyzed. Default: `false`. | ||
* `exportType`: `string|object|function`. Tell the plugin how to determine the export type. | ||
If `exportType` is a function, it receives 1 argument: | ||
- `modulId`: `string`. The ID of the module. | ||
The return value should be the type of export for `moduleId`. | ||
If `exportType` is an object, it is a `"path/to/file.js": type` map. | ||
Default: `"named"`. | ||
Default: `null`. | ||
@@ -371,2 +358,9 @@ Changelog | ||
* 0.5.0 (Jun 29, 2018) | ||
- Add: `options.cache` is a file path now. | ||
- Change: the format of the cache file is changed. The cache file only records modules that export default. | ||
- Fix: correctly record external modules in the cache. | ||
- **Drop: code splitting with `require()` had been split out as [a new plugin](https://github.com/eight04/rollup-plugin-require-split-code).** | ||
* 0.4.0 (Jun 16, 2018) | ||
@@ -373,0 +367,0 @@ |
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
6
18642
8
4
213
387
1
- Removedmerge-source-map@^1.1.0
- Removedmerge-source-map@1.1.0(transitive)
- Removedsource-map@0.6.1(transitive)
Updatedcjs-es@^0.4.9