├── 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 |
2 | Hello Nuxt
3 |
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 |
2 |
3 |
4 |
5 |
6 |
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 |
--------------------------------------------------------------------------------