Skip to content

Commit

Permalink
[feat] install adapters on demand (sveltejs#7462)
Browse files Browse the repository at this point in the history
* [feat] install adapters on demand

Closes sveltejs#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]>
  • Loading branch information
dummdidumm and Rich-Harris authored Nov 15, 2022
1 parent f2018d8 commit fa1265a
Show file tree
Hide file tree
Showing 4 changed files with 98 additions and 30 deletions.
5 changes: 5 additions & 0 deletions .changeset/orange-geckos-bake.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@sveltejs/adapter-auto': patch
---

[feat] install adapters on demand
103 changes: 84 additions & 19 deletions packages/adapter-auto/index.js
Original file line number Diff line number Diff line change
@@ -1,40 +1,105 @@
import { execSync } from 'child_process';
import { pathToFileURL } from 'url';
import { resolve } from 'import-meta-resolve';
import { adapters } from './adapters.js';
import { dirname, join } from 'path';
import { existsSync } from 'fs';

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

/** @type {Record<string, (name: string) => string>} */
const commands = {
npm: (name) => `npm install -D ${name}`,
pnpm: (name) => `pnpm add -D ${name}`,
yarn: (name) => `yarn add -D ${name}`
};

function detect_lockfile() {
let dir = process.cwd();

do {
if (existsSync(join(dir, 'pnpm-lock.yaml'))) return 'pnpm';
if (existsSync(join(dir, 'yarn.lock'))) return 'yarn';
if (existsSync(join(dir, 'package-lock.json'))) return 'npm';
} while (dir !== (dir = dirname(dir)));

return 'npm';
}

function detect_package_manager() {
const manager = detect_lockfile();

try {
execSync(`${manager} --version`);
return manager;
} catch {
return 'npm';
}
}

/** @param {string} name */
async function import_from_cwd(name) {
const cwd = pathToFileURL(process.cwd()).href;
const url = await resolve(name, cwd + '/x.js');

return import(url);
}

for (const candidate of adapters) {
if (candidate.test()) {
/** @type {{ default: () => import('@sveltejs/kit').Adapter }} */
let module;

try {
module = await import(candidate.module);

fn = () => {
const adapter = module.default();
return {
...adapter,
adapt: (builder) => {
builder.log.info(`Detected environment: ${candidate.name}. Using ${candidate.module}`);
return adapter.adapt(builder);
}
};
};

break;
module = await import_from_cwd(candidate.module);
} catch (error) {
if (
error.code === 'ERR_MODULE_NOT_FOUND' &&
error.message.startsWith(`Cannot find package '${candidate.module}'`)
) {
throw new Error(
`It looks like ${candidate.module} is not installed. Please install it and try building your project again.`
);
}
const package_manager = detect_package_manager();
const command = commands[package_manager](candidate.module);

try {
console.log(`Installing ${candidate.module}...`);

execSync(command, {
stdio: 'inherit',
env: {
...process.env,
NODE_ENV: undefined
}
});

throw error;
module = await import_from_cwd(candidate.module);

console.log(`Successfully installed ${candidate.module}.`);
console.warn(
`\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`
);
} catch (e) {
throw new Error(
`Could not install ${candidate.module}. Please install it yourself by adding it to your package.json's devDependencies and try building your project again.`
);
}
} else {
throw error;
}
}

fn = () => {
const adapter = module.default();
return {
...adapter,
adapt: (builder) => {
builder.log.info(`Detected environment: ${candidate.name}. Using ${candidate.module}`);
return adapter.adapt(builder);
}
};
};

break;
}
}

Expand Down
8 changes: 3 additions & 5 deletions packages/adapter-auto/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,11 @@
"format": "pnpm lint --write",
"check": "tsc"
},
"dependencies": {
"@sveltejs/adapter-cloudflare": "workspace:*",
"@sveltejs/adapter-netlify": "workspace:*",
"@sveltejs/adapter-vercel": "workspace:*"
},
"devDependencies": {
"@types/node": "^16.11.68",
"typescript": "^4.8.4"
},
"dependencies": {
"import-meta-resolve": "^2.1.0"
}
}
12 changes: 6 additions & 6 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit fa1265a

Please sign in to comment.