-
Notifications
You must be signed in to change notification settings - Fork 3
/
externals.ts
110 lines (90 loc) · 3.03 KB
/
externals.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
import path from 'path';
import type { FunctionPluginHooks, Plugin } from 'rollup';
import rollupExternals, {
type ExternalsOptions,
} from 'rollup-plugin-node-externals';
import type { PackageJson } from 'type-fest';
import type { Format } from '../../types';
import { promiseMap } from '../../utils/promise-map';
import { resolveFrom } from '../../utils/resolve-from';
class PackagesById extends Map<string, PackageJson> {}
async function findDependencies(config: ExternalsOptions) {
const packagePath = config.packagePath! as string;
const loadPackage = (id: string): PackageJson => require(id);
const packageJson = loadPackage(packagePath);
const externalDeps = [
...Object.keys((config.deps && packageJson.dependencies) || {}),
...Object.keys((config.devDeps && packageJson.devDependencies) || {}),
...Object.keys((config.peerDeps && packageJson.peerDependencies) || {}),
...Object.keys((config.optDeps && packageJson.optionalDependencies) || {}),
];
const packagesById = new PackagesById();
await promiseMap(externalDeps, async (dep) => {
const depPackagePath = await resolveFrom(
packagePath,
`${dep}/package.json`,
);
const depPackage = loadPackage(depPackagePath);
packagesById.set(dep, depPackage);
});
return packagesById;
}
export function externals(packageRoot: string, format: Format = 'esm'): Plugin {
const packagePath = path.join(packageRoot, 'package.json');
const config = {
packagePath,
deps: true,
devDeps: false,
peerDeps: true,
optDeps: true,
};
const plugin = rollupExternals(config);
let packagesById: PackagesById;
const patch = (id: string) => {
const resolvedId = require.resolve(id);
return resolvedId.slice(resolvedId.lastIndexOf(id));
};
return {
...plugin,
name: `crackle:patched-${plugin.name}`,
async buildStart(options) {
await Promise.all([
(plugin as FunctionPluginHooks).buildStart.call(this, options),
findDependencies(config).then((result) => (packagesById = result)),
]);
},
async resolveId(source, importer, options) {
const resolved = (plugin as FunctionPluginHooks).resolveId.call(
this,
source,
importer,
options,
);
if (
(typeof resolved === 'boolean' && !resolved) ||
(typeof resolved === 'object' && resolved?.external)
) {
let id = source;
let isSubpath = false;
if (!source.startsWith('@') && source.includes('/')) {
id = source.split('/')[0];
isSubpath = true;
}
if (source.startsWith('@') && Number(source.match(/\//g)?.length) > 1) {
id = source.split('/').slice(0, 2).join('/');
isSubpath = true;
}
const packageJson = packagesById.get(id);
const patched = {
id:
format === 'esm' && isSubpath && !packageJson?.exports
? patch(source)
: source,
external: true,
};
return patched;
}
return resolved;
},
};
}