├── .eslintrc.js ├── .github ├── ISSUE_TEMPLATE │ ├── generic-bug-report.md │ └── react-bug-report.md ├── actions │ └── setup-env │ │ └── action.yml ├── dependabot.yml ├── pull_request_template.md └── workflows │ ├── release.yml │ └── triage.yml ├── .gitignore ├── .npmrc ├── .prettierignore ├── .vscode ├── extensions.json └── settings.json ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── apps ├── docs │ ├── next-env.d.ts │ ├── next-sitemap.config.js │ ├── next.config.js │ ├── package.json │ ├── pages │ │ ├── _document.tsx │ │ ├── _meta.json │ │ ├── api-docs.mdx │ │ ├── guides │ │ │ ├── _meta.json │ │ │ ├── mpa.mdx │ │ │ ├── policy.mdx │ │ │ └── spa.mdx │ │ ├── index.mdx │ │ └── migrations │ │ │ ├── _meta.json │ │ │ └── v2.mdx │ ├── public │ │ └── logo.png │ ├── theme.config.jsx │ └── tsconfig.json ├── emotion │ ├── .eslintrc.cjs │ ├── index.html │ ├── package.json │ ├── public │ │ └── vite.svg │ ├── src │ │ ├── App.css │ │ ├── App.tsx │ │ ├── assets │ │ │ └── react.svg │ │ ├── components │ │ │ └── StyledExample.tsx │ │ ├── index.css │ │ ├── main.tsx │ │ └── vite-env.d.ts │ ├── tests │ │ ├── main.spec.ts │ │ └── preview-only │ │ │ └── main.spec.ts │ ├── tsconfig.json │ ├── tsconfig.node.json │ └── vite.config.ts ├── less │ ├── .eslintrc.cjs │ ├── index.html │ ├── package.json │ ├── public │ │ └── vite.svg │ ├── src │ │ ├── assets │ │ │ └── react.svg │ │ ├── components │ │ │ ├── App.less │ │ │ ├── App.tsx │ │ │ ├── Button.tsx │ │ │ ├── button.module.less │ │ │ └── variables.less │ │ ├── index.less │ │ ├── main.tsx │ │ └── vite-env.d.ts │ ├── tests │ │ ├── main.spec.ts │ │ └── preview-only │ │ │ └── main.spec.ts │ ├── tsconfig.json │ ├── tsconfig.node.json │ └── vite.config.ts ├── mui │ ├── .eslintrc.cjs │ ├── index.html │ ├── package.json │ ├── public │ │ └── vite.svg │ ├── src │ │ ├── App.tsx │ │ ├── main.tsx │ │ ├── theme.tsx │ │ └── vite-env.d.ts │ ├── tests │ │ ├── main.spec.ts │ │ └── preview-only │ │ │ └── main.spec.ts │ ├── tsconfig.json │ ├── tsconfig.node.json │ └── vite.config.ts ├── preact-app │ ├── index.html │ ├── package.json │ ├── public │ │ └── vite.svg │ ├── src │ │ ├── app.css │ │ ├── app.tsx │ │ ├── assets │ │ │ └── preact.svg │ │ ├── index.css │ │ ├── main.tsx │ │ └── vite-env.d.ts │ ├── tests │ │ ├── main.spec.ts │ │ └── preview-only │ │ │ └── main.spec.ts │ ├── tsconfig.app.json │ ├── tsconfig.json │ ├── tsconfig.node.json │ └── vite.config.ts ├── react │ ├── .eslintrc.cjs │ ├── index.html │ ├── package.json │ ├── public │ │ └── vite.svg │ ├── src │ │ ├── assets │ │ │ └── react.svg │ │ ├── components │ │ │ ├── App.css │ │ │ ├── App.tsx │ │ │ ├── Home.tsx │ │ │ └── Injector.tsx │ │ ├── index.css │ │ ├── main.tsx │ │ └── vite-env.d.ts │ ├── tests │ │ ├── main.spec.ts │ │ └── preview-only │ │ │ └── main.spec.ts │ ├── tsconfig.json │ ├── tsconfig.node.json │ └── vite.config.ts ├── remix-spa │ ├── .eslintrc.cjs │ ├── app │ │ ├── entry.client.tsx │ │ ├── entry.server.tsx │ │ ├── root.tsx │ │ ├── routes │ │ │ └── _index.tsx │ │ └── tailwind.css │ ├── package.json │ ├── postcss.config.js │ ├── public │ │ └── favicon.ico │ ├── tailwind.config.ts │ ├── tsconfig.json │ └── vite.config.ts ├── scss │ ├── .eslintrc.cjs │ ├── index.html │ ├── package.json │ ├── public │ │ └── vite.svg │ ├── src │ │ ├── assets │ │ │ └── react.svg │ │ ├── components │ │ │ ├── App.scss │ │ │ ├── App.tsx │ │ │ ├── Button.tsx │ │ │ ├── button.module.scss │ │ │ └── variables.scss │ │ ├── index.scss │ │ ├── main.tsx │ │ └── vite-env.d.ts │ ├── tests │ │ ├── main.spec.ts │ │ └── preview-only │ │ │ └── main.spec.ts │ ├── tsconfig.json │ ├── tsconfig.node.json │ └── vite.config.ts ├── solid-app │ ├── index.html │ ├── package.json │ ├── public │ │ └── vite.svg │ ├── src │ │ ├── App.css │ │ ├── App.tsx │ │ ├── assets │ │ │ └── solid.svg │ │ ├── index.css │ │ ├── index.tsx │ │ └── vite-env.d.ts │ ├── tests │ │ ├── main.spec.ts │ │ └── preview-only │ │ │ └── main.spec.ts │ ├── tsconfig.app.json │ ├── tsconfig.json │ ├── tsconfig.node.json │ └── vite.config.ts ├── stylus │ ├── .eslintrc.cjs │ ├── index.html │ ├── package.json │ ├── public │ │ └── vite.svg │ ├── src │ │ ├── assets │ │ │ └── react.svg │ │ ├── components │ │ │ ├── App.styl │ │ │ ├── App.tsx │ │ │ ├── Button.tsx │ │ │ ├── button.module.styl │ │ │ └── variables.styl │ │ ├── index.styl │ │ ├── main.tsx │ │ └── vite-env.d.ts │ ├── tests │ │ ├── main.spec.ts │ │ └── preview-only │ │ │ └── main.spec.ts │ ├── tsconfig.json │ ├── tsconfig.node.json │ └── vite.config.ts ├── svelte-app │ ├── index.html │ ├── package.json │ ├── public │ │ └── vite.svg │ ├── src │ │ ├── App.svelte │ │ ├── app.css │ │ ├── assets │ │ │ └── svelte.svg │ │ ├── lib │ │ │ └── Counter.svelte │ │ ├── main.ts │ │ └── vite-env.d.ts │ ├── svelte.config.js │ ├── tests │ │ ├── main.spec.ts │ │ └── preview-only │ │ │ └── main.spec.ts │ ├── tsconfig.json │ ├── tsconfig.node.json │ └── vite.config.ts ├── tailwind │ ├── .eslintrc.cjs │ ├── index.html │ ├── package.json │ ├── postcss.config.js │ ├── public │ │ └── vite.svg │ ├── src │ │ ├── App.tsx │ │ ├── assets │ │ │ └── react.svg │ │ ├── index.css │ │ ├── main.tsx │ │ └── vite-env.d.ts │ ├── tailwind.config.js │ ├── tests │ │ ├── main.spec.ts │ │ └── preview-only │ │ │ └── main.spec.ts │ ├── tsconfig.app.json │ ├── tsconfig.json │ ├── tsconfig.node.json │ └── vite.config.ts ├── tailwind4 │ ├── .eslintrc.cjs │ ├── index.html │ ├── package.json │ ├── public │ │ └── vite.svg │ ├── src │ │ ├── App.tsx │ │ ├── assets │ │ │ └── react.svg │ │ ├── main.tsx │ │ ├── style.css │ │ └── vite-env.d.ts │ ├── tailwind.config.js │ ├── tests │ │ ├── main.spec.ts │ │ └── preview-only │ │ │ └── main.spec.ts │ ├── tsconfig.app.json │ ├── tsconfig.json │ ├── tsconfig.node.json │ └── vite.config.ts ├── vite4 │ ├── .eslintrc.cjs │ ├── index.html │ ├── package.json │ ├── public │ │ └── vite.svg │ ├── src │ │ ├── assets │ │ │ └── react.svg │ │ ├── components │ │ │ ├── App.css │ │ │ ├── App.tsx │ │ │ ├── Home.tsx │ │ │ └── Injector.tsx │ │ ├── index.css │ │ ├── main.tsx │ │ └── vite-env.d.ts │ ├── tests │ │ └── main.spec.ts │ ├── tsconfig.json │ ├── tsconfig.node.json │ └── vite.config.ts ├── vite5 │ ├── .eslintrc.cjs │ ├── index.html │ ├── package.json │ ├── public │ │ └── vite.svg │ ├── src │ │ ├── assets │ │ │ └── react.svg │ │ ├── components │ │ │ ├── App.css │ │ │ ├── App.tsx │ │ │ ├── Home.tsx │ │ │ └── Injector.tsx │ │ ├── index.css │ │ ├── main.tsx │ │ └── vite-env.d.ts │ ├── tests │ │ └── main.spec.ts │ ├── tsconfig.json │ ├── tsconfig.node.json │ └── vite.config.ts ├── vite6 │ ├── .eslintrc.cjs │ ├── index.html │ ├── package.json │ ├── public │ │ └── vite.svg │ ├── src │ │ ├── assets │ │ │ └── react.svg │ │ ├── components │ │ │ ├── App.css │ │ │ ├── App.tsx │ │ │ ├── Home.tsx │ │ │ └── Injector.tsx │ │ ├── index.css │ │ ├── main.tsx │ │ └── vite-env.d.ts │ ├── tests │ │ └── main.spec.ts │ ├── tsconfig.json │ ├── tsconfig.node.json │ └── vite.config.ts ├── vue-app │ ├── .vscode │ │ └── extensions.json │ ├── index.html │ ├── package.json │ ├── public │ │ └── vite.svg │ ├── src │ │ ├── App.vue │ │ ├── assets │ │ │ └── vue.svg │ │ ├── components │ │ │ └── HelloWorld.vue │ │ ├── main.ts │ │ ├── style.css │ │ └── vite-env.d.ts │ ├── tests │ │ ├── main.spec.ts │ │ └── preview-only │ │ │ └── main.spec.ts │ ├── tsconfig.app.json │ ├── tsconfig.json │ ├── tsconfig.node.json │ └── vite.config.ts └── vue-router │ ├── .vscode │ └── extensions.json │ ├── index.html │ ├── package.json │ ├── public │ └── vite.svg │ ├── src │ ├── App.vue │ ├── Bye.vue │ ├── Four.vue │ ├── Hello.vue │ ├── assets │ │ └── vue.svg │ ├── components │ │ └── HelloWorld.vue │ ├── main.ts │ ├── router │ │ └── index.ts │ ├── style.css │ └── vite-env.d.ts │ ├── tests │ ├── main.spec.ts │ └── preview-only │ │ └── main.spec.ts │ ├── tsconfig.app.json │ ├── tsconfig.json │ ├── tsconfig.node.json │ ├── tsconfig.tsbuildinfo │ └── vite.config.ts ├── package.json ├── packages ├── eslint-config │ ├── library.js │ ├── next.js │ ├── package.json │ └── vite-react.js ├── testing │ ├── package.json │ ├── rollup.config.mjs │ ├── src │ │ └── index.ts │ └── tsconfig.json ├── typescript-config │ ├── base.json │ ├── nextjs.json │ ├── node.json │ ├── package.json │ └── vite.json └── vite-plugin-csp-guard │ ├── LICENSE │ ├── README.md │ ├── mocks │ ├── css.ts │ └── post.ts │ ├── package.json │ ├── rollup.config.mjs │ ├── src │ ├── constants.ts │ ├── css │ │ ├── extraction.ts │ │ └── index.ts │ ├── index.ts │ ├── policy │ │ ├── constants.ts │ │ ├── core.ts │ │ └── createPolicy.ts │ ├── transform │ │ ├── constants.ts │ │ ├── handleIndexHtml.ts │ │ ├── index.ts │ │ └── lazy.ts │ ├── types.ts │ └── utils.ts │ ├── tests │ ├── extraction.test.ts │ └── hashing.test.ts │ └── tsconfig.json ├── playwright.config.ts ├── pnpm-lock.yaml ├── pnpm-workspace.yaml ├── scripts ├── cleanup-modules.sh ├── get-package-path.sh ├── hash-file-content.js ├── hash-file-content.sh ├── packages-to-release.sh ├── release.sh └── version-has-changed.sh ├── turbo.json └── turbo └── generators └── config.ts /.eslintrc.js: -------------------------------------------------------------------------------- 1 | // This configuration only applies to the package manager root. 2 | /** @type {import("eslint").Linter.Config} */ 3 | module.exports = { 4 | ignorePatterns: ["apps/**", "packages/**", "scripts/playground/**"], 5 | extends: ["@repo/eslint-config/library.js"], 6 | parser: "@typescript-eslint/parser", 7 | parserOptions: { 8 | project: true, 9 | }, 10 | }; 11 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/generic-bug-report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Generic Bug Report 3 | about: A non framework/library specific bug report 4 | title: "[BUG]" 5 | labels: bug 6 | assignees: tsotimus 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **Expected behaviour** 14 | A clear and concise description of what you expected to happen. 15 | 16 | **Screenshots** 17 | If applicable, add screenshots to help explain your problem. 18 | 19 | **Your setup** 20 | - Vite Version: [e.g. 5.0] 21 | - Frameworks/Librarys [e.g. React, Vue] 22 | - CSS libraries, etc [MUI, SCSS] 23 | 24 | **Additional context** 25 | Add any other context about the problem here. 26 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/react-bug-report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: React Bug Report 3 | about: React specific bug report 4 | title: "[BUG]" 5 | labels: bug, react 6 | assignees: tsotimus 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **Expected behaviour** 14 | A clear and concise description of what you expected to happen. 15 | 16 | **Screenshots** 17 | If applicable, add screenshots to help explain your problem. 18 | 19 | **Your setup** 20 | - Vite Version: [e.g. 5.0] 21 | - React with/without remix 22 | - CSS libraries, etc [MUI, SCSS] 23 | 24 | **Additional context** 25 | Add any other context about the problem here. 26 | -------------------------------------------------------------------------------- /.github/actions/setup-env/action.yml: -------------------------------------------------------------------------------- 1 | name: "Setup Environment" 2 | description: "Sets up Node.js, PNPM, JQ, and TurboRepo" 3 | 4 | inputs: 5 | node-version: 6 | description: "Node.js version" 7 | required: true 8 | default: "20" 9 | 10 | runs: 11 | using: "composite" 12 | steps: 13 | # - name: Checkout code 14 | # uses: actions/checkout@v4 15 | 16 | - name: Setup Node.js 17 | uses: actions/setup-node@v4 18 | with: 19 | node-version: ${{ inputs.node-version }} 20 | 21 | - name: Enable Corepack 22 | run: corepack enable 23 | shell: bash 24 | 25 | - name: Install PNPM 26 | run: pnpm install 27 | shell: bash 28 | 29 | - name: Install JQ 30 | run: sudo apt-get install -y jq 31 | shell: bash -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: "npm" 4 | directory: "/" 5 | schedule: 6 | interval: "weekly" 7 | open-pull-requests-limit: 5 8 | commit-message: 9 | include: scope 10 | prefix: "chore(root-deps)" 11 | prefix-development: "chore" 12 | 13 | - package-ecosystem: "npm" 14 | directories: 15 | - "/apps/*" 16 | schedule: 17 | interval: "weekly" 18 | open-pull-requests-limit: 2 19 | commit-message: 20 | include: scope 21 | prefix: "chore(app-deps)" 22 | prefix-development: "chore" 23 | ignore: 24 | - dependency-name: "typescript" 25 | - dependency-name: "vite" 26 | 27 | - package-ecosystem: "npm" 28 | directories: 29 | - "/packages/*" 30 | schedule: 31 | interval: "weekly" 32 | open-pull-requests-limit: 5 33 | commit-message: 34 | include: scope 35 | prefix: "chore(pkg-deps)" 36 | prefix-development: "chore" 37 | ignore: 38 | - dependency-name: "typescript" 39 | -------------------------------------------------------------------------------- /.github/pull_request_template.md: -------------------------------------------------------------------------------- 1 | # Key Changes 2 | 3 | - Change 1 4 | 5 | ## Approach 6 | 7 | ## Checklist 8 | 9 | - [ ] Tests 10 | - [ ] Documentation 11 | -------------------------------------------------------------------------------- /.github/workflows/triage.yml: -------------------------------------------------------------------------------- 1 | name: PR Workflow 2 | 3 | on: 4 | pull_request: 5 | types: [opened, reopened, synchronize, ready_for_review] 6 | branches: 7 | - main 8 | 9 | jobs: 10 | build: 11 | runs-on: ubuntu-latest 12 | if: github.event.pull_request.draft == false 13 | steps: 14 | - name: Checkout code 15 | uses: actions/checkout@v4 16 | - uses: actions/setup-node@v4 17 | with: 18 | node-version: "23" 19 | - run: node -v 20 | - run: corepack enable 21 | - run: corepack --version 22 | 23 | - run: pnpm install 24 | 25 | - name: Build All Publishable Packages 26 | run: pnpm p:build 27 | 28 | - name: Run Unit Tests 29 | run: pnpm p:test 30 | 31 | - name: Build Apps 32 | run: pnpm build 33 | 34 | - name: Install Playwright Browsers 35 | run: npx playwright install --with-deps chromium 36 | 37 | - name: Run tests 38 | run: pnpm test 39 | - uses: actions/upload-artifact@v4 40 | if: always() 41 | with: 42 | name: playwright-report 43 | path: playwright-report/ 44 | retention-days: 5 45 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # Dependencies 4 | node_modules 5 | .pnp 6 | .pnp.js 7 | 8 | # Local env files 9 | .env 10 | .env.local 11 | .env.development.local 12 | .env.test.local 13 | .env.production.local 14 | 15 | # Testing 16 | coverage 17 | 18 | # Turbo 19 | .turbo 20 | 21 | # Vercel 22 | .vercel 23 | 24 | # Build Outputs 25 | .next/ 26 | out/ 27 | build 28 | dist 29 | 30 | 31 | # Debug 32 | npm-debug.log* 33 | yarn-debug.log* 34 | yarn-error.log* 35 | 36 | # Misc 37 | .DS_Store 38 | *.pem 39 | test-results/ 40 | playwright-report/ 41 | /blob-report/ 42 | /playwright/.cache/ 43 | 44 | 45 | # Ignore scripts playground 46 | scripts/playground/* 47 | 48 | # Temp debug files 49 | apps/**/temp-original-*.js 50 | apps/**/temp-transformed-*.js 51 | 52 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | public-hoist-pattern=@types/stylus -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | scripts/playground/** 2 | 3 | # Ignore artifacts: 4 | build 5 | coverage 6 | dist 7 | 8 | # Ignore all HTML files: 9 | **/*.html -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": ["svelte.svelte-vscode"] 3 | } 4 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "editor.formatOnSave": true, 3 | "editor.codeActionsOnSave": { 4 | "source.fixAll.eslint": true 5 | }, 6 | "editor.defaultFormatter": "esbenp.prettier-vscode", 7 | "typescript.tsdk": "node_modules/typescript/lib", 8 | "typescript.enablePromptUseWorkspaceTsdk": true, 9 | "eslint.workingDirectories": [ 10 | { 11 | "mode": "auto" 12 | } 13 | ] 14 | } 15 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to CSP 2 | 3 | Thank you for your interest in contributing! We welcome all contributions, from bug reports and feature requests to documentation improvements and code enhancements. This guide will help you get started. 4 | 5 | ## Getting Started 6 | 7 | ### Prerequisites 8 | 9 | Make sure you have the following tools installed: 10 | - Node.js 11 | - pnpm (via corepack) 12 | 13 | Run `pnpm install` and you should be good to go! 14 | 15 | ## General Info 16 | All the CSP packages are under `/packages` and these are used inside the vite apps that are housed in `apps` 17 | For development I'd recommend using `pnpm r:dev` which starts up a normal ts-react vite application 18 | 19 | Bear in mind playwright tests run across these applications, so there are some parts of these applications that are crucial to these tests passing. 20 | 21 | ## Submitting your work 22 | - Be on a new branch with a relevent name e.g `fix/react-type-issues` 23 | - Submit your PR filling out the PR Template and linking to any issues you can 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /apps/docs/next-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | 4 | // NOTE: This file should not be edited 5 | // see https://nextjs.org/docs/pages/building-your-application/configuring/typescript for more information. 6 | -------------------------------------------------------------------------------- /apps/docs/next-sitemap.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('next-sitemap').IConfig} */ 2 | module.exports = { 3 | siteUrl: "https://vite-csp.tsotne.co.uk", 4 | generateRobotsTxt: true, // (optional) 5 | generateIndexSitemap: false, 6 | sitemapSize: 100, 7 | output: "export", 8 | additionalPaths: async () => [ 9 | { 10 | loc: "/", 11 | priority: "1.0", 12 | }, 13 | { 14 | loc: "/guides/spa", 15 | priority: 0.9, 16 | }, 17 | { 18 | loc: "/guides/mpa", 19 | priority: 0.9, 20 | }, 21 | { 22 | loc: "/guides/policy", 23 | priority: 0.9, 24 | }, 25 | { 26 | loc: "/api-docs", 27 | priority: 0.6, 28 | }, 29 | { 30 | loc: "/migrations/v2", 31 | priority: 0.6, 32 | }, 33 | ], 34 | }; 35 | -------------------------------------------------------------------------------- /apps/docs/next.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('next').NextConfig} */ 2 | const withNextra = require("nextra")({ 3 | theme: "nextra-theme-docs", 4 | themeConfig: "./theme.config.jsx", 5 | }); 6 | 7 | module.exports = withNextra({ 8 | reactStrictMode: true, 9 | output: "export", 10 | images: { 11 | unoptimized: true, 12 | }, 13 | }); 14 | 15 | // If you have other Next.js configurations, you can pass them as the parameter: 16 | // module.exports = withNextra({ /* other next.js config */ }) 17 | -------------------------------------------------------------------------------- /apps/docs/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "docs", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "dev": "next dev", 7 | "build": "next build", 8 | "postbuild": "next-sitemap", 9 | "preview": "npx serve out -p 3000", 10 | "lint": "next lint" 11 | }, 12 | "dependencies": { 13 | "copy-to-clipboard": "^3.3.3", 14 | "framer-motion": "^11.15.0", 15 | "next": "^14.0.0", 16 | "next-sitemap": "^4.2.3", 17 | "nextra": "^2.13.3", 18 | "nextra-theme-docs": "^2.13.3", 19 | "react": "^18.0.2", 20 | "react-dom": "^18.0.2" 21 | }, 22 | "devDependencies": { 23 | "@types/node": "latest", 24 | "@types/react": "latest", 25 | "eslint": "^8.0.0", 26 | "eslint-config-next": "latest" 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /apps/docs/pages/_document.tsx: -------------------------------------------------------------------------------- 1 | import { Html, Head, Main, NextScript } from "next/document"; 2 | 3 | export default function MyDocument() { 4 | return ( 5 | 6 | 7 | {/* PWA primary color */} 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | ); 17 | } 18 | -------------------------------------------------------------------------------- /apps/docs/pages/_meta.json: -------------------------------------------------------------------------------- 1 | { 2 | "index": { 3 | "title": "Home", 4 | "href": "/" 5 | }, 6 | "guides": { 7 | "title": "Guides", 8 | "href": "/guides" 9 | }, 10 | "migrations": { 11 | "title": "Migrations", 12 | "href": "/migrations" 13 | }, 14 | "api-docs": { 15 | "title": "API", 16 | "href": "/api-docs" 17 | } 18 | } -------------------------------------------------------------------------------- /apps/docs/pages/guides/_meta.json: -------------------------------------------------------------------------------- 1 | { 2 | "spa": { 3 | "title": "SPA", 4 | "href": "/guides/spa" 5 | }, 6 | "mpa": { 7 | "title": "MPA", 8 | "href": "/guides/mpa" 9 | }, 10 | "policy": { 11 | "title": "Creating your Policy", 12 | "href": "/guides/policy" 13 | } 14 | } -------------------------------------------------------------------------------- /apps/docs/pages/guides/mpa.mdx: -------------------------------------------------------------------------------- 1 | import { Callout } from "nextra-theme-docs"; 2 | 3 | # Multi-Page Applications (MPAs) 4 | 5 | 6 | Examples of MPA frameworks include Nuxt, Remix, and others. 7 | 8 | 9 | ## Current Status 10 | 11 | ### The Bad News 12 | The **Vite Plugin CSP Guard** package currently does not support Multi-Page Applications (MPAs). Unfortunately, this limitation is unlikely to change due to the inherent differences between how MPAs operate in Vite. 13 | 14 | ### The Good News 15 | You should be able to use the **CSP Toolkit** to generate a nonce & a CSP policy. Check out the [CSP Toolkit documentation](https://csp-toolkit.tsotne.co.uk) for more information. It has framework specific examples for popular frameworks. 16 | 17 | -------------------------------------------------------------------------------- /apps/docs/pages/migrations/_meta.json: -------------------------------------------------------------------------------- 1 | { 2 | "v2": { 3 | "title": "V2", 4 | "href": "/migrations/v2" 5 | } 6 | } -------------------------------------------------------------------------------- /apps/docs/pages/migrations/v2.mdx: -------------------------------------------------------------------------------- 1 | # Upgrade to V2 2 | 3 | ## Key changes: 4 | 5 | - Support for Vite 6 6 | - Full support for [SRI](https://developer.mozilla.org/en-US/docs/Web/Security/Subresource_Integrity) 7 | 8 | 9 | ## Required changes 10 | 11 | Stop using `build.hash` inside your `vite.config.ts` this has been removed. 12 | Its instead been replaced by `build.sri` -------------------------------------------------------------------------------- /apps/docs/public/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tsotimus/vite-plugin-csp-guard/bd62ed2869dc736d045cb9e03d81968464c95896/apps/docs/public/logo.png -------------------------------------------------------------------------------- /apps/docs/theme.config.jsx: -------------------------------------------------------------------------------- 1 | export default { 2 | logo: Vite CSP Guard, 3 | project: { 4 | link: "https://github.com/tsotimus/vite-plugin-csp-guard", 5 | }, 6 | docsRepositoryBase: "https://github.com/tsotimus/vite-plugin-csp-guard/tree/main/apps/docs", 7 | useNextSeoProps() { 8 | return { 9 | logo: Vite CSP Guard, 10 | titleTemplate: "%s | Vite CSP Guard", 11 | description: "Vite CSP Guard", 12 | openGraph: { 13 | description: "A vite plugin to handle your CSP", 14 | siteName: "Vite CSP Guard", 15 | }, 16 | twitter: {}, 17 | }; 18 | }, 19 | head: <>, 20 | feedback: { 21 | content: null, 22 | }, 23 | footer: { 24 | text: ( 25 | 26 | GPL-3.0 {new Date().getFullYear()} ©{" "} 27 | 28 | Vite CSP Guard{" - "} 29 | 30 | Created by Tsotne 31 | 32 | 33 | ), 34 | }, 35 | darkMode: true, 36 | }; 37 | -------------------------------------------------------------------------------- /apps/docs/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@repo/typescript-config/nextjs.json", 3 | "compilerOptions": { 4 | "plugins": [ 5 | { 6 | "name": "next" 7 | } 8 | ], 9 | "baseUrl": ".", 10 | "paths": { 11 | "@components/*": ["src/components/*"], 12 | "@styles/*": ["src/styles/*"], 13 | "@features/*": ["src/features/*"], 14 | } 15 | }, 16 | "include": [ 17 | "next-env.d.ts", 18 | "next.config.js", 19 | "**/*.ts", 20 | "**/*.tsx", 21 | ".next/types/**/*.ts" 22 | , "pages/index.mdx", ], 23 | "exclude": ["node_modules"] 24 | } 25 | -------------------------------------------------------------------------------- /apps/emotion/.eslintrc.cjs: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | extends: ["@repo/eslint-config/vite-react.js"], 4 | }; 5 | -------------------------------------------------------------------------------- /apps/emotion/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Vite + Emotion 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /apps/emotion/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "emotion", 3 | "private": true, 4 | "version": "0.0.0", 5 | "type": "module", 6 | "scripts": { 7 | "dev": "vite", 8 | "build": "tsc && vite build", 9 | "lint": " tsc && eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0", 10 | "preview": "vite preview" 11 | }, 12 | "dependencies": { 13 | "@emotion/cache": "^11.11.0", 14 | "@emotion/react": "^11.11.4", 15 | "@emotion/styled": "^11.11.5", 16 | "@repo/eslint-config": "workspace:^", 17 | "react": "^18.2.0", 18 | "react-dom": "^18.2.0" 19 | }, 20 | "devDependencies": { 21 | "@repo/typescript-config": "workspace:^", 22 | "@repo/testing": "workspace:^", 23 | "@types/react": "^18.2.66", 24 | "@types/react-dom": "^18.2.22", 25 | "@typescript-eslint/eslint-plugin": "^7.2.0", 26 | "@typescript-eslint/parser": "^7.2.0", 27 | "@vitejs/plugin-react": "^4.3.4", 28 | "eslint": "^8.57.0", 29 | "eslint-plugin-react-hooks": "^4.6.0", 30 | "eslint-plugin-react-refresh": "^0.4.6", 31 | "vite-plugin-csp-guard": "workspace:^" 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /apps/emotion/public/vite.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /apps/emotion/src/App.css: -------------------------------------------------------------------------------- 1 | #root { 2 | max-width: 1280px; 3 | margin: 0 auto; 4 | padding: 2rem; 5 | text-align: center; 6 | } 7 | 8 | .logo { 9 | height: 6em; 10 | padding: 1.5em; 11 | will-change: filter; 12 | transition: filter 300ms; 13 | } 14 | .logo:hover { 15 | filter: drop-shadow(0 0 2em #646cffaa); 16 | } 17 | .logo.react:hover { 18 | filter: drop-shadow(0 0 2em #61dafbaa); 19 | } 20 | 21 | @keyframes logo-spin { 22 | from { 23 | transform: rotate(0deg); 24 | } 25 | to { 26 | transform: rotate(360deg); 27 | } 28 | } 29 | 30 | @media (prefers-reduced-motion: no-preference) { 31 | a:nth-of-type(2) .logo { 32 | animation: logo-spin infinite 20s linear; 33 | } 34 | } 35 | 36 | .card { 37 | padding: 2em; 38 | } 39 | 40 | .read-the-docs { 41 | color: #888; 42 | } 43 | -------------------------------------------------------------------------------- /apps/emotion/src/App.tsx: -------------------------------------------------------------------------------- 1 | import { useState } from "react"; 2 | import reactLogo from "./assets/react.svg"; 3 | import viteLogo from "/vite.svg"; 4 | import "./App.css"; 5 | import StyledExample from "./components/StyledExample"; 6 | 7 | function App() { 8 | const [count, setCount] = useState(0); 9 | 10 | return ( 11 | <> 12 |
13 | 14 | Vite logo 15 | 16 | 17 | React logo 18 | 19 |
20 |

Vite + Emotion

21 |
22 | setCount((count) => count + 1)}> 23 | count is {count} 24 | 25 |

26 | Edit src/App.tsx and save to test HMR 27 |

28 |
29 |

30 | Click on the Vite and React logos to learn more 31 |

32 | 33 | ); 34 | } 35 | 36 | export default App; 37 | -------------------------------------------------------------------------------- /apps/emotion/src/components/StyledExample.tsx: -------------------------------------------------------------------------------- 1 | import styled from "@emotion/styled"; 2 | import { PropsWithChildren } from "react"; 3 | 4 | const Button = styled.button` 5 | color: white; 6 | background-color: red; 7 | padding: 10px; 8 | border: 1px solid black; 9 | cursor: pointer; 10 | &:hover { 11 | color: white; 12 | } 13 | `; 14 | interface StyledExampleProps { 15 | onClick?: () => void 16 | } 17 | const StyledExample = ({children, onClick}:PropsWithChildren) => { 18 | return ; 19 | }; 20 | 21 | export default StyledExample; 22 | -------------------------------------------------------------------------------- /apps/emotion/src/index.css: -------------------------------------------------------------------------------- 1 | :root { 2 | font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif; 3 | line-height: 1.5; 4 | font-weight: 400; 5 | 6 | color-scheme: light dark; 7 | color: rgba(255, 255, 255, 0.87); 8 | background-color: #242424; 9 | 10 | font-synthesis: none; 11 | text-rendering: optimizeLegibility; 12 | -webkit-font-smoothing: antialiased; 13 | -moz-osx-font-smoothing: grayscale; 14 | } 15 | 16 | a { 17 | font-weight: 500; 18 | color: #646cff; 19 | text-decoration: inherit; 20 | } 21 | a:hover { 22 | color: #535bf2; 23 | } 24 | 25 | body { 26 | margin: 0; 27 | display: flex; 28 | place-items: center; 29 | min-width: 320px; 30 | min-height: 100vh; 31 | } 32 | 33 | h1 { 34 | font-size: 3.2em; 35 | line-height: 1.1; 36 | } 37 | 38 | button { 39 | border-radius: 8px; 40 | border: 1px solid transparent; 41 | padding: 0.6em 1.2em; 42 | font-size: 1em; 43 | font-weight: 500; 44 | font-family: inherit; 45 | background-color: #1a1a1a; 46 | cursor: pointer; 47 | transition: border-color 0.25s; 48 | } 49 | button:hover { 50 | border-color: #646cff; 51 | } 52 | button:focus, 53 | button:focus-visible { 54 | outline: 4px auto -webkit-focus-ring-color; 55 | } 56 | 57 | @media (prefers-color-scheme: light) { 58 | :root { 59 | color: #213547; 60 | background-color: #ffffff; 61 | } 62 | a:hover { 63 | color: #747bff; 64 | } 65 | button { 66 | background-color: #f9f9f9; 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /apps/emotion/src/main.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import ReactDOM from "react-dom/client"; 3 | import App from "./App.tsx"; 4 | import "./index.css"; 5 | import { CacheProvider } from "@emotion/react"; 6 | import createCache from "@emotion/cache"; 7 | 8 | const customCache = createCache({ 9 | key: "custom", 10 | insertionPoint: document.getElementById("emotion-cache")!, 11 | }); 12 | 13 | ReactDOM.createRoot(document.getElementById("root")!).render( 14 | 15 | 16 | 17 | 18 | 19 | ); 20 | -------------------------------------------------------------------------------- /apps/emotion/src/vite-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /apps/emotion/tests/main.spec.ts: -------------------------------------------------------------------------------- 1 | import { genericTests, jQueryTest, viteLogoTest } from '@repo/testing'; 2 | 3 | const TITLE = "Vite + Emotion"; 4 | const BTN_COLOUR = "rgb(255, 0, 0)" 5 | const HEADER_COLOUR = "rgb(33, 53, 71)" 6 | 7 | genericTests(TITLE, {headerColour: HEADER_COLOUR, buttonColour: BTN_COLOUR}) 8 | jQueryTest() 9 | viteLogoTest(); 10 | -------------------------------------------------------------------------------- /apps/emotion/tests/preview-only/main.spec.ts: -------------------------------------------------------------------------------- 1 | import { sriTest } from '@repo/testing'; 2 | 3 | sriTest(); 4 | 5 | 6 | -------------------------------------------------------------------------------- /apps/emotion/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@repo/typescript-config/vite", 3 | "include": ["src"], 4 | "references": [{ "path": "./tsconfig.node.json" }] 5 | } 6 | -------------------------------------------------------------------------------- /apps/emotion/tsconfig.node.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/tsconfig", 3 | "extends": "@repo/typescript-config/node", 4 | "compilerOptions": { 5 | "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", 6 | }, 7 | "include": ["vite.config.ts"] 8 | } 9 | -------------------------------------------------------------------------------- /apps/emotion/vite.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig, PluginOption } from "vite"; 2 | import react from "@vitejs/plugin-react"; 3 | import csp from "vite-plugin-csp-guard"; 4 | 5 | // https://vitejs.dev/config/ 6 | export default defineConfig({ 7 | plugins: [ 8 | react() as PluginOption, 9 | csp({ 10 | algorithm: "sha256", 11 | dev: { 12 | run: true, 13 | }, 14 | policy: { 15 | "style-src-elem": ["'self'", "'unsafe-inline'"], 16 | }, 17 | build: { 18 | sri: true, 19 | }, 20 | }), 21 | ], 22 | preview: { 23 | port: 4002, 24 | }, 25 | server: { 26 | port: 3002, 27 | }, 28 | }); 29 | -------------------------------------------------------------------------------- /apps/less/.eslintrc.cjs: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | extends: ["@repo/eslint-config/vite-react.js"], 4 | }; 5 | -------------------------------------------------------------------------------- /apps/less/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Vite + Less 8 | 9 | 10 |
11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /apps/less/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "less", 3 | "private": true, 4 | "version": "0.0.0", 5 | "type": "module", 6 | "scripts": { 7 | "dev": "vite", 8 | "build": "tsc -b && vite build", 9 | "lint": "tsc && eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0", 10 | "preview": "vite preview" 11 | }, 12 | "dependencies": { 13 | "react": "^18.3.1", 14 | "react-dom": "^18.3.1" 15 | }, 16 | "devDependencies": { 17 | "@repo/eslint-config": "workspace:^", 18 | "@repo/typescript-config": "workspace:^", 19 | "@repo/testing": "workspace:^", 20 | "@types/react": "^18.3.3", 21 | "@types/react-dom": "^18.3.0", 22 | "@typescript-eslint/eslint-plugin": "^7.13.1", 23 | "@typescript-eslint/parser": "^7.13.1", 24 | "@vitejs/plugin-react": "^4.3.4", 25 | "eslint": "^8.57.0", 26 | "eslint-plugin-react-hooks": "^4.6.2", 27 | "eslint-plugin-react-refresh": "^0.4.7", 28 | "less": "^4.2.0", 29 | "vite-plugin-csp-guard": "workspace:^" 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /apps/less/public/vite.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /apps/less/src/components/App.less: -------------------------------------------------------------------------------- 1 | #root { 2 | max-width: 1280px; 3 | margin: 0 auto; 4 | padding: 2rem; 5 | text-align: center; 6 | } 7 | 8 | .logo { 9 | height: 6em; 10 | padding: 1.5em; 11 | will-change: filter; 12 | transition: filter 300ms; 13 | } 14 | .logo:hover { 15 | filter: drop-shadow(0 0 2em #646cffaa); 16 | } 17 | .logo.react:hover { 18 | filter: drop-shadow(0 0 2em #61dafbaa); 19 | } 20 | 21 | @keyframes logo-spin { 22 | from { 23 | transform: rotate(0deg); 24 | } 25 | to { 26 | transform: rotate(360deg); 27 | } 28 | } 29 | 30 | @media (prefers-reduced-motion: no-preference) { 31 | a:nth-of-type(2) .logo { 32 | animation: logo-spin infinite 20s linear; 33 | } 34 | } 35 | 36 | .card { 37 | padding: 2em; 38 | } 39 | 40 | .read-the-docs { 41 | color: #888; 42 | } 43 | -------------------------------------------------------------------------------- /apps/less/src/components/App.tsx: -------------------------------------------------------------------------------- 1 | import { useState } from "react"; 2 | import reactLogo from "../assets/react.svg"; 3 | import viteLogo from "/vite.svg"; 4 | import "./App.less"; 5 | import Button from "./Button"; 6 | 7 | function App() { 8 | const [count, setCount] = useState(0); 9 | 10 | return ( 11 | <> 12 | 20 |

Vite + Less

21 |
22 | 25 |

26 | Edit src/App.tsx and save to test HMR 27 |

28 |
29 |

30 | Click on the Vite and React logos to learn more 31 |

32 | 33 | ); 34 | } 35 | 36 | export default App; 37 | -------------------------------------------------------------------------------- /apps/less/src/components/Button.tsx: -------------------------------------------------------------------------------- 1 | import { ButtonHTMLAttributes, PropsWithChildren } from "react"; 2 | import s from "./button.module.less"; 3 | type ButtonProps = ButtonHTMLAttributes; 4 | 5 | const Button = (props: PropsWithChildren) => { 6 | return ( 7 | 10 | ); 11 | }; 12 | 13 | export default Button; 14 | -------------------------------------------------------------------------------- /apps/less/src/components/button.module.less: -------------------------------------------------------------------------------- 1 | @import "variables"; 2 | 3 | .button { 4 | color: white; 5 | background-color: @color-primary; 6 | padding: 1em 2em; 7 | border: 1px solid @color-dark; 8 | } -------------------------------------------------------------------------------- /apps/less/src/components/variables.less: -------------------------------------------------------------------------------- 1 | // Primary Palette 2 | @color-primary: #007bff; 3 | @color-secondary: #6c757d; 4 | @color-success: #28a745; 5 | @color-info: #17a2b8; 6 | @color-warning: #ffc107; 7 | @color-danger: #dc3545; 8 | @color-light: #f8f9fa; 9 | @color-dark: #343a40; 10 | -------------------------------------------------------------------------------- /apps/less/src/index.less: -------------------------------------------------------------------------------- 1 | :root { 2 | font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif; 3 | line-height: 1.5; 4 | font-weight: 400; 5 | 6 | color-scheme: light dark; 7 | color: rgba(255, 255, 255, 0.87); 8 | background-color: #242424; 9 | 10 | font-synthesis: none; 11 | text-rendering: optimizeLegibility; 12 | -webkit-font-smoothing: antialiased; 13 | -moz-osx-font-smoothing: grayscale; 14 | } 15 | 16 | a { 17 | font-weight: 500; 18 | color: #646cff; 19 | text-decoration: inherit; 20 | } 21 | a:hover { 22 | color: #535bf2; 23 | } 24 | 25 | body { 26 | margin: 0; 27 | display: flex; 28 | place-items: center; 29 | min-width: 320px; 30 | min-height: 100vh; 31 | } 32 | 33 | h1 { 34 | font-size: 3.2em; 35 | line-height: 1.1; 36 | } 37 | 38 | button { 39 | border-radius: 8px; 40 | border: 1px solid transparent; 41 | padding: 0.6em 1.2em; 42 | font-size: 1em; 43 | font-weight: 500; 44 | font-family: inherit; 45 | background-color: #1a1a1a; 46 | cursor: pointer; 47 | transition: border-color 0.25s; 48 | } 49 | button:hover { 50 | border-color: #646cff; 51 | } 52 | button:focus, 53 | button:focus-visible { 54 | outline: 4px auto -webkit-focus-ring-color; 55 | } 56 | 57 | @media (prefers-color-scheme: light) { 58 | :root { 59 | color: #213547; 60 | background-color: #ffffff; 61 | } 62 | a:hover { 63 | color: #747bff; 64 | } 65 | button { 66 | background-color: #f9f9f9; 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /apps/less/src/main.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import ReactDOM from "react-dom/client"; 3 | import App from "./components/App.js"; 4 | import "./index.less"; 5 | 6 | ReactDOM.createRoot(document.getElementById("root")!).render( 7 | 8 | 9 | 10 | ); 11 | -------------------------------------------------------------------------------- /apps/less/src/vite-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /apps/less/tests/main.spec.ts: -------------------------------------------------------------------------------- 1 | import { genericTests, viteLogoTest } from '@repo/testing'; 2 | 3 | const TITLE = "Vite + Less"; 4 | const HEADER_COLOUR = "rgb(33, 53, 71)" 5 | const BTN_COLOUR = "rgb(0, 123, 255)" 6 | 7 | genericTests(TITLE, {headerColour: HEADER_COLOUR, buttonColour: BTN_COLOUR}) 8 | viteLogoTest(); 9 | -------------------------------------------------------------------------------- /apps/less/tests/preview-only/main.spec.ts: -------------------------------------------------------------------------------- 1 | import { sriTest } from '@repo/testing'; 2 | 3 | sriTest(); 4 | 5 | 6 | -------------------------------------------------------------------------------- /apps/less/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/tsconfig", 3 | "extends": "@repo/typescript-config/vite", 4 | "include": ["src"], 5 | "compilerOptions": { 6 | "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.tsbuildinfo", 7 | }, 8 | "references": [{ "path": "./tsconfig.node.json" }], 9 | } 10 | -------------------------------------------------------------------------------- /apps/less/tsconfig.node.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/tsconfig", 3 | "extends": "@repo/typescript-config/node", 4 | "compilerOptions": { 5 | "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", 6 | }, 7 | "include": ["vite.config.ts"] 8 | } 9 | -------------------------------------------------------------------------------- /apps/less/vite.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig, PluginOption } from "vite"; 2 | import react from "@vitejs/plugin-react"; 3 | import csp from "vite-plugin-csp-guard"; 4 | 5 | // https://vitejs.dev/config/ 6 | export default defineConfig({ 7 | plugins: [ 8 | react() as PluginOption[], //This is a type assertion due to a monorepo issue regarding stylus, this is not needed in a normal project 9 | csp({ 10 | dev: { 11 | run: true, 12 | outlierSupport: ["less"], 13 | }, 14 | build: { 15 | sri: true, 16 | }, 17 | }) 18 | ], 19 | preview: { 20 | port: 4005, 21 | }, 22 | server: { 23 | port: 3005, 24 | }, 25 | }); 26 | -------------------------------------------------------------------------------- /apps/mui/.eslintrc.cjs: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | extends: ["@repo/eslint-config/vite-react.js"], 4 | }; 5 | -------------------------------------------------------------------------------- /apps/mui/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 14 | Vite + Material UI + TS 15 | 16 | 17 |
18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /apps/mui/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "mui", 3 | "private": true, 4 | "version": "5.0.0", 5 | "type": "module", 6 | "scripts": { 7 | "dev": "vite", 8 | "build": "tsc && vite build", 9 | "lint": "tsc && eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0", 10 | "preview": "vite preview" 11 | }, 12 | "dependencies": { 13 | "@emotion/react": "latest", 14 | "@emotion/styled": "latest", 15 | "@mui/icons-material": "next", 16 | "@mui/material": "next", 17 | "react": "^18.2.0", 18 | "react-dom": "^18.2.0" 19 | }, 20 | "devDependencies": { 21 | "@types/react": "^18.2.66", 22 | "@types/react-dom": "^18.2.22", 23 | "@vitejs/plugin-react": "^4.3.4", 24 | "eslint": "^8.57.0", 25 | "eslint-plugin-react-hooks": "^4.6.0", 26 | "eslint-plugin-react-refresh": "^0.4.6", 27 | "vite-plugin-csp-guard": "workspace:^", 28 | "@repo/typescript-config": "workspace:^", 29 | "@repo/testing": "workspace:^", 30 | "@repo/eslint-config": "workspace:^" 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /apps/mui/public/vite.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /apps/mui/src/App.tsx: -------------------------------------------------------------------------------- 1 | import Container from "@mui/material/Container"; 2 | import Typography from "@mui/material/Typography"; 3 | import Box from "@mui/material/Box"; 4 | import { Button } from "@mui/material"; 5 | import { useState } from "react"; 6 | import viteLogo from "/vite.svg"; 7 | 8 | export default function App() { 9 | 10 | const [count, setCount] = useState(0) 11 | 12 | return ( 13 | 14 | 15 | Vite logo 16 | 21 | Vite + Material UI + TS 22 | 23 | 24 | 25 | 26 | ); 27 | } 28 | -------------------------------------------------------------------------------- /apps/mui/src/main.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import * as ReactDOM from 'react-dom/client'; 3 | import { ThemeProvider } from '@emotion/react'; 4 | import { CssBaseline } from '@mui/material'; 5 | import theme from './theme'; 6 | import App from './App'; 7 | 8 | ReactDOM.createRoot(document.getElementById('root')!).render( 9 | 10 | 11 | 12 | 13 | 14 | , 15 | ); 16 | -------------------------------------------------------------------------------- /apps/mui/src/theme.tsx: -------------------------------------------------------------------------------- 1 | import { createTheme } from '@mui/material/styles'; 2 | import { red } from '@mui/material/colors'; 3 | 4 | // A custom theme for this app 5 | const theme = createTheme({ 6 | palette: { 7 | primary: { 8 | main: '#556cd6', 9 | }, 10 | secondary: { 11 | main: '#19857b', 12 | }, 13 | error: { 14 | main: red.A400, 15 | }, 16 | }, 17 | }); 18 | 19 | export default theme; 20 | -------------------------------------------------------------------------------- /apps/mui/src/vite-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /apps/mui/tests/main.spec.ts: -------------------------------------------------------------------------------- 1 | import { test, expect } from "@playwright/test"; 2 | import { genericTests, jQueryTest, viteLogoTest } from '@repo/testing'; 3 | 4 | const TITLE = "Vite + Material UI + TS"; 5 | const HEADER_COLOUR = "rgb(63, 80, 181)" 6 | const BTN_COLOUR = "rgb(0, 0, 255)" 7 | 8 | genericTests(TITLE, {headerColour: HEADER_COLOUR, buttonColour: BTN_COLOUR}) 9 | viteLogoTest(); 10 | test("Roboto font is loaded", async ({ page }) => { 11 | await page.goto("/"); 12 | 13 | const element = page.getByRole("heading", { name: TITLE }); 14 | await expect(element).toBeVisible(); 15 | 16 | const fontFamily = await element.evaluate( 17 | (el) => window.getComputedStyle(el).fontFamily 18 | ); 19 | 20 | expect(fontFamily).toBe("Roboto, Helvetica, Arial, sans-serif"); 21 | }); 22 | -------------------------------------------------------------------------------- /apps/mui/tests/preview-only/main.spec.ts: -------------------------------------------------------------------------------- 1 | import { sriTest } from '@repo/testing'; 2 | 3 | sriTest(); 4 | 5 | 6 | -------------------------------------------------------------------------------- /apps/mui/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@repo/typescript-config/vite", 3 | "include": ["src"], 4 | "references": [{ "path": "./tsconfig.node.json" }] 5 | } 6 | -------------------------------------------------------------------------------- /apps/mui/tsconfig.node.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/tsconfig", 3 | "extends": "@repo/typescript-config/node", 4 | "compilerOptions": { 5 | "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", 6 | }, 7 | "include": ["vite.config.ts"] 8 | } 9 | -------------------------------------------------------------------------------- /apps/mui/vite.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig, PluginOption } from "vite"; 2 | import react from "@vitejs/plugin-react"; 3 | import csp from "vite-plugin-csp-guard"; 4 | 5 | // https://vitejs.dev/config/ 6 | export default defineConfig({ 7 | plugins: [ 8 | react() as PluginOption, 9 | csp({ 10 | algorithm: "sha256", 11 | dev: { 12 | run: true, 13 | }, 14 | policy: { 15 | "style-src-elem": [ 16 | "'self'", 17 | "https://fonts.googleapis.com", 18 | "'unsafe-inline'", 19 | ], 20 | "font-src": ["'self'", "https://fonts.gstatic.com"], 21 | }, 22 | build: { 23 | sri: true, 24 | }, 25 | }), 26 | ], 27 | preview: { 28 | port: 4001, 29 | }, 30 | server: { 31 | port: 3001, 32 | }, 33 | }); 34 | -------------------------------------------------------------------------------- /apps/preact-app/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Vite + Preact 8 | 9 | 10 |
11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /apps/preact-app/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "preact-app", 3 | "private": true, 4 | "version": "0.0.0", 5 | "type": "module", 6 | "scripts": { 7 | "dev": "vite", 8 | "build": "tsc -b && vite build", 9 | "preview": "vite preview" 10 | }, 11 | "dependencies": { 12 | "preact": "^10.22.1" 13 | }, 14 | "devDependencies": { 15 | "@preact/preset-vite": "^2.8.3", 16 | "vite-plugin-csp-guard": "workspace:^", 17 | "@repo/testing": "workspace:^", 18 | "@repo/typescript-config": "workspace:^" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /apps/preact-app/public/vite.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /apps/preact-app/src/app.css: -------------------------------------------------------------------------------- 1 | #app { 2 | max-width: 1280px; 3 | margin: 0 auto; 4 | padding: 2rem; 5 | text-align: center; 6 | } 7 | 8 | .logo { 9 | height: 6em; 10 | padding: 1.5em; 11 | } 12 | .logo:hover { 13 | filter: drop-shadow(0 0 2em #646cffaa); 14 | } 15 | .logo.preact:hover { 16 | filter: drop-shadow(0 0 2em #673ab8aa); 17 | } 18 | 19 | .card { 20 | padding: 2em; 21 | } 22 | 23 | .read-the-docs { 24 | color: #888; 25 | } 26 | 27 | .button{ 28 | background-color: #673ab8; 29 | color: white; 30 | padding: 1em 2em; 31 | border: none; 32 | border-radius: 0.5em; 33 | font-size: 1em; 34 | cursor: pointer; 35 | } 36 | -------------------------------------------------------------------------------- /apps/preact-app/src/app.tsx: -------------------------------------------------------------------------------- 1 | import { useState } from "preact/hooks"; 2 | import preactLogo from "./assets/preact.svg"; 3 | import viteLogo from "/vite.svg"; 4 | import "./app.css"; 5 | 6 | export function App() { 7 | const [count, setCount] = useState(0); 8 | 9 | return ( 10 | <> 11 | 19 |

Vite + Preact

20 |
21 | 27 |

28 | Edit src/app.tsx and save to test HMR 29 |

30 |
31 |

32 | Check out{" "} 33 | 37 | create-preact 38 | 39 | , the official Preact + Vite starter 40 |

41 |

42 | Click on the Vite and Preact logos to learn more 43 |

44 | 45 | ); 46 | } 47 | -------------------------------------------------------------------------------- /apps/preact-app/src/assets/preact.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /apps/preact-app/src/index.css: -------------------------------------------------------------------------------- 1 | :root { 2 | font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif; 3 | line-height: 1.5; 4 | font-weight: 400; 5 | 6 | color-scheme: light dark; 7 | color: rgba(255, 255, 255, 0.87); 8 | background-color: #242424; 9 | 10 | font-synthesis: none; 11 | text-rendering: optimizeLegibility; 12 | -webkit-font-smoothing: antialiased; 13 | -moz-osx-font-smoothing: grayscale; 14 | } 15 | 16 | a { 17 | font-weight: 500; 18 | color: #646cff; 19 | text-decoration: inherit; 20 | } 21 | a:hover { 22 | color: #535bf2; 23 | } 24 | 25 | body { 26 | margin: 0; 27 | display: flex; 28 | place-items: center; 29 | min-width: 320px; 30 | min-height: 100vh; 31 | } 32 | 33 | h1 { 34 | font-size: 3.2em; 35 | line-height: 1.1; 36 | } 37 | 38 | button { 39 | border-radius: 8px; 40 | border: 1px solid transparent; 41 | padding: 0.6em 1.2em; 42 | font-size: 1em; 43 | font-weight: 500; 44 | font-family: inherit; 45 | background-color: #1a1a1a; 46 | cursor: pointer; 47 | transition: border-color 0.25s; 48 | } 49 | button:hover { 50 | border-color: #646cff; 51 | } 52 | button:focus, 53 | button:focus-visible { 54 | outline: 4px auto -webkit-focus-ring-color; 55 | } 56 | 57 | @media (prefers-color-scheme: light) { 58 | :root { 59 | color: #213547; 60 | background-color: #ffffff; 61 | } 62 | a:hover { 63 | color: #747bff; 64 | } 65 | button { 66 | background-color: #f9f9f9; 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /apps/preact-app/src/main.tsx: -------------------------------------------------------------------------------- 1 | import { render } from 'preact' 2 | import { App } from './app.tsx' 3 | import './index.css' 4 | 5 | render(, document.getElementById('app')!) 6 | -------------------------------------------------------------------------------- /apps/preact-app/src/vite-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /apps/preact-app/tests/main.spec.ts: -------------------------------------------------------------------------------- 1 | import { genericTests, viteLogoTest } from '@repo/testing'; 2 | 3 | const TITLE = "Vite + Preact"; 4 | const HEADER_COLOUR = "rgb(33, 53, 71)" 5 | const BTN_COLOUR = "rgb(103, 58, 184)" 6 | 7 | genericTests(TITLE, {headerColour: HEADER_COLOUR, buttonColour: BTN_COLOUR}) 8 | viteLogoTest(); -------------------------------------------------------------------------------- /apps/preact-app/tests/preview-only/main.spec.ts: -------------------------------------------------------------------------------- 1 | import { sriTest } from '@repo/testing'; 2 | 3 | sriTest(); 4 | 5 | 6 | -------------------------------------------------------------------------------- /apps/preact-app/tsconfig.app.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "composite": true, 4 | "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", 5 | "target": "ES2020", 6 | "useDefineForClassFields": true, 7 | "module": "ESNext", 8 | "lib": ["ES2020", "DOM", "DOM.Iterable"], 9 | "skipLibCheck": true, 10 | "paths": { 11 | "react": ["./node_modules/preact/compat/"], 12 | "react-dom": ["./node_modules/preact/compat/"] 13 | }, 14 | 15 | /* Bundler mode */ 16 | "moduleResolution": "bundler", 17 | "allowImportingTsExtensions": true, 18 | "resolveJsonModule": true, 19 | "isolatedModules": true, 20 | "moduleDetection": "force", 21 | "noEmit": true, 22 | "jsx": "react-jsx", 23 | "jsxImportSource": "preact", 24 | 25 | /* Linting */ 26 | "strict": true, 27 | "noUnusedLocals": true, 28 | "noUnusedParameters": true, 29 | "noFallthroughCasesInSwitch": true 30 | }, 31 | "include": ["src"] 32 | } 33 | -------------------------------------------------------------------------------- /apps/preact-app/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "files": [], 3 | "references": [ 4 | { 5 | "path": "./tsconfig.app.json" 6 | }, 7 | { 8 | "path": "./tsconfig.node.json" 9 | } 10 | ] 11 | } 12 | -------------------------------------------------------------------------------- /apps/preact-app/tsconfig.node.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "composite": true, 4 | "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", 5 | "skipLibCheck": true, 6 | "module": "ESNext", 7 | "moduleResolution": "bundler", 8 | "allowSyntheticDefaultImports": true, 9 | "strict": true, 10 | "noEmit": true 11 | }, 12 | "include": ["vite.config.ts"] 13 | } 14 | -------------------------------------------------------------------------------- /apps/preact-app/vite.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig, PluginOption } from "vite"; 2 | import preact from "@preact/preset-vite"; 3 | import csp from "vite-plugin-csp-guard"; 4 | 5 | // https://vitejs.dev/config/ 6 | export default defineConfig({ 7 | plugins: [ 8 | preact() as PluginOption, 9 | csp({ 10 | dev: { 11 | run: true, 12 | }, 13 | build: { 14 | sri: true, 15 | }, 16 | }) 17 | ], 18 | preview: { 19 | port: 4009, 20 | }, 21 | server: { 22 | port: 3009, 23 | }, 24 | }); 25 | -------------------------------------------------------------------------------- /apps/react/.eslintrc.cjs: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | extends: ["@repo/eslint-config/vite-react.js"], 4 | }; 5 | -------------------------------------------------------------------------------- /apps/react/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Vite + React 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /apps/react/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-app", 3 | "private": true, 4 | "version": "0.0.0", 5 | "type": "module", 6 | "scripts": { 7 | "dev": "vite", 8 | "build": "tsc && vite build", 9 | "lint": "tsc && eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0", 10 | "preview": "vite preview" 11 | }, 12 | "dependencies": { 13 | "@repo/eslint-config": "workspace:^", 14 | "react": "^18.2.0", 15 | "react-dom": "^18.2.0" 16 | }, 17 | "devDependencies": { 18 | "@repo/typescript-config": "workspace:^", 19 | "@repo/testing": "workspace:^", 20 | "@types/react": "^18.2.66", 21 | "@types/react-dom": "^18.2.22", 22 | "@typescript-eslint/eslint-plugin": "^7.2.0", 23 | "@typescript-eslint/parser": "^7.2.0", 24 | "@vitejs/plugin-react": "^4.3.4", 25 | "eslint": "^8.57.0", 26 | "eslint-plugin-react-hooks": "^4.6.0", 27 | "eslint-plugin-react-refresh": "^0.4.6", 28 | "vite-plugin-csp-guard": "workspace:^" 29 | 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /apps/react/public/vite.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /apps/react/src/components/App.css: -------------------------------------------------------------------------------- 1 | #root { 2 | max-width: 1280px; 3 | margin: 0 auto; 4 | padding: 2rem; 5 | text-align: center; 6 | } 7 | 8 | .logo { 9 | height: 6em; 10 | padding: 1.5em; 11 | will-change: filter; 12 | transition: filter 300ms; 13 | } 14 | .logo:hover { 15 | filter: drop-shadow(0 0 2em #646cffaa); 16 | } 17 | .logo.react:hover { 18 | filter: drop-shadow(0 0 2em #61dafbaa); 19 | } 20 | 21 | @keyframes logo-spin { 22 | from { 23 | transform: rotate(0deg); 24 | } 25 | to { 26 | transform: rotate(360deg); 27 | } 28 | } 29 | 30 | @media (prefers-reduced-motion: no-preference) { 31 | a:nth-of-type(2) .logo { 32 | animation: logo-spin infinite 20s linear; 33 | } 34 | } 35 | 36 | .card { 37 | padding: 2em; 38 | } 39 | 40 | .read-the-docs { 41 | color: #888; 42 | } 43 | -------------------------------------------------------------------------------- /apps/react/src/components/App.tsx: -------------------------------------------------------------------------------- 1 | import { useState, lazy } from "react"; 2 | import reactLogo from "../assets/react.svg"; 3 | import viteLogo from "/vite.svg"; 4 | import "./App.css"; 5 | 6 | const Home = lazy(() => import("./Home")); 7 | 8 | function App() { 9 | const [count, setCount] = useState(0); 10 | 11 | return ( 12 | <> 13 | 21 |

Vite + React

22 | 23 |
24 | 27 |

28 | Edit src/App.tsx and save to test HMR 29 |

30 |
31 |

32 | Click on the Vite and React logos to learn more 33 |

34 | 35 | ); 36 | } 37 | 38 | export default App; 39 | -------------------------------------------------------------------------------- /apps/react/src/components/Home.tsx: -------------------------------------------------------------------------------- 1 | import Injector from "./Injector"; 2 | 3 | const Home = () => { 4 | return ( 5 |
6 |

Home

7 | 8 |
9 | ); 10 | }; 11 | 12 | export default Home; 13 | -------------------------------------------------------------------------------- /apps/react/src/components/Injector.tsx: -------------------------------------------------------------------------------- 1 | import { useEffect } from "react"; 2 | 3 | const Injector = () => { 4 | const injectScript = (scriptContent: string) => { 5 | const script = document.createElement("script"); 6 | script.textContent = scriptContent; 7 | script.async = true; 8 | document.body.appendChild(script); 9 | }; 10 | 11 | useEffect(() => { 12 | const scriptContent = ` 13 | // Your inline script code here 14 | console.log('Inline script executed'); 15 | `; 16 | injectScript(scriptContent); 17 | }, []); 18 | 19 | return <>; 20 | }; 21 | 22 | export default Injector; 23 | -------------------------------------------------------------------------------- /apps/react/src/index.css: -------------------------------------------------------------------------------- 1 | :root { 2 | font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif; 3 | line-height: 1.5; 4 | font-weight: 400; 5 | 6 | color-scheme: light dark; 7 | color: rgba(255, 255, 255, 0.87); 8 | background-color: #242424; 9 | 10 | font-synthesis: none; 11 | text-rendering: optimizeLegibility; 12 | -webkit-font-smoothing: antialiased; 13 | -moz-osx-font-smoothing: grayscale; 14 | } 15 | 16 | a { 17 | font-weight: 500; 18 | color: #646cff; 19 | text-decoration: inherit; 20 | } 21 | a:hover { 22 | color: #535bf2; 23 | } 24 | 25 | body { 26 | margin: 0; 27 | display: flex; 28 | place-items: center; 29 | min-width: 320px; 30 | min-height: 100vh; 31 | } 32 | 33 | h1 { 34 | font-size: 3.2em; 35 | line-height: 1.1; 36 | } 37 | 38 | button { 39 | border-radius: 8px; 40 | border: 1px solid transparent; 41 | padding: 0.6em 1.2em; 42 | font-size: 1em; 43 | font-weight: 500; 44 | font-family: inherit; 45 | background-color: #1a1a1a; 46 | cursor: pointer; 47 | transition: border-color 0.25s; 48 | } 49 | button:hover { 50 | border-color: #646cff; 51 | } 52 | button:focus, 53 | button:focus-visible { 54 | outline: 4px auto -webkit-focus-ring-color; 55 | } 56 | 57 | @media (prefers-color-scheme: light) { 58 | :root { 59 | color: #213547; 60 | background-color: #ffffff; 61 | } 62 | a:hover { 63 | color: #747bff; 64 | } 65 | button { 66 | background-color: #f9f9f9; 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /apps/react/src/main.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import ReactDOM from "react-dom/client"; 3 | import App from "./components/App.tsx"; 4 | import "./index.css"; 5 | 6 | ReactDOM.createRoot(document.getElementById("root")!).render( 7 | 8 | 9 | 10 | ); 11 | -------------------------------------------------------------------------------- /apps/react/src/vite-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /apps/react/tests/main.spec.ts: -------------------------------------------------------------------------------- 1 | import { genericTests, jQueryTest, inlineScriptBlockedTest, viteLogoTest } from '@repo/testing'; 2 | 3 | const APP_TITLE = "Vite + React"; 4 | const HEADER_COLOUR = "rgb(33, 53, 71)" 5 | const BTN_COLOUR = "rgb(255, 0, 0)" 6 | 7 | genericTests(APP_TITLE, {headerColour: HEADER_COLOUR, buttonColour: BTN_COLOUR}) 8 | jQueryTest() 9 | viteLogoTest(); 10 | inlineScriptBlockedTest(APP_TITLE) 11 | 12 | -------------------------------------------------------------------------------- /apps/react/tests/preview-only/main.spec.ts: -------------------------------------------------------------------------------- 1 | import { sriTest } from '@repo/testing'; 2 | 3 | sriTest(); 4 | 5 | 6 | -------------------------------------------------------------------------------- /apps/react/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@repo/typescript-config/vite", 3 | "include": ["src"], 4 | "references": [{ "path": "./tsconfig.node.json" }] 5 | } 6 | -------------------------------------------------------------------------------- /apps/react/tsconfig.node.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/tsconfig", 3 | "extends": "@repo/typescript-config/node", 4 | "compilerOptions": { 5 | "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", 6 | }, 7 | "include": ["vite.config.ts",] 8 | } 9 | -------------------------------------------------------------------------------- /apps/react/vite.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig, PluginOption } from "vite"; 2 | import react from "@vitejs/plugin-react"; 3 | import csp from "vite-plugin-csp-guard"; 4 | 5 | // https://vitejs.dev/config/ 6 | export default defineConfig({ 7 | plugins: [ 8 | react() as PluginOption, 9 | csp({ 10 | algorithm: "sha256", 11 | dev: { 12 | run: true, 13 | }, 14 | policy: { 15 | "font-src": ["https://fonts.gstatic.com"], 16 | "connect-src": ["*"], 17 | "object-src": ["'none'"], 18 | }, 19 | build: { 20 | sri: true 21 | }, 22 | }), 23 | ], 24 | preview: { 25 | port: 4000, 26 | }, 27 | server: { 28 | port: 3000, 29 | }, 30 | }); 31 | -------------------------------------------------------------------------------- /apps/remix-spa/app/entry.client.tsx: -------------------------------------------------------------------------------- 1 | /** 2 | * By default, Remix will handle hydrating your app on the client for you. 3 | * You are free to delete this file if you'd like to, but if you ever want it revealed again, you can run `npx remix reveal` ✨ 4 | * For more information, see https://remix.run/file-conventions/entry.client 5 | */ 6 | 7 | import { RemixBrowser } from "@remix-run/react"; 8 | import { startTransition, StrictMode } from "react"; 9 | import { hydrateRoot } from "react-dom/client"; 10 | 11 | startTransition(() => { 12 | hydrateRoot( 13 | document, 14 | 15 | 16 | 17 | ); 18 | }); 19 | -------------------------------------------------------------------------------- /apps/remix-spa/app/root.tsx: -------------------------------------------------------------------------------- 1 | import { 2 | Links, 3 | Meta, 4 | Outlet, 5 | Scripts, 6 | ScrollRestoration, 7 | } from "@remix-run/react"; 8 | import "./tailwind.css"; 9 | 10 | export function Layout({ children }: { children: React.ReactNode }) { 11 | return ( 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | {children} 21 | 22 | 23 | 24 | 25 | ); 26 | } 27 | 28 | export default function App() { 29 | return ; 30 | } 31 | -------------------------------------------------------------------------------- /apps/remix-spa/app/routes/_index.tsx: -------------------------------------------------------------------------------- 1 | import type { MetaFunction } from "@remix-run/node"; 2 | 3 | export const meta: MetaFunction = () => { 4 | return [ 5 | { title: "New Remix App" }, 6 | { name: "description", content: "Welcome to Remix!" }, 7 | ]; 8 | }; 9 | 10 | export default function Index() { 11 | return ( 12 |
13 |

Welcome to Remix

14 | 46 |
47 | ); 48 | } 49 | -------------------------------------------------------------------------------- /apps/remix-spa/app/tailwind.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | -------------------------------------------------------------------------------- /apps/remix-spa/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "remix-spa", 3 | "private": true, 4 | "sideEffects": false, 5 | "type": "module", 6 | "scripts": { 7 | "build": "remix vite:build", 8 | "dev": "remix vite:dev", 9 | "preview": "vite preview", 10 | "lint": "eslint --ignore-path .gitignore --cache --cache-location ./node_modules/.cache/eslint .", 11 | "start": "remix-serve ./build/server/index.js", 12 | "typecheck": "tsc" 13 | }, 14 | "dependencies": { 15 | "@remix-run/node": "^2.16.0", 16 | "@remix-run/react": "^2.16.0", 17 | "@remix-run/serve": "^2.16.0", 18 | "isbot": "^4.1.0", 19 | "react": "^18.2.0", 20 | "react-dom": "^18.2.0" 21 | }, 22 | "devDependencies": { 23 | "@remix-run/dev": "^2.16.0", 24 | "@repo/testing": "workspace:^", 25 | "@repo/typescript-config": "workspace:^", 26 | "@types/react": "^18.2.20", 27 | "@types/react-dom": "^18.2.7", 28 | "@typescript-eslint/eslint-plugin": "^6.7.4", 29 | "@typescript-eslint/parser": "^6.7.4", 30 | "autoprefixer": "^10.4.19", 31 | "eslint": "^8.38.0", 32 | "eslint-import-resolver-typescript": "^3.6.1", 33 | "eslint-plugin-import": "^2.28.1", 34 | "eslint-plugin-jsx-a11y": "^6.7.1", 35 | "eslint-plugin-react": "^7.37.3", 36 | "eslint-plugin-react-hooks": "^4.6.0", 37 | "postcss": "^8.4.38", 38 | "tailwindcss": "^3.4.4", 39 | "vite": "^5.1.0", 40 | "vite-plugin-csp-guard": "workspace:^", 41 | "vite-tsconfig-paths": "^4.2.1" 42 | }, 43 | "engines": { 44 | "node": ">=20.0.0" 45 | } 46 | } -------------------------------------------------------------------------------- /apps/remix-spa/postcss.config.js: -------------------------------------------------------------------------------- 1 | export default { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | }; 7 | -------------------------------------------------------------------------------- /apps/remix-spa/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tsotimus/vite-plugin-csp-guard/bd62ed2869dc736d045cb9e03d81968464c95896/apps/remix-spa/public/favicon.ico -------------------------------------------------------------------------------- /apps/remix-spa/tailwind.config.ts: -------------------------------------------------------------------------------- 1 | import type { Config } from "tailwindcss"; 2 | 3 | export default { 4 | content: ["./app/**/{**,.client,.server}/**/*.{js,jsx,ts,tsx}"], 5 | theme: { 6 | extend: {}, 7 | }, 8 | plugins: [], 9 | } satisfies Config; 10 | -------------------------------------------------------------------------------- /apps/remix-spa/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "include": [ 3 | "**/*.ts", 4 | "**/*.tsx", 5 | "**/.server/**/*.ts", 6 | "**/.server/**/*.tsx", 7 | "**/.client/**/*.ts", 8 | "**/.client/**/*.tsx" 9 | ], 10 | "compilerOptions": { 11 | "lib": ["DOM", "DOM.Iterable", "ES2022"], 12 | "types": ["@remix-run/node", "vite/client"], 13 | "isolatedModules": true, 14 | "esModuleInterop": true, 15 | "jsx": "react-jsx", 16 | "module": "ESNext", 17 | "moduleResolution": "Bundler", 18 | "resolveJsonModule": true, 19 | "target": "ES2022", 20 | "strict": true, 21 | "allowJs": true, 22 | "skipLibCheck": true, 23 | "forceConsistentCasingInFileNames": true, 24 | "baseUrl": ".", 25 | "paths": { 26 | "~/*": ["./app/*"] 27 | }, 28 | 29 | // Vite takes care of building everything, not tsc. 30 | "noEmit": true 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /apps/remix-spa/vite.config.ts: -------------------------------------------------------------------------------- 1 | import { vitePlugin as remix } from "@remix-run/dev"; 2 | import { defineConfig, PluginOption } from "vite"; 3 | import tsconfigPaths from "vite-tsconfig-paths"; 4 | import csp from "vite-plugin-csp-guard"; 5 | 6 | export default defineConfig({ 7 | plugins: [ 8 | remix({ 9 | future: { 10 | v3_fetcherPersist: true, 11 | v3_relativeSplatPath: true, 12 | v3_throwAbortReason: true, 13 | }, 14 | ssr: false, 15 | }), 16 | tsconfigPaths() as PluginOption, 17 | csp({ 18 | dev: { 19 | run: true, 20 | }, 21 | features: { 22 | mpa: true, 23 | }, 24 | }) as PluginOption, 25 | ], 26 | preview: { 27 | port: 4009, 28 | }, 29 | server: { 30 | port: 3009, 31 | }, 32 | }); 33 | -------------------------------------------------------------------------------- /apps/scss/.eslintrc.cjs: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | extends: ["@repo/eslint-config/vite-react.js"], 4 | }; 5 | -------------------------------------------------------------------------------- /apps/scss/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Vite + Sass 8 | 9 | 10 |
11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /apps/scss/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "scss", 3 | "private": true, 4 | "version": "0.0.0", 5 | "type": "module", 6 | "scripts": { 7 | "dev": "vite", 8 | "build": "tsc -b && vite build", 9 | "lint": "tsc && eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0", 10 | "preview": "vite preview" 11 | }, 12 | "dependencies": { 13 | "react": "^18.3.1", 14 | "react-dom": "^18.3.1" 15 | }, 16 | "devDependencies": { 17 | "@repo/typescript-config": "workspace:^", 18 | "@repo/testing": "workspace:^", 19 | "@types/react": "^18.3.3", 20 | "@types/react-dom": "^18.3.0", 21 | "@typescript-eslint/eslint-plugin": "^7.13.1", 22 | "@typescript-eslint/parser": "^7.13.1", 23 | "@vitejs/plugin-react": "^4.3.4", 24 | "eslint": "^8.57.0", 25 | "eslint-plugin-react-hooks": "^4.6.2", 26 | "eslint-plugin-react-refresh": "^0.4.7", 27 | "sass": "^1.77.8", 28 | "vite-plugin-csp-guard": "workspace:^" 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /apps/scss/public/vite.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /apps/scss/src/components/App.scss: -------------------------------------------------------------------------------- 1 | #root { 2 | max-width: 1280px; 3 | margin: 0 auto; 4 | padding: 2rem; 5 | text-align: center; 6 | } 7 | 8 | .logo { 9 | height: 6em; 10 | padding: 1.5em; 11 | will-change: filter; 12 | transition: filter 300ms; 13 | } 14 | .logo:hover { 15 | filter: drop-shadow(0 0 2em #646cffaa); 16 | } 17 | .logo.react:hover { 18 | filter: drop-shadow(0 0 2em #61dafbaa); 19 | } 20 | 21 | @keyframes logo-spin { 22 | from { 23 | transform: rotate(0deg); 24 | } 25 | to { 26 | transform: rotate(360deg); 27 | } 28 | } 29 | 30 | @media (prefers-reduced-motion: no-preference) { 31 | a:nth-of-type(2) .logo { 32 | animation: logo-spin infinite 20s linear; 33 | } 34 | } 35 | 36 | .card { 37 | padding: 2em; 38 | } 39 | 40 | .read-the-docs { 41 | color: #888; 42 | } 43 | -------------------------------------------------------------------------------- /apps/scss/src/components/App.tsx: -------------------------------------------------------------------------------- 1 | import { useState } from "react"; 2 | import reactLogo from "../assets/react.svg"; 3 | import viteLogo from "/vite.svg"; 4 | import "./App.scss"; 5 | import Button from "./Button"; 6 | 7 | function App() { 8 | const [count, setCount] = useState(0); 9 | 10 | return ( 11 | <> 12 | 20 |

Vite + Sass

21 |
22 | 25 |

26 | Edit src/App.tsx and save to test HMR 27 |

28 |
29 |

30 | Click on the Vite and React logos to learn more 31 |

32 | 33 | ); 34 | } 35 | 36 | export default App; 37 | -------------------------------------------------------------------------------- /apps/scss/src/components/Button.tsx: -------------------------------------------------------------------------------- 1 | import { ButtonHTMLAttributes, PropsWithChildren } from "react"; 2 | import s from "./button.module.scss"; 3 | type ButtonProps = ButtonHTMLAttributes; 4 | 5 | const Button = (props: PropsWithChildren) => { 6 | return ( 7 | 10 | ); 11 | }; 12 | 13 | export default Button; 14 | -------------------------------------------------------------------------------- /apps/scss/src/components/button.module.scss: -------------------------------------------------------------------------------- 1 | @import "variables"; 2 | 3 | .button { 4 | color: "white"; 5 | background-color: $color-primary; 6 | padding: 1em 2em; 7 | border: 1px solid $color-dark; 8 | } 9 | -------------------------------------------------------------------------------- /apps/scss/src/components/variables.scss: -------------------------------------------------------------------------------- 1 | // Primary Palette 2 | $color-primary: #007bff; 3 | $color-secondary: #6c757d; 4 | $color-success: #28a745; 5 | $color-info: #17a2b8; 6 | $color-warning: #ffc107; 7 | $color-danger: #dc3545; 8 | $color-light: #f8f9fa; 9 | $color-dark: #343a40; 10 | -------------------------------------------------------------------------------- /apps/scss/src/index.scss: -------------------------------------------------------------------------------- 1 | :root { 2 | font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif; 3 | line-height: 1.5; 4 | font-weight: 400; 5 | 6 | color-scheme: light dark; 7 | color: rgba(255, 255, 255, 0.87); 8 | background-color: #242424; 9 | 10 | font-synthesis: none; 11 | text-rendering: optimizeLegibility; 12 | -webkit-font-smoothing: antialiased; 13 | -moz-osx-font-smoothing: grayscale; 14 | } 15 | 16 | a { 17 | font-weight: 500; 18 | color: #646cff; 19 | text-decoration: inherit; 20 | } 21 | a:hover { 22 | color: #535bf2; 23 | } 24 | 25 | body { 26 | margin: 0; 27 | display: flex; 28 | place-items: center; 29 | min-width: 320px; 30 | min-height: 100vh; 31 | } 32 | 33 | h1 { 34 | font-size: 3.2em; 35 | line-height: 1.1; 36 | } 37 | 38 | button { 39 | border-radius: 8px; 40 | border: 1px solid transparent; 41 | padding: 0.6em 1.2em; 42 | font-size: 1em; 43 | font-weight: 500; 44 | font-family: inherit; 45 | background-color: #1a1a1a; 46 | cursor: pointer; 47 | transition: border-color 0.25s; 48 | } 49 | button:hover { 50 | border-color: #646cff; 51 | } 52 | button:focus, 53 | button:focus-visible { 54 | outline: 4px auto -webkit-focus-ring-color; 55 | } 56 | 57 | @media (prefers-color-scheme: light) { 58 | :root { 59 | color: #213547; 60 | background-color: #ffffff; 61 | } 62 | a:hover { 63 | color: #747bff; 64 | } 65 | button { 66 | background-color: #f9f9f9; 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /apps/scss/src/main.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import ReactDOM from "react-dom/client"; 3 | import App from "./components/App.js"; 4 | import "./index.scss"; 5 | 6 | ReactDOM.createRoot(document.getElementById("root")!).render( 7 | 8 | 9 | 10 | ); 11 | -------------------------------------------------------------------------------- /apps/scss/src/vite-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /apps/scss/tests/main.spec.ts: -------------------------------------------------------------------------------- 1 | import { genericTests, viteLogoTest} from '@repo/testing'; 2 | 3 | const TITLE = "Vite + Sass"; 4 | const BTN_COLOUR = "rgb(0, 123, 255)" 5 | const HEADER_COLOR = "rgb(33, 53, 71)" 6 | 7 | genericTests(TITLE, {headerColour: HEADER_COLOR, buttonColour: BTN_COLOUR}) 8 | viteLogoTest(); 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /apps/scss/tests/preview-only/main.spec.ts: -------------------------------------------------------------------------------- 1 | import { sriTest } from '@repo/testing'; 2 | 3 | sriTest(); 4 | 5 | 6 | -------------------------------------------------------------------------------- /apps/scss/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@repo/typescript-config/vite", 3 | "include": ["src"], 4 | "references": [{ "path": "./tsconfig.node.json" }], 5 | "compilerOptions": { 6 | "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.tsbuildinfo" 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /apps/scss/tsconfig.node.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/tsconfig", 3 | "extends": "@repo/typescript-config/node", 4 | "compilerOptions": { 5 | "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", 6 | }, 7 | "include": ["vite.config.ts"] 8 | } 9 | -------------------------------------------------------------------------------- /apps/scss/vite.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig, PluginOption } from "vite"; 2 | import react from "@vitejs/plugin-react"; 3 | import csp from "vite-plugin-csp-guard"; 4 | 5 | // https://vitejs.dev/config/ 6 | export default defineConfig({ 7 | plugins: [ 8 | react() as PluginOption[], //This is a type assertion due to a monorepo issue regarding stylus, this is not needed in a normal project 9 | csp({ 10 | dev: { 11 | run: true, 12 | outlierSupport: ["sass"], 13 | }, 14 | build: { 15 | sri: true, 16 | }, 17 | }) 18 | ], 19 | preview: { 20 | port: 4004, 21 | }, 22 | server: { 23 | port: 3004, 24 | }, 25 | }); 26 | -------------------------------------------------------------------------------- /apps/solid-app/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Vite + Solid 8 | 9 | 10 |
11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /apps/solid-app/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "solid-app", 3 | "private": true, 4 | "version": "0.0.0", 5 | "type": "module", 6 | "scripts": { 7 | "dev": "vite", 8 | "build": "tsc -b && vite build", 9 | "preview": "vite preview" 10 | }, 11 | "dependencies": { 12 | "solid-js": "^1.8.18" 13 | }, 14 | "devDependencies": { 15 | "vite-plugin-solid": "^2.10.2", 16 | "vite-plugin-csp-guard": "workspace:^", 17 | "@repo/typescript-config": "workspace:^", 18 | "@repo/testing": "workspace:^" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /apps/solid-app/public/vite.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /apps/solid-app/src/App.css: -------------------------------------------------------------------------------- 1 | #root { 2 | max-width: 1280px; 3 | margin: 0 auto; 4 | padding: 2rem; 5 | text-align: center; 6 | } 7 | 8 | .logo { 9 | height: 6em; 10 | padding: 1.5em; 11 | will-change: filter; 12 | transition: filter 300ms; 13 | } 14 | .logo:hover { 15 | filter: drop-shadow(0 0 2em #646cffaa); 16 | } 17 | .logo.solid:hover { 18 | filter: drop-shadow(0 0 2em #61dafbaa); 19 | } 20 | 21 | .card { 22 | padding: 2em; 23 | } 24 | 25 | .read-the-docs { 26 | color: #888; 27 | } 28 | -------------------------------------------------------------------------------- /apps/solid-app/src/App.tsx: -------------------------------------------------------------------------------- 1 | import { createSignal } from 'solid-js' 2 | import solidLogo from './assets/solid.svg' 3 | import viteLogo from '/vite.svg' 4 | import './App.css' 5 | 6 | function App() { 7 | const [count, setCount] = createSignal(0) 8 | 9 | return ( 10 | <> 11 | 19 |

Vite + Solid

20 |
21 | 24 |

25 | Edit src/App.tsx and save to test HMR 26 |

27 |
28 |

29 | Click on the Vite and Solid logos to learn more 30 |

31 | 32 | ) 33 | } 34 | 35 | export default App 36 | -------------------------------------------------------------------------------- /apps/solid-app/src/assets/solid.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /apps/solid-app/src/index.css: -------------------------------------------------------------------------------- 1 | :root { 2 | font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif; 3 | line-height: 1.5; 4 | font-weight: 400; 5 | 6 | color-scheme: light dark; 7 | color: rgba(255, 255, 255, 0.87); 8 | background-color: #242424; 9 | 10 | font-synthesis: none; 11 | text-rendering: optimizeLegibility; 12 | -webkit-font-smoothing: antialiased; 13 | -moz-osx-font-smoothing: grayscale; 14 | } 15 | 16 | a { 17 | font-weight: 500; 18 | color: #646cff; 19 | text-decoration: inherit; 20 | } 21 | a:hover { 22 | color: #535bf2; 23 | } 24 | 25 | body { 26 | margin: 0; 27 | display: flex; 28 | place-items: center; 29 | min-width: 320px; 30 | min-height: 100vh; 31 | } 32 | 33 | h1 { 34 | font-size: 3.2em; 35 | line-height: 1.1; 36 | } 37 | 38 | button { 39 | border-radius: 8px; 40 | border: 1px solid transparent; 41 | padding: 0.6em 1.2em; 42 | font-size: 1em; 43 | font-weight: 500; 44 | font-family: inherit; 45 | background-color: #1a1a1a; 46 | cursor: pointer; 47 | transition: border-color 0.25s; 48 | } 49 | button:hover { 50 | border-color: #646cff; 51 | } 52 | button:focus, 53 | button:focus-visible { 54 | outline: 4px auto -webkit-focus-ring-color; 55 | } 56 | 57 | @media (prefers-color-scheme: light) { 58 | :root { 59 | color: #213547; 60 | background-color: #ffffff; 61 | } 62 | a:hover { 63 | color: #747bff; 64 | } 65 | button { 66 | background-color: #f9f9f9; 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /apps/solid-app/src/index.tsx: -------------------------------------------------------------------------------- 1 | /* @refresh reload */ 2 | import { render } from 'solid-js/web' 3 | 4 | import './index.css' 5 | import App from './App' 6 | 7 | const root = document.getElementById('root') 8 | 9 | render(() => , root!) 10 | -------------------------------------------------------------------------------- /apps/solid-app/src/vite-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /apps/solid-app/tests/main.spec.ts: -------------------------------------------------------------------------------- 1 | import { genericTests, viteLogoTest } from '@repo/testing'; 2 | 3 | const TITLE = "Vite + Solid"; 4 | 5 | 6 | const HEADER_COLOR = "rgb(33, 53, 71)" 7 | const BTN_COLOUR = "rgb(255, 0, 0)" 8 | 9 | genericTests(TITLE, {headerColour: HEADER_COLOR, buttonColour: BTN_COLOUR}) 10 | viteLogoTest(); 11 | -------------------------------------------------------------------------------- /apps/solid-app/tests/preview-only/main.spec.ts: -------------------------------------------------------------------------------- 1 | import { sriTest } from '@repo/testing'; 2 | 3 | sriTest(); 4 | 5 | 6 | -------------------------------------------------------------------------------- /apps/solid-app/tsconfig.app.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "composite": true, 4 | "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", 5 | "target": "ES2020", 6 | "useDefineForClassFields": true, 7 | "module": "ESNext", 8 | "lib": ["ES2020", "DOM", "DOM.Iterable"], 9 | "skipLibCheck": true, 10 | 11 | /* Bundler mode */ 12 | "moduleResolution": "bundler", 13 | "allowImportingTsExtensions": true, 14 | "resolveJsonModule": true, 15 | "isolatedModules": true, 16 | "moduleDetection": "force", 17 | "noEmit": true, 18 | "jsx": "preserve", 19 | "jsxImportSource": "solid-js", 20 | 21 | /* Linting */ 22 | "strict": true, 23 | "noUnusedLocals": true, 24 | "noUnusedParameters": true, 25 | "noFallthroughCasesInSwitch": true 26 | }, 27 | "include": ["src"] 28 | } 29 | -------------------------------------------------------------------------------- /apps/solid-app/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "files": [], 3 | "references": [ 4 | { 5 | "path": "./tsconfig.app.json" 6 | }, 7 | { 8 | "path": "./tsconfig.node.json" 9 | } 10 | ] 11 | } 12 | -------------------------------------------------------------------------------- /apps/solid-app/tsconfig.node.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "composite": true, 4 | "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", 5 | "skipLibCheck": true, 6 | "module": "ESNext", 7 | "moduleResolution": "bundler", 8 | "allowSyntheticDefaultImports": true, 9 | "strict": true, 10 | "noEmit": true 11 | }, 12 | "include": ["vite.config.ts"] 13 | } 14 | -------------------------------------------------------------------------------- /apps/solid-app/vite.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig, PluginOption } from "vite"; 2 | import solid from "vite-plugin-solid"; 3 | import csp from "vite-plugin-csp-guard"; 4 | 5 | export default defineConfig({ 6 | plugins: [ 7 | solid() as PluginOption, 8 | csp({ dev: { run: true }, build: { sri: true } }) as PluginOption, 9 | ], 10 | preview: { 11 | port: 4010, 12 | }, 13 | server: { 14 | port: 3010, 15 | }, 16 | }); 17 | -------------------------------------------------------------------------------- /apps/stylus/.eslintrc.cjs: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | extends: ["@repo/eslint-config/vite-react.js"], 4 | }; 5 | -------------------------------------------------------------------------------- /apps/stylus/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Vite + Stylus 8 | 9 | 10 |
11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /apps/stylus/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "stylus", 3 | "private": true, 4 | "version": "0.0.0", 5 | "type": "module", 6 | "scripts": { 7 | "dev": "vite", 8 | "build": "tsc -b && vite build", 9 | "lint": "tsc && eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0", 10 | "preview": "vite preview" 11 | }, 12 | "dependencies": { 13 | "@repo/eslint-config": "workspace:^", 14 | "react": "^18.3.1", 15 | "react-dom": "^18.3.1" 16 | }, 17 | "devDependencies": { 18 | "@repo/typescript-config": "workspace:^", 19 | "@repo/testing": "workspace:^", 20 | "@types/react": "^18.3.3", 21 | "@types/react-dom": "^18.3.0", 22 | "@typescript-eslint/eslint-plugin": "^7.13.1", 23 | "@typescript-eslint/parser": "^7.13.1", 24 | "@vitejs/plugin-react": "^4.3.4", 25 | "eslint": "^8.57.0", 26 | "eslint-plugin-react-hooks": "^4.6.2", 27 | "eslint-plugin-react-refresh": "^0.4.7", 28 | "stylus": "^0.63.0", 29 | "vite-plugin-csp-guard": "workspace:^" 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /apps/stylus/public/vite.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /apps/stylus/src/components/App.styl: -------------------------------------------------------------------------------- 1 | #root { 2 | max-width: 1280px; 3 | margin: 0 auto; 4 | padding: 2rem; 5 | text-align: center; 6 | } 7 | 8 | .logo { 9 | height: 6em; 10 | padding: 1.5em; 11 | will-change: filter; 12 | transition: filter 300ms; 13 | } 14 | .logo:hover { 15 | filter: drop-shadow(0 0 2em #646cffaa); 16 | } 17 | .logo.react:hover { 18 | filter: drop-shadow(0 0 2em #61dafbaa); 19 | } 20 | 21 | @keyframes logo-spin { 22 | from { 23 | transform: rotate(0deg); 24 | } 25 | to { 26 | transform: rotate(360deg); 27 | } 28 | } 29 | 30 | @media (prefers-reduced-motion: no-preference) { 31 | a:nth-of-type(2) .logo { 32 | animation: logo-spin infinite 20s linear; 33 | } 34 | } 35 | 36 | .card { 37 | padding: 2em; 38 | } 39 | 40 | .read-the-docs { 41 | color: #888; 42 | } 43 | -------------------------------------------------------------------------------- /apps/stylus/src/components/App.tsx: -------------------------------------------------------------------------------- 1 | import { useState } from "react"; 2 | import reactLogo from "../assets/react.svg"; 3 | import viteLogo from "/vite.svg"; 4 | import "./App.styl"; 5 | import Button from "./Button"; 6 | 7 | function App() { 8 | const [count, setCount] = useState(0); 9 | 10 | return ( 11 | <> 12 | 20 |

Vite + Stylus

21 |
22 | 25 |

26 | Edit src/App.tsx and save to test HMR 27 |

28 |
29 |

30 | Click on the Vite and React logos to learn more 31 |

32 | 33 | ); 34 | } 35 | 36 | export default App; 37 | -------------------------------------------------------------------------------- /apps/stylus/src/components/Button.tsx: -------------------------------------------------------------------------------- 1 | import { ButtonHTMLAttributes, PropsWithChildren } from "react"; 2 | import s from "./button.module.styl"; 3 | type ButtonProps = ButtonHTMLAttributes; 4 | 5 | const Button = (props: PropsWithChildren) => { 6 | return ( 7 | 10 | ); 11 | }; 12 | 13 | export default Button; 14 | -------------------------------------------------------------------------------- /apps/stylus/src/components/button.module.styl: -------------------------------------------------------------------------------- 1 | @import 'variables.styl' 2 | 3 | .button 4 | color: white 5 | background-color: color-primary 6 | padding: 1em 2em 7 | border: 1px solid color-dark 8 | -------------------------------------------------------------------------------- /apps/stylus/src/components/variables.styl: -------------------------------------------------------------------------------- 1 | // Primary Palette 2 | color-primary = #007bff 3 | color-secondary = #6c757d 4 | color-success = #28a745 5 | color-info = #17a2b8 6 | color-warning = #ffc107 7 | color-danger = #dc3545 8 | color-light = #f8f9fa 9 | color-dark = #343a40 -------------------------------------------------------------------------------- /apps/stylus/src/index.styl: -------------------------------------------------------------------------------- 1 | :root { 2 | font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif; 3 | line-height: 1.5; 4 | font-weight: 400; 5 | 6 | color-scheme: light dark; 7 | color: rgba(255, 255, 255, 0.87); 8 | background-color: #242424; 9 | 10 | font-synthesis: none; 11 | text-rendering: optimizeLegibility; 12 | -webkit-font-smoothing: antialiased; 13 | -moz-osx-font-smoothing: grayscale; 14 | } 15 | 16 | a { 17 | font-weight: 500; 18 | color: #646cff; 19 | text-decoration: inherit; 20 | } 21 | a:hover { 22 | color: #535bf2; 23 | } 24 | 25 | body { 26 | margin: 0; 27 | display: flex; 28 | place-items: center; 29 | min-width: 320px; 30 | min-height: 100vh; 31 | } 32 | 33 | h1 { 34 | font-size: 3.2em; 35 | line-height: 1.1; 36 | } 37 | 38 | button { 39 | border-radius: 8px; 40 | border: 1px solid transparent; 41 | padding: 0.6em 1.2em; 42 | font-size: 1em; 43 | font-weight: 500; 44 | font-family: inherit; 45 | background-color: #1a1a1a; 46 | cursor: pointer; 47 | transition: border-color 0.25s; 48 | } 49 | button:hover { 50 | border-color: #646cff; 51 | } 52 | button:focus, 53 | button:focus-visible { 54 | outline: 4px auto -webkit-focus-ring-color; 55 | } 56 | 57 | @media (prefers-color-scheme: light) { 58 | :root { 59 | color: #213547; 60 | background-color: #ffffff; 61 | } 62 | a:hover { 63 | color: #747bff; 64 | } 65 | button { 66 | background-color: #f9f9f9; 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /apps/stylus/src/main.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import ReactDOM from "react-dom/client"; 3 | import App from "./components/App.js"; 4 | import "./index.styl"; 5 | 6 | ReactDOM.createRoot(document.getElementById("root")!).render( 7 | 8 | 9 | 10 | ); 11 | -------------------------------------------------------------------------------- /apps/stylus/src/vite-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /apps/stylus/tests/main.spec.ts: -------------------------------------------------------------------------------- 1 | import { genericTests, viteLogoTest } from '@repo/testing'; 2 | 3 | const TITLE = "Vite + Stylus"; 4 | const BTN_COLOUR = "rgb(0, 123, 255)" 5 | const HEADER_COLOR = "rgb(33, 53, 71)" 6 | 7 | genericTests(TITLE, {headerColour: HEADER_COLOR, buttonColour: BTN_COLOUR}) 8 | viteLogoTest(); -------------------------------------------------------------------------------- /apps/stylus/tests/preview-only/main.spec.ts: -------------------------------------------------------------------------------- 1 | import { sriTest } from '@repo/testing'; 2 | 3 | sriTest(); 4 | 5 | 6 | -------------------------------------------------------------------------------- /apps/stylus/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@repo/typescript-config/vite", 3 | "include": ["src"], 4 | "references": [{ "path": "./tsconfig.node.json" }], 5 | "compilerOptions": { 6 | "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.tsbuildinfo", 7 | }, 8 | } 9 | -------------------------------------------------------------------------------- /apps/stylus/tsconfig.node.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/tsconfig", 3 | "extends": "@repo/typescript-config/node", 4 | "compilerOptions": { 5 | "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", 6 | }, 7 | "include": ["vite.config.ts"] 8 | } 9 | -------------------------------------------------------------------------------- /apps/stylus/vite.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig, PluginOption } from "vite"; 2 | import react from "@vitejs/plugin-react"; 3 | import csp from "vite-plugin-csp-guard"; 4 | 5 | // https://vitejs.dev/config/ 6 | export default defineConfig({ 7 | plugins: [ 8 | react() as PluginOption[], //This is a type assertion due to a monorepo issue regarding stylus, this is not needed in a normal project 9 | csp({ 10 | dev: { 11 | run: true, 12 | outlierSupport: ["stylus"], 13 | }, 14 | build: { 15 | sri: true, 16 | }, 17 | }), 18 | ], 19 | preview: { 20 | port: 4006, 21 | }, 22 | server: { 23 | port: 3006, 24 | }, 25 | }); 26 | -------------------------------------------------------------------------------- /apps/svelte-app/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Vite + Svelte 8 | 9 | 10 |
11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /apps/svelte-app/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "svelte-app", 3 | "private": true, 4 | "version": "0.0.0", 5 | "type": "module", 6 | "scripts": { 7 | "dev": "vite", 8 | "build": "vite build", 9 | "preview": "vite preview", 10 | "check": "svelte-check --tsconfig ./tsconfig.json && tsc -p tsconfig.node.json" 11 | }, 12 | "devDependencies": { 13 | "@repo/typescript-config": "workspace:^", 14 | "@repo/testing": "workspace:^", 15 | "@sveltejs/vite-plugin-svelte": "^3.1.1", 16 | "@tsconfig/svelte": "^5.0.4", 17 | "svelte": "^4.2.18", 18 | "svelte-check": "^4.1.1", 19 | "tslib": "^2.6.3", 20 | "vite": "^5.0.0", 21 | "vite-plugin-csp-guard": "workspace:^" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /apps/svelte-app/public/vite.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /apps/svelte-app/src/App.svelte: -------------------------------------------------------------------------------- 1 | 6 | 7 |
8 | 16 |

Vite + Svelte

17 | 18 |
19 | 20 |
21 | 22 |

23 | Check out SvelteKit, the official Svelte app framework powered by Vite! 24 |

25 | 26 |

27 | Click on the Vite and Svelte logos to learn more 28 |

29 |
30 | 31 | 48 | -------------------------------------------------------------------------------- /apps/svelte-app/src/lib/Counter.svelte: -------------------------------------------------------------------------------- 1 | 7 | 8 | 11 | 12 | 26 | -------------------------------------------------------------------------------- /apps/svelte-app/src/main.ts: -------------------------------------------------------------------------------- 1 | import './app.css' 2 | import App from './App.svelte' 3 | 4 | const app = new App({ 5 | target: document.getElementById('app')!, 6 | }) 7 | 8 | export default app 9 | -------------------------------------------------------------------------------- /apps/svelte-app/src/vite-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | -------------------------------------------------------------------------------- /apps/svelte-app/svelte.config.js: -------------------------------------------------------------------------------- 1 | import { vitePreprocess } from '@sveltejs/vite-plugin-svelte' 2 | 3 | export default { 4 | // Consult https://svelte.dev/docs#compile-time-svelte-preprocess 5 | // for more information about preprocessors 6 | preprocess: vitePreprocess(), 7 | } 8 | -------------------------------------------------------------------------------- /apps/svelte-app/tests/main.spec.ts: -------------------------------------------------------------------------------- 1 | import { genericTests,viteLogoTest } from '@repo/testing'; 2 | 3 | const TITLE = "Vite + Svelte"; 4 | 5 | const BTN_COLOUR = "rgb(255, 62, 0)" 6 | const HEADER_COLOR = "rgb(33, 53, 71)" 7 | 8 | genericTests(TITLE, {headerColour: HEADER_COLOR, buttonColour: BTN_COLOUR}) 9 | viteLogoTest() -------------------------------------------------------------------------------- /apps/svelte-app/tests/preview-only/main.spec.ts: -------------------------------------------------------------------------------- 1 | import { sriTest } from '@repo/testing'; 2 | 3 | sriTest(); 4 | 5 | 6 | -------------------------------------------------------------------------------- /apps/svelte-app/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@tsconfig/svelte/tsconfig.json", 3 | "compilerOptions": { 4 | "target": "ESNext", 5 | "useDefineForClassFields": true, 6 | "module": "ESNext", 7 | "resolveJsonModule": true, 8 | /** 9 | * Typecheck JS in `.svelte` and `.js` files by default. 10 | * Disable checkJs if you'd like to use dynamic types in JS. 11 | * Note that setting allowJs false does not prevent the use 12 | * of JS in `.svelte` files. 13 | */ 14 | "allowJs": true, 15 | "checkJs": true, 16 | "isolatedModules": true, 17 | "moduleDetection": "force" 18 | }, 19 | "include": ["src/**/*.ts", "src/**/*.js", "src/**/*.svelte"], 20 | "references": [{ "path": "./tsconfig.node.json" }] 21 | } 22 | -------------------------------------------------------------------------------- /apps/svelte-app/tsconfig.node.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "composite": true, 4 | "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", 5 | "skipLibCheck": true, 6 | "module": "ESNext", 7 | "moduleResolution": "bundler", 8 | "strict": true, 9 | }, 10 | "include": ["vite.config.ts"] 11 | } 12 | -------------------------------------------------------------------------------- /apps/svelte-app/vite.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig, PluginOption } from "vite"; 2 | import { svelte } from "@sveltejs/vite-plugin-svelte"; 3 | import csp from "vite-plugin-csp-guard"; 4 | 5 | // https://vitejs.dev/config/ 6 | export default defineConfig({ 7 | plugins: [ 8 | svelte(), 9 | csp({ 10 | dev: { 11 | run: true, 12 | }, 13 | build: { 14 | sri: true, 15 | }, 16 | }) as PluginOption, 17 | ], 18 | preview: { 19 | port: 4008, 20 | }, 21 | server: { 22 | port: 3008, 23 | }, 24 | }); 25 | -------------------------------------------------------------------------------- /apps/tailwind/.eslintrc.cjs: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | extends: ["@repo/eslint-config/vite-react.js"], 4 | }; 5 | -------------------------------------------------------------------------------- /apps/tailwind/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Vite + Tailwind 8 | 9 | 10 |
11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /apps/tailwind/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "tailwind", 3 | "private": true, 4 | "version": "0.0.0", 5 | "type": "module", 6 | "scripts": { 7 | "dev": "vite", 8 | "build": "tsc -b && vite build", 9 | "lint": "tsc && eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0", 10 | "preview": "vite preview" 11 | }, 12 | "dependencies": { 13 | "@repo/eslint-config": "workspace:^", 14 | "react": "^18.3.1", 15 | "react-dom": "^18.3.1" 16 | }, 17 | "devDependencies": { 18 | "@repo/typescript-config": "workspace:^", 19 | "@repo/testing": "workspace:^", 20 | "@types/react": "^18.3.3", 21 | "@types/react-dom": "^18.3.0", 22 | "@typescript-eslint/eslint-plugin": "^7.13.1", 23 | "@typescript-eslint/parser": "^7.13.1", 24 | "@vitejs/plugin-react": "^4.3.4", 25 | "autoprefixer": "^10.4.19", 26 | "eslint": "^8.57.0", 27 | "eslint-plugin-react-hooks": "^4.6.2", 28 | "eslint-plugin-react-refresh": "^0.4.7", 29 | "postcss": "^8.4.39", 30 | "tailwindcss": "^3.4.4", 31 | "vite-plugin-csp-guard": "workspace:^" 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /apps/tailwind/postcss.config.js: -------------------------------------------------------------------------------- 1 | export default { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | } 7 | -------------------------------------------------------------------------------- /apps/tailwind/public/vite.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /apps/tailwind/src/App.tsx: -------------------------------------------------------------------------------- 1 | import { useState } from "react"; 2 | 3 | function App() { 4 | const [count, setCount] = useState(0); 5 | 6 | return ( 7 |
8 |

Vite + Tailwind

9 |
10 | 16 |

17 | Edit{" "} 18 | 19 | src/App.tsx 20 | {" "} 21 | and save to test HMR 22 |

23 |
24 |
25 | ); 26 | } 27 | 28 | export default App; 29 | -------------------------------------------------------------------------------- /apps/tailwind/src/index.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; -------------------------------------------------------------------------------- /apps/tailwind/src/main.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import ReactDOM from 'react-dom/client' 3 | import App from './App.tsx' 4 | import './index.css' 5 | 6 | ReactDOM.createRoot(document.getElementById('root')!).render( 7 | 8 | 9 | , 10 | ) 11 | -------------------------------------------------------------------------------- /apps/tailwind/src/vite-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /apps/tailwind/tailwind.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('tailwindcss').Config} */ 2 | export default { 3 | content: ["./index.html", "./src/**/*.{js,ts,jsx,tsx}"], 4 | theme: { 5 | extend: {}, 6 | }, 7 | plugins: [], 8 | }; 9 | -------------------------------------------------------------------------------- /apps/tailwind/tests/main.spec.ts: -------------------------------------------------------------------------------- 1 | import { genericTests } from '@repo/testing'; 2 | 3 | const TITLE = "Vite + Tailwind"; 4 | const BTN_COLOUR = "rgb(59, 130, 246)" 5 | const HEADER_COLOR = "rgb(0, 0, 0)" 6 | genericTests(TITLE, {headerColour: HEADER_COLOR, buttonColour: BTN_COLOUR}) 7 | -------------------------------------------------------------------------------- /apps/tailwind/tests/preview-only/main.spec.ts: -------------------------------------------------------------------------------- 1 | import { sriTest } from '@repo/testing'; 2 | 3 | sriTest(); 4 | 5 | 6 | -------------------------------------------------------------------------------- /apps/tailwind/tsconfig.app.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "composite": true, 4 | "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", 5 | "target": "ES2020", 6 | "useDefineForClassFields": true, 7 | "lib": ["ES2020", "DOM", "DOM.Iterable"], 8 | "module": "ESNext", 9 | "skipLibCheck": true, 10 | 11 | /* Bundler mode */ 12 | "moduleResolution": "bundler", 13 | "allowImportingTsExtensions": true, 14 | "resolveJsonModule": true, 15 | "isolatedModules": true, 16 | "moduleDetection": "force", 17 | "noEmit": true, 18 | "jsx": "react-jsx", 19 | 20 | /* Linting */ 21 | "strict": true, 22 | "noUnusedLocals": true, 23 | "noUnusedParameters": true, 24 | "noFallthroughCasesInSwitch": true 25 | }, 26 | "include": ["src"] 27 | } 28 | -------------------------------------------------------------------------------- /apps/tailwind/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "files": [], 3 | "references": [ 4 | { 5 | "path": "./tsconfig.app.json" 6 | }, 7 | { 8 | "path": "./tsconfig.node.json" 9 | } 10 | ] 11 | } 12 | -------------------------------------------------------------------------------- /apps/tailwind/tsconfig.node.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/tsconfig", 3 | "extends": "@repo/typescript-config/node", 4 | "compilerOptions": { 5 | "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", 6 | "noEmit": true 7 | }, 8 | "include": ["vite.config.ts"] 9 | } 10 | -------------------------------------------------------------------------------- /apps/tailwind/vite.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig, PluginOption } from "vite"; 2 | import react from "@vitejs/plugin-react"; 3 | import csp from "vite-plugin-csp-guard"; 4 | 5 | // https://vitejs.dev/config/ 6 | export default defineConfig({ 7 | plugins: [ 8 | react() as PluginOption, 9 | csp({ 10 | dev: { 11 | run: true, 12 | outlierSupport: ["tailwind"], 13 | }, 14 | build: { 15 | sri: true, 16 | }, 17 | }), 18 | ], 19 | preview: { 20 | port: 4003, 21 | }, 22 | server: { 23 | port: 3003, 24 | }, 25 | }); 26 | -------------------------------------------------------------------------------- /apps/tailwind4/.eslintrc.cjs: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | extends: ["@repo/eslint-config/vite-react.js"], 4 | }; 5 | -------------------------------------------------------------------------------- /apps/tailwind4/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Vite + Tailwind 4 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /apps/tailwind4/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "tailwind4", 3 | "private": true, 4 | "version": "0.0.0", 5 | "type": "module", 6 | "scripts": { 7 | "dev": "vite", 8 | "build": "tsc -b && vite build", 9 | "lint": "tsc && eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0", 10 | "preview": "vite preview" 11 | }, 12 | "dependencies": { 13 | "@repo/eslint-config": "workspace:^", 14 | "@tailwindcss/vite": "^4.0.9", 15 | "react": "^18.3.1", 16 | "react-dom": "^18.3.1", 17 | "tailwindcss": "^4.0.0" 18 | }, 19 | "devDependencies": { 20 | "@repo/testing": "workspace:^", 21 | "@repo/typescript-config": "workspace:^", 22 | "@types/react": "^18.3.3", 23 | "@types/react-dom": "^18.3.0", 24 | "@typescript-eslint/eslint-plugin": "^7.13.1", 25 | "@typescript-eslint/parser": "^7.13.1", 26 | "@vitejs/plugin-react": "^4.3.4", 27 | "autoprefixer": "^10.4.19", 28 | "eslint": "^8.57.0", 29 | "eslint-plugin-react-hooks": "^4.6.2", 30 | "eslint-plugin-react-refresh": "^0.4.7", 31 | "vite-plugin-csp-guard": "workspace:^" 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /apps/tailwind4/public/vite.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /apps/tailwind4/src/App.tsx: -------------------------------------------------------------------------------- 1 | import { useState } from "react"; 2 | 3 | function App() { 4 | const [count, setCount] = useState(0); 5 | 6 | return ( 7 |
8 |

Vite + Tailwind 4

9 |
10 | 16 |

17 | Edit{" "} 18 | 19 | src/App.tsx 20 | {" "} 21 | and save to test HMR 22 |

23 |
24 |
25 | ); 26 | } 27 | 28 | export default App; 29 | -------------------------------------------------------------------------------- /apps/tailwind4/src/main.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import ReactDOM from 'react-dom/client' 3 | import App from './App.tsx' 4 | // import './style.css' 5 | 6 | ReactDOM.createRoot(document.getElementById('root')!).render( 7 | 8 | 9 | , 10 | ) 11 | -------------------------------------------------------------------------------- /apps/tailwind4/src/style.css: -------------------------------------------------------------------------------- 1 | @import "tailwindcss"; -------------------------------------------------------------------------------- /apps/tailwind4/src/vite-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /apps/tailwind4/tailwind.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('tailwindcss').Config} */ 2 | export default { 3 | content: ["./index.html", "./src/**/*.{js,ts,jsx,tsx}"], 4 | theme: { 5 | extend: {}, 6 | }, 7 | plugins: [], 8 | }; 9 | -------------------------------------------------------------------------------- /apps/tailwind4/tests/main.spec.ts: -------------------------------------------------------------------------------- 1 | import { genericTests } from '@repo/testing'; 2 | 3 | const TITLE = "Vite + Tailwind 4"; 4 | const BTN_COLOUR = "oklch(0.623 0.214 259.815)" 5 | const HEADER_COLOR = "rgb(0, 0, 0)" 6 | genericTests(TITLE, {headerColour: HEADER_COLOR, buttonColour: BTN_COLOUR}) 7 | -------------------------------------------------------------------------------- /apps/tailwind4/tests/preview-only/main.spec.ts: -------------------------------------------------------------------------------- 1 | import { sriTest } from '@repo/testing'; 2 | 3 | sriTest(); 4 | 5 | 6 | -------------------------------------------------------------------------------- /apps/tailwind4/tsconfig.app.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "composite": true, 4 | "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", 5 | "target": "ES2020", 6 | "useDefineForClassFields": true, 7 | "lib": ["ES2020", "DOM", "DOM.Iterable"], 8 | "module": "ESNext", 9 | "skipLibCheck": true, 10 | 11 | /* Bundler mode */ 12 | "moduleResolution": "bundler", 13 | "allowImportingTsExtensions": true, 14 | "resolveJsonModule": true, 15 | "isolatedModules": true, 16 | "moduleDetection": "force", 17 | "noEmit": true, 18 | "jsx": "react-jsx", 19 | 20 | /* Linting */ 21 | "strict": true, 22 | "noUnusedLocals": true, 23 | "noUnusedParameters": true, 24 | "noFallthroughCasesInSwitch": true 25 | }, 26 | "include": ["src"] 27 | } 28 | -------------------------------------------------------------------------------- /apps/tailwind4/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "files": [], 3 | "references": [ 4 | { 5 | "path": "./tsconfig.app.json" 6 | }, 7 | { 8 | "path": "./tsconfig.node.json" 9 | } 10 | ] 11 | } 12 | -------------------------------------------------------------------------------- /apps/tailwind4/tsconfig.node.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/tsconfig", 3 | "extends": "@repo/typescript-config/node", 4 | "compilerOptions": { 5 | "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", 6 | "noEmit": true 7 | }, 8 | "include": ["vite.config.ts"] 9 | } 10 | -------------------------------------------------------------------------------- /apps/tailwind4/vite.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig, PluginOption } from "vite"; 2 | import react from "@vitejs/plugin-react"; 3 | import csp from "vite-plugin-csp-guard"; 4 | import tailwindcss from "@tailwindcss/vite"; 5 | 6 | // https://vitejs.dev/config/ 7 | export default defineConfig({ 8 | plugins: [ 9 | react() as PluginOption, 10 | tailwindcss() as PluginOption, 11 | csp({ 12 | dev: { 13 | run: true, 14 | outlierSupport: ["tailwind"], 15 | }, 16 | build: { 17 | sri: true, 18 | }, 19 | }), 20 | ], 21 | preview: { 22 | port: 4014, 23 | }, 24 | server: { 25 | port: 3014, 26 | }, 27 | }); 28 | -------------------------------------------------------------------------------- /apps/vite4/.eslintrc.cjs: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | extends: ["@repo/eslint-config/vite-react.js"], 4 | }; 5 | -------------------------------------------------------------------------------- /apps/vite4/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Vite + React 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /apps/vite4/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vite4", 3 | "private": true, 4 | "version": "0.0.0", 5 | "type": "module", 6 | "scripts": { 7 | "dev": "vite", 8 | "build": "tsc && vite build", 9 | "lint": "tsc && eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0", 10 | "preview": "vite preview" 11 | }, 12 | "dependencies": { 13 | "react": "^18.2.0", 14 | "react-dom": "^18.2.0" 15 | }, 16 | "devDependencies": { 17 | "@repo/typescript-config": "workspace:^", 18 | "@repo/eslint-config": "workspace:^", 19 | "@repo/testing": "workspace:^", 20 | "@types/react": "^18.2.66", 21 | "@types/react-dom": "^18.2.22", 22 | "@typescript-eslint/eslint-plugin": "^7.2.0", 23 | "@typescript-eslint/parser": "^7.2.0", 24 | "@vitejs/plugin-react": "^4.3.4", 25 | "eslint": "^8.57.0", 26 | "eslint-plugin-react-hooks": "^4.6.0", 27 | "eslint-plugin-react-refresh": "^0.4.6", 28 | "vite": "^4.0.0", 29 | "vite-plugin-csp-guard": "workspace:^" 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /apps/vite4/public/vite.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /apps/vite4/src/components/App.css: -------------------------------------------------------------------------------- 1 | #root { 2 | max-width: 1280px; 3 | margin: 0 auto; 4 | padding: 2rem; 5 | text-align: center; 6 | } 7 | 8 | .logo { 9 | height: 6em; 10 | padding: 1.5em; 11 | will-change: filter; 12 | transition: filter 300ms; 13 | } 14 | .logo:hover { 15 | filter: drop-shadow(0 0 2em #646cffaa); 16 | } 17 | .logo.react:hover { 18 | filter: drop-shadow(0 0 2em #61dafbaa); 19 | } 20 | 21 | @keyframes logo-spin { 22 | from { 23 | transform: rotate(0deg); 24 | } 25 | to { 26 | transform: rotate(360deg); 27 | } 28 | } 29 | 30 | @media (prefers-reduced-motion: no-preference) { 31 | a:nth-of-type(2) .logo { 32 | animation: logo-spin infinite 20s linear; 33 | } 34 | } 35 | 36 | .card { 37 | padding: 2em; 38 | } 39 | 40 | .read-the-docs { 41 | color: #888; 42 | } 43 | -------------------------------------------------------------------------------- /apps/vite4/src/components/App.tsx: -------------------------------------------------------------------------------- 1 | import { lazy, useState } from "react"; 2 | import reactLogo from "../assets/react.svg"; 3 | import viteLogo from "/vite.svg"; 4 | import "./App.css"; 5 | 6 | const Home = lazy(() => import("./Home")); 7 | 8 | function App() { 9 | const [count, setCount] = useState(0); 10 | 11 | return ( 12 | <> 13 | 21 |

Vite + React

22 | 23 |
24 | 27 |

28 | Edit src/App.tsx and save to test HMR 29 |

30 |
31 |

32 | Click on the Vite and React logos to learn more 33 |

34 | 35 | ); 36 | } 37 | 38 | export default App; 39 | -------------------------------------------------------------------------------- /apps/vite4/src/components/Home.tsx: -------------------------------------------------------------------------------- 1 | import Injector from "./Injector"; 2 | 3 | const Home = () => { 4 | return ( 5 |
6 |

Home

7 | 8 |
9 | ); 10 | }; 11 | 12 | export default Home; 13 | -------------------------------------------------------------------------------- /apps/vite4/src/components/Injector.tsx: -------------------------------------------------------------------------------- 1 | import { useEffect } from "react"; 2 | 3 | const Injector = () => { 4 | const injectScript = (scriptContent: string) => { 5 | const script = document.createElement("script"); 6 | script.textContent = scriptContent; 7 | script.async = true; 8 | document.body.appendChild(script); 9 | }; 10 | 11 | useEffect(() => { 12 | const scriptContent = ` 13 | // Your inline script code here 14 | console.log('Inline script executed'); 15 | `; 16 | injectScript(scriptContent); 17 | }, []); 18 | 19 | return <>; 20 | }; 21 | 22 | export default Injector; 23 | -------------------------------------------------------------------------------- /apps/vite4/src/index.css: -------------------------------------------------------------------------------- 1 | :root { 2 | font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif; 3 | line-height: 1.5; 4 | font-weight: 400; 5 | 6 | color-scheme: light dark; 7 | color: rgba(255, 255, 255, 0.87); 8 | background-color: #242424; 9 | 10 | font-synthesis: none; 11 | text-rendering: optimizeLegibility; 12 | -webkit-font-smoothing: antialiased; 13 | -moz-osx-font-smoothing: grayscale; 14 | } 15 | 16 | a { 17 | font-weight: 500; 18 | color: #646cff; 19 | text-decoration: inherit; 20 | } 21 | a:hover { 22 | color: #535bf2; 23 | } 24 | 25 | body { 26 | margin: 0; 27 | display: flex; 28 | place-items: center; 29 | min-width: 320px; 30 | min-height: 100vh; 31 | } 32 | 33 | h1 { 34 | font-size: 3.2em; 35 | line-height: 1.1; 36 | } 37 | 38 | button { 39 | border-radius: 8px; 40 | border: 1px solid transparent; 41 | padding: 0.6em 1.2em; 42 | font-size: 1em; 43 | font-weight: 500; 44 | font-family: inherit; 45 | background-color: #1a1a1a; 46 | cursor: pointer; 47 | transition: border-color 0.25s; 48 | } 49 | button:hover { 50 | border-color: #646cff; 51 | } 52 | button:focus, 53 | button:focus-visible { 54 | outline: 4px auto -webkit-focus-ring-color; 55 | } 56 | 57 | @media (prefers-color-scheme: light) { 58 | :root { 59 | color: #213547; 60 | background-color: #ffffff; 61 | } 62 | a:hover { 63 | color: #747bff; 64 | } 65 | button { 66 | background-color: #f9f9f9; 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /apps/vite4/src/main.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import ReactDOM from "react-dom/client"; 3 | import App from "./components/App.tsx"; 4 | import "./index.css"; 5 | 6 | ReactDOM.createRoot(document.getElementById("root")!).render( 7 | 8 | 9 | 10 | ); 11 | -------------------------------------------------------------------------------- /apps/vite4/src/vite-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /apps/vite4/tests/main.spec.ts: -------------------------------------------------------------------------------- 1 | import { genericTests, jQueryTest, inlineScriptBlockedTest, viteLogoTest} from '@repo/testing'; 2 | 3 | const APP_TITLE = "Vite + React"; 4 | const HEADER_COLOUR = "rgb(33, 53, 71)" 5 | const BTN_COLOUR = "rgb(255, 0, 0)" 6 | 7 | genericTests(APP_TITLE, {headerColour: HEADER_COLOUR, buttonColour: BTN_COLOUR}) 8 | jQueryTest() 9 | inlineScriptBlockedTest(APP_TITLE) 10 | viteLogoTest() 11 | // cspGenerationTest() 12 | -------------------------------------------------------------------------------- /apps/vite4/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@repo/typescript-config/vite", 3 | "include": ["src"], 4 | "references": [{ "path": "./tsconfig.node.json" }] 5 | } 6 | -------------------------------------------------------------------------------- /apps/vite4/tsconfig.node.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/tsconfig", 3 | "extends": "@repo/typescript-config/node", 4 | "compilerOptions": { 5 | "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", 6 | }, 7 | "include": ["vite.config.ts"] 8 | } 9 | -------------------------------------------------------------------------------- /apps/vite4/vite.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig, PluginOption } from "vite"; 2 | import react from "@vitejs/plugin-react"; 3 | import csp from "vite-plugin-csp-guard"; 4 | 5 | // https://vitejs.dev/config/ 6 | export default defineConfig({ 7 | plugins: [ 8 | react(), 9 | csp({ 10 | algorithm: "sha256", 11 | dev: { 12 | run: true, 13 | }, 14 | policy: { 15 | "font-src": ["https://fonts.gstatic.com"], 16 | "script-src-elem": ["'self'"], 17 | "connect-src": ["*"], 18 | "object-src": ["'none'"], 19 | }, 20 | override: true, 21 | }) as PluginOption // Needed due to pnpm different dependency versions for Vite, 22 | ], 23 | preview: { 24 | port: 4011, 25 | }, 26 | server: { 27 | port: 3011, 28 | }, 29 | }); 30 | -------------------------------------------------------------------------------- /apps/vite5/.eslintrc.cjs: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | extends: ["@repo/eslint-config/vite-react.js"], 4 | }; 5 | -------------------------------------------------------------------------------- /apps/vite5/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Vite + React 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /apps/vite5/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vite5", 3 | "private": true, 4 | "version": "0.0.0", 5 | "type": "module", 6 | "scripts": { 7 | "dev": "vite", 8 | "build": "tsc && vite build", 9 | "lint": "tsc && eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0", 10 | "preview": "vite preview" 11 | }, 12 | "dependencies": { 13 | "react": "^18.2.0", 14 | "react-dom": "^18.2.0" 15 | }, 16 | "devDependencies": { 17 | "@repo/typescript-config": "workspace:^", 18 | "@repo/eslint-config": "workspace:^", 19 | "@repo/testing": "workspace:^", 20 | "@types/react": "^18.2.66", 21 | "@types/react-dom": "^18.2.22", 22 | "@typescript-eslint/eslint-plugin": "^7.2.0", 23 | "@typescript-eslint/parser": "^7.2.0", 24 | "@vitejs/plugin-react": "^4.3.4", 25 | "eslint": "^8.57.0", 26 | "eslint-plugin-react-hooks": "^4.6.0", 27 | "eslint-plugin-react-refresh": "^0.4.6", 28 | "vite": "^5.3.1", 29 | "vite-plugin-csp-guard": "workspace:^" 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /apps/vite5/public/vite.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /apps/vite5/src/components/App.css: -------------------------------------------------------------------------------- 1 | #root { 2 | max-width: 1280px; 3 | margin: 0 auto; 4 | padding: 2rem; 5 | text-align: center; 6 | } 7 | 8 | .logo { 9 | height: 6em; 10 | padding: 1.5em; 11 | will-change: filter; 12 | transition: filter 300ms; 13 | } 14 | .logo:hover { 15 | filter: drop-shadow(0 0 2em #646cffaa); 16 | } 17 | .logo.react:hover { 18 | filter: drop-shadow(0 0 2em #61dafbaa); 19 | } 20 | 21 | @keyframes logo-spin { 22 | from { 23 | transform: rotate(0deg); 24 | } 25 | to { 26 | transform: rotate(360deg); 27 | } 28 | } 29 | 30 | @media (prefers-reduced-motion: no-preference) { 31 | a:nth-of-type(2) .logo { 32 | animation: logo-spin infinite 20s linear; 33 | } 34 | } 35 | 36 | .card { 37 | padding: 2em; 38 | } 39 | 40 | .read-the-docs { 41 | color: #888; 42 | } 43 | -------------------------------------------------------------------------------- /apps/vite5/src/components/App.tsx: -------------------------------------------------------------------------------- 1 | import { lazy, useState } from "react"; 2 | import reactLogo from "../assets/react.svg"; 3 | import viteLogo from "/vite.svg"; 4 | import "./App.css"; 5 | 6 | const Home = lazy(() => import("./Home")); 7 | 8 | function App() { 9 | const [count, setCount] = useState(0); 10 | 11 | return ( 12 | <> 13 | 21 |

Vite + React

22 | 23 |
24 | 27 |

28 | Edit src/App.tsx and save to test HMR 29 |

30 |
31 |

32 | Click on the Vite and React logos to learn more 33 |

34 | 35 | ); 36 | } 37 | 38 | export default App; 39 | -------------------------------------------------------------------------------- /apps/vite5/src/components/Home.tsx: -------------------------------------------------------------------------------- 1 | import Injector from "./Injector"; 2 | 3 | const Home = () => { 4 | return ( 5 |
6 |

Home

7 | 8 |
9 | ); 10 | }; 11 | 12 | export default Home; 13 | -------------------------------------------------------------------------------- /apps/vite5/src/components/Injector.tsx: -------------------------------------------------------------------------------- 1 | import { useEffect } from "react"; 2 | 3 | const Injector = () => { 4 | const injectScript = (scriptContent: string) => { 5 | const script = document.createElement("script"); 6 | script.textContent = scriptContent; 7 | script.async = true; 8 | document.body.appendChild(script); 9 | }; 10 | 11 | useEffect(() => { 12 | const scriptContent = ` 13 | // Your inline script code here 14 | console.log('Inline script executed'); 15 | `; 16 | injectScript(scriptContent); 17 | }, []); 18 | 19 | return <>; 20 | }; 21 | 22 | export default Injector; 23 | -------------------------------------------------------------------------------- /apps/vite5/src/index.css: -------------------------------------------------------------------------------- 1 | :root { 2 | font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif; 3 | line-height: 1.5; 4 | font-weight: 400; 5 | 6 | color-scheme: light dark; 7 | color: rgba(255, 255, 255, 0.87); 8 | background-color: #242424; 9 | 10 | font-synthesis: none; 11 | text-rendering: optimizeLegibility; 12 | -webkit-font-smoothing: antialiased; 13 | -moz-osx-font-smoothing: grayscale; 14 | } 15 | 16 | a { 17 | font-weight: 500; 18 | color: #646cff; 19 | text-decoration: inherit; 20 | } 21 | a:hover { 22 | color: #535bf2; 23 | } 24 | 25 | body { 26 | margin: 0; 27 | display: flex; 28 | place-items: center; 29 | min-width: 320px; 30 | min-height: 100vh; 31 | } 32 | 33 | h1 { 34 | font-size: 3.2em; 35 | line-height: 1.1; 36 | } 37 | 38 | button { 39 | border-radius: 8px; 40 | border: 1px solid transparent; 41 | padding: 0.6em 1.2em; 42 | font-size: 1em; 43 | font-weight: 500; 44 | font-family: inherit; 45 | background-color: #1a1a1a; 46 | cursor: pointer; 47 | transition: border-color 0.25s; 48 | } 49 | button:hover { 50 | border-color: #646cff; 51 | } 52 | button:focus, 53 | button:focus-visible { 54 | outline: 4px auto -webkit-focus-ring-color; 55 | } 56 | 57 | @media (prefers-color-scheme: light) { 58 | :root { 59 | color: #213547; 60 | background-color: #ffffff; 61 | } 62 | a:hover { 63 | color: #747bff; 64 | } 65 | button { 66 | background-color: #f9f9f9; 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /apps/vite5/src/main.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import ReactDOM from "react-dom/client"; 3 | import App from "./components/App.tsx"; 4 | import "./index.css"; 5 | 6 | ReactDOM.createRoot(document.getElementById("root")!).render( 7 | 8 | 9 | 10 | ); 11 | -------------------------------------------------------------------------------- /apps/vite5/src/vite-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /apps/vite5/tests/main.spec.ts: -------------------------------------------------------------------------------- 1 | import { genericTests, jQueryTest, inlineScriptBlockedTest, viteLogoTest } from '@repo/testing'; 2 | 3 | const APP_TITLE = "Vite + React"; 4 | const HEADER_COLOUR = "rgb(33, 53, 71)" 5 | const BTN_COLOUR = "rgb(255, 0, 0)" 6 | 7 | genericTests(APP_TITLE, {headerColour: HEADER_COLOUR, buttonColour: BTN_COLOUR}) 8 | jQueryTest() 9 | inlineScriptBlockedTest(APP_TITLE) 10 | viteLogoTest() 11 | -------------------------------------------------------------------------------- /apps/vite5/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@repo/typescript-config/vite", 3 | "include": ["src"], 4 | "references": [{ "path": "./tsconfig.node.json" }] 5 | } 6 | -------------------------------------------------------------------------------- /apps/vite5/tsconfig.node.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/tsconfig", 3 | "extends": "@repo/typescript-config/node", 4 | "compilerOptions": { 5 | "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", 6 | }, 7 | "include": ["vite.config.ts"] 8 | } 9 | -------------------------------------------------------------------------------- /apps/vite5/vite.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig, PluginOption } from "vite"; 2 | import react from "@vitejs/plugin-react"; 3 | import csp from "vite-plugin-csp-guard"; 4 | 5 | // https://vitejs.dev/config/ 6 | export default defineConfig({ 7 | plugins: [ 8 | react(), 9 | csp({ 10 | algorithm: "sha256", 11 | dev: { 12 | run: true, 13 | }, 14 | policy: { 15 | "font-src": ["https://fonts.gstatic.com"], 16 | "script-src-elem": ["'self'"], 17 | "connect-src": ["*"], 18 | "object-src": ["'none'"], 19 | }, 20 | override: true, 21 | }) as PluginOption // Needed due to pnpm different dependency versions for Vite, 22 | ], 23 | preview: { 24 | port: 4012, 25 | }, 26 | server: { 27 | port: 3012, 28 | }, 29 | }); 30 | -------------------------------------------------------------------------------- /apps/vite6/.eslintrc.cjs: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | extends: ["@repo/eslint-config/vite-react.js"], 4 | }; 5 | -------------------------------------------------------------------------------- /apps/vite6/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Vite + React 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /apps/vite6/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vite6", 3 | "private": true, 4 | "version": "0.0.0", 5 | "type": "module", 6 | "scripts": { 7 | "dev": "vite", 8 | "build": "tsc && vite build", 9 | "lint": "tsc && eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0", 10 | "preview": "vite preview" 11 | }, 12 | "dependencies": { 13 | "react": "^18.2.0", 14 | "react-dom": "^18.2.0" 15 | }, 16 | "devDependencies": { 17 | "@repo/typescript-config": "workspace:^", 18 | "@repo/eslint-config": "workspace:^", 19 | "@repo/testing": "workspace:^", 20 | "@types/react": "^18.2.66", 21 | "@types/react-dom": "^18.2.22", 22 | "@typescript-eslint/eslint-plugin": "^7.2.0", 23 | "@typescript-eslint/parser": "^7.2.0", 24 | "@vitejs/plugin-react": "^4.3.4", 25 | "eslint": "^8.57.0", 26 | "eslint-plugin-react-hooks": "^4.6.0", 27 | "eslint-plugin-react-refresh": "^0.4.6", 28 | "vite": "6.0.5", 29 | "vite-plugin-csp-guard": "workspace:^" 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /apps/vite6/public/vite.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /apps/vite6/src/components/App.css: -------------------------------------------------------------------------------- 1 | #root { 2 | max-width: 1280px; 3 | margin: 0 auto; 4 | padding: 2rem; 5 | text-align: center; 6 | } 7 | 8 | .logo { 9 | height: 6em; 10 | padding: 1.5em; 11 | will-change: filter; 12 | transition: filter 300ms; 13 | } 14 | .logo:hover { 15 | filter: drop-shadow(0 0 2em #646cffaa); 16 | } 17 | .logo.react:hover { 18 | filter: drop-shadow(0 0 2em #61dafbaa); 19 | } 20 | 21 | @keyframes logo-spin { 22 | from { 23 | transform: rotate(0deg); 24 | } 25 | to { 26 | transform: rotate(360deg); 27 | } 28 | } 29 | 30 | @media (prefers-reduced-motion: no-preference) { 31 | a:nth-of-type(2) .logo { 32 | animation: logo-spin infinite 20s linear; 33 | } 34 | } 35 | 36 | .card { 37 | padding: 2em; 38 | } 39 | 40 | .read-the-docs { 41 | color: #888; 42 | } 43 | -------------------------------------------------------------------------------- /apps/vite6/src/components/App.tsx: -------------------------------------------------------------------------------- 1 | import { lazy, useState } from "react"; 2 | import reactLogo from "../assets/react.svg"; 3 | import viteLogo from "/vite.svg"; 4 | import "./App.css"; 5 | 6 | const Home = lazy(() => import("./Home")); 7 | 8 | function App() { 9 | const [count, setCount] = useState(0); 10 | 11 | return ( 12 | <> 13 | 21 |

Vite + React

22 | 23 |
24 | 27 |

28 | Edit src/App.tsx and save to test HMR 29 |

30 |
31 |

32 | Click on the Vite and React logos to learn more 33 |

34 | 35 | ); 36 | } 37 | 38 | export default App; 39 | -------------------------------------------------------------------------------- /apps/vite6/src/components/Home.tsx: -------------------------------------------------------------------------------- 1 | import Injector from "./Injector"; 2 | 3 | const Home = () => { 4 | return ( 5 |
6 |

Home

7 | 8 |
9 | ); 10 | }; 11 | 12 | export default Home; 13 | -------------------------------------------------------------------------------- /apps/vite6/src/components/Injector.tsx: -------------------------------------------------------------------------------- 1 | import { useEffect } from "react"; 2 | 3 | const Injector = () => { 4 | const injectScript = (scriptContent: string) => { 5 | const script = document.createElement("script"); 6 | script.textContent = scriptContent; 7 | script.async = true; 8 | document.body.appendChild(script); 9 | }; 10 | 11 | useEffect(() => { 12 | const scriptContent = ` 13 | // Your inline script code here 14 | console.log('Inline script executed'); 15 | `; 16 | injectScript(scriptContent); 17 | }, []); 18 | 19 | return <>; 20 | }; 21 | 22 | export default Injector; 23 | -------------------------------------------------------------------------------- /apps/vite6/src/index.css: -------------------------------------------------------------------------------- 1 | :root { 2 | font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif; 3 | line-height: 1.5; 4 | font-weight: 400; 5 | 6 | color-scheme: light dark; 7 | color: rgba(255, 255, 255, 0.87); 8 | background-color: #242424; 9 | 10 | font-synthesis: none; 11 | text-rendering: optimizeLegibility; 12 | -webkit-font-smoothing: antialiased; 13 | -moz-osx-font-smoothing: grayscale; 14 | } 15 | 16 | a { 17 | font-weight: 500; 18 | color: #646cff; 19 | text-decoration: inherit; 20 | } 21 | a:hover { 22 | color: #535bf2; 23 | } 24 | 25 | body { 26 | margin: 0; 27 | display: flex; 28 | place-items: center; 29 | min-width: 320px; 30 | min-height: 100vh; 31 | } 32 | 33 | h1 { 34 | font-size: 3.2em; 35 | line-height: 1.1; 36 | } 37 | 38 | button { 39 | border-radius: 8px; 40 | border: 1px solid transparent; 41 | padding: 0.6em 1.2em; 42 | font-size: 1em; 43 | font-weight: 500; 44 | font-family: inherit; 45 | background-color: #1a1a1a; 46 | cursor: pointer; 47 | transition: border-color 0.25s; 48 | } 49 | button:hover { 50 | border-color: #646cff; 51 | } 52 | button:focus, 53 | button:focus-visible { 54 | outline: 4px auto -webkit-focus-ring-color; 55 | } 56 | 57 | @media (prefers-color-scheme: light) { 58 | :root { 59 | color: #213547; 60 | background-color: #ffffff; 61 | } 62 | a:hover { 63 | color: #747bff; 64 | } 65 | button { 66 | background-color: #f9f9f9; 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /apps/vite6/src/main.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import ReactDOM from "react-dom/client"; 3 | import App from "./components/App.tsx"; 4 | import "./index.css"; 5 | 6 | ReactDOM.createRoot(document.getElementById("root")!).render( 7 | 8 | 9 | 10 | ); 11 | -------------------------------------------------------------------------------- /apps/vite6/src/vite-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /apps/vite6/tests/main.spec.ts: -------------------------------------------------------------------------------- 1 | import { genericTests, jQueryTest, inlineScriptBlockedTest, viteLogoTest } from '@repo/testing'; 2 | 3 | const APP_TITLE = "Vite + React"; 4 | const HEADER_COLOUR = "rgb(33, 53, 71)" 5 | const BTN_COLOUR = "rgb(255, 0, 0)" 6 | 7 | genericTests(APP_TITLE, {headerColour: HEADER_COLOUR, buttonColour: BTN_COLOUR}) 8 | jQueryTest() 9 | inlineScriptBlockedTest(APP_TITLE) 10 | viteLogoTest() 11 | -------------------------------------------------------------------------------- /apps/vite6/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@repo/typescript-config/vite", 3 | "include": ["src"], 4 | "references": [{ "path": "./tsconfig.node.json" }] 5 | } 6 | -------------------------------------------------------------------------------- /apps/vite6/tsconfig.node.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/tsconfig", 3 | "extends": "@repo/typescript-config/node", 4 | "compilerOptions": { 5 | "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", 6 | }, 7 | "include": ["vite.config.ts"] 8 | } 9 | -------------------------------------------------------------------------------- /apps/vite6/vite.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig, PluginOption } from "vite"; 2 | import react from "@vitejs/plugin-react"; 3 | import csp from "vite-plugin-csp-guard"; 4 | 5 | // https://vitejs.dev/config/ 6 | export default defineConfig({ 7 | plugins: [ 8 | react(), 9 | csp({ 10 | algorithm: "sha256", 11 | dev: { 12 | run: true, 13 | }, 14 | policy: { 15 | "font-src": ["'self'","https://fonts.gstatic.com"], 16 | "script-src-elem": ["'self'"], 17 | "connect-src": ["*"], 18 | "object-src": ["'none'"], 19 | "img-src": ["'self'","https://placehold.co/600x400", "data:"], 20 | }, 21 | override: true 22 | }) as PluginOption // Needed due to pnpm different dependency versions for Vite, 23 | ], 24 | preview: { 25 | port: 4013, 26 | }, 27 | server: { 28 | port: 3013, 29 | }, 30 | }); 31 | -------------------------------------------------------------------------------- /apps/vue-app/.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": ["Vue.volar"] 3 | } 4 | -------------------------------------------------------------------------------- /apps/vue-app/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Vite + Vue 8 | 9 | 10 |
11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /apps/vue-app/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vue-app", 3 | "private": true, 4 | "version": "0.0.0", 5 | "type": "module", 6 | "scripts": { 7 | "dev": "vite", 8 | "build": "vue-tsc -b && vite build", 9 | "preview": "vite preview" 10 | }, 11 | "dependencies": { 12 | "vue": "^3.4.31" 13 | }, 14 | "devDependencies": { 15 | "@repo/eslint-config": "workspace:^", 16 | "@repo/testing": "workspace:^", 17 | "@vitejs/plugin-vue": "^5.2.1", 18 | "vue-tsc": "^2.0.24", 19 | "vite-plugin-csp-guard": "workspace:^" 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /apps/vue-app/public/vite.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /apps/vue-app/src/App.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 16 | 17 | 31 | -------------------------------------------------------------------------------- /apps/vue-app/src/assets/vue.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /apps/vue-app/src/components/HelloWorld.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 36 | 37 | 51 | -------------------------------------------------------------------------------- /apps/vue-app/src/main.ts: -------------------------------------------------------------------------------- 1 | import { createApp } from 'vue' 2 | import './style.css' 3 | import App from './App.vue' 4 | 5 | createApp(App).mount('#app') 6 | -------------------------------------------------------------------------------- /apps/vue-app/src/style.css: -------------------------------------------------------------------------------- 1 | :root { 2 | font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif; 3 | line-height: 1.5; 4 | font-weight: 400; 5 | 6 | color-scheme: light dark; 7 | color: rgba(255, 255, 255, 0.87); 8 | background-color: #242424; 9 | 10 | font-synthesis: none; 11 | text-rendering: optimizeLegibility; 12 | -webkit-font-smoothing: antialiased; 13 | -moz-osx-font-smoothing: grayscale; 14 | } 15 | 16 | a { 17 | font-weight: 500; 18 | color: #646cff; 19 | text-decoration: inherit; 20 | } 21 | a:hover { 22 | color: #535bf2; 23 | } 24 | 25 | body { 26 | margin: 0; 27 | display: flex; 28 | place-items: center; 29 | min-width: 320px; 30 | min-height: 100vh; 31 | } 32 | 33 | h1 { 34 | font-size: 3.2em; 35 | line-height: 1.1; 36 | } 37 | 38 | button { 39 | border-radius: 8px; 40 | border: 1px solid transparent; 41 | padding: 0.6em 1.2em; 42 | font-size: 1em; 43 | font-weight: 500; 44 | font-family: inherit; 45 | background-color: #1a1a1a; 46 | cursor: pointer; 47 | transition: border-color 0.25s; 48 | } 49 | button:hover { 50 | border-color: #646cff; 51 | } 52 | button:focus, 53 | button:focus-visible { 54 | outline: 4px auto -webkit-focus-ring-color; 55 | } 56 | 57 | .card { 58 | padding: 2em; 59 | } 60 | 61 | #app { 62 | max-width: 1280px; 63 | margin: 0 auto; 64 | padding: 2rem; 65 | text-align: center; 66 | } 67 | 68 | @media (prefers-color-scheme: light) { 69 | :root { 70 | color: #213547; 71 | background-color: #ffffff; 72 | } 73 | a:hover { 74 | color: #747bff; 75 | } 76 | button { 77 | background-color: #f9f9f9; 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /apps/vue-app/src/vite-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /apps/vue-app/tests/main.spec.ts: -------------------------------------------------------------------------------- 1 | import { genericTests, viteLogoTest, } from '@repo/testing'; 2 | 3 | const TITLE = "Vite + Vue"; 4 | 5 | const BTN_COLOUR = "rgb(66, 184, 131)" 6 | const HEADER_COLOR = "rgb(33, 53, 71)" 7 | 8 | genericTests(TITLE, {headerColour: HEADER_COLOR, buttonColour: BTN_COLOUR}) 9 | viteLogoTest() -------------------------------------------------------------------------------- /apps/vue-app/tests/preview-only/main.spec.ts: -------------------------------------------------------------------------------- 1 | import { sriTest } from '@repo/testing'; 2 | 3 | sriTest(); 4 | 5 | 6 | -------------------------------------------------------------------------------- /apps/vue-app/tsconfig.app.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "composite": true, 4 | "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", 5 | "target": "ES2020", 6 | "useDefineForClassFields": true, 7 | "module": "ESNext", 8 | "lib": ["ES2020", "DOM", "DOM.Iterable"], 9 | "skipLibCheck": true, 10 | 11 | /* Bundler mode */ 12 | "moduleResolution": "bundler", 13 | "allowImportingTsExtensions": true, 14 | "resolveJsonModule": true, 15 | "isolatedModules": true, 16 | "moduleDetection": "force", 17 | "noEmit": true, 18 | "jsx": "preserve", 19 | 20 | /* Linting */ 21 | "strict": true, 22 | "noUnusedLocals": true, 23 | "noUnusedParameters": true, 24 | "noFallthroughCasesInSwitch": true 25 | }, 26 | "include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"] 27 | } 28 | -------------------------------------------------------------------------------- /apps/vue-app/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "files": [], 3 | "references": [ 4 | { 5 | "path": "./tsconfig.app.json" 6 | }, 7 | { 8 | "path": "./tsconfig.node.json" 9 | } 10 | ] 11 | } 12 | -------------------------------------------------------------------------------- /apps/vue-app/tsconfig.node.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "composite": true, 4 | "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", 5 | "skipLibCheck": true, 6 | "module": "ESNext", 7 | "moduleResolution": "bundler", 8 | "allowSyntheticDefaultImports": true, 9 | "strict": true, 10 | "noEmit": true 11 | }, 12 | "include": ["vite.config.ts"] 13 | } 14 | -------------------------------------------------------------------------------- /apps/vue-app/vite.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig, PluginOption } from "vite"; 2 | import vue from "@vitejs/plugin-vue"; 3 | import csp from "vite-plugin-csp-guard"; 4 | 5 | // https://vitejs.dev/config/ 6 | export default defineConfig({ 7 | plugins: [ 8 | vue() as PluginOption, 9 | csp({ 10 | dev: { run: true, outlierSupport: ["vue"] }, 11 | build: { sri: true }, 12 | }), 13 | ], 14 | preview: { 15 | port: 4007, 16 | }, 17 | server: { 18 | port: 3007, 19 | }, 20 | }); 21 | -------------------------------------------------------------------------------- /apps/vue-router/.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": ["Vue.volar"] 3 | } 4 | -------------------------------------------------------------------------------- /apps/vue-router/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Vite + Vue 8 | 9 | 10 |
11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /apps/vue-router/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vue-router", 3 | "private": true, 4 | "version": "0.0.0", 5 | "type": "module", 6 | "scripts": { 7 | "dev": "vite", 8 | "build": "vue-tsc -b && vite build", 9 | "preview": "vite preview" 10 | }, 11 | "dependencies": { 12 | "vue": "^3.5.13", 13 | "vue-router": "^4.5.0" 14 | }, 15 | "devDependencies": { 16 | "@repo/eslint-config": "workspace:*", 17 | "@repo/typescript-config": "workspace:*", 18 | "@repo/testing": "workspace:*", 19 | "@vitejs/plugin-vue": "^5.2.1", 20 | "@vue/tsconfig": "^0.7.0", 21 | "typescript": "~5.7.2", 22 | "vite": "^6.2.0", 23 | "vite-plugin-csp-guard": "workspace:*", 24 | "vue-tsc": "^2.2.4" 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /apps/vue-router/public/vite.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /apps/vue-router/src/App.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 16 | 17 | 31 | -------------------------------------------------------------------------------- /apps/vue-router/src/Bye.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 16 | 17 | 31 | -------------------------------------------------------------------------------- /apps/vue-router/src/Four.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 16 | 17 | 31 | -------------------------------------------------------------------------------- /apps/vue-router/src/Hello.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 16 | 17 | 31 | -------------------------------------------------------------------------------- /apps/vue-router/src/assets/vue.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /apps/vue-router/src/components/HelloWorld.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 36 | 37 | 42 | -------------------------------------------------------------------------------- /apps/vue-router/src/main.ts: -------------------------------------------------------------------------------- 1 | import { createApp } from "vue"; 2 | import "./style.css"; 3 | import App from "./App.vue"; 4 | import router from "./router"; 5 | 6 | createApp(App).use(router).mount("#app"); 7 | -------------------------------------------------------------------------------- /apps/vue-router/src/router/index.ts: -------------------------------------------------------------------------------- 1 | import { createRouter, createWebHistory } from "vue-router"; 2 | 3 | const router = createRouter({ 4 | history: createWebHistory(), 5 | routes: [ 6 | { 7 | path: "/", 8 | name: "root", 9 | component: () => import("../App.vue"), 10 | }, 11 | { 12 | path: "/hello", 13 | name: "hello", 14 | component: () => import("../Hello.vue"), 15 | }, 16 | { 17 | path: "/bye", 18 | name: "bye", 19 | component: () => import("../Bye.vue"), 20 | }, 21 | { 22 | path: "/four", 23 | name: "four", 24 | component: () => import("../Four.vue"), 25 | }, 26 | ], 27 | }); 28 | 29 | export default router; 30 | -------------------------------------------------------------------------------- /apps/vue-router/src/vite-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /apps/vue-router/tests/main.spec.ts: -------------------------------------------------------------------------------- 1 | import { genericTests, viteLogoTest } from "@repo/testing"; 2 | 3 | const TITLE = "Vite + Vue"; 4 | const HEADER_COLOUR = "rgb(33, 53, 71)"; 5 | const BTN_COLOUR = "rgb(249, 249, 249)"; 6 | 7 | genericTests(TITLE, { headerColour: HEADER_COLOUR, buttonColour: BTN_COLOUR }); 8 | viteLogoTest(); 9 | -------------------------------------------------------------------------------- /apps/vue-router/tests/preview-only/main.spec.ts: -------------------------------------------------------------------------------- 1 | import { sriTest } from '@repo/testing'; 2 | 3 | sriTest(); 4 | 5 | 6 | -------------------------------------------------------------------------------- /apps/vue-router/tsconfig.app.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@vue/tsconfig/tsconfig.dom.json", 3 | "compilerOptions": { 4 | "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", 5 | 6 | /* Linting */ 7 | "strict": true, 8 | "noUnusedLocals": true, 9 | "noUnusedParameters": true, 10 | "noFallthroughCasesInSwitch": true, 11 | "noUncheckedSideEffectImports": true 12 | }, 13 | "include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"] 14 | } 15 | -------------------------------------------------------------------------------- /apps/vue-router/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@repo/typescript-config/vite.json", 3 | "include": [ 4 | "src" 5 | ], 6 | "exclude": [ 7 | "node_modules" 8 | ], 9 | "compilerOptions": { 10 | "baseUrl": "." 11 | } 12 | } -------------------------------------------------------------------------------- /apps/vue-router/tsconfig.node.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", 4 | "target": "ES2022", 5 | "lib": ["ES2023"], 6 | "module": "ESNext", 7 | "skipLibCheck": true, 8 | 9 | /* Bundler mode */ 10 | "moduleResolution": "bundler", 11 | "allowImportingTsExtensions": true, 12 | "isolatedModules": true, 13 | "moduleDetection": "force", 14 | "noEmit": true, 15 | 16 | /* Linting */ 17 | "strict": true, 18 | "noUnusedLocals": true, 19 | "noUnusedParameters": true, 20 | "noFallthroughCasesInSwitch": true, 21 | "noUncheckedSideEffectImports": true 22 | }, 23 | "include": ["vite.config.ts"] 24 | } 25 | -------------------------------------------------------------------------------- /apps/vue-router/tsconfig.tsbuildinfo: -------------------------------------------------------------------------------- 1 | {"root":["./src/app.vue","./src/bye.vue","./src/four.vue","./src/hello.vue","./src/main.ts","./src/vite-env.d.ts","./src/components/helloworld.vue","./src/router/index.ts"],"version":"5.7.3"} -------------------------------------------------------------------------------- /apps/vue-router/vite.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig, PluginOption } from "vite"; 2 | import vue from "@vitejs/plugin-vue"; 3 | import csp from "vite-plugin-csp-guard"; 4 | 5 | // https://vite.dev/config/ 6 | export default defineConfig({ 7 | plugins: [ 8 | vue(), 9 | csp({ 10 | policy: { 11 | "img-src": ["'self'", "data:"], 12 | }, 13 | build: { 14 | sri: true, 15 | outlierSupport: ["vue-router"], 16 | }, 17 | debug: true, 18 | }) as PluginOption, 19 | ], 20 | preview: { 21 | port: 4020, 22 | }, 23 | server: { 24 | port: 3020, 25 | }, 26 | }); 27 | -------------------------------------------------------------------------------- /packages/eslint-config/library.js: -------------------------------------------------------------------------------- 1 | const { resolve } = require("node:path"); 2 | 3 | const project = resolve(process.cwd(), "tsconfig.json"); 4 | 5 | /** @type {import("eslint").Linter.Config} */ 6 | module.exports = { 7 | extends: ["eslint:recommended", "prettier", "eslint-config-turbo"], 8 | plugins: ["only-warn"], 9 | globals: { 10 | React: true, 11 | JSX: true, 12 | }, 13 | env: { 14 | node: true, 15 | }, 16 | settings: { 17 | "import/resolver": { 18 | typescript: { 19 | project, 20 | }, 21 | }, 22 | }, 23 | ignorePatterns: [ 24 | // Ignore dotfiles 25 | ".*.js", 26 | "node_modules/", 27 | "dist/", 28 | ], 29 | overrides: [ 30 | { 31 | files: ["*.js?(x)", "*.ts?(x)"], 32 | }, 33 | ], 34 | }; 35 | -------------------------------------------------------------------------------- /packages/eslint-config/next.js: -------------------------------------------------------------------------------- 1 | const { resolve } = require("node:path"); 2 | 3 | const project = resolve(process.cwd(), "tsconfig.json"); 4 | 5 | /** @type {import("eslint").Linter.Config} */ 6 | module.exports = { 7 | extends: [ 8 | "eslint:recommended", 9 | "prettier", 10 | require.resolve("@vercel/style-guide/eslint/next"), 11 | "eslint-config-turbo", 12 | ], 13 | globals: { 14 | React: true, 15 | JSX: true, 16 | }, 17 | env: { 18 | node: true, 19 | browser: true, 20 | }, 21 | plugins: ["only-warn"], 22 | settings: { 23 | "import/resolver": { 24 | typescript: { 25 | project, 26 | }, 27 | }, 28 | }, 29 | ignorePatterns: [ 30 | // Ignore dotfiles 31 | ".*.js", 32 | "node_modules/", 33 | ], 34 | overrides: [{ files: ["*.js?(x)", "*.ts?(x)"] }], 35 | }; 36 | -------------------------------------------------------------------------------- /packages/eslint-config/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@repo/eslint-config", 3 | "version": "0.0.0", 4 | "private": true, 5 | "files": [ 6 | "library.js", 7 | "next.js", 8 | "react-internal.js" 9 | ], 10 | "devDependencies": { 11 | "@typescript-eslint/eslint-plugin": "^6.17.0", 12 | "@typescript-eslint/parser": "^6.17.0", 13 | "@vercel/style-guide": "^5.1.0", 14 | "eslint-config-prettier": "^9.1.0", 15 | "eslint-config-turbo": "^2.3.3", 16 | "eslint-plugin-only-warn": "^1.1.0" 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /packages/eslint-config/vite-react.js: -------------------------------------------------------------------------------- 1 | const { resolve } = require("node:path"); 2 | 3 | const project = resolve(process.cwd(), "tsconfig.json"); 4 | 5 | /** @type {import("eslint").Linter.Config} */ 6 | module.exports = { 7 | env: { browser: true, es2020: true }, 8 | extends: [ 9 | "eslint:recommended", 10 | "plugin:@typescript-eslint/recommended", 11 | "plugin:react-hooks/recommended", 12 | ], 13 | ignorePatterns: ["dist", ".eslintrc.cjs"], 14 | parser: "@typescript-eslint/parser", 15 | plugins: ["react-refresh"], 16 | rules: { 17 | "react-refresh/only-export-components": [ 18 | "warn", 19 | { allowConstantExport: true }, 20 | ], 21 | }, 22 | settings: { 23 | "import/resolver": { 24 | typescript: { 25 | project, 26 | }, 27 | }, 28 | }, 29 | }; 30 | -------------------------------------------------------------------------------- /packages/testing/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@repo/testing", 3 | "version": "0.0.0", 4 | "private": true, 5 | "license": "MIT", 6 | "type": "module", 7 | "scripts": { 8 | "build": "rollup -c" 9 | }, 10 | "exports": { 11 | ".": { 12 | "types": "./dist/index.d.ts", 13 | "import": "./dist/index.js" 14 | } 15 | }, 16 | "dependencies": { 17 | "csp-toolkit": "1.3.1" 18 | }, 19 | "devDependencies": { 20 | "@rollup/plugin-node-resolve": "^15.2.3", 21 | "@rollup/plugin-typescript": "^12.1.2", 22 | "rollup": "^4.28.1", 23 | "@repo/typescript-config": "workspace:^" 24 | } 25 | } -------------------------------------------------------------------------------- /packages/testing/rollup.config.mjs: -------------------------------------------------------------------------------- 1 | import typescript from '@rollup/plugin-typescript'; 2 | import { nodeResolve } from '@rollup/plugin-node-resolve'; 3 | 4 | export default { 5 | input: 'src/index.ts', // Assuming your main entry is index.ts 6 | output: [ 7 | { 8 | file: 'dist/index.js', 9 | format: 'esm', // Can be 'cjs' or 'esm' depending on your requirements 10 | sourcemap: true, 11 | }, 12 | ], 13 | plugins: [ 14 | nodeResolve(), 15 | typescript( 16 | { 17 | tsconfig: "tsconfig.json", 18 | declaration: true, 19 | declarationDir: "dist", 20 | include: ["src/**/*.ts"], 21 | sourceMap: true, 22 | } 23 | ), 24 | ], 25 | external: [ 26 | 'react', 27 | 'vite', 28 | "@playwright/test", 29 | ], 30 | }; -------------------------------------------------------------------------------- /packages/testing/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@repo/typescript-config/base.json", 3 | "compilerOptions": { 4 | "jsx": "react-jsx", 5 | "module": "ESNext", 6 | "target": "esnext", 7 | "moduleResolution": "Bundler", 8 | "strict": true, 9 | "noUnusedLocals": true, 10 | "resolveJsonModule": true, 11 | "esModuleInterop": true, 12 | "noImplicitAny": true, 13 | "lib": ["dom", "esnext"], 14 | "types": ["node"], 15 | "noEmitOnError": true, 16 | }, 17 | "include": ["src/**/*"], 18 | } 19 | -------------------------------------------------------------------------------- /packages/typescript-config/base.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/tsconfig", 3 | "display": "Default", 4 | "compilerOptions": { 5 | "declaration": true, 6 | "declarationMap": true, 7 | "esModuleInterop": true, 8 | "incremental": false, 9 | "isolatedModules": true, 10 | "lib": ["es2022", "DOM", "DOM.Iterable"], 11 | "module": "NodeNext", 12 | "moduleDetection": "force", 13 | "moduleResolution": "NodeNext", 14 | "noUncheckedIndexedAccess": true, 15 | "resolveJsonModule": true, 16 | "skipLibCheck": true, 17 | "strict": true, 18 | "target": "ES2022" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /packages/typescript-config/nextjs.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/tsconfig", 3 | "display": "Next.js", 4 | "extends": "./base.json", 5 | "compilerOptions": { 6 | "plugins": [{ "name": "next" }], 7 | "module": "ESNext", 8 | "moduleResolution": "Bundler", 9 | "allowJs": true, 10 | "jsx": "preserve", 11 | "noEmit": true 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /packages/typescript-config/node.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/tsconfig", 3 | "compilerOptions": { 4 | "composite": true, 5 | "skipLibCheck": true, 6 | "module": "ESNext", 7 | "moduleResolution": "bundler", 8 | "allowSyntheticDefaultImports": true, 9 | "strict": true, 10 | "noEmit": false, 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /packages/typescript-config/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@repo/typescript-config", 3 | "version": "0.0.0", 4 | "private": true, 5 | "license": "MIT", 6 | "publishConfig": { 7 | "access": "public" 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /packages/typescript-config/vite.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/tsconfig", 3 | "display": "React Library", 4 | "compilerOptions": { 5 | "jsx": "react-jsx", 6 | "moduleResolution": "bundler", 7 | "allowImportingTsExtensions": true, 8 | "resolveJsonModule": true, 9 | "isolatedModules": true, 10 | "noEmit": true, 11 | "strict": true, 12 | "noUnusedLocals": true, 13 | "noUnusedParameters": true, 14 | "noFallthroughCasesInSwitch": true, 15 | "target": "ES2020", 16 | "useDefineForClassFields": true, 17 | "lib": ["ES2020", "DOM", "DOM.Iterable"], 18 | "module": "ESNext", 19 | "skipLibCheck": true 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /packages/vite-plugin-csp-guard/rollup.config.mjs: -------------------------------------------------------------------------------- 1 | import resolve from "@rollup/plugin-node-resolve"; 2 | import commonjs from "@rollup/plugin-commonjs"; 3 | import typescript from "@rollup/plugin-typescript"; 4 | import { defineConfig } from "rollup"; 5 | import terser from "@rollup/plugin-terser"; 6 | 7 | export default defineConfig( 8 | [ 9 | { 10 | input: "src/index.ts", // Main plugin entry point 11 | output: [ 12 | { 13 | file: "dist/index.esm.js", 14 | format: "esm", 15 | sourcemap: true, // Enable sourcemaps for debugging 16 | }, 17 | { 18 | file: "dist/index.cjs.js", 19 | format: "cjs", 20 | sourcemap: true, 21 | }, 22 | ], 23 | external: ["lightningcss", "fsevents", "vite", "cheerio"], 24 | plugins: [ 25 | typescript({ 26 | tsconfig: "tsconfig.json", 27 | declaration: true, 28 | declarationDir: "dist", 29 | include: ["src/**/*.ts"], 30 | exclude: ["src/server/**/*.ts"], 31 | sourceMap: true, 32 | }), 33 | resolve(), 34 | commonjs(), 35 | terser(), 36 | ], 37 | } 38 | ] 39 | ); 40 | -------------------------------------------------------------------------------- /packages/vite-plugin-csp-guard/src/constants.ts: -------------------------------------------------------------------------------- 1 | export const FEATURE_FLAGS = { 2 | mpa: false, 3 | cssInJs: false, 4 | }; 5 | -------------------------------------------------------------------------------- /packages/vite-plugin-csp-guard/src/css/extraction.ts: -------------------------------------------------------------------------------- 1 | const cssParser = (unparsed: string) => { 2 | // Step 1: Remove the enclosing double quotes 3 | let convertedCss = unparsed.slice(1, -1); 4 | 5 | // This was found to be an issue with classnames that have a \ in them, tailwind uses this. 6 | // Adjusted Step: Directly replace double backslashes before a colon with a single backslash. 7 | convertedCss = convertedCss.replace(/\\\\:/g, "\\:"); 8 | 9 | // Step 2: Replace \n with actual newlines 10 | convertedCss = convertedCss.replace(/\\n/g, "\n"); 11 | 12 | // Step 3: Unescape double quotes (if any) 13 | convertedCss = convertedCss.replace(/\\"/g, '"'); 14 | 15 | return convertedCss; 16 | }; 17 | 18 | const extractCSSFromVariable = (code: string) => { 19 | // Step 2: Use regex to find and extract the CSS content 20 | const regex = 21 | /const __vite__css\s*=\s*([\s\S]*?)(?=\s*__vite__updateStyle\(__vite__id,\s*__vite__css\))/; 22 | const match = code.match(regex); 23 | if (match && match[1]) { 24 | let cssContent = match[1]; 25 | return cssContent; 26 | } else { 27 | // Return an empty string if the variable or its content is not found 28 | return ""; 29 | } 30 | }; 31 | 32 | export const getCSS = (code: string): string => { 33 | // Step 1: Extract the CSS content from the code 34 | const cssContent = extractCSSFromVariable(code); 35 | 36 | // Step 2: Parse the CSS content 37 | const parsedCss = cssParser(cssContent); 38 | 39 | return parsedCss; 40 | }; 41 | -------------------------------------------------------------------------------- /packages/vite-plugin-csp-guard/src/policy/constants.ts: -------------------------------------------------------------------------------- 1 | import { CSPPolicy } from "csp-toolkit"; 2 | 3 | export const DEFAULT_DEV_POLICY: CSPPolicy = { 4 | "default-src": ["'self'"], 5 | "img-src": ["'self'", "data:"], 6 | "script-src-elem": ["'self'"], 7 | "style-src-elem": ["'self'"], 8 | }; 9 | 10 | export const DEFAULT_POLICY: CSPPolicy = { 11 | "default-src": ["'self'"], 12 | "img-src": ["'self'"], 13 | "script-src-elem": ["'self'"], 14 | "style-src-elem": ["'self'"], 15 | }; 16 | -------------------------------------------------------------------------------- /packages/vite-plugin-csp-guard/src/policy/createPolicy.ts: -------------------------------------------------------------------------------- 1 | import { HtmlTagDescriptor } from "vite"; 2 | import { HashCollection } from "../types"; 3 | import { policyToString, CSPPolicy} from "csp-toolkit"; 4 | 5 | type GeneratePolicyProps = { 6 | policy: CSPPolicy; 7 | collection: HashCollection; 8 | }; 9 | export const generatePolicyString = ({ 10 | collection, 11 | policy, 12 | }: GeneratePolicyProps) => { 13 | const finalPolicy = { ...policy }; 14 | 15 | // Generate the final policy 16 | for (const [key, value] of Object.entries(collection)) { 17 | const currentMap = value; 18 | const currentPolicy = finalPolicy[key as keyof CSPPolicy] ?? []; 19 | 20 | if (currentPolicy.includes("'unsafe-inline'")) { 21 | // If we have unsafe-inline, we should not add any hashes because this will override the unsafe-inline 22 | continue; 23 | } 24 | 25 | if (currentMap.size > 0) { 26 | finalPolicy[key as keyof CSPPolicy] = [ 27 | ...currentPolicy, 28 | ...Array.from(currentMap.keys()), 29 | ]; 30 | } 31 | } 32 | // Create the policy string 33 | const policyString = policyToString(finalPolicy); 34 | 35 | return policyString; 36 | }; 37 | 38 | export const policyToTag = (policy: string): HtmlTagDescriptor[] => { 39 | return [ 40 | { 41 | tag: "meta", 42 | attrs: { 43 | "http-equiv": "Content-Security-Policy", 44 | content: policy, 45 | }, 46 | injectTo: "head-prepend", 47 | }, 48 | ]; 49 | }; 50 | -------------------------------------------------------------------------------- /packages/vite-plugin-csp-guard/src/transform/constants.ts: -------------------------------------------------------------------------------- 1 | import { BuildOutlier, DevOptions, DevOutlier } from "../types"; 2 | 3 | export const REQUIRE_POST_TRANSFORM: Array = [ 4 | "tailwind", 5 | "sass", 6 | "less", 7 | "stylus", 8 | "vue", 9 | ]; 10 | 11 | export const REQUIRE_STRONGER_LAZY_LOADING: Array = [ 12 | "vue-router", 13 | ]; 14 | 15 | export const DEFAULT_DEV_OPTIONS: DevOptions = { 16 | run: false, 17 | outlierSupport: [], 18 | }; 19 | -------------------------------------------------------------------------------- /packages/vite-plugin-csp-guard/tests/extraction.test.ts: -------------------------------------------------------------------------------- 1 | import { describe, expect, test } from "vitest"; 2 | import { 3 | EDGE_CASE_APP_CSS, 4 | EDGE_CASE_INDEX_CSS, 5 | EDGE_CASE_TAILWIND, 6 | } from "../mocks/post"; 7 | import { getCSS } from "../src/css/extraction"; 8 | import { EDGE_CASE_INDEX, EDGE_CASE_APP, TAILWIND_CSS } from "../mocks/css"; 9 | 10 | describe("Extracting CSS", () => { 11 | test("Extract CSS from Post Code Bundle", () => { 12 | const cssIndex = getCSS(EDGE_CASE_INDEX_CSS); 13 | const cssApp = getCSS(EDGE_CASE_APP_CSS); 14 | expect(cssIndex).toEqual(EDGE_CASE_INDEX); 15 | expect(cssApp).toEqual(EDGE_CASE_APP); 16 | }); 17 | 18 | test("Extract Tailwind CSS from Post Code Bundle", () => { 19 | const css = getCSS(EDGE_CASE_TAILWIND); 20 | expect(css).toEqual(TAILWIND_CSS); 21 | }); 22 | }); 23 | -------------------------------------------------------------------------------- /packages/vite-plugin-csp-guard/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@repo/typescript-config/base.json", 3 | "compilerOptions": { 4 | "jsx": "react-jsx", 5 | "module": "ESNext", 6 | "target": "esnext", 7 | "moduleResolution": "Bundler", 8 | "strict": true, 9 | "noUnusedLocals": true, 10 | "resolveJsonModule": true, 11 | "esModuleInterop": true, 12 | "noImplicitAny": true, 13 | "lib": ["dom", "esnext"], 14 | "types": ["node"], 15 | "noEmitOnError": true, 16 | }, 17 | "include": ["src/**/*", "tests/**/*", "mocks/**/*"], 18 | } 19 | -------------------------------------------------------------------------------- /pnpm-workspace.yaml: -------------------------------------------------------------------------------- 1 | packages: 2 | - 'packages/*' 3 | - 'apps/*' -------------------------------------------------------------------------------- /scripts/cleanup-modules.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Find all directories containing node_modules and remove them 4 | find . -type d -name "node_modules" -exec rm -rf {} + 5 | 6 | echo "node_modules directories have been removed from all apps and packages." -------------------------------------------------------------------------------- /scripts/get-package-path.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Check if the package name is passed as an argument 4 | if [ -z "$1" ]; then 5 | echo "Error: Package name is required as an argument." 6 | exit 1 7 | fi 8 | 9 | PACKAGE_NAME=$1 10 | 11 | # Use pnpm list with depth -1 and output JSON 12 | PACKAGE_PATH=$(pnpm list --depth=-1 --json -r | jq -r --arg PACKAGE_NAME "$PACKAGE_NAME" '.[] | select(.name == $PACKAGE_NAME) | .path') 13 | 14 | # Check if the package was found 15 | if [ -z "$PACKAGE_PATH" ]; then 16 | echo "Error: Package '$PACKAGE_NAME' not found." 17 | exit 1 18 | fi 19 | 20 | # Output the path to the package 21 | echo "$PACKAGE_PATH" -------------------------------------------------------------------------------- /scripts/hash-file-content.js: -------------------------------------------------------------------------------- 1 | const fs = require("fs"); 2 | const crypto = require("crypto"); 3 | const process = require("process"); 4 | 5 | const generateHashFromFile = (filePath, algorithm = "sha256") => { 6 | try { 7 | const fileContent = fs.readFileSync(filePath, { encoding: "utf-8" }); 8 | const hash = crypto.createHash(algorithm); 9 | hash.update(fileContent); 10 | return hash.digest("base64"); 11 | } catch (error) { 12 | console.error(`Error reading or hashing file: ${error.message}`); 13 | process.exit(1); 14 | } 15 | }; 16 | 17 | // Check if a file path is provided 18 | if (process.argv.length < 3) { 19 | console.log("Usage: node hash-file-content.js "); 20 | process.exit(1); 21 | } 22 | 23 | const filePath = process.argv[2]; 24 | const hashResult = generateHashFromFile(filePath); 25 | console.log(`Hash for '${filePath}': ${hashResult}`); 26 | -------------------------------------------------------------------------------- /scripts/hash-file-content.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Check if a file path is provided as an argument 4 | if [ "$#" -ne 1 ]; then 5 | echo "Usage: $0 " 6 | exit 1 7 | fi 8 | 9 | file_path="$1" 10 | 11 | # Check if the file exists 12 | if [ ! -f "$file_path" ]; then 13 | echo "Error: File does not exist." 14 | exit 1 15 | fi 16 | 17 | # Generate SHA-256 hash of the file content in binary format and then base64 encode it 18 | openssl dgst -sha256 -binary "$file_path" | base64 -------------------------------------------------------------------------------- /scripts/packages-to-release.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Disallowed packages (packages to ignore for publishing) 4 | DISALLOWED_PACKAGES=("@repo/eslint-config" "@repo/testing" "@repo/typescript-config") 5 | 6 | # Get changed packages using Turbo 7 | CHANGED_PACKAGES=$(pnpm exec turbo build \ 8 | --filter="./packages/*" \ 9 | --filter='!./apps/*' \ 10 | --filter='[HEAD^1]' \ 11 | --dry-run=json | jq -r '.packages[]' | sed 's|^//||') 12 | 13 | # Filter out disallowed packages 14 | ALLOWED_CHANGED_PACKAGES=() 15 | for package in $CHANGED_PACKAGES; do 16 | if [[ ! " ${DISALLOWED_PACKAGES[*]} " == *" $package "* ]]; then 17 | ALLOWED_CHANGED_PACKAGES+=("$package") 18 | fi 19 | done 20 | 21 | # Join the array into a space-separated string, then use jq to create a JSON array 22 | echo "${ALLOWED_CHANGED_PACKAGES[@]}" | jq -R 'split(" ") | map(select(length > 0)) | @json' | jq -r . -------------------------------------------------------------------------------- /scripts/version-has-changed.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Inputs 4 | from=$1 5 | to=$2 6 | packages_input=$3 7 | 8 | # Parse the input string into a JSON array using jq 9 | # The input should already be a valid JSON string representing an array 10 | packages=$(echo "$packages_input" | jq -r '.[]') 11 | 12 | # Filter changed packages 13 | changed_packages=() 14 | 15 | for package in $packages; do 16 | # Get the package path using pnpm 17 | PACKAGE_PATH=$(pnpm list --depth=-1 --json -r | jq -r --arg PACKAGE_NAME "$package" '.[] | select(.name == $PACKAGE_NAME) | .path') 18 | 19 | # Check if the path exists 20 | if [[ -d "$PACKAGE_PATH" ]]; then 21 | # Check for version changes in the package.json 22 | diff_output=$(git diff "$from".."$to" -- "$PACKAGE_PATH/package.json" || true) 23 | 24 | # Check if the diff contains a version change 25 | if [[ $diff_output == *"\"version\":"* ]]; then 26 | changed_packages+=("$package") 27 | fi 28 | fi 29 | done 30 | 31 | # Output the changed packages as a JSON array 32 | echo "${changed_packages[@]}" | jq -R 'split(" ") | map(select(length > 0)) | @json' | jq -r . -------------------------------------------------------------------------------- /turbo.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://turbo.build/schema.json", 3 | "globalDependencies": ["**/.env.*local"], 4 | "tasks": { 5 | "build": { 6 | "dependsOn": ["^build"], 7 | "outputs": [".next/**", "!.next/cache/**", "dist/**", "build/**"] 8 | }, 9 | "lint": { 10 | "dependsOn": ["^lint"] 11 | }, 12 | "test": { 13 | "dependsOn": ["^build"] 14 | }, 15 | "test:ui": { 16 | "dependsOn": ["^build"] 17 | }, 18 | "dev": { 19 | "cache": false, 20 | "persistent": true, 21 | "dependsOn": ["^build"] 22 | }, 23 | "preview": { 24 | "dependsOn": ["^build", "build"], 25 | "persistent": true 26 | } 27 | }, 28 | "ui": "stream" 29 | } 30 | --------------------------------------------------------------------------------