diff --git a/.github/renovate.json b/.github/renovate.json
new file mode 100644
index 0000000..4e8d910
--- /dev/null
+++ b/.github/renovate.json
@@ -0,0 +1,70 @@
+{
+ "$schema": "https://docs.renovatebot.com/renovate-schema.json",
+ "extends": ["config:recommended"],
+ "schedule": ["before 6am on monday"],
+ "timezone": "UTC",
+ "labels": ["dependencies"],
+ "assigneesFromCodeOwners": true,
+ "reviewersFromCodeOwners": true,
+ "lockFileMaintenance": {
+ "enabled": true,
+ "schedule": ["before 6am on monday"]
+ },
+ "packageRules": [
+ {
+ "matchPackageNames": ["svelte", "@sveltejs/kit", "@sveltejs/adapter-static"],
+ "groupName": "svelte core",
+ "schedule": ["before 6am on monday"],
+ "minimumReleaseAge": "3 days"
+ },
+ {
+ "matchPackageNames": ["tailwindcss", "@tailwindcss/vite"],
+ "groupName": "tailwind",
+ "schedule": ["before 6am on monday"]
+ },
+ {
+ "matchPackageNames": [
+ "shadcn-svelte",
+ "@lucide/svelte",
+ "clsx",
+ "tailwind-merge",
+ "tailwind-variants"
+ ],
+ "groupName": "shadcn ecosystem",
+ "schedule": ["before 6am on monday"]
+ },
+ {
+ "matchPackageNames": ["vitest", "@vitest/browser", "playwright", "@playwright/test"],
+ "groupName": "testing tools",
+ "schedule": ["before 6am on monday"]
+ },
+ {
+ "matchPackageNames": ["eslint", "prettier", "typescript"],
+ "groupName": "dev tools",
+ "schedule": ["before 6am on monday"]
+ },
+ {
+ "matchPackageNames": ["vite"],
+ "groupName": "build tools",
+ "schedule": ["before 6am on monday"]
+ },
+ {
+ "matchDepTypes": ["devDependencies"],
+ "automerge": true,
+ "automergeType": "pr",
+ "requiredStatusChecks": null,
+ "matchUpdateTypes": ["patch", "minor"]
+ }
+ ],
+ "vulnerabilityAlerts": {
+ "enabled": true,
+ "schedule": ["at any time"],
+ "dependencyDashboardApproval": false
+ },
+ "dependencyDashboard": true,
+ "dependencyDashboardTitle": "๐ค Dependency Dashboard",
+ "dependencyDashboardLabels": ["dependencies"],
+ "prHourlyLimit": 3,
+ "prConcurrentLimit": 5,
+ "gitignore": ["node_modules/", ".svelte-kit/", "build/", "dist/"]
+}
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 0e93597..5c2c141 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -10,10 +10,6 @@ jobs:
test:
runs-on: ubuntu-latest
- strategy:
- matrix:
- node-version: [20, 22]
-
steps:
- name: Checkout code
uses: actions/checkout@v4
@@ -23,85 +19,22 @@ jobs:
with:
bun-version: '1.2.20'
- - name: Verify Bun installation
- run: bun --version
-
- - name: Cache dependencies
- uses: actions/cache@v4
+ - name: Setup Nushell
+ uses: hustcer/setup-nu@v3
with:
- path: |
- ~/.bun/install/cache
- node_modules
- key: ${{ runner.os }}-bun-${{ hashFiles('**/bun.lock') }}
- restore-keys: |
- ${{ runner.os }}-bun-
+ version: '0.99'
+
+ - name: Setup Just
+ uses: extractions/setup-just@v2
- name: Install dependencies
- run: bun install --frozen-lockfile
-
- - name: Run linting
- run: bun run lint
-
- - name: Run type checking
- run: bun run check
-
- - name: Run unit tests
- run: bun run test:unit --run
+ run: just install
- name: Install Playwright browsers
- run: bunx playwright install --with-deps
+ run: just install-browsers
- - name: Run E2E tests
- run: bun run test:e2e
-
- - name: Upload test results
- uses: actions/upload-artifact@v4
- if: failure()
- with:
- name: test-results-${{ matrix.node-version }}
- path: |
- test-results/
- playwright-report/
- retention-days: 30
-
- build:
- runs-on: ubuntu-latest
- needs: test
-
- steps:
- - name: Checkout code
- uses: actions/checkout@v4
-
- - name: Setup Bun
- uses: oven-sh/setup-bun@v2
- with:
- bun-version: '1.2.20'
-
- - name: Verify Bun installation
- run: bun --version
-
- - name: Cache dependencies
- uses: actions/cache@v4
- with:
- path: |
- ~/.bun/install/cache
- node_modules
- key: ${{ runner.os }}-bun-${{ hashFiles('**/bun.lock') }}
- restore-keys: |
- ${{ runner.os }}-bun-
-
- - name: Install dependencies
- run: bun install --frozen-lockfile
-
- - name: Build application
- run: bun run build
-
- - name: Upload build artifacts
- uses: actions/upload-artifact@v4
- with:
- name: build-files
- path: build/
- retention-days: 7
+ - name: Run CI pipeline
+ run: just ci
security:
runs-on: ubuntu-latest
@@ -115,20 +48,63 @@ jobs:
with:
bun-version: '1.2.20'
- - name: Verify Bun installation
- run: bun --version
+ - name: Setup Nushell
+ uses: hustcer/setup-nu@v3
+ with:
+ version: '0.99'
+
+ - name: Setup Just
+ uses: extractions/setup-just@v2
- name: Install dependencies
- run: bun install --frozen-lockfile
+ run: just install
- name: Run security audit
- run: bun audit
+ run: just audit
continue-on-error: true
- - name: Run CodeQL Analysis
- uses: github/codeql-action/init@v3
+ - name: Run Semgrep security scan
+ uses: semgrep/semgrep-action@v1
with:
- languages: javascript
+ config: >-
+ p/security-audit
+ p/secrets
+ p/owasp-top-ten
+ p/javascript
+ p/typescript
+ generateSarif: '1'
+ # Token only needed for Semgrep Cloud features (optional)
+ env:
+ SEMGREP_APP_TOKEN: ${{ secrets.SEMGREP_APP_TOKEN }}
+ continue-on-error: true
- - name: Perform CodeQL Analysis
- uses: github/codeql-action/analyze@v3
+ docker-build:
+ runs-on: ubuntu-latest
+ needs: [test, security]
+ if: github.ref == 'refs/heads/master'
+
+ steps:
+ - name: Checkout code
+ uses: actions/checkout@v4
+
+ - name: Set up Docker Buildx
+ uses: docker/setup-buildx-action@v2
+
+ - name: Log in to Container Registry
+ uses: docker/login-action@v2
+ with:
+ registry: ${{ vars.DOCKER_REGISTRY }}
+ username: ${{ secrets.DOCKER_USERNAME }}
+ password: ${{ secrets.DOCKER_PASSWORD }}
+
+ - name: Build and push Docker image
+ uses: docker/build-push-action@v4
+ with:
+ context: .
+ platforms: linux/amd64,linux/arm64
+ push: true
+ tags: |
+ ${{ vars.DOCKER_REGISTRY }}/${{ vars.DOCKER_REPOSITORY }}:latest
+ ${{ vars.DOCKER_REGISTRY }}/${{ vars.DOCKER_REPOSITORY }}:${{ github.sha }}
+ cache-from: type=gha
+ cache-to: type=gha,mode=max
diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml
deleted file mode 100644
index e40c8ed..0000000
--- a/.github/workflows/deploy.yml
+++ /dev/null
@@ -1,99 +0,0 @@
-name: Deploy
-
-on:
- push:
- branches: [master]
- workflow_dispatch:
-
-jobs:
- build-and-deploy:
- runs-on: ubuntu-latest
-
- permissions:
- contents: read
- pages: write
- id-token: write
-
- environment:
- name: github-pages
- url: ${{ steps.deployment.outputs.page_url }}
-
- steps:
- - name: Checkout code
- uses: actions/checkout@v4
-
- - name: Setup Bun
- uses: oven-sh/setup-bun@v2
- with:
- bun-version: '1.2.20'
-
- - name: Verify Bun installation
- run: bun --version
-
- - name: Cache dependencies
- uses: actions/cache@v4
- with:
- path: |
- ~/.bun/install/cache
- node_modules
- key: ${{ runner.os }}-bun-${{ hashFiles('**/bun.lock') }}
- restore-keys: |
- ${{ runner.os }}-bun-
-
- - name: Install dependencies
- run: bun install --frozen-lockfile
-
- - name: Build application
- run: bun run build
-
- - name: Setup Pages
- uses: actions/configure-pages@v5
-
- - name: Upload to GitHub Pages
- uses: actions/upload-pages-artifact@v3
- with:
- path: build/
-
- - name: Deploy to GitHub Pages
- id: deployment
- uses: actions/deploy-pages@v4
-
- docker-build:
- runs-on: ubuntu-latest
- if: github.event_name == 'push' && github.ref == 'refs/heads/master'
-
- steps:
- - name: Checkout code
- uses: actions/checkout@v4
-
- - name: Set up Docker Buildx
- uses: docker/setup-buildx-action@v3
-
- - name: Log in to Container Registry
- uses: docker/login-action@v3
- with:
- registry: ghcr.io
- username: ${{ github.actor }}
- password: ${{ secrets.GITHUB_TOKEN }}
-
- - name: Extract metadata
- id: meta
- uses: docker/metadata-action@v5
- with:
- images: ghcr.io/${{ github.repository }}
- tags: |
- type=ref,event=branch
- type=ref,event=pr
- type=sha
- type=raw,value=latest,enable={{is_default_branch}}
-
- - name: Build and push Docker image
- uses: docker/build-push-action@v6
- with:
- context: .
- platforms: linux/amd64,linux/arm64
- push: true
- tags: ${{ steps.meta.outputs.tags }}
- labels: ${{ steps.meta.outputs.labels }}
- cache-from: type=gha
- cache-to: type=gha,mode=max
diff --git a/.github/workflows/gitea-ci.yml b/.github/workflows/gitea-ci.yml
deleted file mode 100644
index 9d3db61..0000000
--- a/.github/workflows/gitea-ci.yml
+++ /dev/null
@@ -1,72 +0,0 @@
-name: Gitea CI
-
-on:
- push:
- branches: [master, develop]
- pull_request:
- branches: [master, develop]
-
-jobs:
- test:
- runs-on: ubuntu-latest
-
- steps:
- - name: Checkout code
- uses: actions/checkout@v4
-
- - name: Setup Bun
- uses: oven-sh/setup-bun@v2
- with:
- bun-version: '1.2.20'
-
- - name: Verify Bun installation
- run: bun --version
-
- - name: Install dependencies
- run: bun install --frozen-lockfile
-
- - name: Run linting
- run: bun run lint
-
- - name: Run type checking
- run: bun run check
-
- - name: Run unit tests
- run: bun run test:unit --run
-
- - name: Install Playwright browsers
- run: bunx playwright install --with-deps
-
- - name: Run E2E tests
- run: bun run test:e2e
-
- docker-build:
- runs-on: ubuntu-latest
- needs: test
- if: github.ref == 'refs/heads/master'
-
- steps:
- - name: Checkout code
- uses: actions/checkout@v4
-
- - name: Set up Docker Buildx
- uses: docker/setup-buildx-action@v2
-
- - name: Log in to Container Registry
- uses: docker/login-action@v2
- with:
- registry: ${{ vars.DOCKER_REGISTRY }}
- username: ${{ secrets.DOCKER_USERNAME }}
- password: ${{ secrets.DOCKER_PASSWORD }}
-
- - name: Build and push Docker image
- uses: docker/build-push-action@v4
- with:
- context: .
- platforms: linux/amd64,linux/arm64
- push: true
- tags: |
- ${{ vars.DOCKER_REGISTRY }}/${{ vars.DOCKER_REPOSITORY }}:latest
- ${{ vars.DOCKER_REGISTRY }}/${{ vars.DOCKER_REPOSITORY }}:${{ github.sha }}
- cache-from: type=gha
- cache-to: type=gha,mode=max
diff --git a/README.md b/README.md
index e2cf4c7..4974298 100644
--- a/README.md
+++ b/README.md
@@ -11,6 +11,8 @@ A modern, production-ready template for building static websites with Svelte 5,
- ๐ **TypeScript** - Type safety out of the box
- ๐งช **Testing Suite** - Vitest for unit tests, Playwright for E2E
- ๐ **Code Quality** - ESLint + Prettier configured
+- ๐ **Security** - Semgrep static analysis + Bun audit
+- ๐ค **Dependencies** - Renovate for automated updates
- ๐ณ **Docker Ready** - Production nginx container
- ๐ **Static Generation** - Optimized for deployment anywhere
@@ -22,6 +24,14 @@ A modern, production-ready template for building static websites with Svelte 5,
# Install dependencies
bun install
+# Install Playwright browsers (for E2E tests)
+just install-browsers
+# OR: bunx playwright install
+
+# Install system dependencies for Playwright (Linux/WSL)
+just install-deps
+# OR: sudo bunx playwright install-deps
+
# Start development server
bun run dev
```
@@ -111,14 +121,30 @@ Production nginx configuration in `nginx.conf` includes:
- Security headers
- SPA routing support
-## Deployment
+## CI/CD & Deployment
+
+### GitHub Actions / Gitea Actions
+
+Single workflow (`.github/workflows/ci.yml`) that runs:
+
+- **Tests & Linting** - Full CI pipeline with Just commands
+- **Security Scanning** - Semgrep static analysis + Bun audit
+- **Docker Build** - Pushes to your container registry
+
+**Required Secrets/Variables:**
+
+- `DOCKER_REGISTRY` - Your container registry URL
+- `DOCKER_REPOSITORY` - Your repository path
+- `DOCKER_USERNAME` / `DOCKER_PASSWORD` - Registry credentials
+- `SEMGREP_APP_TOKEN` - Optional for advanced Semgrep features
+
+### Deployment Options
This template generates a static site that can be deployed to:
-- **Static Hosts**: Netlify, Vercel, GitHub Pages
-- **Docker**: Any container platform (production nginx setup)
-- **CDN**: Any CDN with the built files
-- **Traditional Hosting**: Any web server
+- **Container Platforms** - Docker with nginx (recommended)
+- **Static Hosts** - Netlify, Vercel, any CDN
+- **Traditional Hosting** - Any web server
## Contributing
diff --git a/bun.lock b/bun.lock
index 828dc59..2e7a4ed 100644
--- a/bun.lock
+++ b/bun.lock
@@ -12,7 +12,7 @@
"@sveltejs/kit": "^2.22.0",
"@sveltejs/vite-plugin-svelte": "^6.0.0",
"@tailwindcss/vite": "^4.0.0",
- "@vitest/browser": "^3.2.3",
+ "@vitest/browser": "^3.2.4",
"clsx": "^2.1.1",
"eslint": "^9.18.0",
"eslint-config-prettier": "^10.0.1",
@@ -33,7 +33,7 @@
"vite": "^7.0.4",
"vite-plugin-devtools-json": "^0.2.0",
"vitest": "^3.2.3",
- "vitest-browser-svelte": "^0.1.0",
+ "vitest-browser-svelte": "^1.1.0",
},
},
},
@@ -660,7 +660,7 @@
"vitest": ["vitest@3.2.4", "", { "dependencies": { "@types/chai": "^5.2.2", "@vitest/expect": "3.2.4", "@vitest/mocker": "3.2.4", "@vitest/pretty-format": "^3.2.4", "@vitest/runner": "3.2.4", "@vitest/snapshot": "3.2.4", "@vitest/spy": "3.2.4", "@vitest/utils": "3.2.4", "chai": "^5.2.0", "debug": "^4.4.1", "expect-type": "^1.2.1", "magic-string": "^0.30.17", "pathe": "^2.0.3", "picomatch": "^4.0.2", "std-env": "^3.9.0", "tinybench": "^2.9.0", "tinyexec": "^0.3.2", "tinyglobby": "^0.2.14", "tinypool": "^1.1.1", "tinyrainbow": "^2.0.0", "vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0", "vite-node": "3.2.4", "why-is-node-running": "^2.3.0" }, "peerDependencies": { "@edge-runtime/vm": "*", "@types/debug": "^4.1.12", "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", "@vitest/browser": "3.2.4", "@vitest/ui": "3.2.4", "happy-dom": "*", "jsdom": "*" }, "optionalPeers": ["@edge-runtime/vm", "@types/debug", "@types/node", "@vitest/browser", "@vitest/ui", "happy-dom", "jsdom"], "bin": { "vitest": "vitest.mjs" } }, "sha512-LUCP5ev3GURDysTWiP47wRRUpLKMOfPh+yKTx3kVIEiu5KOMeqzpnYNsKyOoVrULivR8tLcks4+lga33Whn90A=="],
- "vitest-browser-svelte": ["vitest-browser-svelte@0.1.0", "", { "peerDependencies": { "@vitest/browser": "^2.1.0 || ^3.0.0-0", "svelte": ">3.0.0", "vitest": "^2.1.0 || ^3.0.0-0" } }, "sha512-YB6ZUZZQNqU1T9NzvTEDpwpPv35Ng1NZMPBh81zDrLEdOgROGE6nJb79NWb1Eu/a8VkHifqArpOZfJfALge6xQ=="],
+ "vitest-browser-svelte": ["vitest-browser-svelte@1.1.0", "", { "peerDependencies": { "@vitest/browser": "^2.1.0 || ^3.0.0 || ^4.0.0-0", "svelte": "^3 || ^4 || ^5 || ^5.0.0-next.0", "vitest": "^2.1.0 || ^3.0.0 || ^4.0.0-0" } }, "sha512-o98mCzKkWBjvmaGzi69rvyBd1IJ7zFPGI0jcID9vI4F5DmdG//YxkIbeQ7TS27hAVR+MULnBZNja2DUiuUBZyA=="],
"which": ["which@2.0.2", "", { "dependencies": { "isexe": "^2.0.0" }, "bin": { "node-which": "./bin/node-which" } }, "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA=="],
diff --git a/justfile b/justfile
index a19d816..334f565 100644
--- a/justfile
+++ b/justfile
@@ -35,6 +35,14 @@ test-unit:
test-e2e:
bun run test:e2e
+# Install Playwright browsers
+install-browsers:
+ bunx playwright install
+
+# Install Playwright system dependencies (requires sudo)
+install-deps:
+ bunx playwright install-deps
+
# Run tests in watch mode
test-watch:
bun run test:unit --watch
@@ -116,4 +124,4 @@ report:
bun run build --reporter=verbose
echo ""
echo "๐ฆ Build artifacts:"
- ls -la build/
\ No newline at end of file
+ ls -la build/
diff --git a/package.json b/package.json
index 8274b46..ba9455b 100644
--- a/package.json
+++ b/package.json
@@ -25,7 +25,7 @@
"@sveltejs/kit": "^2.22.0",
"@sveltejs/vite-plugin-svelte": "^6.0.0",
"@tailwindcss/vite": "^4.0.0",
- "@vitest/browser": "^3.2.3",
+ "@vitest/browser": "^3.2.4",
"clsx": "^2.1.1",
"eslint": "^9.18.0",
"eslint-config-prettier": "^10.0.1",
@@ -46,6 +46,6 @@
"vite": "^7.0.4",
"vite-plugin-devtools-json": "^0.2.0",
"vitest": "^3.2.3",
- "vitest-browser-svelte": "^0.1.0"
+ "vitest-browser-svelte": "^1.1.0"
}
}
diff --git a/renovate.json b/renovate.json
new file mode 100644
index 0000000..3e6ac92
--- /dev/null
+++ b/renovate.json
@@ -0,0 +1,3 @@
+{
+ "extends": [".github/renovate.json"]
+}
diff --git a/vite.config.ts b/vite.config.ts
index b15c0ae..9e47eef 100644
--- a/vite.config.ts
+++ b/vite.config.ts
@@ -6,7 +6,6 @@ import { defineConfig } from 'vite';
export default defineConfig({
plugins: [tailwindcss(), sveltekit(), devtoolsJson()],
test: {
- expect: { requireAssertions: true },
projects: [
{
extends: './vite.config.ts',
@@ -18,9 +17,7 @@ export default defineConfig({
provider: 'playwright',
instances: [{ browser: 'chromium' }]
},
- include: ['src/**/*.svelte.{test,spec}.{js,ts}'],
- exclude: ['src/lib/server/**'],
- setupFiles: ['./vitest-setup-client.ts']
+ include: ['src/**/*.svelte.{test,spec}.{js,ts}']
}
},
{
diff --git a/vitest-setup-client.ts b/vitest-setup-client.ts
deleted file mode 100644
index 570b9f0..0000000
--- a/vitest-setup-client.ts
+++ /dev/null
@@ -1,2 +0,0 @@
-///
-///