/
loadConfigFile.ts
134 lines (125 loc) · 4.46 KB
/
loadConfigFile.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
import { extname, isAbsolute } from 'node:path';
import { pathToFileURL } from 'node:url';
import getPackageType from 'get-package-type';
import * as rollup from '../../src/node-entry';
import type { MergedRollupOptions } from '../../src/rollup/types';
import { bold } from '../../src/utils/colors';
import { errMissingConfig, error, errTranspiledEsmConfig } from '../../src/utils/error';
import { mergeOptions } from '../../src/utils/options/mergeOptions';
import type { GenericConfigObject } from '../../src/utils/options/options';
import relativeId from '../../src/utils/relativeId';
import { stderr } from '../logging';
import batchWarnings, { type BatchWarnings } from './batchWarnings';
import { addCommandPluginsToInputOptions, addPluginsFromCommandOption } from './commandPlugins';
interface NodeModuleWithCompile extends NodeModule {
_compile(code: string, filename: string): any;
}
export async function loadConfigFile(
fileName: string,
commandOptions: any = {}
): Promise<{ options: MergedRollupOptions[]; warnings: BatchWarnings }> {
const configs = await loadConfigsFromFile(fileName, commandOptions);
const warnings = batchWarnings();
try {
const normalizedConfigs: MergedRollupOptions[] = [];
for (const config of configs) {
const options = mergeOptions(config, commandOptions, warnings.add);
await addCommandPluginsToInputOptions(options, commandOptions);
normalizedConfigs.push(options);
}
return { options: normalizedConfigs, warnings };
} catch (err) {
warnings.flush();
throw err;
}
}
async function loadConfigsFromFile(
fileName: string,
commandOptions: Record<string, unknown>
): Promise<GenericConfigObject[]> {
const extension = extname(fileName);
const configFileExport =
commandOptions.configPlugin ||
// We always transpile the .js non-module case because many legacy code bases rely on this
(extension === '.js' && getPackageType.sync(fileName) !== 'module')
? await getDefaultFromTranspiledConfigFile(fileName, commandOptions)
: getDefaultFromCjs((await import(pathToFileURL(fileName).href)).default);
return getConfigList(configFileExport, commandOptions);
}
function getDefaultFromCjs(namespace: GenericConfigObject): unknown {
return namespace.__esModule ? namespace.default : namespace;
}
async function getDefaultFromTranspiledConfigFile(
fileName: string,
commandOptions: Record<string, unknown>
): Promise<unknown> {
const warnings = batchWarnings();
const inputOptions = {
external: (id: string) =>
(id[0] !== '.' && !isAbsolute(id)) || id.slice(-5, id.length) === '.json',
input: fileName,
onwarn: warnings.add,
plugins: [],
treeshake: false
};
await addPluginsFromCommandOption(commandOptions.configPlugin, inputOptions);
const bundle = await rollup.rollup(inputOptions);
if (!commandOptions.silent && warnings.count > 0) {
stderr(bold(`loaded ${relativeId(fileName)} with warnings`));
warnings.flush();
}
const {
output: [{ code }]
} = await bundle.generate({
exports: 'named',
format: 'cjs',
plugins: [
{
name: 'transpile-import-meta',
resolveImportMeta(property, { moduleId }) {
if (property === 'url') {
return `'${pathToFileURL(moduleId).href}'`;
}
if (property == null) {
return `{url:'${pathToFileURL(moduleId).href}'}`;
}
}
}
]
});
return loadConfigFromBundledFile(fileName, code);
}
function loadConfigFromBundledFile(fileName: string, bundledCode: string): unknown {
const resolvedFileName = require.resolve(fileName);
const extension = extname(resolvedFileName);
const defaultLoader = require.extensions[extension];
require.extensions[extension] = (module: NodeModule, requiredFileName: string) => {
if (requiredFileName === resolvedFileName) {
(module as NodeModuleWithCompile)._compile(bundledCode, requiredFileName);
} else {
if (defaultLoader) {
defaultLoader(module, requiredFileName);
}
}
};
delete require.cache[resolvedFileName];
try {
const config = getDefaultFromCjs(require(fileName));
require.extensions[extension] = defaultLoader;
return config;
} catch (err: any) {
if (err.code === 'ERR_REQUIRE_ESM') {
return error(errTranspiledEsmConfig(fileName));
}
throw err;
}
}
async function getConfigList(configFileExport: any, commandOptions: any): Promise<any[]> {
const config = await (typeof configFileExport === 'function'
? configFileExport(commandOptions)
: configFileExport);
if (Object.keys(config).length === 0) {
return error(errMissingConfig());
}
return Array.isArray(config) ? config : [config];
}