diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index 80b455a..c473f89 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -37,4 +37,4 @@ body: label: System Info description: Node.js version, npm version, OS validations: - required: true \ No newline at end of file + required: true diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/feature_request.yml index e3b2103..1a30fc7 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.yml +++ b/.github/ISSUE_TEMPLATE/feature_request.yml @@ -32,4 +32,4 @@ body: id: context attributes: label: Additional Context - description: Any other context, screenshots, or examples? \ No newline at end of file + description: Any other context, screenshots, or examples? diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 89da4a7..423724a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -33,6 +33,16 @@ jobs: - name: Install dependencies run: ${{ matrix.package-manager }} install + - name: Build package + run: ${{ matrix.package-manager }} run build + + - name: Smoke test built artifact + run: | + mkdir -p test-logs + node dist/create-next-quick.js --version > test-logs/smoke-test.txt 2>&1 + if [ $? -ne 0 ]; then cat test-logs/smoke-test.txt; exit 1; fi + cat test-logs/smoke-test.txt + - name: Run tests and save logs run: | mkdir -p test-logs diff --git a/.github/workflows/post-test-results.yml b/.github/workflows/post-test-results.yml index 0a2c016..f658587 100644 --- a/.github/workflows/post-test-results.yml +++ b/.github/workflows/post-test-results.yml @@ -40,14 +40,14 @@ jobs: github-token: ${{ secrets.GITHUB_TOKEN }} script: | const fs = require('fs'); - + // Get all jobs from the triggering workflow run const { data: jobs } = await github.rest.actions.listJobsForWorkflowRun({ owner: context.repo.owner, repo: context.repo.repo, run_id: ${{ github.event.workflow_run.id }} }); - + // Extract job results for each node version const results = jobs.jobs .filter(job => job.name.includes('build-and-test')) @@ -75,14 +75,14 @@ jobs: htmlUrl: job.html_url }; }); - + // Save results to file fs.mkdirSync('./job-results', { recursive: true }); fs.writeFileSync( './job-results/results.json', JSON.stringify(results, null, 2) ); - + console.log('Job results:', JSON.stringify(results, null, 2)); return results; @@ -99,22 +99,22 @@ jobs: const fs = require('fs'); const owner = context.repo.owner; const repo = context.repo.repo; - + // 1) Try payload PR (works when GH provides it) let prNumber = context.payload.workflow_run?.pull_requests?.[0]?.number; - + // 2) Resolve from workflow run's head repo + head branch (works for forks) if (!prNumber) { const runId = context.payload.workflow_run.id; const { data: run } = await github.rest.actions.getWorkflowRun({ owner, repo, run_id: runId }); - + const headBranch = run.head_branch; const headRepoFull = run.head_repository?.full_name; if (headRepoFull && headBranch) { const headSpecifier = `${headRepoFull.split('/')[0]}:${headBranch}`; - + // List PRs where this fork branch is the head const { data: prs } = await github.rest.pulls.list({ owner, repo, state: 'open', head: headSpecifier @@ -129,12 +129,12 @@ jobs: core.info('head_repository or head_branch missing on workflow run.'); } } - + if (!prNumber) { core.info('No pull request associated with this run.'); return; } - + // Read job results (if generated by the earlier step) const resultsPath = './job-results/results.json'; let results = []; @@ -143,16 +143,16 @@ jobs: } else { core.info('No job results file found; proceeding with overall status only.'); } - + // Build comment body const overallStatus = context.payload.workflow_run.conclusion; const statusEmoji = overallStatus === 'success' ? 'βœ…' : overallStatus === 'failure' ? '❌' : 'ℹ️'; - + let body = `### ${statusEmoji} CI/CD Test Results\n\n`; body += `**Overall Status**: ${overallStatus}\n\n`; - + if (results.length) { body += `#### Node.js Version Results:\n\n`; for (const r of results) { @@ -160,9 +160,9 @@ jobs: } body += `\n`; } - + body += `---\n[View full workflow run](${context.payload.workflow_run.html_url})`; - + // Upsert comment const { data: comments } = await github.rest.issues.listComments({ owner, repo, issue_number: prNumber @@ -170,7 +170,7 @@ jobs: const botComment = comments.find(c => c.user?.type === 'Bot' && c.body?.includes('CI/CD Test Results') ); - + if (botComment) { await github.rest.issues.updateComment({ owner, repo, comment_id: botComment.id, body diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 10ec670..0b368ee 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -4,9 +4,9 @@ on: workflow_dispatch: inputs: release_type: - description: 'Release type' + description: "Release type" required: true - default: 'patch' + default: "patch" type: choice options: - patch @@ -36,9 +36,9 @@ jobs: - name: Setup Node.js uses: actions/setup-node@v4 with: - node-version: '20' - registry-url: 'https://registry.npmjs.org' - cache: 'pnpm' + node-version: "20" + registry-url: "https://registry.npmjs.org" + cache: "pnpm" - name: Install dependencies run: pnpm install --frozen-lockfile @@ -46,6 +46,9 @@ jobs: - name: Run Tests run: pnpm test + - name: Build package + run: pnpm build + - name: Configure Git run: | git config user.name "github-actions[bot]" diff --git a/.github/workflows/welcome.yml b/.github/workflows/welcome.yml index c3c004b..b46ba7e 100644 --- a/.github/workflows/welcome.yml +++ b/.github/workflows/welcome.yml @@ -27,4 +27,4 @@ jobs: πŸŽ‰ Hi @${{ github.actor }}! Thanks for submitting your first Pull Request! - We’re thrilled to have your contribution and will review it shortly. \ No newline at end of file + We’re thrilled to have your contribution and will review it shortly. diff --git a/.gitignore b/.gitignore index 6090503..5be106e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ *node_modules *generated-test-cases.js +dist/ *test-project *.tgz test-project* diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index b09d88a..17ccc0b 100644 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -4,20 +4,20 @@ As maintainers and contributors of the **Create Next Quick** npm package, we pledge to make participation in our project and community a harassment-free experience for everyone. We are committed to fostering a respectful, inclusive, and healthy environment for all contributors, users, and participants, regardless of: -- Age -- Body size -- Visible or invisible disabilities -- Ethnicity -- Sex characteristics -- Gender identity and expression -- Level of technical experience -- Educational background -- Socio-economic status -- Nationality -- Personal appearance -- Race -- Religion -- Sexual identity and orientation +- Age +- Body size +- Visible or invisible disabilities +- Ethnicity +- Sex characteristics +- Gender identity and expression +- Level of technical experience +- Educational background +- Socio-economic status +- Nationality +- Personal appearance +- Race +- Religion +- Sexual identity and orientation We pledge to prioritize the needs of our package users while maintaining a **welcoming, diverse, inclusive, and professional** development community. @@ -73,20 +73,24 @@ Violations may be reported by contacting the organizing team. All reports will b Community leaders will follow these guidelines when determining consequences: ### 1. **Correction** -- **Impact:** Inappropriate language or unprofessional behavior -- **Consequence:** Private warning, possibly with a public apology request + +- **Impact:** Inappropriate language or unprofessional behavior +- **Consequence:** Private warning, possibly with a public apology request ### 2. **Warning** -- **Impact:** Serious or repeated misconduct -- **Consequence:** Formal warning with outlined future consequences + +- **Impact:** Serious or repeated misconduct +- **Consequence:** Formal warning with outlined future consequences ### 3. **Temporary Ban** -- **Impact:** Sustained inappropriate behavior -- **Consequence:** Temporary exclusion from community spaces + +- **Impact:** Sustained inappropriate behavior +- **Consequence:** Temporary exclusion from community spaces ### 4. **Permanent Ban** -- **Impact:** Severe or repeated violations (e.g., harassment) -- **Consequence:** Permanent ban from all **Create Next Quick** activities and spaces + +- **Impact:** Severe or repeated violations (e.g., harassment) +- **Consequence:** Permanent ban from all **Create Next Quick** activities and spaces ## **Attribution** @@ -96,4 +100,4 @@ This Code of Conduct is adapted from the **Contributor Covenant**, version 2.0: Community Impact Guidelines are inspired by **Mozilla's enforcement ladder**. Need help understanding this document? Visit the [Contributor Covenant FAQ](https://www.contributor-covenant.org/faq). -Translations are available [here](https://www.contributor-covenant.org/translations). \ No newline at end of file +Translations are available at [Contributor Covenant translations](https://www.contributor-covenant.org/translations). diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 977ae72..a4256c2 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -6,32 +6,38 @@ Your contributions help make this project better for everyone. ## How You Can Contribute ### πŸš€ Reporting Bugs + - Use the [Issues](https://github.com/gaureshpai/create-next-quick/issues) tab to report bugs - Include your package version (`npx create-next-quick --version`) - Provide clear steps to reproduce, expected behavior, and screenshots if applicable - Share your environment details (Node.js and npm versions) ### πŸ› οΈ Submitting Enhancements or Features + - Open an issue first to discuss your idea - Please wait for approval before starting major work - Consider compatibility with different Next.js versions ### πŸ§ͺ Writing Tests + - Add tests for new features or bug fixes - Ensure all tests pass before submitting a PR ## Getting Started ### 1. Fork the Repository + Click the "Fork" button at the top right of the [repo](https://github.com/gaureshpai/create-next-quick). ### 2. Clone Your Fork + ```bash git clone https://github.com/your-username/create-next-quick.git cd create-next-quick ``` ### 3. Development Setup + ```bash # Install dependencies npm install @@ -53,21 +59,25 @@ npx create-next-quick my-app ## Submitting a Pull Request 1. Create a feature branch: + ```bash git checkout -b feature/your-feature-name ``` 2. Commit your changes: + ```bash git commit -m "feat: your feature description" ``` 3. Push to your fork and open a PR: + ```bash git push origin feature/your-feature-name ``` ### PR Checklist + - [ ] Tests added/updated - [ ] Documentation updated - [ ] Code follows project style @@ -79,9 +89,11 @@ Please review our [Code of Conduct](https://github.com/gaureshpai/create-next-qu By participating, you agree to abide by its terms. ## Need Help? + If you have questions: + - Open an issue in our [repository](https://github.com/gaureshpai/create-next-quick/issues) - Use the discussions tab for general queries - Review existing issues and documentation -Happy coding! πŸš€ \ No newline at end of file +Happy coding! πŸš€ diff --git a/README.md b/README.md index ca20b35..aa93787 100644 --- a/README.md +++ b/README.md @@ -49,19 +49,19 @@ ### Comparison with create-next-app -| Feature | `create-next-quick` | `create-next-app` | -| ------------------------------ | ---------------------------------------------- | ----------------- | -| **Multi-page Generation** | βœ… Yes (e.g., `home, about, contact`) | ❌ No | -| **ORM Support** | βœ… Yes (Prisma, Drizzle) | ❌ No | -| **Linter Choice** | βœ… Yes (ESLint, Biome) | ❌ ESLint only | -| **Shadcn UI Auto-Setup** | βœ… Yes (non-interactive) | ❌ No | -| **Authentication Integration** | βœ… Yes (NextAuth, Clerk, Lucia) | ❌ No | -| **Testing Framework Setup** | βœ… Yes (Vitest, Jest) | ❌ No | -| **Docker Configuration** | βœ… Yes (Dockerfile + .dockerignore) | ❌ No | -| **Clean Project Start** | βœ… Yes (removes boilerplate & default assets) | ❌ No | -| **Package Manager Detection** | βœ… Yes (npm, yarn, pnpm) | βœ… Yes | -| **Robust Error Handling** | βœ… Yes (retries, cleanup, clear tips) | ❌ Basic | -| **Interactive Mode** | βœ… Yes (add features to existing projects) | ❌ No | +| Feature | `create-next-quick` | `create-next-app` | +| ------------------------------ | --------------------------------------------- | ----------------- | +| **Multi-page Generation** | βœ… Yes (e.g., `home, about, contact`) | ❌ No | +| **ORM Support** | βœ… Yes (Prisma, Drizzle) | ❌ No | +| **Linter Choice** | βœ… Yes (ESLint, Biome) | ❌ ESLint only | +| **Shadcn UI Auto-Setup** | βœ… Yes (non-interactive) | ❌ No | +| **Authentication Integration** | βœ… Yes (NextAuth, Clerk, Lucia) | ❌ No | +| **Testing Framework Setup** | βœ… Yes (Vitest, Jest) | ❌ No | +| **Docker Configuration** | βœ… Yes (Dockerfile + .dockerignore) | ❌ No | +| **Clean Project Start** | βœ… Yes (removes boilerplate & default assets) | ❌ No | +| **Package Manager Detection** | βœ… Yes (npm, yarn, pnpm) | βœ… Yes | +| **Robust Error Handling** | βœ… Yes (retries, cleanup, clear tips) | ❌ Basic | +| **Interactive Mode** | βœ… Yes (add features to existing projects) | ❌ No | --- @@ -132,9 +132,10 @@ npx create-next-quick -i ``` When you run in interactive mode, the tool will: + 1. **Detect Your Project's Setup**: Automatically detects if you're using TypeScript, the `src` directory, the `app` directory, and Tailwind CSS 2. **Skip Project Creation**: It will not run `create-next-app` or remove any existing files -3. **Prompt for Additions**: It will only ask you what you want to *add* to your project, such as new pages, a linter, an ORM, or Shadcn UI +3. **Prompt for Additions**: It will only ask you what you want to _add_ to your project, such as new pages, a linter, an ORM, or Shadcn UI This is perfect for when you want to add a new feature to your project and want to use the same streamlined setup process. @@ -142,20 +143,20 @@ This is perfect for when you want to add a new feature to your project and want The CLI will guide you through the following options: -| Prompt | Description | Default | -| --------------------- | -------------------------------------------------- | ------- | -| **Package Manager** | Auto-detects installed `npm`, `yarn`, `pnpm` | `pnpm` | -| **TypeScript** | Use TypeScript for type safety | `Yes` | -| **Tailwind CSS** | Use Tailwind CSS for styling | `Yes` | -| **`src/` Directory** | Use the `src/` directory for project structure | `Yes` | -| **App Router** | Use the Next.js App Router | `Yes` | -| **Pages** | Enter page names to create (comma-separated) | `none` | -| **Linter** | Choose a linter (`ESLint`, `Biome`) | `none` | -| **ORM** | Choose an ORM (`Prisma`, `Drizzle`) | `none` | -| **Testing** | Choose a testing framework (`Vitest`, `Jest`) | `none` | -| **Authentication** | Choose auth solution (`NextAuth`, `Clerk`, `Lucia`)| `none` | -| **Shadcn UI** | Automatically install and set up Shadcn UI | `Yes` | -| **Docker** | Add Docker support with Dockerfile | `No` | +| Prompt | Description | Default | +| -------------------- | --------------------------------------------------- | ------- | +| **Package Manager** | Auto-detects installed `npm`, `yarn`, `pnpm` | `pnpm` | +| **TypeScript** | Use TypeScript for type safety | `Yes` | +| **Tailwind CSS** | Use Tailwind CSS for styling | `Yes` | +| **`src/` Directory** | Use the `src/` directory for project structure | `Yes` | +| **App Router** | Use the Next.js App Router | `Yes` | +| **Pages** | Enter page names to create (comma-separated) | `none` | +| **Linter** | Choose a linter (`ESLint`, `Biome`) | `none` | +| **ORM** | Choose an ORM (`Prisma`, `Drizzle`) | `none` | +| **Testing** | Choose a testing framework (`Vitest`, `Jest`) | `none` | +| **Authentication** | Choose auth solution (`NextAuth`, `Clerk`, `Lucia`) | `none` | +| **Shadcn UI** | Automatically install and set up Shadcn UI | `Yes` | +| **Docker** | Add Docker support with Dockerfile | `No` | ### Example Walkthrough @@ -265,6 +266,7 @@ Automatically configures: ### Docker Support Generates production-ready Docker configuration: + - Multi-stage build for optimized image size - Standalone output mode in `next.config.mjs` - `.dockerignore` for efficient builds @@ -288,13 +290,13 @@ node --version Once your project is created, you can use the following commands: -| `pnpm` | `npm` | `yarn` | Description | -| --------------- | --------------- | --------------- | ------------------------------ | -| `pnpm dev` | `npm run dev` | `yarn dev` | Starts the development server | -| `pnpm build` | `npm run build` | `yarn build` | Builds the app for production | -| `pnpm start` | `npm start` | `yarn start` | Starts the production server | -| `pnpm lint` | `npm run lint` | `yarn lint` | Runs the linter (if configured)| -| `pnpm test` | `npm test` | `yarn test` | Runs tests (if configured) | +| `pnpm` | `npm` | `yarn` | Description | +| ------------ | --------------- | ------------ | ------------------------------- | +| `pnpm dev` | `npm run dev` | `yarn dev` | Starts the development server | +| `pnpm build` | `npm run build` | `yarn build` | Builds the app for production | +| `pnpm start` | `npm start` | `yarn start` | Starts the production server | +| `pnpm lint` | `npm run lint` | `yarn lint` | Runs the linter (if configured) | +| `pnpm test` | `npm test` | `yarn test` | Runs tests (if configured) | --- @@ -456,4 +458,4 @@ This project is licensed under the **MIT License**. See the [LICENSE](./LICENSE) Report Bug β€’ Request Feature

- \ No newline at end of file + diff --git a/SECURITY.md b/SECURITY.md index 829b94e..013697d 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -1,6 +1,7 @@ # Security Policy ## Reporting a Vulnerability + If you discover a security vulnerability in this project, please report it responsibly. We appreciate your help in making this project more secure. @@ -14,20 +15,23 @@ We will acknowledge receipt of your report within 2 business days. We aim to investigate and respond with an initial assessment within 7 business days. ## Supported Versions + We currently support the latest version of the project. Please ensure you're using the latest release before reporting a vulnerability. | Version | Supported | -|---------|-----------| +| ------- | --------- | | latest | βœ… | Older versions are not actively maintained unless critical. ## Disclosure Policy + Once a vulnerability is confirmed and a fix is available, we will disclose it in a responsible and transparent manner. We may credit the reporter if desired. ## Contact + Email: [paigauresh@gmail.com](mailto:paigauresh@gmail.com) GitHub: [@gaureshpai](https://github.com/gaureshpai) diff --git a/docs/index.html b/docs/index.html index 9310414..d9374e7 100644 --- a/docs/index.html +++ b/docs/index.html @@ -1,360 +1,477 @@ - + - - - - + + + create-next-quick Docs - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + - +
-
-
- create-next-quick - create-next-quick -
- - +
+
+ create-next-quick + create-next-quick
+ + +
-
-
-

create-next-quick

-

Bootstrap your Next.js project in seconds with your preferred setup

- -
+
+
+

create-next-quick

+

+ Bootstrap your Next.js project in seconds with your preferred setup +

+ +
-
-

Why create-next-quick?

-

- create-next-quick is a powerful, lightweight alternative to - create-next-app, designed for developers who want more control and speed right from the - start. -

-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Featurecreate-next-quickcreate-next-app
Multi-page Generationβœ… Yes (e.g., home, about, contact)❌ No
ORM Supportβœ… Yes (Prisma, Drizzle)❌ No
Linter Choiceβœ… Yes (ESLint, Biome)❌ ESLint only
Shadcn UI Auto-Setupβœ… Yes (non-interactive)❌ No
Clean Project Startβœ… Yes (removes boilerplate & default assets)❌ No
Package Manager Detectionβœ… Yes (npm, yarn, pnpm)βœ… Yes
Robust Error Handlingβœ… Yes (retries, cleanup, clear tips)❌ Basic
-
-
+
+

Why create-next-quick?

+

+ create-next-quick is a powerful, lightweight + alternative to create-next-app, designed for developers + who want more control and speed right from the start. +

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Featurecreate-next-quickcreate-next-app
Multi-page Generationβœ… Yes (e.g., home, about, contact)❌ No
ORM Supportβœ… Yes (Prisma, Drizzle)❌ No
Linter Choiceβœ… Yes (ESLint, Biome)❌ ESLint only
Shadcn UI Auto-Setupβœ… Yes (non-interactive)❌ No
Clean Project Startβœ… Yes (removes boilerplate & default assets)❌ No
Package Manager Detectionβœ… Yes (npm, yarn, pnpm)βœ… Yes
Robust Error Handlingβœ… Yes (retries, cleanup, clear tips)❌ Basic
+
+
-
-

Features

-
-
-

Project Scaffolding

-
    -
  • - CLI Argument for Project Name: Skip the project name prompt by passing - it as an argument. -
  • -
  • - Custom Page Generation: Create multiple pages at once from the CLI. -
  • -
  • - Clean Project Setup: Automatically removes the default favicon, clears - the public folder, and provides a clean page.tsx and - layout.tsx. -
  • -
  • - Safe Project Creation: Prevents accidental overwrites by checking if - the target directory is empty. -
  • -
  • - Conditional API Route Deletion: Removes the default - hello.js - API route when not needed. -
  • -
-
-
-

Tooling & Integrations

-
    -
  • - Package Manager Detection: Auto-detects npm, - yarn, and pnpm. -
  • -
  • Linter Support: Choose between ESLint, Biome, or no linter.
  • -
  • ORM Support: Integrated setup for Prisma or Drizzle.
  • -
  • - Shadcn UI: Automatically installs and configures Shadcn UI - non-interactively. -
  • -
  • - TypeScript CSS Module Support: Generates global.d.ts to - provide type declarations for CSS imports. -
  • -
  • - Authentication: Integrated setup for NextAuth.js, - Clerk, or Lucia with middleware and API routes. -
  • -
  • - Testing: Ready-to-use configuration for Vitest or - Jest with React Testing Library. -
  • -
  • - Docker: Auto-generated Dockerfile and - .dockerignore for containerized deployments. -
  • -
-
-
-

Developer Experience

-
    -
  • - Robust Error Handling: Automatic retries for failed installs, - intelligent cleanup of incomplete projects, and actionable troubleshooting tips. -
  • -
  • - Automated CI/CD Feedback: Get automated comments on the test status of - your Pull Requests. -
  • -
-
-
-
+
+

Features

+
+
+

Project Scaffolding

+
    +
  • + CLI Argument for Project Name: Skip the + project name prompt by passing it as an argument. +
  • +
  • + Custom Page Generation: Create multiple pages + at once from the CLI. +
  • +
  • + Clean Project Setup: Automatically removes + the default favicon, clears the public folder, and provides a + clean page.tsx and layout.tsx. +
  • +
  • + Safe Project Creation: Prevents accidental + overwrites by checking if the target directory is empty. +
  • +
  • + Conditional API Route Deletion: Removes the + default + hello.js + API route when not needed. +
  • +
+
+
+

Tooling & Integrations

+
    +
  • + Package Manager Detection: Auto-detects + npm, yarn, and pnpm. +
  • +
  • + Linter Support: Choose between ESLint, Biome, + or no linter. +
  • +
  • + ORM Support: Integrated setup for Prisma or + Drizzle. +
  • +
  • + Shadcn UI: Automatically installs and + configures Shadcn UI non-interactively. +
  • +
  • + TypeScript CSS Module Support: Generates + global.d.ts to provide type declarations for CSS + imports. +
  • +
  • + Authentication: Integrated setup for + NextAuth.js, Clerk, or + Lucia with middleware and API routes. +
  • +
  • + Testing: Ready-to-use configuration for + Vitest or Jest with React + Testing Library. +
  • +
  • + Docker: Auto-generated + Dockerfile and .dockerignore for + containerized deployments. +
  • +
+
+
+

Developer Experience

+
    +
  • + Robust Error Handling: Automatic retries for + failed installs, intelligent cleanup of incomplete projects, + and actionable troubleshooting tips. +
  • +
  • + Automated CI/CD Feedback: Get automated + comments on the test status of your Pull Requests. +
  • +
+
+
+
-
-

Usage

-

No global installation is needed. Run it instantly with npx:

-
- npx create-next-quick [project-name] - -
-

- If you omit [project-name], the tool will prompt you for it. Use . to - create in the current directory (must be empty). -

+
+

Usage

+

+ No global installation is needed. Run it instantly with + npx: +

+
+ npx create-next-quick [project-name] + +
+

+ If you omit [project-name], the tool will prompt you + for it. Use . to create in the current directory (must + be empty). +

-

Other Flags

-
    -
  • -v, --version: Display the version number
  • -
  • -h, --help: Display the help message
  • -
+

Other Flags

+
    +
  • -v, --version: Display the version number
  • +
  • -h, --help: Display the help message
  • +
-

Interactive Mode (for existing projects)

-

- Already have a Next.js project? Use the -i or --interactive flag to run - create-next-quick on your existing project and add new features without starting from - scratch. -

-
- npx create-next-quick -i - -
-

When you run in interactive mode, the tool will:

-
    -
  1. - Detect Your Project's Setup: It automatically detects if you're using - TypeScript, the src directory, the app directory, and Tailwind CSS. -
  2. -
  3. - Skip Project Creation: It will not run create-next-app or remove - any existing files. -
  4. -
  5. - Prompt for Additions: It will only ask you what you want to add to - your project, such as new pages, a linter, an ORM, or Shadcn UI. -
  6. -
-

- This is perfect for when you want to add a new feature to your project and want to use the same - streamlined setup process. -

+

Interactive Mode (for existing projects)

+

+ Already have a Next.js project? Use the -i or + --interactive flag to run + create-next-quick on your existing project and add new + features without starting from scratch. +

+
+ npx create-next-quick -i + +
+

When you run in interactive mode, the tool will:

+
    +
  1. + Detect Your Project's Setup: It automatically + detects if you're using TypeScript, the + src directory, the app directory, and + Tailwind CSS. +
  2. +
  3. + Skip Project Creation: It will not run + create-next-app or remove any existing files. +
  4. +
  5. + Prompt for Additions: It will only ask you what + you want to add to your project, such as new pages, a + linter, an ORM, or Shadcn UI. +
  6. +
+

+ This is perfect for when you want to add a new feature to your + project and want to use the same streamlined setup process. +

-

Interactive Prompts

-

The CLI will guide you through the following options:

-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
PromptDescriptionDefault
Package ManagerAuto-detects installed npm, yarn, pnpmpnpm
TypeScriptUse TypeScript for type safetyYes
Tailwind CSSUse Tailwind CSS for stylingYes
src/ DirectoryUse the src/ directory for project structureYes
App RouterUse the Next.js App RouterYes
PagesEnter page names to create (comma-separated)none
LinterChoose a linter (ESLint, Biome)none
ORMChoose an ORM (Prisma, Drizzle)none
Shadcn UIAutomatically install and set up Shadcn UIYes
TestingChoose a testing framework (Vitest, Jest)none
AuthenticationChoose auth solution (NextAuth, Clerk, Lucia)none
DockerAdd Docker support with Dockerfile and .dockerignoreNo
-
+

Interactive Prompts

+

The CLI will guide you through the following options:

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
PromptDescriptionDefault
Package Manager + Auto-detects installed npm, yarn, + pnpm + pnpm
TypeScriptUse TypeScript for type safetyYes
Tailwind CSSUse Tailwind CSS for stylingYes
+ src/ Directory + + Use the src/ directory for project structure + Yes
App RouterUse the Next.js App RouterYes
PagesEnter page names to create (comma-separated)none
Linter + Choose a linter (ESLint, Biome) + none
ORM + Choose an ORM (Prisma, Drizzle) + none
Shadcn UIAutomatically install and set up Shadcn UIYes
Testing + Choose a testing framework (Vitest, + Jest) + none
Authentication + Choose auth solution (NextAuth, + Clerk, Lucia) + none
DockerAdd Docker support with Dockerfile and .dockerignoreNo
+
-

Example Walkthrough

-
-
$ npx create-next-quick my-portfolio
+          

Example Walkthrough

+
+
$ npx create-next-quick my-portfolio
 βœ” Using default for package manager: pnpm
 βœ” Using default for TypeScript: Yes
 βœ” Using default for Tailwind CSS: Yes
@@ -364,119 +481,138 @@ 

Example Walkthrough

βœ” Using default for linter: none βœ” Using default for ORM: none βœ” Using default for Shadcn UI: Yes
-
-
+
+ -
-

Prerequisites

-

Before you begin, ensure you have the following installed:

- -
+
+

Prerequisites

+

Before you begin, ensure you have the following installed:

+ +
-
-

Available Scripts

-

Once your project is created, you can use the following commands:

-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
pnpmnpmyarnDescription
pnpm devnpm run devyarn devStarts the development server.
pnpm buildnpm run buildyarn buildBuilds the app for production.
pnpm startnpm startyarn startStarts the production server.
-
-
+
+

Available Scripts

+

+ Once your project is created, you can use the following commands: +

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
pnpmnpmyarnDescription
pnpm devnpm run devyarn devStarts the development server.
pnpm buildnpm run buildyarn buildBuilds the app for production.
pnpm startnpm startyarn startStarts the production server.
+
+
-
-

Testing

-

The test suite is dynamically generated to ensure comprehensive coverage.

-
    -
  1. Generate Test Cases: -
    - npm run test:generate - -
    -
  2. -
  3. Run Tests: -
    - npm test - -
    -
  4. -
-
+
+

Testing

+

+ The test suite is dynamically generated to ensure comprehensive + coverage. +

+
    +
  1. + Generate Test Cases: +
    + npm run test:generate + +
    +
  2. +
  3. + Run Tests: +
    + npm test + +
    +
  4. +
+
-
-

Contributing

-

- Contributions are welcome! Please fork the repository, create a feature branch, and open a Pull - Request. -

-
    -
  1. Fork the repository.
  2. -
  3. Create a new branch: git checkout -b feature/your-feature-name
  4. -
  5. Commit your changes: git commit -m "feat: Add some amazing feature"
  6. -
  7. Push to the branch: git push origin feature/your-feature-name
  8. -
  9. Open a Pull Request.
  10. -
-
+
+

Contributing

+

+ Contributions are welcome! Please fork the repository, create a + feature branch, and open a Pull Request. +

+
    +
  1. Fork the repository.
  2. +
  3. + Create a new branch: + git checkout -b feature/your-feature-name +
  4. +
  5. + Commit your changes: + git commit -m "feat: Add some amazing feature" +
  6. +
  7. + Push to the branch: + git push origin feature/your-feature-name +
  8. +
  9. Open a Pull Request.
  10. +
+
-
-

Show Your Support

-

Give a ⭐️ if this project helped you!

-
+
+

Show Your Support

+

Give a ⭐️ if this project helped you!

+
-
-

License

-

- This project is licensed under the MIT License. See the LICENSE file for - details. -

-
+
+

License

+

+ This project is licensed under the MIT License. See the + LICENSE file for details. +

+
-
-

Contributors

-
- - - -
-
- +
+

Contributors

+
+ + + +
+
+ - - - \ No newline at end of file + + diff --git a/package.json b/package.json index 8b5f35b..ba3b2fd 100644 --- a/package.json +++ b/package.json @@ -2,27 +2,31 @@ "name": "create-next-quick", "version": "2.0.2", "description": "A CLI tool to quickly scaffold a Next.js project", - "main": "src/index.js", - "files": [ - "src" - ], + "main": "dist/create-next-quick.js", "type": "module", "scripts": { + "build": "rollup -c --environment BUILD:production", + "start": "node dist/create-next-quick.js", + "pretest": "pnpm build", "test": "mocha src/test/test.js && echo \"Tests passed successfully\" || (echo \"Tests failed\" && exit 1)", + "test:build-config": "mocha src/test/build-config.test.js", "test:interactive": "mocha src/test/interactive.test.js", "test:generate": "node src/test/generate-tests.js", - "start": "node src/index.js", - "lint": "biome check . --write", + "check": "biome check . --write", + "lint": "biome lint . --write", "format": "biome format . --write", "prepare": "husky" }, "lint-staged": { "src/**/*.{js,json,md}": [ - "biome check . --write" + "biome check --write" ] }, + "files": [ + "dist" + ], "bin": { - "create-next-quick": "src/index.js" + "create-next-quick": "dist/create-next-quick.js" }, "keywords": [ "next.js", @@ -47,9 +51,12 @@ "homepage": "https://gaureshpai.github.io/create-next-quick/", "devDependencies": { "@biomejs/biome": "^2.3.13", + "@rollup/plugin-node-resolve": "^16.0.3", + "@rollup/plugin-terser": "^1.0.0", "husky": "^9.1.7", "inquirer-test": "^2.0.1", + "lint-staged": "^16.2.7", "mocha": "^11.0.0", - "lint-staged": "^16.2.7" + "rollup": "^4.59.1" } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 18cc351..190821c 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -11,6 +11,12 @@ importers: '@biomejs/biome': specifier: ^2.3.13 version: 2.3.13 + '@rollup/plugin-node-resolve': + specifier: ^16.0.3 + version: 16.0.3(rollup@4.59.1) + '@rollup/plugin-terser': + specifier: ^1.0.0 + version: 1.0.0(rollup@4.59.1) husky: specifier: ^9.1.7 version: 9.1.7 @@ -23,6 +29,9 @@ importers: mocha: specifier: ^11.0.0 version: 11.7.5 + rollup: + specifier: ^4.59.1 + version: 4.59.1 packages: @@ -87,10 +96,202 @@ packages: resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} engines: {node: '>=12'} + '@jridgewell/gen-mapping@0.3.13': + resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==} + + '@jridgewell/resolve-uri@3.1.2': + resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} + engines: {node: '>=6.0.0'} + + '@jridgewell/source-map@0.3.11': + resolution: {integrity: sha512-ZMp1V8ZFcPG5dIWnQLr3NSI1MiCU7UETdS/A0G8V/XWHvJv3ZsFqutJn1Y5RPmAPX6F3BiE397OqveU/9NCuIA==} + + '@jridgewell/sourcemap-codec@1.5.5': + resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==} + + '@jridgewell/trace-mapping@0.3.31': + resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} + '@pkgjs/parseargs@0.11.0': resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} engines: {node: '>=14'} + '@rollup/plugin-node-resolve@16.0.3': + resolution: {integrity: sha512-lUYM3UBGuM93CnMPG1YocWu7X802BrNF3jW2zny5gQyLQgRFJhV1Sq0Zi74+dh/6NBx1DxFC4b4GXg9wUCG5Qg==} + engines: {node: '>=14.0.0'} + peerDependencies: + rollup: ^2.78.0||^3.0.0||^4.0.0 + peerDependenciesMeta: + rollup: + optional: true + + '@rollup/plugin-terser@1.0.0': + resolution: {integrity: sha512-FnCxhTBx6bMOYQrar6C8h3scPt8/JwIzw3+AJ2K++6guogH5fYaIFia+zZuhqv0eo1RN7W1Pz630SyvLbDjhtQ==} + engines: {node: '>=20.0.0'} + peerDependencies: + rollup: ^2.0.0||^3.0.0||^4.0.0 + peerDependenciesMeta: + rollup: + optional: true + + '@rollup/pluginutils@5.3.0': + resolution: {integrity: sha512-5EdhGZtnu3V88ces7s53hhfK5KSASnJZv8Lulpc04cWO3REESroJXg73DFsOmgbU2BhwV0E20bu2IDZb3VKW4Q==} + engines: {node: '>=14.0.0'} + peerDependencies: + rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0 + peerDependenciesMeta: + rollup: + optional: true + + '@rollup/rollup-android-arm-eabi@4.59.1': + resolution: {integrity: sha512-xB0b51TB7IfDEzAojXahmr+gfA00uYVInJGgNNkeQG6RPnCPGr7udsylFLTubuIUSRE6FkcI1NElyRt83PP5oQ==} + cpu: [arm] + os: [android] + + '@rollup/rollup-android-arm64@4.59.1': + resolution: {integrity: sha512-XOjPId0qwSDKHaIsdzHJtKCxX0+nH8MhBwvrNsT7tVyKmdTx1jJ4XzN5RZXCdTzMpufLb+B8llTC0D8uCrLhcw==} + cpu: [arm64] + os: [android] + + '@rollup/rollup-darwin-arm64@4.59.1': + resolution: {integrity: sha512-vQuRd28p0gQpPrS6kppd8IrWmFo42U8Pz1XLRjSZXq5zCqyMDYFABT7/sywL11mO1EL10Qhh7MVPEwkG8GiBeg==} + cpu: [arm64] + os: [darwin] + + '@rollup/rollup-darwin-x64@4.59.1': + resolution: {integrity: sha512-x6VG6U29+Ivlnajrg1IHdzXeAwSoEHBFVO+CtC9Brugx6de712CUJobRUxsIA0KYrQvCmzNrMPFTT1A4CCqNTg==} + cpu: [x64] + os: [darwin] + + '@rollup/rollup-freebsd-arm64@4.59.1': + resolution: {integrity: sha512-Sgi0Uo6t1YCHJMNO3Y8+bm+SvOanUGkoZKn/VJPwYUe2kp31X5KnXmzKd/NjW8iA3gFcfNZ64zh14uOGrIllCQ==} + cpu: [arm64] + os: [freebsd] + + '@rollup/rollup-freebsd-x64@4.59.1': + resolution: {integrity: sha512-AM4xnwEZwukdhk7laMWfzWu9JGSVnJd+Fowt6Fd7QW1nrf3h0Hp7Qx5881M4aqrUlKBCybOxz0jofvIIfl7C5g==} + cpu: [x64] + os: [freebsd] + + '@rollup/rollup-linux-arm-gnueabihf@4.59.1': + resolution: {integrity: sha512-KUizqxpwaR2AZdAUsMWfL/C94pUu7TKpoPd88c8yFVixJ+l9hejkrwoK5Zj3wiNh65UeyryKnJyxL1b7yNqFQA==} + cpu: [arm] + os: [linux] + libc: [glibc] + + '@rollup/rollup-linux-arm-musleabihf@4.59.1': + resolution: {integrity: sha512-MZoQ/am77ckJtZGFAtPucgUuJWiop3m2R3lw7tC0QCcbfl4DRhQUBUkHWCkcrT3pqy5Mzv5QQgY6Dmlba6iTWg==} + cpu: [arm] + os: [linux] + libc: [musl] + + '@rollup/rollup-linux-arm64-gnu@4.59.1': + resolution: {integrity: sha512-Sez95TP6xGjkWB1608EfhCX1gdGrO5wzyN99VqzRtC17x/1bhw5VU1V0GfKUwbW/Xr1J8mSasoFoJa6Y7aGGSA==} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@rollup/rollup-linux-arm64-musl@4.59.1': + resolution: {integrity: sha512-9Cs2Seq98LWNOJzR89EGTZoiP8EkZ9UbQhBlDgfAkM6asVna1xJ04W2CLYWDN/RpUgOjtQvcv8wQVi1t5oQazA==} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@rollup/rollup-linux-loong64-gnu@4.59.1': + resolution: {integrity: sha512-n9yqttftgFy7IrNEnHy1bOp6B4OSe8mJDiPkT7EqlM9FnKOwUMnCK62ixW0Kd9Clw0/wgvh8+SqaDXMFvw3KqQ==} + cpu: [loong64] + os: [linux] + libc: [glibc] + + '@rollup/rollup-linux-loong64-musl@4.59.1': + resolution: {integrity: sha512-SfpNXDzVTqs/riak4xXcLpq5gIQWsqGWMhN1AGRQKB4qGSs4r0sEs3ervXPcE1O9RsQ5bm8Muz6zmQpQnPss1g==} + cpu: [loong64] + os: [linux] + libc: [musl] + + '@rollup/rollup-linux-ppc64-gnu@4.59.1': + resolution: {integrity: sha512-LjaChED0wQnjKZU+tsmGbN+9nN1XhaWUkAlSbTdhpEseCS4a15f/Q8xC2BN4GDKRzhhLZpYtJBZr2NZhR0jvNw==} + cpu: [ppc64] + os: [linux] + libc: [glibc] + + '@rollup/rollup-linux-ppc64-musl@4.59.1': + resolution: {integrity: sha512-ojW7iTJSIs4pwB2xV6QXGwNyDctvXOivYllttuPbXguuKDX5vwpqYJsHc6D2LZzjDGHML414Tuj3LvVPe1CT1A==} + cpu: [ppc64] + os: [linux] + libc: [musl] + + '@rollup/rollup-linux-riscv64-gnu@4.59.1': + resolution: {integrity: sha512-FP+Q6WTcxxvsr0wQczhSE+tOZvFPV8A/mUE6mhZYFW9/eea/y/XqAgRoLLMuE9Cz0hfX5bi7p116IWoB+P237A==} + cpu: [riscv64] + os: [linux] + libc: [glibc] + + '@rollup/rollup-linux-riscv64-musl@4.59.1': + resolution: {integrity: sha512-L1uD9b/Ig8Z+rn1KttCJjwhN1FgjRMBKsPaBsDKkfUl7GfFq71pU4vWCnpOsGljycFEbkHWARZLf4lMYg3WOLw==} + cpu: [riscv64] + os: [linux] + libc: [musl] + + '@rollup/rollup-linux-s390x-gnu@4.59.1': + resolution: {integrity: sha512-EZc9NGTk/oSUzzOD4nYY4gIjteo2M3CiozX6t1IXGCOdgxJTlVu/7EdPeiqeHPSIrxkLhavqpBAUCfvC6vBOug==} + cpu: [s390x] + os: [linux] + libc: [glibc] + + '@rollup/rollup-linux-x64-gnu@4.59.1': + resolution: {integrity: sha512-NQ9KyU1Anuy59L8+HHOKM++CoUxrQWrZWXRik4BJFm+7i5NP6q/SW43xIBr80zzt+PDBJ7LeNmloQGfa0JGk0w==} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@rollup/rollup-linux-x64-musl@4.59.1': + resolution: {integrity: sha512-GZkLk2t6naywsveSFBsEb0PLU+JC9ggVjbndsbG20VPhar6D1gkMfCx4NfP9owpovBXTN+eRdqGSkDGIxPHhmQ==} + cpu: [x64] + os: [linux] + libc: [musl] + + '@rollup/rollup-openbsd-x64@4.59.1': + resolution: {integrity: sha512-1hjG9Jpl2KDOetr64iQd8AZAEjkDUUK5RbDkYWsViYLC1op1oNzdjMJeFiofcGhqbNTaY2kfgqowE7DILifsrA==} + cpu: [x64] + os: [openbsd] + + '@rollup/rollup-openharmony-arm64@4.59.1': + resolution: {integrity: sha512-ARoKfflk0SiiYm3r1fmF73K/yB+PThmOwfWCk1sr7x/k9dc3uGLWuEE9if+Pw21el8MSpp3TMnG5vLNsJ/MMGQ==} + cpu: [arm64] + os: [openharmony] + + '@rollup/rollup-win32-arm64-msvc@4.59.1': + resolution: {integrity: sha512-oOST61G6VM45Mz2vdzWMr1s2slI7y9LqxEV5fCoWi2MDONmMvgsJVHSXxce/I2xOSZPTZ47nDPOl1tkwKWSHcw==} + cpu: [arm64] + os: [win32] + + '@rollup/rollup-win32-ia32-msvc@4.59.1': + resolution: {integrity: sha512-x5WgLi5dWpRz7WclKBGEF15LcWTh0ewrHM6Cq4A+WUbkysUMZNeqt05bwPonOQ3ihPS/WMhAZV5zB1DfnI4Sxg==} + cpu: [ia32] + os: [win32] + + '@rollup/rollup-win32-x64-gnu@4.59.1': + resolution: {integrity: sha512-wS+zHAJRVP5zOL0e+a3V3E/NTEwM2HEvvNKoDy5Xcfs0o8lljxn+EAFPkUsxihBdmDq1JWzXmmB9cbssCPdxxw==} + cpu: [x64] + os: [win32] + + '@rollup/rollup-win32-x64-msvc@4.59.1': + resolution: {integrity: sha512-rhHyrMeLpErT/C7BxcEsU4COHQUzHyrPYW5tOZUeUhziNtRuYxmDWvqQqzpuUt8xpOgmbKa1btGXfnA/ANVO+g==} + cpu: [x64] + os: [win32] + + '@types/estree@1.0.8': + resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} + + '@types/resolve@1.20.2': + resolution: {integrity: sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==} + + acorn@8.16.0: + resolution: {integrity: sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==} + engines: {node: '>=0.4.0'} + hasBin: true + ansi-escapes@7.2.0: resolution: {integrity: sha512-g6LhBsl+GBPRWGWsBtutpzBYuIIdBkLEvad5C/va/74Db018+5TZiyA26cZJAr3Rft5lprVqOIPxf5Vid6tqAw==} engines: {node: '>=18'} @@ -168,6 +369,9 @@ packages: resolution: {integrity: sha512-H+y0Jo/T1RZ9qPP4Eh1pkcQcLRglraJaSLoyOtHxu6AapkjWVCy2Sit1QQ4x3Dng8qDlSsZEet7g5Pq06MvTgw==} engines: {node: '>=20'} + commander@2.20.3: + resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==} + concat-stream@1.6.2: resolution: {integrity: sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==} engines: {'0': node >= 0.8} @@ -192,6 +396,10 @@ packages: resolution: {integrity: sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==} engines: {node: '>=10'} + deepmerge@4.3.1: + resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==} + engines: {node: '>=0.10.0'} + diff@7.0.0: resolution: {integrity: sha512-PJWHUb1RFevKCwaFA9RlG5tCd+FO5iRh9A8HEtkmBH2Li03iJriB6m6JIN4rGz3K3JLawI7/veA1xzRKP6ISBw==} engines: {node: '>=0.3.1'} @@ -220,6 +428,9 @@ packages: resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} engines: {node: '>=10'} + estree-walker@2.0.2: + resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==} + eventemitter3@5.0.4: resolution: {integrity: sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw==} @@ -239,6 +450,14 @@ packages: resolution: {integrity: sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==} engines: {node: '>=14'} + fsevents@2.3.3: + resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] + + function-bind@1.1.2: + resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} + get-caller-file@2.0.5: resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} engines: {node: 6.* || 8.* || >= 10.*} @@ -255,6 +474,10 @@ packages: resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} engines: {node: '>=8'} + hasown@2.0.2: + resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} + engines: {node: '>= 0.4'} + he@1.2.0: resolution: {integrity: sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==} hasBin: true @@ -271,6 +494,10 @@ packages: resolution: {integrity: sha512-gpO6+E/VtPMNp7FBnIJtEWPHMzZ0GJK/EI3ThxtdBHbmbFW5PRl150CCMT3SpmqJY5x9nBeviyn8ZalDIABmFQ==} engines: {node: '>=6.0'} + is-core-module@2.16.1: + resolution: {integrity: sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==} + engines: {node: '>= 0.4'} + is-fullwidth-code-point@3.0.0: resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} engines: {node: '>=8'} @@ -279,6 +506,9 @@ packages: resolution: {integrity: sha512-5XHYaSyiqADb4RnZ1Bdad6cPp8Toise4TzEjcOYDHZkTCbKgiUl7WTUCpNWHuxmDt91wnsZBc9xinNzopv3JMQ==} engines: {node: '>=18'} + is-module@1.0.0: + resolution: {integrity: sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==} + is-number@7.0.0: resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} engines: {node: '>=0.12.0'} @@ -383,6 +613,9 @@ packages: resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} engines: {node: '>=8'} + path-parse@1.0.7: + resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} + path-scurry@1.11.1: resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==} engines: {node: '>=16 || 14 >=14.18'} @@ -394,6 +627,10 @@ packages: resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} engines: {node: '>=8.6'} + picomatch@4.0.3: + resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==} + engines: {node: '>=12'} + pidtree@0.6.0: resolution: {integrity: sha512-eG2dWTVw5bzqGRztnHExczNxt5VGsE6OwTeCG3fdUf9KBsZzO3R5OIIIzWR+iZA0NtZ+RDVdaoE2dK1cn6jH4g==} engines: {node: '>=0.10'} @@ -416,6 +653,11 @@ packages: resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} engines: {node: '>=0.10.0'} + resolve@1.22.11: + resolution: {integrity: sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==} + engines: {node: '>= 0.4'} + hasBin: true + restore-cursor@5.1.0: resolution: {integrity: sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA==} engines: {node: '>=18'} @@ -423,6 +665,11 @@ packages: rfdc@1.4.1: resolution: {integrity: sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==} + rollup@4.59.1: + resolution: {integrity: sha512-iZKH8BeoCwTCBTZBZWQQMreekd4mdomwdjIQ40GC1oZm6o+8PnNMIxFOiCsGMWeS8iDJ7KZcl7KwmKk/0HOQpA==} + engines: {node: '>=18.0.0', npm: '>=8.0.0'} + hasBin: true + safe-buffer@5.1.2: resolution: {integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==} @@ -432,6 +679,10 @@ packages: serialize-javascript@6.0.2: resolution: {integrity: sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==} + serialize-javascript@7.0.4: + resolution: {integrity: sha512-DuGdB+Po43Q5Jxwpzt1lhyFSYKryqoNjQSA9M92tyw0lyHIOur+XCalOUe0KTJpyqzT8+fQ5A0Jf7vCx/NKmIg==} + engines: {node: '>=20.0.0'} + shebang-command@2.0.0: resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} engines: {node: '>=8'} @@ -448,6 +699,17 @@ packages: resolution: {integrity: sha512-iOBWFgUX7caIZiuutICxVgX1SdxwAVFFKwt1EvMYYec/NWO5meOJ6K5uQxhrYBdQJne4KxiqZc+KptFOWFSI9w==} engines: {node: '>=18'} + smob@1.6.1: + resolution: {integrity: sha512-KAkBqZl3c2GvNgNhcoyJae1aKldDW0LO279wF9bk1PnluRTETKBq0WyzRXxEhoQLk56yHaOY4JCBEKDuJIET5g==} + engines: {node: '>=20.0.0'} + + source-map-support@0.5.21: + resolution: {integrity: sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==} + + source-map@0.6.1: + resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} + engines: {node: '>=0.10.0'} + string-argv@0.3.2: resolution: {integrity: sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==} engines: {node: '>=0.6.19'} @@ -491,6 +753,15 @@ packages: resolution: {integrity: sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==} engines: {node: '>=10'} + supports-preserve-symlinks-flag@1.0.0: + resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} + engines: {node: '>= 0.4'} + + terser@5.46.1: + resolution: {integrity: sha512-vzCjQO/rgUuK9sf8VJZvjqiqiHFaZLnOiimmUuOKODxWL8mm/xua7viT7aqX7dgPY60otQjUotzFMmCB4VdmqQ==} + engines: {node: '>=10'} + hasBin: true + to-regex-range@5.0.1: resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} engines: {node: '>=8.0'} @@ -592,9 +863,135 @@ snapshots: wrap-ansi: 8.1.0 wrap-ansi-cjs: wrap-ansi@7.0.0 + '@jridgewell/gen-mapping@0.3.13': + dependencies: + '@jridgewell/sourcemap-codec': 1.5.5 + '@jridgewell/trace-mapping': 0.3.31 + + '@jridgewell/resolve-uri@3.1.2': {} + + '@jridgewell/source-map@0.3.11': + dependencies: + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.31 + + '@jridgewell/sourcemap-codec@1.5.5': {} + + '@jridgewell/trace-mapping@0.3.31': + dependencies: + '@jridgewell/resolve-uri': 3.1.2 + '@jridgewell/sourcemap-codec': 1.5.5 + '@pkgjs/parseargs@0.11.0': optional: true + '@rollup/plugin-node-resolve@16.0.3(rollup@4.59.1)': + dependencies: + '@rollup/pluginutils': 5.3.0(rollup@4.59.1) + '@types/resolve': 1.20.2 + deepmerge: 4.3.1 + is-module: 1.0.0 + resolve: 1.22.11 + optionalDependencies: + rollup: 4.59.1 + + '@rollup/plugin-terser@1.0.0(rollup@4.59.1)': + dependencies: + serialize-javascript: 7.0.4 + smob: 1.6.1 + terser: 5.46.1 + optionalDependencies: + rollup: 4.59.1 + + '@rollup/pluginutils@5.3.0(rollup@4.59.1)': + dependencies: + '@types/estree': 1.0.8 + estree-walker: 2.0.2 + picomatch: 4.0.3 + optionalDependencies: + rollup: 4.59.1 + + '@rollup/rollup-android-arm-eabi@4.59.1': + optional: true + + '@rollup/rollup-android-arm64@4.59.1': + optional: true + + '@rollup/rollup-darwin-arm64@4.59.1': + optional: true + + '@rollup/rollup-darwin-x64@4.59.1': + optional: true + + '@rollup/rollup-freebsd-arm64@4.59.1': + optional: true + + '@rollup/rollup-freebsd-x64@4.59.1': + optional: true + + '@rollup/rollup-linux-arm-gnueabihf@4.59.1': + optional: true + + '@rollup/rollup-linux-arm-musleabihf@4.59.1': + optional: true + + '@rollup/rollup-linux-arm64-gnu@4.59.1': + optional: true + + '@rollup/rollup-linux-arm64-musl@4.59.1': + optional: true + + '@rollup/rollup-linux-loong64-gnu@4.59.1': + optional: true + + '@rollup/rollup-linux-loong64-musl@4.59.1': + optional: true + + '@rollup/rollup-linux-ppc64-gnu@4.59.1': + optional: true + + '@rollup/rollup-linux-ppc64-musl@4.59.1': + optional: true + + '@rollup/rollup-linux-riscv64-gnu@4.59.1': + optional: true + + '@rollup/rollup-linux-riscv64-musl@4.59.1': + optional: true + + '@rollup/rollup-linux-s390x-gnu@4.59.1': + optional: true + + '@rollup/rollup-linux-x64-gnu@4.59.1': + optional: true + + '@rollup/rollup-linux-x64-musl@4.59.1': + optional: true + + '@rollup/rollup-openbsd-x64@4.59.1': + optional: true + + '@rollup/rollup-openharmony-arm64@4.59.1': + optional: true + + '@rollup/rollup-win32-arm64-msvc@4.59.1': + optional: true + + '@rollup/rollup-win32-ia32-msvc@4.59.1': + optional: true + + '@rollup/rollup-win32-x64-gnu@4.59.1': + optional: true + + '@rollup/rollup-win32-x64-msvc@4.59.1': + optional: true + + '@types/estree@1.0.8': {} + + '@types/resolve@1.20.2': {} + + acorn@8.16.0: {} + ansi-escapes@7.2.0: dependencies: environment: 1.1.0 @@ -661,6 +1058,8 @@ snapshots: commander@14.0.3: {} + commander@2.20.3: {} + concat-stream@1.6.2: dependencies: buffer-from: 1.1.2 @@ -684,6 +1083,8 @@ snapshots: decamelize@4.0.0: {} + deepmerge@4.3.1: {} + diff@7.0.0: {} eastasianwidth@0.2.0: {} @@ -700,6 +1101,8 @@ snapshots: escape-string-regexp@4.0.0: {} + estree-walker@2.0.2: {} + eventemitter3@5.0.4: {} fill-range@7.1.1: @@ -718,6 +1121,11 @@ snapshots: cross-spawn: 7.0.6 signal-exit: 4.1.0 + fsevents@2.3.3: + optional: true + + function-bind@1.1.2: {} + get-caller-file@2.0.5: {} get-east-asian-width@1.4.0: {} @@ -733,6 +1141,10 @@ snapshots: has-flag@4.0.0: {} + hasown@2.0.2: + dependencies: + function-bind: 1.1.2 + he@1.2.0: {} husky@9.1.7: {} @@ -743,12 +1155,18 @@ snapshots: dependencies: concat-stream: 1.6.2 + is-core-module@2.16.1: + dependencies: + hasown: 2.0.2 + is-fullwidth-code-point@3.0.0: {} is-fullwidth-code-point@5.1.0: dependencies: get-east-asian-width: 1.4.0 + is-module@1.0.0: {} + is-number@7.0.0: {} is-path-inside@3.0.3: {} @@ -868,6 +1286,8 @@ snapshots: path-key@3.1.1: {} + path-parse@1.0.7: {} + path-scurry@1.11.1: dependencies: lru-cache: 10.4.3 @@ -877,6 +1297,8 @@ snapshots: picomatch@2.3.1: {} + picomatch@4.0.3: {} + pidtree@0.6.0: {} process-nextick-args@2.0.1: {} @@ -899,6 +1321,12 @@ snapshots: require-directory@2.1.1: {} + resolve@1.22.11: + dependencies: + is-core-module: 2.16.1 + path-parse: 1.0.7 + supports-preserve-symlinks-flag: 1.0.0 + restore-cursor@5.1.0: dependencies: onetime: 7.0.0 @@ -906,6 +1334,37 @@ snapshots: rfdc@1.4.1: {} + rollup@4.59.1: + dependencies: + '@types/estree': 1.0.8 + optionalDependencies: + '@rollup/rollup-android-arm-eabi': 4.59.1 + '@rollup/rollup-android-arm64': 4.59.1 + '@rollup/rollup-darwin-arm64': 4.59.1 + '@rollup/rollup-darwin-x64': 4.59.1 + '@rollup/rollup-freebsd-arm64': 4.59.1 + '@rollup/rollup-freebsd-x64': 4.59.1 + '@rollup/rollup-linux-arm-gnueabihf': 4.59.1 + '@rollup/rollup-linux-arm-musleabihf': 4.59.1 + '@rollup/rollup-linux-arm64-gnu': 4.59.1 + '@rollup/rollup-linux-arm64-musl': 4.59.1 + '@rollup/rollup-linux-loong64-gnu': 4.59.1 + '@rollup/rollup-linux-loong64-musl': 4.59.1 + '@rollup/rollup-linux-ppc64-gnu': 4.59.1 + '@rollup/rollup-linux-ppc64-musl': 4.59.1 + '@rollup/rollup-linux-riscv64-gnu': 4.59.1 + '@rollup/rollup-linux-riscv64-musl': 4.59.1 + '@rollup/rollup-linux-s390x-gnu': 4.59.1 + '@rollup/rollup-linux-x64-gnu': 4.59.1 + '@rollup/rollup-linux-x64-musl': 4.59.1 + '@rollup/rollup-openbsd-x64': 4.59.1 + '@rollup/rollup-openharmony-arm64': 4.59.1 + '@rollup/rollup-win32-arm64-msvc': 4.59.1 + '@rollup/rollup-win32-ia32-msvc': 4.59.1 + '@rollup/rollup-win32-x64-gnu': 4.59.1 + '@rollup/rollup-win32-x64-msvc': 4.59.1 + fsevents: 2.3.3 + safe-buffer@5.1.2: {} safe-buffer@5.2.1: {} @@ -914,6 +1373,8 @@ snapshots: dependencies: randombytes: 2.1.0 + serialize-javascript@7.0.4: {} + shebang-command@2.0.0: dependencies: shebang-regex: 3.0.0 @@ -927,6 +1388,15 @@ snapshots: ansi-styles: 6.2.3 is-fullwidth-code-point: 5.1.0 + smob@1.6.1: {} + + source-map-support@0.5.21: + dependencies: + buffer-from: 1.1.2 + source-map: 0.6.1 + + source-map@0.6.1: {} + string-argv@0.3.2: {} string-width@4.2.3: @@ -974,6 +1444,15 @@ snapshots: dependencies: has-flag: 4.0.0 + supports-preserve-symlinks-flag@1.0.0: {} + + terser@5.46.1: + dependencies: + '@jridgewell/source-map': 0.3.11 + acorn: 8.16.0 + commander: 2.20.3 + source-map-support: 0.5.21 + to-regex-range@5.0.1: dependencies: is-number: 7.0.0 diff --git a/rollup.config.mjs b/rollup.config.mjs new file mode 100644 index 0000000..4aa73d4 --- /dev/null +++ b/rollup.config.mjs @@ -0,0 +1,37 @@ +import resolve from "@rollup/plugin-node-resolve"; +import terser from "@rollup/plugin-terser"; + +export default { + input: "src/create-next-quick.js", + output: { + dir: "dist", + format: "esm", + entryFileNames: "[name].js", + chunkFileNames: "[name]-[hash].js", + hoistTransitiveImports: false, + generatedCode: { + preset: "es2015", + constBindings: true, + }, + }, + plugins: [ + resolve({ + preferBuiltins: true, + }), + terser({ + compress: { + passes: 2, + drop_console: false, + drop_debugger: true, + }, + mangle: { + properties: false, + }, + format: { + comments: false, + shebang: true, + }, + }), + ], + external: [], +}; diff --git a/src/index.js b/src/create-next-quick.js similarity index 100% rename from src/index.js rename to src/create-next-quick.js diff --git a/src/test/build-config.test.js b/src/test/build-config.test.js new file mode 100644 index 0000000..b1fb80b --- /dev/null +++ b/src/test/build-config.test.js @@ -0,0 +1,290 @@ +import { strict as assert } from "node:assert"; +import { readFileSync } from "node:fs"; +import { fileURLToPath, pathToFileURL } from "node:url"; +import path from "node:path"; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); +const ROOT = path.join(__dirname, "..", ".."); + +describe("rollup.config.mjs", () => { + let config; + + before(async () => { + const configPath = path.join(ROOT, "rollup.config.mjs"); + const configUrl = pathToFileURL(configPath); + const mod = await import(configUrl); + config = mod.default; + }); + + describe("input", () => { + it("should use src/create-next-quick.js as the entry point", () => { + assert.strictEqual(config.input, "src/create-next-quick.js"); + }); + }); + + describe("output", () => { + it("should output to the dist directory", () => { + assert.strictEqual(config.output.dir, "dist"); + }); + + it("should use ESM output format", () => { + assert.strictEqual(config.output.format, "esm"); + }); + + it("should use [name].js pattern for entry file names", () => { + assert.strictEqual(config.output.entryFileNames, "[name].js"); + }); + + it("should use [name]-[hash].js pattern for chunk file names", () => { + assert.strictEqual(config.output.chunkFileNames, "[name]-[hash].js"); + }); + + it("should disable hoistTransitiveImports", () => { + assert.strictEqual(config.output.hoistTransitiveImports, false); + }); + + it("should enable constBindings in generatedCode", () => { + assert.strictEqual(config.output.generatedCode.constBindings, true); + }); + }); + + describe("plugins", () => { + it("should have exactly 2 plugins configured", () => { + assert.ok(Array.isArray(config.plugins), "plugins should be an array"); + assert.strictEqual(config.plugins.length, 2); + }); + + it("should have a node-resolve plugin as the first plugin", () => { + const resolvePlugin = config.plugins[0]; + assert.ok(resolvePlugin != null, "first plugin should not be null"); + assert.ok(typeof resolvePlugin === "object", "first plugin should be an object"); + assert.strictEqual(resolvePlugin.name, "node-resolve", "first plugin should be node-resolve"); + }); + + it("should have a terser plugin as the second plugin", () => { + const terserPlugin = config.plugins[1]; + assert.ok(terserPlugin != null, "second plugin should not be null"); + assert.ok(typeof terserPlugin === "object", "second plugin should be an object"); + assert.strictEqual(terserPlugin.name, "terser", "second plugin should be terser"); + }); + }); + + describe("external", () => { + it("should have an empty external array (bundle all dependencies)", () => { + assert.ok(Array.isArray(config.external), "external should be an array"); + assert.strictEqual(config.external.length, 0); + }); + }); +}); + +describe("package.json build configuration", () => { + let pkg; + + before(() => { + const pkgPath = path.join(ROOT, "package.json"); + pkg = JSON.parse(readFileSync(pkgPath, "utf-8")); + }); + + describe("main entry point", () => { + it("should point to dist/create-next-quick.js (compiled output)", () => { + assert.strictEqual(pkg.main, "dist/create-next-quick.js"); + }); + + it("should not point to the source file src/create-next-quick.js", () => { + assert.notStrictEqual(pkg.main, "src/create-next-quick.js"); + }); + }); + + describe("bin entry point", () => { + it("should have create-next-quick binary pointing to dist/create-next-quick.js", () => { + assert.strictEqual(pkg.bin["create-next-quick"], "dist/create-next-quick.js"); + }); + + it("should not point the binary to the source file src/create-next-quick.js", () => { + assert.notStrictEqual(pkg.bin["create-next-quick"], "src/create-next-quick.js"); + }); + }); + + describe("published files", () => { + it("should include dist in the files array", () => { + assert.ok(Array.isArray(pkg.files), "files should be an array"); + assert.ok(pkg.files.includes("dist"), "files should include 'dist'"); + }); + + it("should not include src in the published files", () => { + assert.ok(!pkg.files.includes("src"), "files should not include 'src'"); + }); + }); + + describe("scripts", () => { + it("should have a build script using rollup", () => { + assert.ok(pkg.scripts.build != null, "build script should exist"); + assert.ok(pkg.scripts.build.includes("rollup"), "build script should invoke rollup"); + }); + + it("build script should use the rollup config file (-c flag)", () => { + assert.ok( + pkg.scripts.build.includes("-c"), + "build script should include -c flag to use rollup.config.mjs", + ); + }); + + it("build script should set BUILD:production environment", () => { + assert.ok( + pkg.scripts.build.includes("BUILD:production"), + "build script should set BUILD:production environment variable", + ); + }); + + it("should have a start script pointing to dist/create-next-quick.js", () => { + assert.ok(pkg.scripts.start != null, "start script should exist"); + assert.strictEqual(pkg.scripts.start, "node dist/create-next-quick.js"); + }); + }); + + describe("devDependencies", () => { + it("should include rollup as a devDependency", () => { + assert.ok(pkg.devDependencies.rollup != null, "rollup should be in devDependencies"); + }); + + it("rollup version should be >= 4.0.0", () => { + const version = pkg.devDependencies.rollup; + const validMajor4 = /^(?:[\^~]|>=?4(?:\.|$)|>=4\.0\.0|4(?:\.x?|$))/; + assert.ok( + validMajor4.test(version), + `rollup version '${version}' should be >=4.0.0 (e.g. ^4, ~4, 4, 4.x, >=4)`, + ); + }); + + it("should include @rollup/plugin-node-resolve", () => { + assert.ok( + pkg.devDependencies["@rollup/plugin-node-resolve"] != null, + "@rollup/plugin-node-resolve should be in devDependencies", + ); + }); + + it("should include @rollup/plugin-terser", () => { + assert.ok( + pkg.devDependencies["@rollup/plugin-terser"] != null, + "@rollup/plugin-terser should be in devDependencies", + ); + }); + }); +}); + +describe(".gitignore build artifact exclusion", () => { + let gitignoreContent; + + before(() => { + gitignoreContent = readFileSync(path.join(ROOT, ".gitignore"), "utf-8"); + }); + + it("should exclude dist/ from version control", () => { + assert.ok( + gitignoreContent.includes("dist/"), + ".gitignore should contain 'dist/' to exclude the build output directory", + ); + }); + + it("dist/ entry should be on its own line", () => { + const lines = gitignoreContent.split("\n").map((l) => l.trim()); + assert.ok(lines.includes("dist/"), ".gitignore should have 'dist/' as a standalone line entry"); + }); +}); + +describe("CI workflow build step", () => { + let ciYml; + + before(() => { + ciYml = readFileSync(path.join(ROOT, ".github", "workflows", "ci.yml"), "utf-8"); + }); + + it("should contain a build step", () => { + assert.ok(ciYml.includes("Build package"), "ci.yml should include a 'Build package' step"); + }); + + it("build step should run before the test step", () => { + const buildIndex = ciYml.indexOf("Build package"); + const testIndex = ciYml.indexOf("Run tests"); + assert.ok(buildIndex !== -1, "ci.yml should have a Build package step"); + assert.ok(testIndex !== -1, "ci.yml should have a Run tests step"); + assert.ok(buildIndex < testIndex, "Build package step should appear before Run tests step"); + }); + + it("build step should use the matrix package-manager variable", () => { + const buildIndex = ciYml.indexOf("Build package"); + assert.ok(buildIndex !== -1, "ci.yml should have a Build package step"); + const nextStepMatch = ciYml.slice(buildIndex + 1).match(/(?=\n {6}- name:)/); + const endIndex = nextStepMatch ? buildIndex + 1 + nextStepMatch.index : ciYml.length; + const buildStepSection = ciYml.slice(buildIndex, endIndex); + assert.ok( + buildStepSection.includes("matrix.package-manager"), + `Build step should use ${matrix.package - manager} to run build`, + ); + }); + + it("build step should invoke the build command", () => { + const buildIndex = ciYml.indexOf("Build package"); + assert.ok(buildIndex !== -1, "ci.yml should have a Build package step"); + const nextStepMatch = ciYml.slice(buildIndex + 1).match(/(?=\n {6}- name:)/); + const endIndex = nextStepMatch ? buildIndex + 1 + nextStepMatch.index : ciYml.length; + const buildStepSection = ciYml.slice(buildIndex, endIndex); + assert.ok(buildStepSection.includes("run build"), "Build step should run the 'build' script"); + }); + + it("should contain a smoke test step after build", () => { + const smokeTestIndex = ciYml.indexOf("Smoke test built artifact"); + const buildIndex = ciYml.indexOf("Build package"); + assert.ok(smokeTestIndex !== -1, "ci.yml should have a Smoke test built artifact step"); + assert.ok( + smokeTestIndex > buildIndex, + "Smoke test step should appear after Build package step", + ); + }); +}); + +describe("publish workflow build step", () => { + let publishYml; + + before(() => { + publishYml = readFileSync(path.join(ROOT, ".github", "workflows", "publish.yml"), "utf-8"); + }); + + it("should contain a build step", () => { + assert.ok( + publishYml.includes("Build package"), + "publish.yml should include a 'Build package' step", + ); + }); + + it("build step should run before the Configure Git step", () => { + const buildIndex = publishYml.indexOf("Build package"); + const configureGitIndex = publishYml.indexOf("Configure Git"); + assert.ok(buildIndex !== -1, "publish.yml should have a Build package step"); + assert.ok(configureGitIndex !== -1, "publish.yml should have a Configure Git step"); + assert.ok( + buildIndex < configureGitIndex, + "Build package step should appear before Configure Git step", + ); + }); + + it("build step should use pnpm to run build", () => { + const buildStepSection = publishYml.slice( + publishYml.indexOf("Build package"), + publishYml.indexOf("Build package") + 200, + ); + assert.ok( + buildStepSection.includes("pnpm build"), + "publish.yml build step should use 'pnpm build'", + ); + }); + + it("build step should run after tests", () => { + const testIndex = publishYml.indexOf("Run Tests"); + const buildIndex = publishYml.indexOf("Build package"); + assert.ok(testIndex !== -1, "publish.yml should have a Run Tests step"); + assert.ok(buildIndex !== -1, "publish.yml should have a Build package step"); + assert.ok(testIndex < buildIndex, "Run Tests step should appear before Build package step"); + }); +}); diff --git a/src/test/interactive.test.js b/src/test/interactive.test.js index 106383c..ab2b4c4 100644 --- a/src/test/interactive.test.js +++ b/src/test/interactive.test.js @@ -169,7 +169,9 @@ describe("create-next-quick interactive mode", function () { it("should skip installation if feature already exists", (done) => { const firstRunAnswers = ["", "\x1b[B\x1b[B", "", "n"]; - const firstRun = spawn("node", [cliPath, "-i"], { cwd: currentProjectPath }); + const firstRun = spawn("node", [cliPath, "-i"], { + cwd: currentProjectPath, + }); let i = 0; const firstInterval = setInterval(() => { @@ -187,7 +189,9 @@ describe("create-next-quick interactive mode", function () { const secondRunAnswers = ["", "\x1b[B\x1b[B", "", "n"]; - const secondRun = spawn("node", [cliPath, "-i"], { cwd: currentProjectPath }); + const secondRun = spawn("node", [cliPath, "-i"], { + cwd: currentProjectPath, + }); let stdout = ""; secondRun.stdout.on("data", (data) => { diff --git a/src/test/test.js b/src/test/test.js index eead730..f7f2a9c 100644 --- a/src/test/test.js +++ b/src/test/test.js @@ -8,7 +8,7 @@ import { testCases } from "./test-cases.js"; const __filename = fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename); -const cliPath = path.join(__dirname, "..", "index.js"); +const cliPath = path.join(__dirname, "..", "..", "dist", "create-next-quick.js"); describe("create-next-quick", function () { this.timeout(0);