UNPKG

3.13 kBJavaScriptView Raw
1"use strict";
2
3const Bluebird = require('bluebird');
4const npmWrapper = require('./npmWrapper');
5const ora = require('ora');
6const path = require('path');
7const logger = require('./logger').getLogger("lazy-require");
8const { getCliLocation } = require('../utils');
9const { requireWithFallback } = require("./requireWithFallback")
10
11const packageJson = require(path.resolve(getCliLocation(), 'package.json'));
12const ongoingCalls = new Map();
13
14module.exports = async function memoizedLazyRequireApi(dependency, options = {}) {
15 const packageLocally = npmWrapper.getPackageIfInstalledLocally(dependency);
16 if (packageLocally) {
17 return packageLocally;
18 }
19
20 let spinner;
21 if (!options.silent) {
22 spinner = ora(`Installing ${dependency} before first usage...`).start();
23 }
24
25 try {
26 const requiredModule = await memoizedLazyRequire(dependency);
27 if (spinner) {
28 spinner.succeed();
29 }
30 return requiredModule;
31 } catch (error) {
32 logger.warn("failed to install dependency lazily", {dependency, err: error});
33 const depVersionToInstall = getVersionOfLazyDep(dependency);
34 const depWithVersions = `${dependency}@${depVersionToInstall}`;
35
36 const removeGlobal = process.argv.includes('npx');
37 const globalFlag = removeGlobal ? '' : '-g '
38 const errorMessage = `Installation of ${dependency} failed. This typically means you are running an out-of-date version of Node.js or NPM.` +
39 `Please manually install by running the following command: npm install ${globalFlag}${depWithVersions}`
40
41 if (spinner) {
42 spinner.fail(errorMessage);
43 }
44
45 throw error;
46 }
47};
48
49async function memoizedLazyRequire(identifier, options = {}) {
50 if (ongoingCalls.has(identifier)) {
51 return ongoingCalls.get(identifier);
52 }
53
54 ongoingCalls.set(identifier, lazyRequireImpl(identifier, options));
55 ongoingCalls.get(identifier).catch(err => {
56 ongoingCalls.delete(identifier);
57 });
58
59 return ongoingCalls.get(identifier);
60};
61
62async function lazyRequireImpl(dependency) {
63 const packageLocally = npmWrapper.getPackageIfInstalledLocally(dependency);
64
65 if (packageLocally) {
66 return packageLocally;
67 }
68
69 const depVersionToInstall = getVersionOfLazyDep(dependency);
70
71 const depWithVersions = `${dependency}@${depVersionToInstall}`;
72
73 await npmWrapper.installPackageLocally(getCliLocation(), depWithVersions);
74
75 return requireWithFallback(dependency);
76}
77
78function installAllLazyDependencies() {
79 const allLazyDependencies = Object.keys(packageJson.lazyDependencies);
80
81 return Bluebird.each(allLazyDependencies, dep => lazyRequireImpl(dep));
82}
83
84if (require.main === module) {
85 installAllLazyDependencies();
86}
87
88/**
89 *
90 * @param {string} dependencyToFind
91 */
92function getVersionOfLazyDep(dependencyToFind) {
93 const depEntry = Object.entries(packageJson.lazyDependencies)
94 .find(([dep]) => dep === dependencyToFind);
95
96 if (!depEntry) {
97 throw new Error("The given package name is not lazyDependencies");
98 }
99
100 return depEntry[1];
101}