2021-03-01 15:06:11 +08:00

100 lines
3.0 KiB
JavaScript

const path = require('path');
const { walk } = require('estree-walker');
const MagicString = require('magic-string');
const globby = require('globby');
const { createFilter } = require('@rollup/pluginutils');
const {
dynamicImportToGlob,
VariableDynamicImportError,
} = require('./src/dynamic-import-to-glob');
function dynamicImportVariables({ include, exclude, warnOnError } = {}) {
const filter = createFilter(include, exclude);
return {
name: 'rollup-plugin-dynamic-import-variables',
transform(code, id) {
if (!filter(id)) {
return null;
}
const parsed = this.parse(code);
let dynamicImportIndex = -1;
let ms;
walk(parsed, {
enter: (node) => {
if (node.type !== 'ImportExpression') {
return;
}
dynamicImportIndex += 1;
try {
// see if this is a variable dynamic import, and generate a glob expression
const glob = dynamicImportToGlob(
node.source,
code.substring(node.start, node.end)
);
if (!glob) {
// this was not a variable dynamic import
return;
}
// execute the glob
const result = globby.sync(glob, { cwd: path.dirname(id) });
const paths = result.map((r) =>
r.startsWith('./') || r.startsWith('../') ? r : `./${r}`
);
// create magic string if it wasn't created already
ms = ms || new MagicString(code);
// unpack variable dynamic import into a function with import statements per file, rollup
// will turn these into chunks automatically
ms.prepend(
`function __variableDynamicImportRuntime${dynamicImportIndex}__(path) {
switch (path) {
${paths.map((p) => ` case '${p}': return import('${p}');`).join('\n ')}
default: return Promise.reject(new Error("Unknown variable dynamic import: " + path));
}
}\n\n`
);
// call the runtime function instead of doing a dynamic import, the import specifier will
// be evaluated at runtime and the correct import will be returned by the injected function
ms.overwrite(
node.start,
node.start + 6,
`__variableDynamicImportRuntime${dynamicImportIndex}__`
);
} catch (error) {
if (error instanceof VariableDynamicImportError) {
// TODO: line number
if (warnOnError) {
this.warn(error);
} else {
this.error(error);
}
} else {
this.error(error);
}
}
},
});
if (ms && dynamicImportIndex !== -1) {
return {
code: ms.toString(),
map: ms.generateMap({
file: id,
includeContent: true,
hires: true,
}),
};
}
},
};
}
module.exports = dynamicImportVariables;