├── .github └── workflows │ ├── production.yml │ └── staging.yml ├── .gitignore ├── Dockerfile ├── LICENSE ├── README.md ├── backend ├── .editorconfig ├── .env.example ├── .eslintignore ├── .eslintrc ├── .gitignore ├── Dockerfile ├── README.md ├── config │ ├── admin.js │ ├── api.js │ ├── database.js │ ├── middlewares.js │ └── server.js ├── database │ └── migrations │ │ └── .gitkeep ├── favicon.ico ├── favicon.png ├── package.json ├── public │ ├── robots.txt │ └── uploads │ │ └── .gitkeep ├── src │ ├── admin │ │ ├── app.example.js │ │ └── webpack.config.example.js │ ├── api │ │ ├── .gitkeep │ │ ├── board │ │ │ ├── content-types │ │ │ │ └── board │ │ │ │ │ └── schema.json │ │ │ ├── controllers │ │ │ │ └── board.js │ │ │ ├── routes │ │ │ │ └── board.js │ │ │ └── services │ │ │ │ └── board.js │ │ └── photo │ │ │ ├── content-types │ │ │ └── photo │ │ │ │ └── schema.json │ │ │ ├── controllers │ │ │ └── photo.js │ │ │ ├── routes │ │ │ └── photo.js │ │ │ └── services │ │ │ └── photo.js │ ├── extensions │ │ └── .gitkeep │ └── index.js └── yarn.lock ├── docker-compose.yaml ├── frontend ├── .env ├── .eslintrc.js ├── .github │ └── workflows │ │ ├── production.yml │ │ └── staging.yml ├── .gitignore ├── .prettierrc.json ├── .storybook │ ├── main.js │ └── preview.js ├── .vscode │ └── extensions.json ├── Dockerfile ├── budget.json ├── cypress.config.js ├── index.html ├── package-lock.json ├── package.json ├── postcss.config.js ├── public │ └── favicon.ico ├── src │ ├── App.vue │ ├── assets │ │ ├── code-brackets.svg │ │ ├── colors.svg │ │ ├── comments.svg │ │ ├── direction.svg │ │ ├── flow.svg │ │ ├── kunal-img.jpg │ │ ├── logo.png │ │ ├── plugin.svg │ │ ├── repo.svg │ │ └── stackalt.svg │ ├── components │ │ ├── atoms │ │ │ ├── Button.stories.js │ │ │ ├── Button.vue │ │ │ ├── CheckField.vue │ │ │ ├── Icon.vue │ │ │ ├── Photo.vue │ │ │ ├── RadioInput.vue │ │ │ └── TextField.vue │ │ ├── molecules │ │ │ ├── Card.vue │ │ │ ├── FormInput.vue │ │ │ ├── JobForm.vue │ │ │ ├── PhotoFilter.vue │ │ │ └── SearchField.vue │ │ ├── organisms │ │ │ ├── Cards.vue │ │ │ ├── DialogBox.vue │ │ │ ├── Header.stories.js │ │ │ ├── Header.vue │ │ │ ├── Login.vue │ │ │ └── Register.vue │ │ └── templates │ │ │ ├── HomeOverview.vue │ │ │ ├── LoginOverview.vue │ │ │ └── RegisterOverview.vue │ ├── graphql │ │ ├── auth │ │ │ └── mutations.js │ │ ├── index.js │ │ ├── photos │ │ │ ├── mutations.js │ │ │ └── queries.js │ │ └── users │ │ │ ├── mutations.js │ │ │ └── queries.js │ ├── helpers │ │ ├── increment.js │ │ └── index.js │ ├── index.css │ ├── locales │ │ ├── de.json │ │ ├── en.json │ │ ├── fr.json │ │ └── index.js │ ├── main.js │ ├── plugins │ │ └── apollo.config.js │ ├── router │ │ └── index.js │ ├── store │ │ └── index.js │ ├── tests │ │ ├── components │ │ │ ├── Button.spec.js │ │ │ └── HomeOverview.spec.js │ │ ├── e2e │ │ │ └── Login.spec.js │ │ ├── index.js │ │ └── unit │ │ │ ├── card.spec.js │ │ │ └── helpers.spec.js │ └── views │ │ ├── HomeView.vue │ │ ├── LoginView.vue │ │ └── RegisterView.vue ├── tailwind.config.js ├── vite.config.js └── yarn.lock ├── package.json ├── postcss.config.js ├── tailwind.config.js ├── vite.config.js └── yarn.lock /.github/workflows/production.yml: -------------------------------------------------------------------------------- 1 | name: PRODUCTION - Deploy container to AWS App Runner # Name of the workflow 2 | on: 3 | pull_request: 4 | branches: 5 | - main 6 | workflow_dispatch: # Allow manual invocation of the workflow 7 | env: 8 | ENVIRONMENT_NAME: production 9 | ECR_REPOSITORY_NAME: vue-pinterest-demo-2 10 | PACKAGE_PATH: frontend 11 | WORKING_DIR: /usr/src/ 12 | 13 | defaults: 14 | run: 15 | working-directory: frontend 16 | 17 | jobs: 18 | deploy: 19 | runs-on: ubuntu-latest 20 | 21 | steps: 22 | - name: Checkout 23 | uses: actions/checkout@v2 24 | with: 25 | persist-credentials: false 26 | 27 | - name: Configure AWS credentials 28 | id: aws-credentials 29 | uses: aws-actions/configure-aws-credentials@v1 30 | with: 31 | aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} 32 | aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} 33 | aws-region: ${{ secrets.AWS_REGION }} 34 | 35 | - name: Login to Amazon ECR 36 | id: ecr-login 37 | uses: aws-actions/amazon-ecr-login@v1 38 | 39 | - name: Build, tag, and push image to Amazon ECR 40 | id: build-image 41 | env: 42 | ECR_REGISTRY: ${{ steps.ecr-login.outputs.registry }} 43 | ECR_REPOSITORY: ${{ env.ECR_REPOSITORY_NAME }} 44 | IMAGE_TAG: ${{ github.sha }} 45 | run: | 46 | docker build -t $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG . 47 | docker push $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG 48 | echo "::set-output name=image::$ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG" 49 | 50 | - name: Deploy to App Runner 51 | id: deploy-app 52 | uses: awslabs/amazon-app-runner-deploy@main 53 | with: 54 | service: erp-app-${{ env.ENVIRONMENT_NAME }} 55 | image: ${{ steps.build-image.outputs.image }} 56 | access-role-arn: ${{ secrets.ROLE_ARN }} 57 | region: ${{ secrets.AWS_REGION }} 58 | cpu: 1 59 | memory: 2 60 | port: 80 61 | wait-for-service-stability: false 62 | 63 | - name: App Runner output 64 | run: echo "App runner output ${{ steps.deploy-app.outputs.service-id }}" 65 | -------------------------------------------------------------------------------- /.github/workflows/staging.yml: -------------------------------------------------------------------------------- 1 | on: 2 | push: 3 | branches: 4 | - chapter-12 5 | 6 | defaults: 7 | run: 8 | working-directory: frontend 9 | 10 | jobs: 11 | # lint: 12 | # runs-on: ubuntu-latest 13 | # container: node:14-alpine 14 | # steps: 15 | # - uses: actions/checkout@v3 16 | # - run: | 17 | # yarn 18 | # yarn lint 19 | 20 | # unit_test: 21 | # runs-on: ubuntu-latest 22 | # container: node:14-alpine 23 | # steps: 24 | # - uses: actions/checkout@v3 25 | # - run: | 26 | # yarn 27 | # yarn test:unit 28 | 29 | # component_test: 30 | # runs-on: ubuntu-latest 31 | # container: node:14-alpine 32 | # needs: unit_test 33 | # steps: 34 | # - uses: actions/checkout@v3 35 | # - run: | 36 | # yarn 37 | # yarn test:component 38 | 39 | e2e_test: 40 | runs-on: ubuntu-latest 41 | # container: node:14-alpine 42 | # needs: component_test 43 | steps: 44 | - name: Checkout 45 | uses: actions/checkout@v3 46 | 47 | - name: Run backend nohup 48 | working-directory: backend 49 | run: | 50 | nohup yarn 51 | nohup yarn develop & 52 | 53 | # - uses: actions/checkout@v3 54 | # - name: Run Frontend Dev server 55 | # run: | 56 | # yarn 57 | # yarn dev 58 | - name: Run E2E test 59 | uses: cypress-io/github-action@v5 60 | with: 61 | record: true 62 | install-command: yarn --silent 63 | start: yarn dev 64 | config-file: frontend/cypress.config.js 65 | wait-on: http://localhost:1337 66 | run: | 67 | yarn test:e2e:ci 68 | 69 | deploy: 70 | runs-on: ubuntu-latest 71 | container: node:14-alpine 72 | needs: e2e_test 73 | steps: 74 | - uses: actions/checkout@v2 75 | - name: Deploy to Netlify 76 | uses: nwtgck/actions-netlify@v1.2 77 | id: deploy-to-netlify 78 | with: 79 | publish-dir: "./dist" 80 | production-branch: chapter-12 81 | github-token: ${{ secrets.GITHUB_TOKEN }} 82 | deploy-message: "Deploy from GitHub Actions" 83 | enable-pull-request-comment: false 84 | enable-commit-comment: true 85 | overwrites-pull-request-comment: true 86 | env: 87 | NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_AUTH_TOKEN }} 88 | NETLIFY_SITE_ID: ${{ secrets.NETLIFY_SITE_ID }} 89 | timeout-minutes: 1 90 | outputs: 91 | preview-url: ${{ steps.deploy-to-netlify.outputs.deploy-url }} 92 | 93 | lighthouse: 94 | runs-on: ubuntu-latest 95 | container: node:14-alpine 96 | needs: deploy 97 | steps: 98 | - uses: actions/checkout@v2 99 | - name: Run Lighthouse on urls and validate with lighthouserc 100 | uses: treosh/lighthouse-ci-action@v7 101 | with: 102 | urls: | 103 | ${{ needs.deploy.outputs.preview-url }} 104 | budgetPath: ./budget.json 105 | runs: 3 106 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:14.15.0 2 | 3 | ARG PACKAGE_PATH= 4 | 5 | ARG WORKING_DIR= 6 | 7 | WORKDIR ${WORKING_DIR} 8 | 9 | COPY ${PACKAGE_PATH}/package*.json ${WORKING_DIR} 10 | 11 | RUN npm install --silent 12 | 13 | COPY ${PACKAGE_PATH} ${WORKING_DIR} 14 | 15 | VOLUME $WORKING_DIR/node_modules 16 | 17 | CMD [ "npm", "start" ] -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Packt 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Architecting Vue.js 3 Enterprise-Ready Web Applications 2 | 3 | Architecting Vue.js 3 Enterprise-Ready Web Applications 4 | 5 | This is the code repository for [Architecting Vue.js 3 Enterprise-Ready Web Applications](https://www.packtpub.com/product/architecting-vuejs-3-enterprise-ready-web-applications/9781801073905), published by Packt. 6 | 7 | **Build and deliver scalable and high-performant enterprise-ready applications with Vue and JavaScript** 8 | 9 | ## What is this book about? 10 | Building enterprise-ready Vue.js apps entails following best practices for creating high-performance and scalable applications. Complete with step-by-step explanations and best practices outlined, this Vue.js book is a must-read for any developer who works with a large Vue.js codebase where performance and scalability are indispensable. 11 | 12 | This book covers the following exciting features: 13 | * Scale your app’s performance in Vue.js 3 using best practices 14 | * Implement testing strategies for large-scale Vue.js codebase 15 | * Manage large file structures using the micro frontend architecture 16 | * Discover the industry standard to Dockerize and deploy an enterprise Vue.js 3 web application 17 | * Use GraphQL to deliver scalable and high-performing applications 18 | 19 | If you feel this book is for you, get your [copy](https://www.amazon.com/dp/1801073902) today! 20 | 21 | https://www.packtpub.com/ 23 | 24 | 25 | ## Instructions and Navigations 26 | All of the code is organized into branches. 27 | 28 | The code will look like the following: 29 | ``` 30 | lint: 31 | runs-on: ubuntu-latest 32 | steps: 33 | - uses: actions/checkout@v3 34 | - run: | 35 | yarn 36 | yarn lint 37 | ``` 38 | 39 | **Following is what you need for this book:** 40 | The Vue.js 3 book is for Vue.js developers and professional frontend developers who want to build high-performance, production-grade, and highly scalable enterprise Vue.js apps from design to deployment. The book assumes working knowledge of Vue.js and JavaScript programming. 41 | 42 | With the following software and hardware list you can run all code files present in the book (Chapter 1-13). 43 | 44 | ### Software and Hardware List 45 | 46 | | Chapter | Software required | OS required | 47 | | -------- | ------------------------------------| -----------------------------------| 48 | | 1-13 | Vue.js | Windows, Mac OS X, and Linux (Any) | 49 | 50 | 51 | We also provide a PDF file that has color images of the screenshots/diagrams used in this book. [Click here to download it](https://packt.link/4Lgta). 52 | 53 | 54 | ### Related products 55 | * ASP.NET Core and Vue.js [[Packt]](https://www.packtpub.com/product/aspnet-core-and-vuejs/9781800206694) [[Amazon]](https://www.amazon.com/dp/1800206690) 56 | 57 | * Vue.js 3 By Example [[Packt]](https://www.packtpub.com/product/vuejs-3-by-example/9781838826345) [[Amazon]](https://www.amazon.com/dp/1838826343) 58 | 59 | ## Get to Know the Author 60 | **Solomon Eseme** 61 | is an experienced Software Engineer, Content Creator, and Founder of [Mastering Backend](https://masteringbackend.com?source=packt_github) with 5+ years of experience working across multiple frontend and backend technologies to design and build high-performing, scalable and innovative applications following best practices and industry standards in a variety of workplaces from start-ups to larger consultancies. He started using Vue since it was first integrated with Laravel and never looked back. He is also a panelist on the ViewsOnVue podcast and technical writer with VueJs Developers. 62 | 63 | ### Download a free PDF 64 | 65 | If you have already purchased a print or Kindle version of this book, you can get a DRM-free PDF version at no cost.
Simply click on the link to claim your free PDF.
66 |

https://packt.link/free-ebook/9781801073905

67 | -------------------------------------------------------------------------------- /backend/.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | indent_style = space 5 | indent_size = 2 6 | end_of_line = lf 7 | charset = utf-8 8 | trim_trailing_whitespace = true 9 | insert_final_newline = true 10 | 11 | [{package.json,*.yml}] 12 | indent_style = space 13 | indent_size = 2 14 | 15 | [*.md] 16 | trim_trailing_whitespace = false 17 | -------------------------------------------------------------------------------- /backend/.env.example: -------------------------------------------------------------------------------- 1 | HOST=0.0.0.0 2 | PORT=1337 3 | APP_KEYS="toBeModified1,toBeModified2" 4 | API_TOKEN_SALT=tobemodified 5 | ADMIN_JWT_SECRET=tobemodified 6 | JWT_SECRET=tobemodified 7 | 8 | -------------------------------------------------------------------------------- /backend/.eslintignore: -------------------------------------------------------------------------------- 1 | .cache 2 | build 3 | **/node_modules/** 4 | -------------------------------------------------------------------------------- /backend/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "parser": "babel-eslint", 3 | "extends": "eslint:recommended", 4 | "env": { 5 | "commonjs": true, 6 | "es6": true, 7 | "node": true, 8 | "browser": false 9 | }, 10 | "parserOptions": { 11 | "ecmaFeatures": { 12 | "experimentalObjectRestSpread": true, 13 | "jsx": false 14 | }, 15 | "sourceType": "module" 16 | }, 17 | "globals": { 18 | "strapi": true 19 | }, 20 | "rules": { 21 | "indent": ["error", 2, { "SwitchCase": 1 }], 22 | "linebreak-style": ["error", "unix"], 23 | "no-console": 0, 24 | "quotes": ["error", "single"], 25 | "semi": ["error", "always"] 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /backend/.gitignore: -------------------------------------------------------------------------------- 1 | ############################ 2 | # OS X 3 | ############################ 4 | 5 | .DS_Store 6 | .AppleDouble 7 | .LSOverride 8 | Icon 9 | .Spotlight-V100 10 | .Trashes 11 | ._* 12 | 13 | 14 | ############################ 15 | # Linux 16 | ############################ 17 | 18 | *~ 19 | 20 | 21 | ############################ 22 | # Windows 23 | ############################ 24 | 25 | Thumbs.db 26 | ehthumbs.db 27 | Desktop.ini 28 | $RECYCLE.BIN/ 29 | *.cab 30 | *.msi 31 | *.msm 32 | *.msp 33 | 34 | 35 | ############################ 36 | # Packages 37 | ############################ 38 | 39 | *.7z 40 | *.csv 41 | *.dat 42 | *.dmg 43 | *.gz 44 | *.iso 45 | *.jar 46 | *.rar 47 | *.tar 48 | *.zip 49 | *.com 50 | *.class 51 | *.dll 52 | *.exe 53 | *.o 54 | *.seed 55 | *.so 56 | *.swo 57 | *.swp 58 | *.swn 59 | *.swm 60 | *.out 61 | *.pid 62 | 63 | 64 | ############################ 65 | # Logs and databases 66 | ############################ 67 | 68 | .tmp 69 | *.log 70 | *.sql 71 | *.sqlite 72 | *.sqlite3 73 | 74 | 75 | ############################ 76 | # Misc. 77 | ############################ 78 | 79 | *# 80 | ssl 81 | .idea 82 | nbproject 83 | public/uploads/* 84 | !public/uploads/.gitkeep 85 | 86 | ############################ 87 | # Node.js 88 | ############################ 89 | 90 | lib-cov 91 | lcov.info 92 | pids 93 | logs 94 | results 95 | node_modules 96 | .node_history 97 | 98 | ############################ 99 | # Tests 100 | ############################ 101 | 102 | testApp 103 | coverage 104 | 105 | ############################ 106 | # Strapi 107 | ############################ 108 | 109 | .env 110 | license.txt 111 | exports 112 | *.cache 113 | dist 114 | build 115 | .strapi-updater.json 116 | -------------------------------------------------------------------------------- /backend/Dockerfile: -------------------------------------------------------------------------------- 1 | # Use the official Node.js 14 Alpine image from https://hub.docker.com/_/node. 2 | # Using an image with specific version tags allow deterministic builds. 3 | FROM node:14.16.1 AS builder 4 | 5 | # Create and change to the app directory. 6 | WORKDIR /usr/src/backend 7 | 8 | # Copy important root files to the builder image. 9 | COPY package*.json ./ 10 | 11 | # Install production dependencies. 12 | RUN npm install 13 | 14 | # Copy the Backend source to the container image. 15 | COPY . . 16 | 17 | # build app for production with minification 18 | RUN npm run build 19 | 20 | EXPOSE 1337 21 | 22 | # Init final image generation. 23 | FROM node:14.16.1 24 | 25 | # Run the Strapi service on container startup. 26 | CMD ["npm", "start"] 27 | -------------------------------------------------------------------------------- /backend/README.md: -------------------------------------------------------------------------------- 1 | # 🚀 Getting started with Strapi 2 | 3 | Strapi comes with a full featured [Command Line Interface](https://docs.strapi.io/developer-docs/latest/developer-resources/cli/CLI.html) (CLI) which lets you scaffold and manage your project in seconds. 4 | 5 | ### `develop` 6 | 7 | Start your Strapi application with autoReload enabled. [Learn more](https://docs.strapi.io/developer-docs/latest/developer-resources/cli/CLI.html#strapi-develop) 8 | 9 | ``` 10 | npm run develop 11 | # or 12 | yarn develop 13 | ``` 14 | 15 | ### `start` 16 | 17 | Start your Strapi application with autoReload disabled. [Learn more](https://docs.strapi.io/developer-docs/latest/developer-resources/cli/CLI.html#strapi-start) 18 | 19 | ``` 20 | npm run start 21 | # or 22 | yarn start 23 | ``` 24 | 25 | ### `build` 26 | 27 | Build your admin panel. [Learn more](https://docs.strapi.io/developer-docs/latest/developer-resources/cli/CLI.html#strapi-build) 28 | 29 | ``` 30 | npm run build 31 | # or 32 | yarn build 33 | ``` 34 | 35 | ## ⚙️ Deployment 36 | 37 | Strapi gives you many possible deployment options for your project. Find the one that suits you on the [deployment section of the documentation](https://docs.strapi.io/developer-docs/latest/setup-deployment-guides/deployment.html). 38 | 39 | ## 📚 Learn more 40 | 41 | - [Resource center](https://strapi.io/resource-center) - Strapi resource center. 42 | - [Strapi documentation](https://docs.strapi.io) - Official Strapi documentation. 43 | - [Strapi tutorials](https://strapi.io/tutorials) - List of tutorials made by the core team and the community. 44 | - [Strapi blog](https://docs.strapi.io) - Official Strapi blog containing articles made by the Strapi team and the community. 45 | - [Changelog](https://strapi.io/changelog) - Find out about the Strapi product updates, new features and general improvements. 46 | 47 | Feel free to check out the [Strapi GitHub repository](https://github.com/strapi/strapi). Your feedback and contributions are welcome! 48 | 49 | ## ✨ Community 50 | 51 | - [Discord](https://discord.strapi.io) - Come chat with the Strapi community including the core team. 52 | - [Forum](https://forum.strapi.io/) - Place to discuss, ask questions and find answers, show your Strapi project and get feedback or just talk with other Community members. 53 | - [Awesome Strapi](https://github.com/strapi/awesome-strapi) - A curated list of awesome things related to Strapi. 54 | 55 | --- 56 | 57 | 🤫 Psst! [Strapi is hiring](https://strapi.io/careers). 58 | -------------------------------------------------------------------------------- /backend/config/admin.js: -------------------------------------------------------------------------------- 1 | module.exports = ({ env }) => ({ 2 | auth: { 3 | secret: env('ADMIN_JWT_SECRET'), 4 | }, 5 | apiToken: { 6 | salt: env('API_TOKEN_SALT'), 7 | }, 8 | }); 9 | -------------------------------------------------------------------------------- /backend/config/api.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | rest: { 3 | defaultLimit: 25, 4 | maxLimit: 100, 5 | withCount: true, 6 | }, 7 | }; 8 | -------------------------------------------------------------------------------- /backend/config/database.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | 3 | module.exports = ({ env }) => ({ 4 | connection: { 5 | client: 'sqlite', 6 | connection: { 7 | filename: path.join(__dirname, '..', env('DATABASE_FILENAME', '.tmp/data.db')), 8 | }, 9 | useNullAsDefault: true, 10 | }, 11 | }); 12 | -------------------------------------------------------------------------------- /backend/config/middlewares.js: -------------------------------------------------------------------------------- 1 | module.exports = [ 2 | 'strapi::errors', 3 | 'strapi::security', 4 | 'strapi::cors', 5 | 'strapi::poweredBy', 6 | 'strapi::logger', 7 | 'strapi::query', 8 | 'strapi::body', 9 | 'strapi::session', 10 | 'strapi::favicon', 11 | 'strapi::public', 12 | ]; 13 | -------------------------------------------------------------------------------- /backend/config/server.js: -------------------------------------------------------------------------------- 1 | module.exports = ({ env }) => ({ 2 | host: env('HOST', '0.0.0.0'), 3 | port: env.int('PORT', 1337), 4 | app: { 5 | keys: env.array('APP_KEYS'), 6 | }, 7 | }); 8 | -------------------------------------------------------------------------------- /backend/database/migrations/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Architecting-Vue.js-3-Enterprise-Ready-Web-Applications/2a46900038fc42672cbda9922e76b0dca05605a8/backend/database/migrations/.gitkeep -------------------------------------------------------------------------------- /backend/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Architecting-Vue.js-3-Enterprise-Ready-Web-Applications/2a46900038fc42672cbda9922e76b0dca05605a8/backend/favicon.ico -------------------------------------------------------------------------------- /backend/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Architecting-Vue.js-3-Enterprise-Ready-Web-Applications/2a46900038fc42672cbda9922e76b0dca05605a8/backend/favicon.png -------------------------------------------------------------------------------- /backend/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "backend", 3 | "private": true, 4 | "version": "0.1.0", 5 | "description": "A Strapi application", 6 | "scripts": { 7 | "develop": "strapi develop", 8 | "start": "strapi start", 9 | "build": "strapi build", 10 | "strapi": "strapi" 11 | }, 12 | "devDependencies": {}, 13 | "dependencies": { 14 | "@strapi/plugin-graphql": "^4.5.5", 15 | "@strapi/plugin-i18n": "4.5.5", 16 | "@strapi/plugin-users-permissions": "4.5.5", 17 | "@strapi/strapi": "4.5.5", 18 | "better-sqlite3": "7.4.6" 19 | }, 20 | "author": { 21 | "name": "A Strapi developer" 22 | }, 23 | "strapi": { 24 | "uuid": "daec4bf8-e7a1-441c-90f9-ecbb4783b589" 25 | }, 26 | "engines": { 27 | "node": ">=14.19.1 <=18.x.x", 28 | "npm": ">=6.0.0" 29 | }, 30 | "license": "MIT" 31 | } 32 | -------------------------------------------------------------------------------- /backend/public/robots.txt: -------------------------------------------------------------------------------- 1 | # To prevent search engines from seeing the site altogether, uncomment the next two lines: 2 | # User-Agent: * 3 | # Disallow: / 4 | -------------------------------------------------------------------------------- /backend/public/uploads/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Architecting-Vue.js-3-Enterprise-Ready-Web-Applications/2a46900038fc42672cbda9922e76b0dca05605a8/backend/public/uploads/.gitkeep -------------------------------------------------------------------------------- /backend/src/admin/app.example.js: -------------------------------------------------------------------------------- 1 | const config = { 2 | locales: [ 3 | // 'ar', 4 | // 'fr', 5 | // 'cs', 6 | // 'de', 7 | // 'dk', 8 | // 'es', 9 | // 'he', 10 | // 'id', 11 | // 'it', 12 | // 'ja', 13 | // 'ko', 14 | // 'ms', 15 | // 'nl', 16 | // 'no', 17 | // 'pl', 18 | // 'pt-BR', 19 | // 'pt', 20 | // 'ru', 21 | // 'sk', 22 | // 'sv', 23 | // 'th', 24 | // 'tr', 25 | // 'uk', 26 | // 'vi', 27 | // 'zh-Hans', 28 | // 'zh', 29 | ], 30 | }; 31 | 32 | const bootstrap = (app) => { 33 | console.log(app); 34 | }; 35 | 36 | export default { 37 | config, 38 | bootstrap, 39 | }; 40 | -------------------------------------------------------------------------------- /backend/src/admin/webpack.config.example.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /* eslint-disable no-unused-vars */ 4 | module.exports = (config, webpack) => { 5 | // Note: we provide webpack above so you should not `require` it 6 | // Perform customizations to webpack config 7 | // Important: return the modified config 8 | return config; 9 | }; 10 | -------------------------------------------------------------------------------- /backend/src/api/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Architecting-Vue.js-3-Enterprise-Ready-Web-Applications/2a46900038fc42672cbda9922e76b0dca05605a8/backend/src/api/.gitkeep -------------------------------------------------------------------------------- /backend/src/api/board/content-types/board/schema.json: -------------------------------------------------------------------------------- 1 | { 2 | "kind": "collectionType", 3 | "collectionName": "boards", 4 | "info": { 5 | "singularName": "board", 6 | "pluralName": "boards", 7 | "displayName": "Board" 8 | }, 9 | "options": { 10 | "draftAndPublish": true 11 | }, 12 | "pluginOptions": {}, 13 | "attributes": { 14 | "title": { 15 | "type": "text" 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /backend/src/api/board/controllers/board.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /** 4 | * board controller 5 | */ 6 | 7 | const { createCoreController } = require('@strapi/strapi').factories; 8 | 9 | module.exports = createCoreController('api::board.board'); 10 | -------------------------------------------------------------------------------- /backend/src/api/board/routes/board.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /** 4 | * board router 5 | */ 6 | 7 | const { createCoreRouter } = require('@strapi/strapi').factories; 8 | 9 | module.exports = createCoreRouter('api::board.board'); 10 | -------------------------------------------------------------------------------- /backend/src/api/board/services/board.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /** 4 | * board service 5 | */ 6 | 7 | const { createCoreService } = require('@strapi/strapi').factories; 8 | 9 | module.exports = createCoreService('api::board.board'); 10 | -------------------------------------------------------------------------------- /backend/src/api/photo/content-types/photo/schema.json: -------------------------------------------------------------------------------- 1 | { 2 | "kind": "collectionType", 3 | "collectionName": "photos", 4 | "info": { 5 | "singularName": "photo", 6 | "pluralName": "photos", 7 | "displayName": "Photo" 8 | }, 9 | "options": { 10 | "draftAndPublish": true 11 | }, 12 | "pluginOptions": {}, 13 | "attributes": { 14 | "title": { 15 | "type": "text" 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /backend/src/api/photo/controllers/photo.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /** 4 | * photo controller 5 | */ 6 | 7 | const { createCoreController } = require('@strapi/strapi').factories; 8 | 9 | module.exports = createCoreController('api::photo.photo'); 10 | -------------------------------------------------------------------------------- /backend/src/api/photo/routes/photo.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /** 4 | * photo router 5 | */ 6 | 7 | const { createCoreRouter } = require('@strapi/strapi').factories; 8 | 9 | module.exports = createCoreRouter('api::photo.photo'); 10 | -------------------------------------------------------------------------------- /backend/src/api/photo/services/photo.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /** 4 | * photo service 5 | */ 6 | 7 | const { createCoreService } = require('@strapi/strapi').factories; 8 | 9 | module.exports = createCoreService('api::photo.photo'); 10 | -------------------------------------------------------------------------------- /backend/src/extensions/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Architecting-Vue.js-3-Enterprise-Ready-Web-Applications/2a46900038fc42672cbda9922e76b0dca05605a8/backend/src/extensions/.gitkeep -------------------------------------------------------------------------------- /backend/src/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = { 4 | /** 5 | * An asynchronous register function that runs before 6 | * your application is initialized. 7 | * 8 | * This gives you an opportunity to extend code. 9 | */ 10 | register(/*{ strapi }*/) {}, 11 | 12 | /** 13 | * An asynchronous bootstrap function that runs before 14 | * your application gets started. 15 | * 16 | * This gives you an opportunity to set up your data model, 17 | * run jobs, or perform some special logic. 18 | */ 19 | bootstrap(/*{ strapi }*/) {}, 20 | }; 21 | -------------------------------------------------------------------------------- /docker-compose.yaml: -------------------------------------------------------------------------------- 1 | version: "3.5" 2 | 3 | services: 4 | 5 | api: 6 | 7 | build: 8 | 9 | context: . 10 | 11 | dockerfile: Dockerfile 12 | 13 | args: 14 | PACKAGE_PATH: backend 15 | WORKING_DIR: /usr/src/ 16 | 17 | expose: 18 | - 1337 19 | 20 | ports: 21 | - 1337:1337 22 | 23 | environment: 24 | - NODE_ENV=development 25 | - HOST=0.0.0.0 26 | - PORT=1337 27 | - BASE_URL=http://api:1337 28 | 29 | env_file: 30 | - ./.env 31 | 32 | volumes: 33 | - ./backend:/usr/src 34 | 35 | command: > 36 | sh -c "npm install" 37 | 38 | frontend: 39 | 40 | build: 41 | 42 | context: . 43 | 44 | dockerfile: Dockerfile 45 | 46 | args: 47 | PACKAGE_PATH: frontend 48 | WORKING_DIR: /usr/src/ 49 | 50 | expose: 51 | - 3000 52 | 53 | ports: 54 | - 3000:3000 55 | 56 | environment: 57 | - APP_ENV=production 58 | - APP_BACKEND=http://0.0.0.0:1337/api 59 | - NODE_PATH=/usr/src/ 60 | - APP_TOKEN=eyJhbGciOiJIUzI1NiJ9.c29sb[STRAPI_TOKEN] 61 | 62 | env_file: 63 | - ./common.env 64 | 65 | volumes: 66 | - ./frontend:/usr/src 67 | 68 | depends_on: 69 | - api 70 | 71 | command: [ "npm", "start" ] 72 | -------------------------------------------------------------------------------- /frontend/.env: -------------------------------------------------------------------------------- 1 | BE_URL=http://localhost:1337 2 | FE_URL=http://localhost:3000 -------------------------------------------------------------------------------- /frontend/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | extends: [ 3 | // add more generic rulesets here, such as: 4 | // 'eslint:recommended', 5 | "plugin:vue/vue3-recommended", 6 | // 'plugin:vue/vue3-essential', // This option doesn't impose formatting rules 7 | // 'plugin:vue/vue3-strongly-recommended', // This option imposes formatting rules on your code to improve readability 8 | ], 9 | rules: { 10 | // override/add rules settings here, such as: 11 | // 'vue/no-unused-vars': 'error' 12 | }, 13 | }; 14 | -------------------------------------------------------------------------------- /frontend/.github/workflows/production.yml: -------------------------------------------------------------------------------- 1 | name: PRODUCTION - Deploy container to AWS App Runner # Name of the workflow 2 | on: 3 | pull_request: 4 | branches: 5 | - main 6 | workflow_dispatch: # Allow manual invocation of the workflow 7 | env: 8 | ENVIRONMENT_NAME: production 9 | ECR_REPOSITORY_NAME: vue-pinterest-demo 10 | jobs: 11 | deploy: 12 | runs-on: ubuntu-latest 13 | 14 | steps: 15 | - name: Checkout 16 | uses: actions/checkout@v2 17 | with: 18 | persist-credentials: false 19 | 20 | - name: Configure AWS credentials 21 | id: aws-credentials 22 | uses: aws-actions/configure-aws-credentials@v1 23 | with: 24 | aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} 25 | aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} 26 | aws-region: ${{ secrets.AWS_REGION }} 27 | 28 | - name: Login to Amazon ECR 29 | id: ecr-login 30 | uses: aws-actions/amazon-ecr-login@v1 31 | 32 | - name: Build, tag, and push image to Amazon ECR 33 | id: build-image 34 | env: 35 | ECR_REGISTRY: ${{ steps.ecr-login.outputs.registry }} 36 | ECR_REPOSITORY: ${{ env.ECR_REPOSITORY_NAME }} 37 | IMAGE_TAG: ${{ github.sha }} 38 | run: | 39 | docker build -t $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG . 40 | docker push $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG 41 | echo "::set-output name=image::$ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG" 42 | 43 | - name: Deploy to App Runner 44 | id: deploy-app 45 | uses: awslabs/amazon-app-runner-deploy@main 46 | with: 47 | service: erp-app-${{ env.ENVIRONMENT_NAME }} 48 | image: ${{ steps.build-image.outputs.image }} 49 | access-role-arn: ${{ secrets.ROLE_ARN }} 50 | region: ${{ secrets.AWS_REGION }} 51 | cpu : 1 52 | memory : 2 53 | port: 80 54 | wait-for-service-stability: false 55 | 56 | - name: App Runner output 57 | run: echo "App runner output ${{ steps.deploy-app.outputs.service-id }}" -------------------------------------------------------------------------------- /frontend/.github/workflows/staging.yml: -------------------------------------------------------------------------------- 1 | on: 2 | push: 3 | branches: 4 | - chapter-12 5 | 6 | jobs: 7 | lint: 8 | runs-on: ubuntu-latest 9 | steps: 10 | - uses: actions/checkout@v3 11 | - run: | 12 | yarn 13 | yarn lint 14 | 15 | unit_test: 16 | runs-on: ubuntu-latest 17 | steps: 18 | - uses: actions/checkout@v3 19 | - run: | 20 | yarn 21 | yarn test:unit 22 | 23 | component_test: 24 | runs-on: ubuntu-latest 25 | needs: unit_test 26 | steps: 27 | - uses: actions/checkout@v3 28 | - run: | 29 | yarn 30 | yarn test:component 31 | 32 | e2e_test: 33 | runs-on: ubuntu-latest 34 | needs: component_test 35 | steps: 36 | - uses: actions/checkout@v3 37 | - run: | 38 | yarn 39 | yarn test:e2e 40 | 41 | deploy: 42 | runs-on: ubuntu-latest 43 | needs: e2e_test 44 | steps: 45 | - uses: actions/checkout@v2 46 | - name: Deploy to Netlify 47 | uses: nwtgck/actions-netlify@v1.2 48 | id: deploy-to-netlify 49 | with: 50 | publish-dir: './dist' 51 | production-branch: chapter-12 52 | github-token: ${{ secrets.GITHUB_TOKEN }} 53 | deploy-message: "Deploy from GitHub Actions" 54 | enable-pull-request-comment: false 55 | enable-commit-comment: true 56 | overwrites-pull-request-comment: true 57 | env: 58 | NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_AUTH_TOKEN }} 59 | NETLIFY_SITE_ID: ${{ secrets.NETLIFY_SITE_ID }} 60 | timeout-minutes: 1 61 | outputs: 62 | preview-url: ${{ steps.deploy-to-netlify.outputs.deploy-url }} 63 | 64 | lighthouse: 65 | runs-on: ubuntu-latest 66 | needs: deploy 67 | steps: 68 | - uses: actions/checkout@v2 69 | - name: Run Lighthouse on urls and validate with lighthouserc 70 | uses: treosh/lighthouse-ci-action@v7 71 | with: 72 | urls: | 73 | ${{ needs.deploy.outputs.preview-url }} 74 | budgetPath: ./budget.json 75 | runs: 3 76 | 77 | -------------------------------------------------------------------------------- /frontend/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | package-lock.json 11 | yarn.lock 12 | 13 | node_modules 14 | dist 15 | dist-ssr 16 | *.local 17 | 18 | # Editor directories and files 19 | .vscode/* 20 | !.vscode/extensions.json 21 | .idea 22 | .DS_Store 23 | *.suo 24 | *.ntvs* 25 | *.njsproj 26 | *.sln 27 | *.sw? 28 | 29 | cypress/* -------------------------------------------------------------------------------- /frontend/.prettierrc.json: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /frontend/.storybook/main.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | "stories": [ 3 | "../src/**/*.stories.mdx", 4 | "../src/**/*.stories.@(js|jsx|ts|tsx)" 5 | ], 6 | "addons": [ 7 | "@storybook/addon-links", 8 | "@storybook/addon-essentials" 9 | ], 10 | "framework": "@storybook/vue3" 11 | } -------------------------------------------------------------------------------- /frontend/.storybook/preview.js: -------------------------------------------------------------------------------- 1 | export const parameters = { 2 | actions: { argTypesRegex: "^on[A-Z].*" }, 3 | controls: { 4 | matchers: { 5 | color: /(background|color)$/i, 6 | date: /Date$/, 7 | }, 8 | }, 9 | } -------------------------------------------------------------------------------- /frontend/.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": ["johnsoncodehk.volar"] 3 | } 4 | -------------------------------------------------------------------------------- /frontend/Dockerfile: -------------------------------------------------------------------------------- 1 | # Use the official Node.js 14 Alpine image from https://hub.docker.com/_/node. 2 | # Using an image with specific version tags allow deterministic builds. 3 | FROM node:fermium-alpine3.14 AS builder 4 | 5 | # Create and change to the app directory. 6 | WORKDIR /app 7 | 8 | # Copy important root files to the builder image. 9 | COPY package*.json ./ 10 | 11 | RUN npm cache verify 12 | 13 | # Install production dependencies. 14 | RUN npm install 15 | 16 | # Copy the Vue 3 source to the container image. 17 | COPY . . 18 | 19 | # build app for production with minification 20 | RUN npm run build 21 | 22 | # Production stage 23 | FROM nginx:stable-alpine as production-stage 24 | 25 | # Copy the Vue 3 source to the container image. 26 | COPY --from=builder /app/dist /usr/share/nginx/html 27 | 28 | VOLUME /app/node_modules 29 | 30 | EXPOSE 80 31 | 32 | # Run the Vue service on container startup. 33 | CMD ["nginx", "-g", "daemon off;"] -------------------------------------------------------------------------------- /frontend/budget.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "path": "/*", 4 | "timings": [ 5 | { 6 | "metric": "first-contentful-paint", 7 | "budget": 2200 8 | }, 9 | { 10 | "metric": "speed-index", 11 | "budget": 3000 12 | }, 13 | { 14 | "metric": "largest-contentful-paint", 15 | "budget": 3000 16 | }, 17 | { 18 | "metric": "interactive", 19 | "budget": 3000 20 | }, 21 | { 22 | "metric": "total-blocking-time", 23 | "budget": 250 24 | }, 25 | { 26 | "metric": "cumulative-layout-shift", 27 | "budget": 0 28 | } 29 | ], 30 | "resourceSizes": [ 31 | { 32 | "resourceType": "script", 33 | "budget": 150 34 | }, 35 | { 36 | "resourceType": "total", 37 | "budget": 400 38 | } 39 | ], 40 | "resourceCounts": [ 41 | { 42 | "resourceType": "third-party", 43 | "budget": 5 44 | } 45 | ] 46 | } 47 | ] 48 | -------------------------------------------------------------------------------- /frontend/cypress.config.js: -------------------------------------------------------------------------------- 1 | const { defineConfig } = require("cypress"); 2 | 3 | module.exports = defineConfig({ 4 | component: {}, 5 | 6 | env: { 7 | // HINT: here we read these keys from .env file, feel free to remove the items that you don't need 8 | baseUrl: process.env.FE_URL ?? "http://localhost:3000", 9 | apiUrl: process.env.BE_URL ?? "http://localhost:1337", 10 | email: "admin@test.com", 11 | password: "Admin111", 12 | }, 13 | 14 | e2e: { 15 | supportFolder: false, 16 | supportFile: false, 17 | specPattern: "src/tests/e2e/**/*.spec.js", 18 | // eslint-disable-next-line no-unused-vars 19 | setupNodeEvents(on, config) { 20 | // implement node event listeners here 21 | }, 22 | 23 | baseUrl: process.env.FE_URL ?? "http://localhost:3000", 24 | }, 25 | }); 26 | -------------------------------------------------------------------------------- /frontend/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Vite App 8 | 9 | 10 |
11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /frontend/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "architecting-vue", 3 | "private": true, 4 | "version": "0.0.0", 5 | "scripts": { 6 | "dev": "vite", 7 | "build": "vite build", 8 | "preview": "vite preview", 9 | "storybook": "start-storybook -p 6006", 10 | "build-storybook": "build-storybook", 11 | "lint": "eslint . --ext .vue,.js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts --fix --ignore-path .gitignore", 12 | "test:unit": "vitest run", 13 | "test:component": "vitest run", 14 | "test:e2e": "cypress open --e2e", 15 | "test:e2e:ci": "cypress run --e2e" 16 | }, 17 | "dependencies": { 18 | "@apollo/client": "^3.6.4", 19 | "@cypress/vue": "^3.1.0", 20 | "@cypress/webpack-dev-server": "^3.2.1", 21 | "@vue/apollo-composable": "^4.0.0-beta.4", 22 | "cypress": "^12.2.0", 23 | "graphql": "^16.5.0", 24 | "graphql-tag": "^2.12.6", 25 | "jest": "^28.1.3", 26 | "storybook": "^1.0.0", 27 | "vue": "^3.2.25", 28 | "vue-i18n": "^9.1.9", 29 | "vue-router": "^4.1.6" 30 | }, 31 | "devDependencies": { 32 | "@babel/core": "^7.17.9", 33 | "@storybook/addon-actions": "^6.4.22", 34 | "@storybook/addon-essentials": "^6.4.22", 35 | "@storybook/addon-links": "^6.4.22", 36 | "@storybook/vue3": "^6.4.22", 37 | "@testing-library/vue": "^6.6.1", 38 | "@vitejs/plugin-vue": "^2.3.1", 39 | "@vue/cli-plugin-router": "~4.5.13", 40 | "@vue/test-utils": "^2.0.2", 41 | "@vue/vue3-jest": "28", 42 | "autoprefixer": "^10.4.7", 43 | "babel-loader": "^8.2.4", 44 | "eslint": "^8.27.0", 45 | "eslint-config-prettier": "^8.5.0", 46 | "eslint-plugin-vue": "^9.7.0", 47 | "happy-dom": "^6.0.4", 48 | "postcss": "^8.4.14", 49 | "tailwindcss": "^3.1.4", 50 | "vite": "^2.9.2", 51 | "vitest": "^0.22.1", 52 | "vue-loader": "^16.8.3" 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /frontend/postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | } 7 | -------------------------------------------------------------------------------- /frontend/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Architecting-Vue.js-3-Enterprise-Ready-Web-Applications/2a46900038fc42672cbda9922e76b0dca05605a8/frontend/public/favicon.ico -------------------------------------------------------------------------------- /frontend/src/App.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 8 | 9 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /frontend/src/assets/code-brackets.svg: -------------------------------------------------------------------------------- 1 | illustration/code-brackets -------------------------------------------------------------------------------- /frontend/src/assets/colors.svg: -------------------------------------------------------------------------------- 1 | illustration/colors -------------------------------------------------------------------------------- /frontend/src/assets/comments.svg: -------------------------------------------------------------------------------- 1 | illustration/comments -------------------------------------------------------------------------------- /frontend/src/assets/direction.svg: -------------------------------------------------------------------------------- 1 | illustration/direction -------------------------------------------------------------------------------- /frontend/src/assets/flow.svg: -------------------------------------------------------------------------------- 1 | illustration/flow -------------------------------------------------------------------------------- /frontend/src/assets/kunal-img.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Architecting-Vue.js-3-Enterprise-Ready-Web-Applications/2a46900038fc42672cbda9922e76b0dca05605a8/frontend/src/assets/kunal-img.jpg -------------------------------------------------------------------------------- /frontend/src/assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Architecting-Vue.js-3-Enterprise-Ready-Web-Applications/2a46900038fc42672cbda9922e76b0dca05605a8/frontend/src/assets/logo.png -------------------------------------------------------------------------------- /frontend/src/assets/plugin.svg: -------------------------------------------------------------------------------- 1 | illustration/plugin -------------------------------------------------------------------------------- /frontend/src/assets/repo.svg: -------------------------------------------------------------------------------- 1 | illustration/repo -------------------------------------------------------------------------------- /frontend/src/assets/stackalt.svg: -------------------------------------------------------------------------------- 1 | illustration/stackalt -------------------------------------------------------------------------------- /frontend/src/components/atoms/Button.stories.js: -------------------------------------------------------------------------------- 1 | import MyButton from './Button.vue'; 2 | 3 | // More on default export: https://storybook.js.org/docs/vue/writing-stories/introduction#default-export 4 | export default { 5 | title: 'Example/Button', 6 | component: MyButton, 7 | // More on argTypes: https://storybook.js.org/docs/vue/api/argtypes 8 | argTypes: { 9 | backgroundColor: { control: 'color' }, 10 | onClick: {}, 11 | size: { 12 | control: { type: 'select' }, 13 | options: ['small', 'medium', 'large'], 14 | }, 15 | }, 16 | }; 17 | 18 | // More on component templates: https://storybook.js.org/docs/vue/writing-stories/introduction#using-args 19 | const Template = (args) => ({ 20 | // Components used in your story `template` are defined in the `components` object 21 | components: { MyButton }, 22 | // The story's `args` need to be mapped into the template through the `setup()` method 23 | setup() { 24 | return { args }; 25 | }, 26 | // And then the `args` are bound to your component with `v-bind="args"` 27 | template: '', 28 | }); 29 | 30 | export const Primary = Template.bind({}); 31 | // More on args: https://storybook.js.org/docs/vue/writing-stories/args 32 | Primary.args = { 33 | primary: true, 34 | label: 'Button', 35 | }; 36 | 37 | export const Secondary = Template.bind({}); 38 | Secondary.args = { 39 | label: 'Button', 40 | }; 41 | 42 | export const Large = Template.bind({}); 43 | Large.args = { 44 | size: 'large', 45 | label: 'Button', 46 | }; 47 | 48 | export const Small = Template.bind({}); 49 | Small.args = { 50 | size: 'small', 51 | label: 'Button', 52 | }; 53 | -------------------------------------------------------------------------------- /frontend/src/components/atoms/Button.vue: -------------------------------------------------------------------------------- 1 | 17 | 18 | 78 | 133 | -------------------------------------------------------------------------------- /frontend/src/components/atoms/CheckField.vue: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Architecting-Vue.js-3-Enterprise-Ready-Web-Applications/2a46900038fc42672cbda9922e76b0dca05605a8/frontend/src/components/atoms/CheckField.vue -------------------------------------------------------------------------------- /frontend/src/components/atoms/Icon.vue: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 12 | 17 | 18 | -------------------------------------------------------------------------------- /frontend/src/components/atoms/Photo.vue: -------------------------------------------------------------------------------- 1 | 6 | -------------------------------------------------------------------------------- /frontend/src/components/atoms/RadioInput.vue: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Architecting-Vue.js-3-Enterprise-Ready-Web-Applications/2a46900038fc42672cbda9922e76b0dca05605a8/frontend/src/components/atoms/RadioInput.vue -------------------------------------------------------------------------------- /frontend/src/components/atoms/TextField.vue: -------------------------------------------------------------------------------- 1 | 37 | 38 | 129 | 130 | -------------------------------------------------------------------------------- /frontend/src/components/molecules/Card.vue: -------------------------------------------------------------------------------- 1 | 2 | 456 | 457 | 468 | 469 | 474 | 475 | 476 | -------------------------------------------------------------------------------- /frontend/src/components/molecules/FormInput.vue: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Architecting-Vue.js-3-Enterprise-Ready-Web-Applications/2a46900038fc42672cbda9922e76b0dca05605a8/frontend/src/components/molecules/FormInput.vue -------------------------------------------------------------------------------- /frontend/src/components/molecules/JobForm.vue: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Architecting-Vue.js-3-Enterprise-Ready-Web-Applications/2a46900038fc42672cbda9922e76b0dca05605a8/frontend/src/components/molecules/JobForm.vue -------------------------------------------------------------------------------- /frontend/src/components/molecules/PhotoFilter.vue: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Architecting-Vue.js-3-Enterprise-Ready-Web-Applications/2a46900038fc42672cbda9922e76b0dca05605a8/frontend/src/components/molecules/PhotoFilter.vue -------------------------------------------------------------------------------- /frontend/src/components/molecules/SearchField.vue: -------------------------------------------------------------------------------- 1 | 18 | 19 | 22 | 23 | -------------------------------------------------------------------------------- /frontend/src/components/organisms/Cards.vue: -------------------------------------------------------------------------------- 1 | 2 | 77 | 78 | 109 | 114 | 115 | 116 | 117 | -------------------------------------------------------------------------------- /frontend/src/components/organisms/DialogBox.vue: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Architecting-Vue.js-3-Enterprise-Ready-Web-Applications/2a46900038fc42672cbda9922e76b0dca05605a8/frontend/src/components/organisms/DialogBox.vue -------------------------------------------------------------------------------- /frontend/src/components/organisms/Header.stories.js: -------------------------------------------------------------------------------- 1 | import MyHeader from "./Header.vue"; 2 | 3 | export default { 4 | title: "Example/Header", 5 | component: MyHeader, 6 | }; 7 | 8 | const Template = (args) => ({ 9 | // Components used in your story `template` are defined in the `components` object 10 | components: { MyHeader }, 11 | // The story's `args` need to be mapped into the template through the `setup()` method 12 | setup() { 13 | // Story args can be spread into the returned object 14 | return { ...args }; 15 | }, 16 | // Then, the spread values can be accessed directly in the template 17 | template: '', 18 | }); 19 | 20 | export const LoggedIn = Template.bind({}); 21 | LoggedIn.args = { 22 | user: {}, 23 | }; 24 | 25 | export const LoggedOut = Template.bind({}); 26 | LoggedOut.args = { 27 | user: null, 28 | }; 29 | -------------------------------------------------------------------------------- /frontend/src/components/organisms/Header.vue: -------------------------------------------------------------------------------- 1 | 2 | 162 | 163 | 175 | 176 | 181 | 183 | -------------------------------------------------------------------------------- /frontend/src/components/organisms/Login.vue: -------------------------------------------------------------------------------- 1 | 2 | 38 | 39 | 72 | 73 | 78 | 79 | -------------------------------------------------------------------------------- /frontend/src/components/organisms/Register.vue: -------------------------------------------------------------------------------- 1 | 2 | 38 | 39 | 75 | -------------------------------------------------------------------------------- /frontend/src/components/templates/HomeOverview.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 14 | -------------------------------------------------------------------------------- /frontend/src/components/templates/LoginOverview.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 12 | -------------------------------------------------------------------------------- /frontend/src/components/templates/RegisterOverview.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 12 | -------------------------------------------------------------------------------- /frontend/src/graphql/auth/mutations.js: -------------------------------------------------------------------------------- 1 | import { gql } from "graphql-tag"; 2 | 3 | export const LOGIN_USER = gql` 4 | mutation login($input: UsersPermissionsLoginInput!) { 5 | login(input: $input) { 6 | jwt 7 | user { 8 | id 9 | email 10 | username 11 | } 12 | } 13 | } 14 | `; 15 | 16 | export const REGISTER = gql` 17 | mutation register($input: RegisterUserInput!) { 18 | register(data: $input) { 19 | id 20 | name 21 | email 22 | } 23 | } 24 | `; 25 | -------------------------------------------------------------------------------- /frontend/src/graphql/index.js: -------------------------------------------------------------------------------- 1 | export * from "./auth/mutations"; 2 | export * from "./photos/queries"; 3 | -------------------------------------------------------------------------------- /frontend/src/graphql/photos/mutations.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Architecting-Vue.js-3-Enterprise-Ready-Web-Applications/2a46900038fc42672cbda9922e76b0dca05605a8/frontend/src/graphql/photos/mutations.js -------------------------------------------------------------------------------- /frontend/src/graphql/photos/queries.js: -------------------------------------------------------------------------------- 1 | import gql from "graphql-tag"; 2 | 3 | export const GET_PHOTOS = gql` 4 | query photos( 5 | $sort: [String] = [] 6 | $pagination: PaginationArg = {} 7 | $filters: PhotoFiltersInput 8 | $publicationState: PublicationState = LIVE 9 | ) { 10 | photos( 11 | filters: $filters 12 | pagination: $pagination 13 | sort: $sort 14 | publicationState: $publicationState 15 | ) { 16 | data { 17 | id 18 | attributes { 19 | title 20 | } 21 | } 22 | } 23 | } 24 | `; 25 | -------------------------------------------------------------------------------- /frontend/src/graphql/users/mutations.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Architecting-Vue.js-3-Enterprise-Ready-Web-Applications/2a46900038fc42672cbda9922e76b0dca05605a8/frontend/src/graphql/users/mutations.js -------------------------------------------------------------------------------- /frontend/src/graphql/users/queries.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Architecting-Vue.js-3-Enterprise-Ready-Web-Applications/2a46900038fc42672cbda9922e76b0dca05605a8/frontend/src/graphql/users/queries.js -------------------------------------------------------------------------------- /frontend/src/helpers/increment.js: -------------------------------------------------------------------------------- 1 | export function increment(current, max = 10) { 2 | if (current < max) { 3 | return current + 1; 4 | } 5 | return current; 6 | } 7 | -------------------------------------------------------------------------------- /frontend/src/helpers/index.js: -------------------------------------------------------------------------------- 1 | export * from './increment'; 2 | -------------------------------------------------------------------------------- /frontend/src/index.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | 5 | :root { 6 | --card_width: 230px; 7 | --card_border_radius: 16px; 8 | --row_increment: 10px; 9 | --card_small: 26; 10 | --card_medium: 33; 11 | --card_large: 45; 12 | --card_smaller: 17.7; 13 | } 14 | 15 | 16 | .pin_container { 17 | margin: 0 10px; 18 | padding: 0 10px; 19 | display: grid; 20 | grid-template-columns: repeat(auto-fill, var(--card_width)); 21 | grid-template-rows: var(--row_increment); 22 | align-items: center; 23 | 24 | } 25 | 26 | .card { 27 | padding: 0; 28 | margin: 15px 10px; 29 | border-radius: var(--card_border_radius); 30 | background-color: red; 31 | } 32 | 33 | .card_small { 34 | grid-row-end: span var(--card_small); 35 | } 36 | 37 | .card_smaller { 38 | grid-row-end: span var(--card_small); 39 | } 40 | 41 | .card_medium { 42 | grid-row-end: span var(--card_medium); 43 | } 44 | 45 | .card_large { 46 | grid-row-end: span var(--card_large); 47 | } -------------------------------------------------------------------------------- /frontend/src/locales/de.json: -------------------------------------------------------------------------------- 1 | { 2 | "welcomeMsg": "Welcome to Your Vue.js App" 3 | } 4 | -------------------------------------------------------------------------------- /frontend/src/locales/en.json: -------------------------------------------------------------------------------- 1 | { 2 | "welcomeMsg": "Welcome to Your Vue.js App" 3 | } 4 | -------------------------------------------------------------------------------- /frontend/src/locales/fr.json: -------------------------------------------------------------------------------- 1 | { 2 | "welcomeMsg": "Welcome to Your Vue.js App" 3 | } 4 | -------------------------------------------------------------------------------- /frontend/src/locales/index.js: -------------------------------------------------------------------------------- 1 | import en from "./en.json"; 2 | import fr from "./fr.json"; 3 | import de from "./de.json"; 4 | 5 | const messages = { 6 | en, 7 | fr, 8 | de, 9 | }; 10 | 11 | export default messages; 12 | -------------------------------------------------------------------------------- /frontend/src/main.js: -------------------------------------------------------------------------------- 1 | import { createApp, provide, h } from "vue"; 2 | import { createI18n } from "vue-i18n"; 3 | import App from "./App.vue"; 4 | import locales from "./locales/index.js"; 5 | import apolloClient from "./plugins/apollo.config"; 6 | import { DefaultApolloClient } from "@vue/apollo-composable"; 7 | import router from "./router"; 8 | import "./index.css"; 9 | 10 | const i18n = createI18n({ 11 | locale: "en", // set locale 12 | fallbackLocale: "en", // set fallback locale 13 | messages: locales, // set locale messages 14 | }); 15 | 16 | const app = createApp({ 17 | setup() { 18 | provide(DefaultApolloClient, apolloClient); 19 | }, 20 | render: () => h(App), 21 | }); 22 | 23 | app.use(router); 24 | app.use(i18n); 25 | app.mount("#app"); 26 | -------------------------------------------------------------------------------- /frontend/src/plugins/apollo.config.js: -------------------------------------------------------------------------------- 1 | import { 2 | ApolloClient, 3 | createHttpLink, 4 | InMemoryCache, 5 | } from "@apollo/client/core"; 6 | 7 | // HTTP connection to the API 8 | const httpLink = createHttpLink({ 9 | // You should use an absolute URL here 10 | uri: "http://localhost:1337/graphql", 11 | }); 12 | 13 | // Cache implementation 14 | const cache = new InMemoryCache(); 15 | 16 | // Create the apollo client 17 | const apolloClient = new ApolloClient({ 18 | link: httpLink, 19 | cache, 20 | }); 21 | 22 | export default apolloClient; 23 | -------------------------------------------------------------------------------- /frontend/src/router/index.js: -------------------------------------------------------------------------------- 1 | import { createRouter, createWebHistory } from "vue-router"; 2 | import HomeView from "@/views/HomeView.vue"; 3 | 4 | const router = createRouter({ 5 | history: createWebHistory(import.meta.env.BASE_URL), 6 | routes: [ 7 | { 8 | path: "/", 9 | name: "home", 10 | component: HomeView, 11 | }, 12 | { 13 | path: "/login", 14 | name: "login", 15 | component: () => import("@/views/LoginView.vue"), 16 | }, 17 | { 18 | path: "/register", 19 | name: "register", 20 | component: () => import("@/views/RegisterView.vue"), 21 | }, 22 | ], 23 | }); 24 | 25 | export default router; 26 | -------------------------------------------------------------------------------- /frontend/src/store/index.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Architecting-Vue.js-3-Enterprise-Ready-Web-Applications/2a46900038fc42672cbda9922e76b0dca05605a8/frontend/src/store/index.js -------------------------------------------------------------------------------- /frontend/src/tests/components/Button.spec.js: -------------------------------------------------------------------------------- 1 | import { render } from "@testing-library/vue"; 2 | import { test } from "vitest"; 3 | import Button from "../../components/atoms/Button.vue"; 4 | 5 | test("mounted a button with custom label", async () => { 6 | // The render method returns a collection of utilities to query your component. 7 | const { getByText } = render(Button, { 8 | props: { 9 | label: "Test", 10 | }, 11 | }); 12 | 13 | // getByText returns the first matching node for the provided text, and 14 | 15 | // Check if button is render with Label from props 16 | getByText("Test"); 17 | }); 18 | -------------------------------------------------------------------------------- /frontend/src/tests/components/HomeOverview.spec.js: -------------------------------------------------------------------------------- 1 | import { fireEvent, render } from "@testing-library/vue"; 2 | import { describe, expect, it } from "vitest"; 3 | import HomeOverview from "../../components/templates/HomeOverview.vue"; 4 | 5 | describe("HomeOverview.vue", () => { 6 | it("renders component", async () => { 7 | const { getByText } = render(HomeOverview); 8 | getByText("Home"); 9 | }); 10 | 11 | it("creates pin on button click", async () => { 12 | const { getByTestId, emitted } = render(HomeOverview); 13 | 14 | await fireEvent.click(getByTestId("create")); 15 | expect(emitted()).toHaveProperty("click"); 16 | }); 17 | 18 | it("dismisses notification", async () => { 19 | const { getByTestId, emitted } = render(HomeOverview); 20 | 21 | await fireEvent.click(getByTestId("dismissed")); 22 | expect(emitted()).toHaveProperty("click"); 23 | }); 24 | 25 | it("displays first 14 pins", async () => { 26 | const { getAllByText } = render(HomeOverview); 27 | const card = getAllByText("Quick save and organize later"); 28 | expect(card.length).toBe(14); 29 | }); 30 | 31 | it("renders Search component", async () => { 32 | const { getByTestId } = render(HomeOverview); 33 | getByTestId("search"); 34 | }); 35 | }); 36 | -------------------------------------------------------------------------------- /frontend/src/tests/e2e/Login.spec.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-undef */ 2 | 3 | const afterLoginFunction = () => { 4 | cy.visit(`${Cypress.env("baseUrl")}/login`); 5 | }; 6 | 7 | describe("Login tests", () => { 8 | beforeEach(() => { 9 | afterLoginFunction(); 10 | cy.wait(5000); 11 | }); 12 | 13 | it("Should show an success message if the email address and password is valid", () => { 14 | cy.get("#passwordField").type(`${Cypress.env("password")}`); 15 | cy.get("#emailField").type(`${Cypress.env("email")}`); 16 | 17 | cy.get("#loginForm").then(() => { 18 | cy.get("#submitButton").click(); 19 | cy.wait(1000); 20 | cy.get("#loggedIn").should("be.visible"); 21 | }); 22 | }); 23 | 24 | it("Should show an error message if the email address and password is not valid", () => { 25 | cy.get("#emailField").type("test@test.com"); 26 | cy.get("#passwordField").type("test"); 27 | 28 | cy.get("#loginForm").then(() => { 29 | cy.get("#submitButton").click(); 30 | cy.wait(1000); 31 | cy.get("#failed").should("be.visible"); 32 | }); 33 | }); 34 | }); 35 | -------------------------------------------------------------------------------- /frontend/src/tests/index.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Architecting-Vue.js-3-Enterprise-Ready-Web-Applications/2a46900038fc42672cbda9922e76b0dca05605a8/frontend/src/tests/index.js -------------------------------------------------------------------------------- /frontend/src/tests/unit/card.spec.js: -------------------------------------------------------------------------------- 1 | import { render, fireEvent } from "@testing-library/vue"; 2 | import { expect, test } from "vitest"; 3 | import Card from "../../components/molecules/Card.vue"; 4 | 5 | test("displays a card with success status", async () => { 6 | const { getByTestId } = render(Card, { 7 | props: { 8 | status: "success", 9 | }, 10 | }); 11 | const card = getByTestId("pin"); 12 | expect(card).toBeDefined(); 13 | }); 14 | 15 | test("displays a card with error status", async () => { 16 | const { getByText } = render(Card, { 17 | props: { 18 | status: "error", 19 | }, 20 | }); 21 | const card = getByText("An error occurred"); 22 | expect(card.textContent).toEqual("An error occurred"); 23 | }); 24 | 25 | test("displays a card with loading status", async () => { 26 | const { getByText } = render(Card, { 27 | props: { 28 | status: "loading", 29 | }, 30 | }); 31 | const card = getByText("Loading photo..."); 32 | expect(card.textContent).toEqual("Loading photo..."); 33 | }); 34 | 35 | test("clicks a create pin button", async () => { 36 | const { getByTestId, emitted } = render(Card); 37 | 38 | await fireEvent.click(getByTestId("create_pin")); 39 | expect(emitted()).toHaveProperty("click"); 40 | }); 41 | -------------------------------------------------------------------------------- /frontend/src/tests/unit/helpers.spec.js: -------------------------------------------------------------------------------- 1 | import { describe, it, expect } from "vitest"; 2 | import { increment } from "../../helpers"; 3 | 4 | describe("increment", () => { 5 | it("increments the current number by 1", () => { 6 | expect(increment(0, 10)).toBe(1); 7 | }); 8 | 9 | it("does not increment the current number over the max", () => { 10 | expect(increment(10, 10)).toBe(10); 11 | }); 12 | 13 | it("has a default max of 10", () => { 14 | expect(increment(10)).toBe(10); 15 | }); 16 | }); 17 | -------------------------------------------------------------------------------- /frontend/src/views/HomeView.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 10 | -------------------------------------------------------------------------------- /frontend/src/views/LoginView.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 10 | -------------------------------------------------------------------------------- /frontend/src/views/RegisterView.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 10 | -------------------------------------------------------------------------------- /frontend/tailwind.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('tailwindcss').Config} */ 2 | module.exports = { 3 | content: ['./index.html', './src/**/*.{vue,js,ts,jsx,tsx}'], 4 | theme: { 5 | extend: {}, 6 | }, 7 | plugins: [], 8 | }; 9 | -------------------------------------------------------------------------------- /frontend/vite.config.js: -------------------------------------------------------------------------------- 1 | import { defineConfig } from "vite"; 2 | import { configDefaults } from "vitest/config"; 3 | import vue from "@vitejs/plugin-vue"; 4 | const path = require("path"); 5 | // https://vitejs.dev/config/ 6 | export default defineConfig({ 7 | plugins: [vue()], 8 | resolve: { 9 | alias: { 10 | "@": path.resolve(__dirname, "./src"), 11 | }, 12 | }, 13 | test: { 14 | exclude: [...configDefaults.exclude, "**/tests/e2e/**"], 15 | environment: "happy-dom", 16 | globals: true, 17 | }, 18 | }); 19 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "architecting-vue", 3 | "private": true, 4 | "version": "0.0.0", 5 | "scripts": { 6 | "dev": "vite", 7 | "build": "vite build", 8 | "preview": "vite preview", 9 | "storybook": "start-storybook -p 6006", 10 | "build-storybook": "build-storybook", 11 | "lint": "eslint . --ext .vue,.js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts --fix --ignore-path .gitignore", 12 | "test:unit": "vitest run", 13 | "test:component": "vitest run", 14 | "test:e2e": "cypress open --e2e", 15 | "test:e2e:ci": "cypress run --e2e" 16 | }, 17 | "dependencies": { 18 | "@apollo/client": "^3.6.4", 19 | "@cypress/vue": "^3.1.0", 20 | "@cypress/webpack-dev-server": "^3.2.1", 21 | "@vue/apollo-composable": "^4.0.0-alpha.17", 22 | "cypress": "^12.2.0", 23 | "graphql": "^16.5.0", 24 | "graphql-tag": "^2.12.6", 25 | "jest": "^28.1.3", 26 | "storybook": "^1.0.0", 27 | "vue": "^3.2.25", 28 | "vue-i18n": "^9.1.9" 29 | }, 30 | "devDependencies": { 31 | "@babel/core": "^7.17.9", 32 | "@storybook/addon-actions": "^6.4.22", 33 | "@storybook/addon-essentials": "^6.4.22", 34 | "@storybook/addon-links": "^6.4.22", 35 | "@storybook/vue3": "^6.4.22", 36 | "@testing-library/vue": "^6.6.1", 37 | "@vitejs/plugin-vue": "^2.3.1", 38 | "@vue/test-utils": "^2.0.2", 39 | "@vue/vue3-jest": "28", 40 | "autoprefixer": "^10.4.7", 41 | "babel-loader": "^8.2.4", 42 | "eslint": "^8.27.0", 43 | "eslint-config-prettier": "^8.5.0", 44 | "eslint-plugin-vue": "^9.7.0", 45 | "happy-dom": "^6.0.4", 46 | "postcss": "^8.4.14", 47 | "tailwindcss": "^3.1.4", 48 | "vite": "^2.9.2", 49 | "vitest": "^0.22.1", 50 | "vue-loader": "^16.8.3" 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | } 7 | -------------------------------------------------------------------------------- /tailwind.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('tailwindcss').Config} */ 2 | module.exports = { 3 | content: ['./index.html', './src/**/*.{vue,js,ts,jsx,tsx}'], 4 | theme: { 5 | extend: {}, 6 | }, 7 | plugins: [], 8 | }; 9 | -------------------------------------------------------------------------------- /vite.config.js: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite' 2 | import vue from '@vitejs/plugin-vue' 3 | 4 | // https://vitejs.dev/config/ 5 | export default defineConfig({ 6 | plugins: [vue()] 7 | }) 8 | --------------------------------------------------------------------------------