rollup-plugin-commonjs
Version:
Convert CommonJS modules to ES2015
177 lines (150 loc) • 5.19 kB
JavaScript
import { realpathSync, existsSync } from 'fs';
import { extname, resolve, normalize } from 'path';
import { sync as nodeResolveSync, isCore } from 'resolve';
import { createFilter } from 'rollup-pluginutils';
import { peerDependencies } from '../package.json';
import {
EXTERNAL_SUFFIX,
getIdFromExternalProxyId,
getIdFromProxyId,
HELPERS,
HELPERS_ID,
PROXY_SUFFIX
} from './helpers';
import { getIsCjsPromise, setIsCjsPromise } from './is-cjs';
import { getResolveId } from './resolve-id';
import { checkEsModule, hasCjsKeywords, transformCommonjs } from './transform.js';
import { getName } from './utils.js';
export default function commonjs(options = {}) {
const extensions = options.extensions || ['.js'];
const filter = createFilter(options.include, options.exclude);
const ignoreGlobal = options.ignoreGlobal;
const customNamedExports = {};
if (options.namedExports) {
Object.keys(options.namedExports).forEach(id => {
let resolveId = id;
let resolvedId;
if (isCore(id)) {
// resolve will not find npm modules with the same name as
// core modules without a trailing slash. Since core modules
// must be external, we can assume any core modules defined
// here are npm modules by that name.
resolveId += '/';
}
try {
resolvedId = nodeResolveSync(resolveId, { basedir: process.cwd() });
} catch (err) {
resolvedId = resolve(id);
}
// Note: customNamedExport's keys must be normalized file paths.
// resolve and nodeResolveSync both return normalized file paths
// so no additional normalization is necessary.
customNamedExports[resolvedId] = options.namedExports[id];
if (existsSync(resolvedId)) {
const realpath = realpathSync(resolvedId);
if (realpath !== resolvedId) {
customNamedExports[realpath] = options.namedExports[id];
}
}
});
}
const esModulesWithoutDefaultExport = new Set();
const esModulesWithDefaultExport = new Set();
const allowDynamicRequire = !!options.ignore; // TODO maybe this should be configurable?
const ignoreRequire =
typeof options.ignore === 'function'
? options.ignore
: Array.isArray(options.ignore)
? id => options.ignore.includes(id)
: () => false;
const resolveId = getResolveId(extensions);
const sourceMap = options.sourceMap !== false;
function transformAndCheckExports(code, id) {
{
const { isEsModule, hasDefaultExport, ast } = checkEsModule(this.parse, code, id);
if (isEsModule) {
(hasDefaultExport ? esModulesWithDefaultExport : esModulesWithoutDefaultExport).add(id);
return null;
}
// it is not an ES module but it does not have CJS-specific elements.
if (!hasCjsKeywords(code, ignoreGlobal)) {
esModulesWithoutDefaultExport.add(id);
return null;
}
const normalizedId = normalize(id);
const transformed = transformCommonjs(
this.parse,
code,
id,
this.getModuleInfo(id).isEntry,
ignoreGlobal,
ignoreRequire,
customNamedExports[normalizedId],
sourceMap,
allowDynamicRequire,
ast
);
if (!transformed) {
esModulesWithoutDefaultExport.add(id);
return null;
}
return transformed;
}
}
return {
name: 'commonjs',
buildStart() {
const [major, minor] = this.meta.rollupVersion.split('.').map(Number);
const minVersion = peerDependencies.rollup.slice(2);
const [minMajor, minMinor] = minVersion.split('.').map(Number);
if (major < minMajor || (major === minMajor && minor < minMinor)) {
this.error(
`Insufficient Rollup version: "rollup-plugin-commonjs" requires at least rollup@${minVersion} but found rollup@${this.meta.rollupVersion}.`
);
}
},
resolveId,
load(id) {
if (id === HELPERS_ID) return HELPERS;
// generate proxy modules
if (id.endsWith(EXTERNAL_SUFFIX)) {
const actualId = getIdFromExternalProxyId(id);
const name = getName(actualId);
return `import ${name} from ${JSON.stringify(actualId)}; export default ${name};`;
}
if (id.endsWith(PROXY_SUFFIX)) {
const actualId = getIdFromProxyId(id);
const name = getName(actualId);
return getIsCjsPromise(actualId).then(isCjs => {
if (isCjs)
return `import { __moduleExports } from ${JSON.stringify(
actualId
)}; export default __moduleExports;`;
else if (esModulesWithoutDefaultExport.has(actualId))
return `import * as ${name} from ${JSON.stringify(actualId)}; export default ${name};`;
else if (esModulesWithDefaultExport.has(actualId)) {
return `export {default} from ${JSON.stringify(actualId)};`;
} else
return `import * as ${name} from ${JSON.stringify(
actualId
)}; import {getCjsExportFromNamespace} from "${HELPERS_ID}"; export default getCjsExportFromNamespace(${name})`;
});
}
},
transform(code, id) {
if (!filter(id) || extensions.indexOf(extname(id)) === -1) {
setIsCjsPromise(id, null);
return null;
}
let transformed;
try {
transformed = transformAndCheckExports.call(this, code, id);
} catch (err) {
transformed = null;
this.error(err, err.loc);
}
setIsCjsPromise(id, Boolean(transformed));
return transformed;
}
};
}