diff --git a/create/main.js b/create/main.js index 553149d..1df8092 100644 --- a/create/main.js +++ b/create/main.js @@ -22,6 +22,10 @@ export async function main({ cwd, templateDir, exampleTemplatesDir, targetDir, e errorOnExist: true, }); + // npm strips `.gitignore` from published packages, so the template ships it as + // `gitignore`. Restore the dotfile name in the generated project. + await restoreGitignore(targetDir); + const EXAMPLE_ENV_PATH = path.join(targetDir, '.env.example'); const ENV_PATH = path.join(targetDir, '.env'); const PKG_PATH = path.join(targetDir, 'package.json'); @@ -100,6 +104,8 @@ export async function main({ cwd, templateDir, exampleTemplatesDir, targetDir, e errorOnExist: true, }); + await restoreGitignore(exampleTargetDir); + // Apply the same token replacements as for the main project, remapped to exampleTargetDir. const remap = (f) => path.join(exampleTargetDir, path.relative(targetDir, f)); await replaceTokensInFiles(filesWithAppTitle.map(remap), appTitleRegex, APP_TITLE); @@ -148,6 +154,18 @@ What's next? ); } +async function restoreGitignore(dir) { + const shipped = path.join(dir, 'gitignore'); + const dotfile = path.join(dir, '.gitignore'); + try { + await fs.rename(shipped, dotfile); + } catch (error) { + if (error.code !== 'ENOENT') { + throw error; + } + } +} + async function mergeExampleFiles(sourceDir, targetDir) { const entries = await fs.readdir(sourceDir, { recursive: true, withFileTypes: true }); for (const entry of entries) { diff --git a/package.json b/package.json index bfbae1c..58ced1a 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,17 @@ "files": [ "template", "example-templates", - "create" + "create", + "!**/node_modules/**", + "!**/dist/**", + "!**/build/**", + "!**/.turbo/**", + "!**/.react-router/**", + "!**/coverage/**", + "!**/data-mocks/**", + "!**/.cache/**", + "!**/*.tsbuildinfo", + "!**/package-lock.json" ], "engines": { "node": ">=22.3.0" @@ -33,7 +43,8 @@ "create-tinker-stack" ], "scripts": { - "prerelease": "find template example-templates -name package-lock.json -delete && find template example-templates -name tsconfig.tsbuildinfo -delete && find template example-templates -name .turbo -type d -prune -exec rm -rf {} +", + "clean:template": "find template example-templates -type d \\( -name node_modules -o -name dist -o -name build -o -name .turbo -o -name .react-router -o -name coverage -o -name data-mocks -o -name .cache \\) -prune -exec rm -rf {} + && find template example-templates -type f \\( -name package-lock.json -o -name '*.tsbuildinfo' \\) -delete", + "prerelease": "npm run clean:template", "release": "commit-and-tag-version", "test": "npm run test:e2e", "test:e2e": "vitest run --no-file-parallelism", diff --git a/template/.gitignore b/template/gitignore similarity index 86% rename from template/.gitignore rename to template/gitignore index a6fecbd..cf137cd 100644 --- a/template/.gitignore +++ b/template/gitignore @@ -39,6 +39,9 @@ data-mocks/ vite.config.ts.timestamp-* .playwright-mcp/ +# Example templates (self-contained, generated into examples//) +examples/ + # Misc .DS_Store *.pem diff --git a/tests/generator.test.mjs b/tests/generator.test.mjs index 4f3095b..87c2472 100644 --- a/tests/generator.test.mjs +++ b/tests/generator.test.mjs @@ -52,6 +52,17 @@ describe('create-tinker-stack generator', () => { ); expect(examplePackageJson.scripts).toHaveProperty('build'); + // npm strips `.gitignore` from published packages, so the template ships + // it as `gitignore` and the generator restores the dotfile name. + const gitignore = await readFile(path.join(projectDir, '.gitignore'), 'utf8'); + expect(gitignore).toContain('node_modules'); + expect(gitignore).toContain('examples/'); + await expect(readFile(path.join(projectDir, 'gitignore'), 'utf8')) + .rejects.toMatchObject({ code: 'ENOENT' }); + await expect(readFile(path.join(exampleDir, '.gitignore'), 'utf8')).resolves.toContain( + 'node_modules' + ); + await runCommand('npm', ['install'], { cwd: projectDir }); await runCommand('npm', ['run', 'typecheck'], { cwd: projectDir }); await runCommand('npm', ['run', 'build:data'], { cwd: projectDir });