Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add hosting config files #440

Merged
merged 20 commits into from
Mar 31, 2025
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
ac47667
feat(scaffolding): add hosting config files for common providers
RonithManikonda Nov 7, 2024
5de42a3
Attempted to fix error with locating config files
RonithManikonda Nov 21, 2024
2c062e9
feat(cli): move hosting configuration generation to dedicated file
RonithManikonda Dec 19, 2024
986ec67
feat(wizard): restrict hosting provider selection to a single option
RonithManikonda Jan 9, 2025
686174d
feat(cli): adjusted the order in which files are generated to avoid e…
RonithManikonda Jan 29, 2025
b4247e1
deleted tutorials that were made during testing
RonithManikonda Feb 6, 2025
14e3408
Merge branch 'main' into ronith/add-hosting-config-files
AriPerkkio Feb 20, 2025
4df1fc6
fix(cli): add 'skip' option and update defaults for hosting config
RonithManikonda Feb 27, 2025
edd717d
chore(prettier): fix formatting errors
RonithManikonda Mar 5, 2025
af74cd9
feat(cli): add provider flag to hosting config prompt
RonithManikonda Mar 12, 2025
facf7d2
chore(prettier): fix formatting errors
RonithManikonda Mar 13, 2025
7c45e6e
fix(cli): ensure --no-provider skips hosting config prompt
RonithManikonda Mar 19, 2025
bbc7ec9
chore(prettier): fix formatting errors
RonithManikonda Mar 19, 2025
13103d9
chore(prettier): fix formatting errors
RonithManikonda Mar 19, 2025
675c5fb
Apply suggestions from code review
RonithManikonda Mar 26, 2025
a1771db
test(cli): add tests for Netlify, Cloudflare, and Vercel providers
RonithManikonda Mar 26, 2025
8de3e52
Merge branch 'ronith/add-hosting-config-files' of https://github.com/…
RonithManikonda Mar 26, 2025
8abfb97
test(cli): updated test for Cloudflare to reflect functionality
RonithManikonda Mar 26, 2025
9dcefcb
Update packages/cli/src/commands/create/index.ts
AriPerkkio Mar 31, 2025
97a237d
fix: handle `--no-provider` value
AriPerkkio Mar 31, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@
"demo:build": "pnpm run build && pnpm run --filter=demo.tutorialkit.dev build",
"lint": "eslint \"{packages,docs,extensions,integration}/**/*\"",
"test": "pnpm run --stream --filter='@tutorialkit/*' test --run",
"test:e2e": "pnpm run --filter='./e2e' test"
"test:e2e": "pnpm run --filter='./e2e' test",
"postbuild": "cp _headers ./dist/"
},
"license": "MIT",
"packageManager": "[email protected]",
Expand Down
79 changes: 79 additions & 0 deletions packages/cli/src/commands/create/generate-hosting-config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import fs from 'node:fs';
import path from 'node:path';
import { fileURLToPath } from 'node:url';
import cloudflareConfigRaw from './hosting-config/_headers.txt?raw';
import netlifyConfigRaw from './hosting-config/netlify_toml.txt?raw';
import vercelConfigRaw from './hosting-config/vercel.json?raw';

const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);

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

if (!fs.existsSync(resolvedDest)) {
console.log(`Directory does not exist. Creating directory: ${resolvedDest}`);
fs.mkdirSync(resolvedDest, { recursive: true });
} else {
console.log(`Directory already exists: ${resolvedDest}`);
}

if (provider.includes('Vercel')) {
const vercelConfigPath = path.join(resolvedDest, 'vercel.json');
console.log('Writing Vercel config file to:', vercelConfigPath);

try {
const vercelConfig = typeof vercelConfigRaw === 'string' ? JSON.parse(vercelConfigRaw) : vercelConfigRaw;
fs.writeFileSync(vercelConfigPath, JSON.stringify(vercelConfig, null, 2));
} catch (error) {
console.error('Failed to write Vercel config file:', error);
}
}

if (provider.includes('Netlify')) {
const netlifyConfigPath = path.join(resolvedDest, 'netlify.toml');
console.log('Writing Netlify config file to:', netlifyConfigPath);

try {
if (typeof netlifyConfigRaw !== 'string') {
throw new Error('Netlify config must be a string.');
}

fs.writeFileSync(netlifyConfigPath, netlifyConfigRaw);
} catch (error) {
console.error('Failed to write Netlify config file:', error);
}
}

if (provider.includes('Cloudflare')) {
const cloudflareConfigPath = path.join(resolvedDest, '_headers');
console.log('Writing Cloudflare config file to:', cloudflareConfigPath);

try {
if (typeof cloudflareConfigRaw !== 'string') {
throw new Error('Cloudflare config must be a string.');
}

fs.writeFileSync(cloudflareConfigPath, cloudflareConfigRaw);
} catch (error) {
console.error('Failed to write Cloudflare config file:', error);
}
}

const templateDir = path.resolve(__dirname, '_template');
console.log('Looking for template directory at:', templateDir);

if (fs.existsSync(templateDir)) {
const gitignoreTemplatePath = path.join(templateDir, '.gitignore');

if (fs.existsSync(gitignoreTemplatePath)) {
const gitignoreDestPath = path.join(resolvedDest, '.gitignore');
console.log('Copying .gitignore to:', gitignoreDestPath);
fs.copyFileSync(gitignoreTemplatePath, gitignoreDestPath);
} else {
console.warn('No .gitignore file found in template directory, skipping copy.');
}
} else {
console.warn('Template directory does not exist, skipping .gitignore copy.');
}
}
3 changes: 3 additions & 0 deletions packages/cli/src/commands/create/hosting-config/_headers.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
/*
Cross-Origin-Embedder-Policy: require-corp
Cross-Origin-Opener-Policy: same-origin
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
[[headers]]
for = "/*"
[headers.values]
Cross-Origin-Embedder-Policy = "require-corp"
Cross-Origin-Opener-Policy = "same-origin"
17 changes: 17 additions & 0 deletions packages/cli/src/commands/create/hosting-config/vercel.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"headers": [
{
"source": "/(.*)",
"headers": [
{
"key": "Cross-Origin-Embedder-Policy",
"value": "require-crop"
},
{
"key": "Cross-Origin-Embedder-Policy",
"value": "same-origin"
}
]
}
]
}
16 changes: 16 additions & 0 deletions packages/cli/src/commands/create/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { generateProjectName } from '../../utils/project.js';
import { assertNotCanceled } from '../../utils/tasks.js';
import { updateWorkspaceVersions } from '../../utils/workspace-version.js';
import { setupEnterpriseConfig } from './enterprise.js';
import { generateHostingConfig } from './generate-hosting-config.js';
import { initGitRepo } from './git.js';
import { installAndStart } from './install-start.js';
import { DEFAULT_VALUES, type CreateOptions } from './options.js';
Expand Down Expand Up @@ -143,6 +144,21 @@ async function _createTutorial(flags: CreateOptions): Promise<undefined> {

await copyTemplate(resolvedDest, flags);

const provider = await prompts.select({
message: 'Select hosting providers for automatic configuration:',
options: [
{ value: 'Vercel', label: 'Vercel' },
{ value: 'Netlify', label: 'Netlify' },
{ value: 'Cloudflare', label: 'Cloudflare' },
],
initialValue: 'Vercel',
});

assertNotCanceled(provider);
prompts.log.info(`Configuring for: ${provider}`);

await generateHostingConfig(resolvedDest, provider);

updatePackageJson(resolvedDest, tutorialName, flags);

const selectedPackageManager = await selectPackageManager(resolvedDest, flags);
Expand Down
4 changes: 4 additions & 0 deletions packages/cli/src/types.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
declare module '*?raw' {
const content: string;
export default content;
}
Loading