Skip to content

Commit fa1265a

Browse files
[feat] install adapters on demand (#7462)
* [feat] install adapters on demand Closes #5123 * oops * lock file, more logs * use postinstall hook * maybe * ugh * ignore errors that are not about module not found * debug * test node_env findings * remove dev omit and set node_env through JS * no env whatsoever? * this seems to work? * diy * tweak copy to mention deployment configuration Co-authored-by: Rich Harris <[email protected]>
1 parent f2018d8 commit fa1265a

File tree

4 files changed

+98
-30
lines changed

4 files changed

+98
-30
lines changed

.changeset/orange-geckos-bake.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@sveltejs/adapter-auto': patch
3+
---
4+
5+
[feat] install adapters on demand

packages/adapter-auto/index.js

+84-19
Original file line numberDiff line numberDiff line change
@@ -1,40 +1,105 @@
1+
import { execSync } from 'child_process';
2+
import { pathToFileURL } from 'url';
3+
import { resolve } from 'import-meta-resolve';
14
import { adapters } from './adapters.js';
5+
import { dirname, join } from 'path';
6+
import { existsSync } from 'fs';
27

38
/** @type {import('./index').default} */
49
let fn;
510

11+
/** @type {Record<string, (name: string) => string>} */
12+
const commands = {
13+
npm: (name) => `npm install -D ${name}`,
14+
pnpm: (name) => `pnpm add -D ${name}`,
15+
yarn: (name) => `yarn add -D ${name}`
16+
};
17+
18+
function detect_lockfile() {
19+
let dir = process.cwd();
20+
21+
do {
22+
if (existsSync(join(dir, 'pnpm-lock.yaml'))) return 'pnpm';
23+
if (existsSync(join(dir, 'yarn.lock'))) return 'yarn';
24+
if (existsSync(join(dir, 'package-lock.json'))) return 'npm';
25+
} while (dir !== (dir = dirname(dir)));
26+
27+
return 'npm';
28+
}
29+
30+
function detect_package_manager() {
31+
const manager = detect_lockfile();
32+
33+
try {
34+
execSync(`${manager} --version`);
35+
return manager;
36+
} catch {
37+
return 'npm';
38+
}
39+
}
40+
41+
/** @param {string} name */
42+
async function import_from_cwd(name) {
43+
const cwd = pathToFileURL(process.cwd()).href;
44+
const url = await resolve(name, cwd + '/x.js');
45+
46+
return import(url);
47+
}
48+
649
for (const candidate of adapters) {
750
if (candidate.test()) {
851
/** @type {{ default: () => import('@sveltejs/kit').Adapter }} */
952
let module;
1053

1154
try {
12-
module = await import(candidate.module);
13-
14-
fn = () => {
15-
const adapter = module.default();
16-
return {
17-
...adapter,
18-
adapt: (builder) => {
19-
builder.log.info(`Detected environment: ${candidate.name}. Using ${candidate.module}`);
20-
return adapter.adapt(builder);
21-
}
22-
};
23-
};
24-
25-
break;
55+
module = await import_from_cwd(candidate.module);
2656
} catch (error) {
2757
if (
2858
error.code === 'ERR_MODULE_NOT_FOUND' &&
2959
error.message.startsWith(`Cannot find package '${candidate.module}'`)
3060
) {
31-
throw new Error(
32-
`It looks like ${candidate.module} is not installed. Please install it and try building your project again.`
33-
);
34-
}
61+
const package_manager = detect_package_manager();
62+
const command = commands[package_manager](candidate.module);
63+
64+
try {
65+
console.log(`Installing ${candidate.module}...`);
66+
67+
execSync(command, {
68+
stdio: 'inherit',
69+
env: {
70+
...process.env,
71+
NODE_ENV: undefined
72+
}
73+
});
3574

36-
throw error;
75+
module = await import_from_cwd(candidate.module);
76+
77+
console.log(`Successfully installed ${candidate.module}.`);
78+
console.warn(
79+
`\nIf you plan on staying on this deployment platform, consider replacing @sveltejs/adapter-auto with ${candidate.module}. This will give you faster and more robust installs, and more control over deployment configuration.\n`
80+
);
81+
} catch (e) {
82+
throw new Error(
83+
`Could not install ${candidate.module}. Please install it yourself by adding it to your package.json's devDependencies and try building your project again.`
84+
);
85+
}
86+
} else {
87+
throw error;
88+
}
3789
}
90+
91+
fn = () => {
92+
const adapter = module.default();
93+
return {
94+
...adapter,
95+
adapt: (builder) => {
96+
builder.log.info(`Detected environment: ${candidate.name}. Using ${candidate.module}`);
97+
return adapter.adapt(builder);
98+
}
99+
};
100+
};
101+
102+
break;
38103
}
39104
}
40105

packages/adapter-auto/package.json

+3-5
Original file line numberDiff line numberDiff line change
@@ -29,13 +29,11 @@
2929
"format": "pnpm lint --write",
3030
"check": "tsc"
3131
},
32-
"dependencies": {
33-
"@sveltejs/adapter-cloudflare": "workspace:*",
34-
"@sveltejs/adapter-netlify": "workspace:*",
35-
"@sveltejs/adapter-vercel": "workspace:*"
36-
},
3732
"devDependencies": {
3833
"@types/node": "^16.11.68",
3934
"typescript": "^4.8.4"
35+
},
36+
"dependencies": {
37+
"import-meta-resolve": "^2.1.0"
4038
}
4139
}

pnpm-lock.yaml

+6-6
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)