Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 4df1fc6

Browse files
committedFeb 27, 2025·
fix(cli): add 'skip' option and update defaults for hosting config
close #234
1 parent 14e3408 commit 4df1fc6

File tree

4 files changed

+44
-70
lines changed

4 files changed

+44
-70
lines changed
 

‎package.json

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,7 @@
1717
"demo:build": "pnpm run build && pnpm run --filter=demo.tutorialkit.dev build",
1818
"lint": "eslint \"{packages,docs,extensions,integration}/**/*\"",
1919
"test": "pnpm run --stream --filter='@tutorialkit/*' test --run",
20-
"test:e2e": "pnpm run --filter='./e2e' test",
21-
"postbuild": "cp _headers ./dist/"
20+
"test:e2e": "pnpm run --filter='./e2e' test"
2221
},
2322
"license": "MIT",
2423
"packageManager": "pnpm@8.15.6",
Lines changed: 31 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -1,79 +1,50 @@
11
import fs from 'node:fs';
22
import path from 'node:path';
3-
import { fileURLToPath } from 'node:url';
3+
import * as prompts from '@clack/prompts';
4+
import chalk from 'chalk';
5+
import { warnLabel } from 'src/utils/messages.js';
6+
import { runTask } from 'src/utils/tasks.js';
47
import cloudflareConfigRaw from './hosting-config/_headers.txt?raw';
58
import netlifyConfigRaw from './hosting-config/netlify_toml.txt?raw';
69
import vercelConfigRaw from './hosting-config/vercel.json?raw';
710

8-
const __filename = fileURLToPath(import.meta.url);
9-
const __dirname = path.dirname(__filename);
11+
export async function generateHostingConfig(dest: string, provider: string, flags: { dryRun: boolean }) {
12+
prompts.log.info(`${chalk.blue('Hosting Configuration')} Setting up configuration for ${provider}`);
1013

11-
export async function generateHostingConfig(dest: string, provider: string) {
1214
const resolvedDest = path.resolve(dest);
1315

1416
if (!fs.existsSync(resolvedDest)) {
15-
console.log(`Directory does not exist. Creating directory: ${resolvedDest}`);
1617
fs.mkdirSync(resolvedDest, { recursive: true });
17-
} else {
18-
console.log(`Directory already exists: ${resolvedDest}`);
1918
}
2019

21-
if (provider.includes('Vercel')) {
22-
const vercelConfigPath = path.join(resolvedDest, 'vercel.json');
23-
console.log('Writing Vercel config file to:', vercelConfigPath);
24-
25-
try {
26-
const vercelConfig = typeof vercelConfigRaw === 'string' ? JSON.parse(vercelConfigRaw) : vercelConfigRaw;
27-
fs.writeFileSync(vercelConfigPath, JSON.stringify(vercelConfig, null, 2));
28-
} catch (error) {
29-
console.error('Failed to write Vercel config file:', error);
30-
}
31-
}
20+
let config;
21+
let filename;
3222

33-
if (provider.includes('Netlify')) {
34-
const netlifyConfigPath = path.join(resolvedDest, 'netlify.toml');
35-
console.log('Writing Netlify config file to:', netlifyConfigPath);
36-
37-
try {
38-
if (typeof netlifyConfigRaw !== 'string') {
39-
throw new Error('Netlify config must be a string.');
40-
}
41-
42-
fs.writeFileSync(netlifyConfigPath, netlifyConfigRaw);
43-
} catch (error) {
44-
console.error('Failed to write Netlify config file:', error);
45-
}
46-
}
47-
48-
if (provider.includes('Cloudflare')) {
49-
const cloudflareConfigPath = path.join(resolvedDest, '_headers');
50-
console.log('Writing Cloudflare config file to:', cloudflareConfigPath);
51-
52-
try {
53-
if (typeof cloudflareConfigRaw !== 'string') {
54-
throw new Error('Cloudflare config must be a string.');
55-
}
56-
57-
fs.writeFileSync(cloudflareConfigPath, cloudflareConfigRaw);
58-
} catch (error) {
59-
console.error('Failed to write Cloudflare config file:', error);
60-
}
23+
if (provider.includes('Vercel')) {
24+
config = typeof vercelConfigRaw === 'string' ? vercelConfigRaw : JSON.stringify(vercelConfigRaw, null, 2);
25+
filename = 'vercel.json';
26+
} else if (provider.includes('Netlify')) {
27+
config = netlifyConfigRaw;
28+
filename = 'netlify.toml';
29+
} else if (provider.includes('Cloudflare')) {
30+
config = cloudflareConfigRaw;
31+
filename = '_headers';
6132
}
6233

63-
const templateDir = path.resolve(__dirname, '_template');
64-
console.log('Looking for template directory at:', templateDir);
65-
66-
if (fs.existsSync(templateDir)) {
67-
const gitignoreTemplatePath = path.join(templateDir, '.gitignore');
68-
69-
if (fs.existsSync(gitignoreTemplatePath)) {
70-
const gitignoreDestPath = path.join(resolvedDest, '.gitignore');
71-
console.log('Copying .gitignore to:', gitignoreDestPath);
72-
fs.copyFileSync(gitignoreTemplatePath, gitignoreDestPath);
73-
} else {
74-
console.warn('No .gitignore file found in template directory, skipping copy.');
75-
}
34+
if (config && filename) {
35+
await runTask({
36+
title: `Create hosting files for ${provider}`,
37+
dryRun: flags.dryRun,
38+
dryRunMessage: `${warnLabel('DRY RUN')} Skipped hosting provider config creation`,
39+
task: async () => {
40+
const filepath = path.join(resolvedDest, filename);
41+
fs.writeFileSync(filepath, config);
42+
return `Added ${filepath}`;
43+
},
44+
});
7645
} else {
77-
console.warn('Template directory does not exist, skipping .gitignore copy.');
46+
prompts.log.message(
47+
`${chalk.blue('hosting provider config [skip]')} You can configure hosting provider settings manually later. For more information see https://tutorialkit.dev/guides/deployment/#headers-configuration`
48+
);
7849
}
7950
}

‎packages/cli/src/commands/create/index.ts

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -150,16 +150,14 @@ async function _createTutorial(flags: CreateOptions): Promise<undefined> {
150150
{ value: 'Vercel', label: 'Vercel' },
151151
{ value: 'Netlify', label: 'Netlify' },
152152
{ value: 'Cloudflare', label: 'Cloudflare' },
153+
{ value: 'skip', label: 'Skip hosting configuration' },
153154
],
154155
initialValue: 'Vercel',
155156
});
156157

157-
assertNotCanceled(provider);
158-
prompts.log.info(`Configuring for: ${provider}`);
158+
await generateHostingConfig(resolvedDest, String(provider), { dryRun: flags.dryRun });
159159

160-
await generateHostingConfig(resolvedDest, provider);
161-
162-
updatePackageJson(resolvedDest, tutorialName, flags);
160+
updatePackageJson(resolvedDest, tutorialName, flags, String(provider));
163161

164162
const selectedPackageManager = await selectPackageManager(resolvedDest, flags);
165163

@@ -264,7 +262,7 @@ function printNextSteps(dest: string, packageManager: PackageManager, dependenci
264262
}
265263
}
266264

267-
function updatePackageJson(dest: string, projectName: string, flags: CreateOptions) {
265+
function updatePackageJson(dest: string, projectName: string, flags: CreateOptions, provider: string) {
268266
if (flags.dryRun) {
269267
return;
270268
}
@@ -277,7 +275,12 @@ function updatePackageJson(dest: string, projectName: string, flags: CreateOptio
277275
updateWorkspaceVersions(pkgJson.dependencies, TUTORIALKIT_VERSION);
278276
updateWorkspaceVersions(pkgJson.devDependencies, TUTORIALKIT_VERSION);
279277

280-
fs.writeFileSync(pkgPath, JSON.stringify(pkgJson, undefined, 2));
278+
if (provider === 'Netlify' || provider === 'Cloudflare') {
279+
pkgJson.scripts = pkgJson.scripts || {};
280+
pkgJson.scripts.postbuild = "cp _headers ./dist/";
281+
}
282+
283+
fs.writeFileSync(pkgPath, JSON.stringify(pkgJson, null, 2));
281284

282285
try {
283286
const pkgLockPath = path.resolve(dest, 'package-lock.json');
@@ -290,7 +293,7 @@ function updatePackageJson(dest: string, projectName: string, flags: CreateOptio
290293
defaultPackage.name = projectName;
291294
}
292295

293-
fs.writeFileSync(pkgLockPath, JSON.stringify(pkgLockJson, undefined, 2));
296+
fs.writeFileSync(pkgLockPath, JSON.stringify(pkgLockJson, null, 2));
294297
} catch {
295298
// ignore any errors
296299
}

‎packages/cli/src/commands/create/options.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ export const DEFAULT_VALUES = {
2525
dryRun: false,
2626
force: false,
2727
packageManager: 'npm',
28+
provider: 'skip',
2829
};
2930

3031
type Flags = Omit<CreateOptions, '_'>;

0 commit comments

Comments
 (0)
Please sign in to comment.