├── public ├── robots.txt └── favicon.ico ├── components ├── HelloNuxt.vue └── HelloNuxt.spec.ts ├── server └── tsconfig.json ├── .prettierrc ├── app.vue ├── tsconfig.json ├── vitest.config.ts ├── .editorconfig ├── .gitignore ├── e2e └── app.test.ts ├── Dockerfile ├── eslint.config.mjs ├── nuxt.config.ts ├── lighthouserc.json ├── package.json ├── README.md └── .github └── workflows └── ci.yml /public/robots.txt: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /components/HelloNuxt.vue: -------------------------------------------------------------------------------- 1 | 4 | -------------------------------------------------------------------------------- /server/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../.nuxt/tsconfig.server.json" 3 | } 4 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Baroshem/nuxt-starter/HEAD/public/favicon.ico -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "singleQuote": true, 3 | "trailingComma": "none", 4 | "semi": false 5 | } 6 | -------------------------------------------------------------------------------- /app.vue: -------------------------------------------------------------------------------- 1 | 7 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | // https://nuxt.com/docs/guide/concepts/typescript 3 | "extends": "./.nuxt/tsconfig.json" 4 | } 5 | -------------------------------------------------------------------------------- /vitest.config.ts: -------------------------------------------------------------------------------- 1 | import { defineVitestConfig } from '@nuxt/test-utils/config' 2 | 3 | export default defineVitestConfig({ 4 | test: { 5 | environment: 'nuxt' 6 | } 7 | }) 8 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | indent_size = 2 5 | indent_style = space 6 | end_of_line = lf 7 | charset = utf-8 8 | trim_trailing_whitespace = true 9 | insert_final_newline = true 10 | 11 | [*.md] 12 | trim_trailing_whitespace = false 13 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Nuxt dev/build outputs 2 | .output 3 | .data 4 | .nuxt 5 | .nitro 6 | .cache 7 | dist 8 | 9 | # Node dependencies 10 | node_modules 11 | 12 | # Logs 13 | logs 14 | *.log 15 | 16 | # Misc 17 | .DS_Store 18 | .fleet 19 | .idea 20 | 21 | # Local env files 22 | .env 23 | .env.* 24 | !.env.example 25 | 26 | # Lighthouse CI 27 | .lighthouseci 28 | -------------------------------------------------------------------------------- /e2e/app.test.ts: -------------------------------------------------------------------------------- 1 | import { setup, $fetch } from '@nuxt/test-utils/e2e' 2 | import { describe, expect, test } from "vitest"; 3 | 4 | const NUXT_TEXT = 'Welcome to Nuxt!' 5 | 6 | describe('app', async () => { 7 | await setup() 8 | 9 | test(`it should have ${NUXT_TEXT} text in the body`, async () => { 10 | const html = await $fetch('/') 11 | 12 | expect(html).toContain(NUXT_TEXT) 13 | }) 14 | }) 15 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | ARG NODE_VERSION=18.20.4 2 | 3 | FROM node:${NODE_VERSION}-slim as base 4 | 5 | ARG PORT=3000 6 | 7 | ENV NODE_ENV=production 8 | 9 | WORKDIR /src 10 | 11 | # Build 12 | FROM base as build 13 | 14 | COPY --link package.json pnpm-lock.yaml ./ 15 | RUN pnpm install 16 | 17 | COPY --link . . 18 | 19 | RUN pnpm run build 20 | 21 | # Run 22 | FROM base 23 | 24 | ENV PORT=$PORT 25 | 26 | COPY --from=build /src/.output /src/.output 27 | 28 | CMD [ "node", ".output/server/index.mjs" ] 29 | -------------------------------------------------------------------------------- /eslint.config.mjs: -------------------------------------------------------------------------------- 1 | import path from "node:path"; 2 | import { fileURLToPath } from "node:url"; 3 | import js from "@eslint/js"; 4 | import { FlatCompat } from "@eslint/eslintrc"; 5 | 6 | const __filename = fileURLToPath(import.meta.url); 7 | const __dirname = path.dirname(__filename); 8 | const compat = new FlatCompat({ 9 | baseDirectory: __dirname, 10 | recommendedConfig: js.configs.recommended, 11 | allConfig: js.configs.all 12 | }); 13 | 14 | export default [{ 15 | ignores: ["**/dist", "**/node_modules"], 16 | }, ...compat.extends()]; 17 | -------------------------------------------------------------------------------- /nuxt.config.ts: -------------------------------------------------------------------------------- 1 | // https://nuxt.com/docs/api/configuration/nuxt-config 2 | export default defineNuxtConfig({ 3 | app: { 4 | head: { 5 | title: 'Nuxt Starter', 6 | meta: [ 7 | { 8 | name: 'description', content: 'Opinionated Nuxt Starter' 9 | } 10 | ], 11 | htmlAttrs: { 12 | lang: 'en' 13 | } 14 | } 15 | }, 16 | compatibilityDate: '2024-04-03', 17 | devtools: { enabled: true }, 18 | modules: [ 19 | '@nuxt/image', 20 | '@nuxtjs/tailwindcss', 21 | 'nuxt-security', 22 | ], 23 | }) 24 | -------------------------------------------------------------------------------- /components/HelloNuxt.spec.ts: -------------------------------------------------------------------------------- 1 | import { describe, expect, it } from "vitest"; 2 | import { mountSuspended } from '@nuxt/test-utils/runtime' 3 | import HelloNuxt from './HelloNuxt.vue' 4 | 5 | describe('HelloNuxt', () => { 6 | it('can mount the component', async () => { 7 | const component = await mountSuspended(HelloNuxt) 8 | expect(component.html()).toBeDefined() 9 | }) 10 | 11 | it('contains p tag and text Hello Nuxt', async () => { 12 | const component = await mountSuspended(HelloNuxt) 13 | expect(component.html()).toBeDefined() 14 | expect(component.html()).toContain('p') 15 | expect(component.html()).toContain('Hello Nuxt') 16 | }) 17 | }) 18 | -------------------------------------------------------------------------------- /lighthouserc.json: -------------------------------------------------------------------------------- 1 | { 2 | "ci": { 3 | "assert": { 4 | "assertions": { 5 | "categories:performance": [ 6 | "error", 7 | { 8 | "minScore": 0.9 9 | } 10 | ], 11 | "categories:accessibility": ["error", { "minScore": 0.9 }], 12 | "categories:seo": ["error", { "minScore": 0.9 }], 13 | "categories:best-practices": ["error", { "minScore": 0.9 }] 14 | } 15 | }, 16 | "collect": { 17 | "staticDistDir": "./.output/public", 18 | "url": [ 19 | "http://localhost:3000/" 20 | ], 21 | "numberOfRuns": 3 22 | }, 23 | "upload": { 24 | "target": "temporary-public-storage" 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "nuxt-starter", 3 | "private": true, 4 | "type": "module", 5 | "scripts": { 6 | "build": "nuxt build", 7 | "dev": "nuxt dev", 8 | "generate": "nuxt generate", 9 | "preview": "nuxt preview", 10 | "postinstall": "nuxt prepare", 11 | "lint": "eslint .", 12 | "test": "vitest run --silent", 13 | "test:watch": "vitest watch", 14 | "lhci": "lhci autorun", 15 | "lhci:desktop": "lhci autorun --collect.settings.preset=desktop" 16 | }, 17 | "dependencies": { 18 | "@nuxt/image": "^1.8.1", 19 | "@nuxtjs/tailwindcss": "^6.12.2", 20 | "nuxt": "^3.13.2", 21 | "nuxt-security": "^2.0.0", 22 | "vue": "latest", 23 | "vue-router": "latest" 24 | }, 25 | "devDependencies": { 26 | "@eslint/eslintrc": "^3.1.0", 27 | "@eslint/js": "^9.11.1", 28 | "@lhci/cli": "^0.14.0", 29 | "eslint": "^9.11.1", 30 | "playwright-core": "^1.47.2", 31 | "@nuxt/test-utils": "^3.14.2", 32 | "@vue/test-utils": "^2.4.6", 33 | "happy-dom": "^15.7.4", 34 | "lint-staged": "^15.2.7", 35 | "vitest": "^2.1.1" 36 | }, 37 | "packageManager": "pnpm@8.11.0+sha512.9df87c16c98db27b4e051d787e67f2207ec47e809ccb07bf7b5ec4acdcd1613355839a38d0b900144923d6a7057700b74d2a0ccb1558beb241647a1206a9a7ab" 38 | } 39 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Nuxt Starter 2 | 3 | This is a Nuxt Starter with several goodies that I have found really useful when I recently had to build several small applications where I was using these additions: 4 | 5 | * Testing with Unit & E2E Setup 6 | * Static code improvements with Linter/Prettier/Editorconfig 7 | * Dockerfile for containerization 8 | * Lighthouse CI for continous Software Quality audits (Performance, SEO, A11Y, Best Practices) 9 | * Useful modules like Image, TailwindCSS, Security 10 | * GitHub Actions Continous Integration script 11 | 12 | Look at the [Nuxt documentation](https://nuxt.com/docs/getting-started/introduction) to learn more. 13 | 14 | ## Setup 15 | 16 | Make sure to install dependencies: 17 | 18 | ```bash 19 | # npm 20 | npm install 21 | 22 | # pnpm 23 | pnpm install 24 | 25 | # yarn 26 | yarn install 27 | 28 | # bun 29 | bun install 30 | ``` 31 | 32 | ## Development Server 33 | 34 | Start the development server on `http://localhost:3000`: 35 | 36 | ```bash 37 | # npm 38 | npm run dev 39 | 40 | # pnpm 41 | pnpm dev 42 | 43 | # yarn 44 | yarn dev 45 | 46 | # bun 47 | bun run dev 48 | ``` 49 | 50 | ## Production 51 | 52 | Build the application for production: 53 | 54 | ```bash 55 | # npm 56 | npm run build 57 | 58 | # pnpm 59 | pnpm build 60 | 61 | # yarn 62 | yarn build 63 | 64 | # bun 65 | bun run build 66 | ``` 67 | 68 | Locally preview production build: 69 | 70 | ```bash 71 | # npm 72 | npm run preview 73 | 74 | # pnpm 75 | pnpm preview 76 | 77 | # yarn 78 | yarn preview 79 | 80 | # bun 81 | bun run preview 82 | ``` 83 | 84 | Check out the [deployment documentation](https://nuxt.com/docs/getting-started/deployment) for more information. 85 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: ci 2 | 3 | on: 4 | push: 5 | branches: 6 | - 'main' 7 | pull_request: 8 | workflow_dispatch: 9 | 10 | jobs: 11 | ci: 12 | runs-on: ${{ matrix.os }} 13 | 14 | strategy: 15 | matrix: 16 | os: [ubuntu-latest] 17 | node: [18] 18 | 19 | steps: 20 | - uses: actions/setup-node@v3 21 | with: 22 | node-version: ${{ matrix.node }} 23 | 24 | - name: checkout 25 | uses: actions/checkout@master 26 | 27 | - name: Setup pnpm 28 | uses: pnpm/action-setup@v4 29 | - name: Use Node.js ${{ matrix.node-version }} 30 | uses: actions/setup-node@v4 31 | with: 32 | node-version: ${{ matrix.node-version }} 33 | cache: pnpm 34 | 35 | - name: cache node_modules 36 | uses: actions/cache@v3 37 | with: 38 | path: node_modules 39 | key: ${{ matrix.os }}-node-v${{ matrix.node }}-deps-${{ hashFiles(format('{0}{1}', github.workspace, '/pnpm-lock.yaml')) }} 40 | 41 | - name: Install dependencies 42 | if: steps.cache.outputs.cache-hit != 'true' 43 | run: pnpm install 44 | 45 | - name: Lint 46 | run: pnpm run lint 47 | 48 | - name: Test 49 | run: pnpm run test 50 | 51 | - name: Generate Project 52 | run: pnpm run generate 53 | 54 | - name: lighthouse mobile audit 55 | run: pnpm run lhci 56 | env: 57 | LHCI_GITHUB_APP_TOKEN: ${{ secrets.LHCI_GITHUB_APP_TOKEN }} 58 | 59 | - name: lighthouse desktop audit 60 | run: pnpm run lhci:desktop 61 | env: 62 | LHCI_GITHUB_APP_TOKEN: ${{ secrets.LHCI_GITHUB_APP_TOKEN }} 63 | --------------------------------------------------------------------------------