├── .browserslistrc ├── babel.config.js ├── public ├── favicon.ico └── index.html ├── vue.config.js ├── src ├── assets │ └── logo.png ├── main.ts ├── shims-vue.d.ts ├── composables │ ├── api.ts │ └── products.ts ├── App.vue └── components │ └── HelloWorld.vue ├── .editorconfig ├── .github ├── PULL_REQUEST_TEMPLATE.md ├── CONTRIBUTING.md ├── ISSUE_TEMPLATE │ ├── FEATURE_REQUEST.md │ └── BUG_REPORT.md └── CODE_OF_CONDUCT.md ├── .gitignore ├── .eslintrc.js ├── tsconfig.json ├── package.json ├── LICENSE └── README.md /.browserslistrc: -------------------------------------------------------------------------------- 1 | > 1% 2 | last 2 versions 3 | not dead 4 | -------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: ["@vue/cli-plugin-babel/preset"] 3 | }; 4 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moduslabs/vue3-example-hooks-ts/HEAD/public/favicon.ico -------------------------------------------------------------------------------- /vue.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | devServer: { 3 | disableHostCheck: true, 4 | }, 5 | }; 6 | -------------------------------------------------------------------------------- /src/assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/moduslabs/vue3-example-hooks-ts/HEAD/src/assets/logo.png -------------------------------------------------------------------------------- /src/main.ts: -------------------------------------------------------------------------------- 1 | import { createApp } from "vue"; 2 | import App from "./App.vue"; 3 | 4 | createApp(App).mount("#app"); 5 | -------------------------------------------------------------------------------- /src/shims-vue.d.ts: -------------------------------------------------------------------------------- 1 | declare module "*.vue" { 2 | import { Component } from "vue"; 3 | var component: Component; 4 | export default component; 5 | } 6 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | [*] 3 | end_of_line = lf 4 | insert_final_newline = true 5 | trim_trailing_whitespace = true 6 | 7 | [*.{js,vue,css}] 8 | charset = utf-8 9 | indent_style = space 10 | indent_size = 2 11 | continuation_indent_size = 6 12 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ### Change 2 | 3 | {Describe what kind of change does this PR introduce} 4 | 5 | ### Does this PR introduce a breaking change? 6 | 7 | {...} 8 | 9 | ### What needs to be documented once your changes are merged? 10 | 11 | {...} 12 | 13 | ### Additional Comments 14 | 15 | {...} 16 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /dist 4 | 5 | # local env files 6 | .env.local 7 | .env.*.local 8 | 9 | # Log files 10 | npm-debug.log* 11 | yarn-debug.log* 12 | yarn-error.log* 13 | pnpm-debug.log* 14 | 15 | # Editor directories and files 16 | .idea 17 | .vscode 18 | *.suo 19 | *.ntvs* 20 | *.njsproj 21 | *.sln 22 | *.sw? 23 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | env: { 4 | node: true 5 | }, 6 | extends: [ 7 | "plugin:vue/vue3-essential", 8 | "eslint:recommended", 9 | "@vue/typescript/recommended", 10 | "@vue/prettier", 11 | "@vue/prettier/@typescript-eslint" 12 | ], 13 | parserOptions: { 14 | ecmaVersion: 2020 15 | }, 16 | rules: { 17 | "no-console": process.env.NODE_ENV === "production" ? "warn" : "off", 18 | "no-debugger": process.env.NODE_ENV === "production" ? "warn" : "off" 19 | } 20 | }; 21 | -------------------------------------------------------------------------------- /.github/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to Project 2 | 3 | ### Code of Conduct 4 | 5 | Modus has adopted a [Code of Conduct](./CODE_OF_CONDUCT.md) that we expect project participants to adhere to. 6 | 7 | ### Submitting a Pull Request 8 | 9 | If you are a first time contributor, you can learn how from this _free_ series [How to Contribute to an Open Source Project on GitHub](https://egghead.io/series/how-to-contribute-to-an-open-source-project-on-github). 10 | 11 | ### License 12 | 13 | By contributing, you agree that your contributions will be licensed under it's [license](../LICENSE). 14 | -------------------------------------------------------------------------------- /src/composables/api.ts: -------------------------------------------------------------------------------- 1 | import { ref, Ref } from "vue"; 2 | 3 | export type ApiRequest = () => Promise; 4 | 5 | export interface UsableAPI { 6 | response: Ref; 7 | request: ApiRequest; 8 | } 9 | 10 | export default function useApi( 11 | url: RequestInfo, 12 | options?: RequestInit 13 | ): UsableAPI { 14 | const response: Ref = ref(); 15 | 16 | const request: ApiRequest = async () => { 17 | const res = await fetch(url, options); 18 | const data = await res.json(); 19 | response.value = data; 20 | }; 21 | 22 | return { response, request }; 23 | } 24 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/FEATURE_REQUEST.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | --- 5 | 6 | **Is your feature request related to a problem? Please describe.** 7 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 8 | 9 | **Describe the solution you'd like** 10 | A clear and concise description of what you want to happen. 11 | 12 | **Describe alternatives you've considered** 13 | A clear and concise description of any alternative solutions or features you've considered. 14 | 15 | **Additional context** 16 | Add any other context or screenshots about the feature request here. 17 | -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | <%= htmlWebpackPlugin.options.title %> 9 | 10 | 11 | 14 |
15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "esnext", 4 | "module": "esnext", 5 | "strict": true, 6 | "jsx": "preserve", 7 | "importHelpers": true, 8 | "moduleResolution": "node", 9 | "experimentalDecorators": true, 10 | "esModuleInterop": true, 11 | "allowSyntheticDefaultImports": true, 12 | "sourceMap": true, 13 | "baseUrl": ".", 14 | "types": [ 15 | "webpack-env" 16 | ], 17 | "paths": { 18 | "@/*": [ 19 | "src/*" 20 | ] 21 | }, 22 | "lib": [ 23 | "esnext", 24 | "dom", 25 | "dom.iterable", 26 | "scripthost" 27 | ] 28 | }, 29 | "include": [ 30 | "src/**/*.ts", 31 | "src/**/*.tsx", 32 | "src/**/*.vue", 33 | "tests/**/*.ts", 34 | "tests/**/*.tsx" 35 | ], 36 | "exclude": [ 37 | "node_modules" 38 | ] 39 | } 40 | -------------------------------------------------------------------------------- /src/App.vue: -------------------------------------------------------------------------------- 1 | 14 | 15 | 25 | 26 | 36 | -------------------------------------------------------------------------------- /src/composables/products.ts: -------------------------------------------------------------------------------- 1 | import useApi from "./api"; 2 | import { Ref, ref } from "vue"; 3 | 4 | export interface Variant { 5 | id: string; 6 | title: string; 7 | sku: string; 8 | quantity: number; 9 | } 10 | 11 | export interface Product { 12 | id: string; 13 | title: string; 14 | description: string; 15 | images: string[]; 16 | category: string; 17 | variants: Variant[]; 18 | price: number; 19 | tags: string[]; 20 | } 21 | 22 | export type UsableProducts = Promise<{ products: Ref }>; 23 | 24 | export default async function useProducts(): UsableProducts { 25 | const { response: products, request } = useApi( 26 | "https://ecomm-products.modus.workers.dev/" 27 | ); 28 | 29 | const loaded = ref(false); 30 | 31 | if (loaded.value === false) { 32 | await request(); 33 | loaded.value = true; 34 | } 35 | 36 | return { products }; 37 | } 38 | -------------------------------------------------------------------------------- /src/components/HelloWorld.vue: -------------------------------------------------------------------------------- 1 | 12 | 13 | 29 | 30 | 31 | 46 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vue3-ts", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "serve": "vue-cli-service serve", 7 | "build": "vue-cli-service build", 8 | "lint": "vue-cli-service lint" 9 | }, 10 | "dependencies": { 11 | "core-js": "^3.6.5", 12 | "vue": "^3.0.0" 13 | }, 14 | "devDependencies": { 15 | "@typescript-eslint/eslint-plugin": "^4.4.0", 16 | "@typescript-eslint/parser": "^4.4.0", 17 | "@vue/cli-plugin-babel": "~4.5.7", 18 | "@vue/cli-plugin-eslint": "~4.5.7", 19 | "@vue/cli-plugin-typescript": "~4.5.7", 20 | "@vue/cli-service": "~4.5.7", 21 | "@vue/compiler-sfc": "^3.0.0", 22 | "@vue/eslint-config-prettier": "^6.0.0", 23 | "@vue/eslint-config-typescript": "^7.0.0", 24 | "eslint": "^6.7.2", 25 | "eslint-plugin-prettier": "^3.1.4", 26 | "eslint-plugin-vue": "^7.0.1", 27 | "prettier": "^2.1.2", 28 | "typescript": "^4.0.3", 29 | "vue-template-compiler": "^2.6.12" 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright 2019 Modus Create, Inc. 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 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/BUG_REPORT.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | --- 5 | 6 | **Environment:** 7 | 8 | **Application version** 9 | 10 | - App version or git commit number + branch 11 | - App location (local, dev, test, stage, prod) 12 | - Any paticular configuration of the app 13 | 14 | **Desktop (please complete the following information):** 15 | 16 | - OS: [e.g. iOS] 17 | - Browser [e.g. chrome, safari] 18 | - Version [e.g. 22] 19 | 20 | **Smartphone (please complete the following information):** 21 | 22 | - Device: [e.g. iPhone6] 23 | - OS: [e.g. iOS8.1] 24 | - Browser [e.g. stock browser, safari] 25 | - Version [e.g. 22] 26 | 27 | **Additional context** 28 | Add any other context about the problem here. 29 | 30 | **To Reproduce** 31 | Steps to reproduce the behavior: 32 | 33 | 1. Go to '...' 34 | 2. Click on '....' 35 | 3. Scroll down to '....' 36 | 4. See error 37 | 38 | **Expected behavior** 39 | A clear and concise description of what you expected to happen. 40 | 41 | **Actual behavior** 42 | A clear and concise description of what is actually happening. 43 | 44 | **Screenshots or videos** 45 | If applicable, add screenshots or videos to help explain your problem. 46 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Vue 3 Composable Hooks with TypeScript 2 | 3 | [![MIT Licensed](https://img.shields.io/badge/license-MIT-blue.svg?style=flat-square)](./LICENSE) 4 | [![Powered by Modus_Create](https://img.shields.io/badge/powered_by-Modus_Create-blue.svg?longCache=true&style=flat&logo=data:image/svg+xml;base64,PHN2ZyB2aWV3Qm94PSIwIDAgMzIwIDMwMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KICA8cGF0aCBkPSJNOTguODI0IDE0OS40OThjMCAxMi41Ny0yLjM1NiAyNC41ODItNi42MzcgMzUuNjM3LTQ5LjEtMjQuODEtODIuNzc1LTc1LjY5Mi04Mi43NzUtMTM0LjQ2IDAtMTcuNzgyIDMuMDkxLTM0LjgzOCA4Ljc0OS01MC42NzVhMTQ5LjUzNSAxNDkuNTM1IDAgMCAxIDQxLjEyNCAxMS4wNDYgMTA3Ljg3NyAxMDcuODc3IDAgMCAwLTcuNTIgMzkuNjI4YzAgMzYuODQyIDE4LjQyMyA2OS4zNiA0Ni41NDQgODguOTAzLjMyNiAzLjI2NS41MTUgNi41Ny41MTUgOS45MjF6TTY3LjgyIDE1LjAxOGM0OS4xIDI0LjgxMSA4Mi43NjggNzUuNzExIDgyLjc2OCAxMzQuNDggMCA4My4xNjgtNjcuNDIgMTUwLjU4OC0xNTAuNTg4IDE1MC41ODh2LTQyLjM1M2M1OS43NzggMCAxMDguMjM1LTQ4LjQ1OSAxMDguMjM1LTEwOC4yMzUgMC0zNi44NS0xOC40My02OS4zOC00Ni41NjItODguOTI3YTk5Ljk0OSA5OS45NDkgMCAwIDEtLjQ5Ny05Ljg5NyA5OC41MTIgOTguNTEyIDAgMCAxIDYuNjQ0LTM1LjY1NnptMTU1LjI5MiAxODIuNzE4YzE3LjczNyAzNS41NTggNTQuNDUgNTkuOTk3IDk2Ljg4OCA1OS45OTd2NDIuMzUzYy02MS45NTUgMC0xMTUuMTYyLTM3LjQyLTEzOC4yOC05MC44ODZhMTU4LjgxMSAxNTguODExIDAgMCAwIDQxLjM5Mi0xMS40NjR6bS0xMC4yNi02My41ODlhOTguMjMyIDk4LjIzMiAwIDAgMS00My40MjggMTQuODg5QzE2OS42NTQgNzIuMjI0IDIyNy4zOSA4Ljk1IDMwMS44NDUuMDAzYzQuNzAxIDEzLjE1MiA3LjU5MyAyNy4xNiA4LjQ1IDQxLjcxNC01MC4xMzMgNC40Ni05MC40MzMgNDMuMDgtOTcuNDQzIDkyLjQzem01NC4yNzgtNjguMTA1YzEyLjc5NC04LjEyNyAyNy41NjctMTMuNDA3IDQzLjQ1Mi0xNC45MTEtLjI0NyA4Mi45NTctNjcuNTY3IDE1MC4xMzItMTUwLjU4MiAxNTAuMTMyLTIuODQ2IDAtNS42NzMtLjA4OC04LjQ4LS4yNDNhMTU5LjM3OCAxNTkuMzc4IDAgMCAwIDguMTk4LTQyLjExOGMuMDk0IDAgLjE4Ny4wMDguMjgyLjAwOCA1NC41NTcgMCA5OS42NjUtNDAuMzczIDEwNy4xMy05Mi44Njh6IiBmaWxsPSIjRkZGIiBmaWxsLXJ1bGU9ImV2ZW5vZGQiLz4KPC9zdmc+)](https://moduscreate.com) 5 | [![Run on Repl.it](https://repl.it/badge/github/moduslabs/vue3-example-hooks-ts)](https://repl.it/github/moduslabs/vue3-example-hooks-ts) 6 | 7 | Example project that demonstrates how to use Vue 3 hooks with Composition API - and to compose them. Powered with type safety and TypeScript, this project shows how to compose an API hook and fetch product data in a scalable way. 8 | 9 | # Getting Started 10 | 11 | You can watch this video to learn how to get started with Vue 3 Composable Hooks and Typescript. 12 | 13 | ### Vue 3 Hooks and Type Safety with TypeScript 14 | 15 | [![Vue 3 Hooks and Type Safety with TypeScript](https://img.youtube.com/vi/aJdi-uEKYAc/0.jpg)](https://youtu.be/aJdi-uEKYAc) 16 | 17 | # How it works 18 | 19 | Test in: 20 | 21 | - Repl.it: [https://repl.it/@Modus/vue3-example-hooks-ts](https://repl.it/@Modus/vue3-example-hooks-ts) 22 | - CodeSandbox: [https://codesandbox.io/s/vue3-example-hooks-ts-77ykv](https://codesandbox.io/s/vue3-example-hooks-ts-77ykv) 23 | 24 | ## Project setup 25 | 26 | ``` 27 | npm install 28 | ``` 29 | 30 | ### Compiles and hot-reloads for development 31 | 32 | ``` 33 | npm run serve 34 | ``` 35 | 36 | ### Compiles and minifies for production 37 | 38 | ``` 39 | npm run build 40 | ``` 41 | 42 | ### Lints and fixes files 43 | 44 | ``` 45 | npm run lint 46 | ``` 47 | 48 | ### Customize configuration 49 | 50 | See [Configuration Reference](https://cli.vuejs.org/config/). 51 | 52 | # Modus Create 53 | 54 | [Modus Create](https://moduscreate.com) is a digital product consultancy. We use a distributed team of the best talent in the world to offer a full suite of digital product design-build services; ranging from consumer facing apps, to digital migration, to agile development training, and business transformation. 55 | 56 | Modus Create 57 |
58 | 59 | This project is part of [Modus Labs](https://labs.moduscreate.com/?utm_source=labs&utm_medium=github&utm_campaign=vue3-example-hooks-ts). 60 | 61 | Modus Labs 62 | 63 | # Licensing 64 | 65 | This project is [MIT licensed](./LICENSE). 66 | -------------------------------------------------------------------------------- /.github/CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Open Source Code Of Conduct 2 | 3 | This code of conduct outlines our expectations for participants within the Modus Create community, as well as steps to reporting unacceptable behavior. We are committed to providing a welcoming and inspiring community for all and expect our code of conduct to be honored. Anyone who violates this code of conduct may be banned from the community. 4 | 5 | Our open source community strives to: 6 | 7 | #### Be friendly and patient. 8 | 9 | #### Be welcoming 10 | 11 | We strive to be a community that welcomes and supports people of all backgrounds and identities. This includes, but is not limited to members of any race, ethnicity, culture, national origin, colour, immigration status, social and economic class, educational level, sex, sexual orientation, gender identity and expression, age, size, family status, political belief, religion, and mental and physical ability. 12 | 13 | #### Be considerate 14 | 15 | Your work will be used by other people, and you in turn will depend on the work of others. Any decision you take will affect users and colleagues, and you should take those consequences into account when making decisions. Remember that we’re a world-wide community, so you might not be communicating in someone else’s primary language. 16 | 17 | #### Be respectful 18 | 19 | Not all of us will agree all the time, but disagreement is no excuse for poor behavior and poor manners. We might all experience some frustration now and then, but we cannot allow that frustration to turn into a personal attack. It’s important to remember that a community where people feel uncomfortable or threatened is not a productive one. 20 | Be careful in the words that you choose: we are a community of professionals, and we conduct ourselves professionally. Be kind to others. Do not insult or put down other participants. Harassment and other exclusionary behavior aren’t acceptable. This includes, but is not limited to: 21 | 22 | - Violent threats or language directed against another person. 23 | - Discriminatory jokes and language. 24 | - Posting sexually explicit or violent material. 25 | - Posting (or threatening to post) other people’s personally identifying information (“doxing”). 26 | - Personal insults, especially those using racist or sexist terms. 27 | - Unwelcome sexual attention. 28 | - Advocating for, or encouraging, any of the above behavior. 29 | - Repeated harassment of others. In general, if someone asks you to stop, then stop. 30 | 31 | #### When we disagree, try to understand why 32 | 33 | Disagreements, both social and technical, happen all the time. It is important that we resolve disagreements and differing views constructively. 34 | 35 | #### Remember that we’re different 36 | 37 | The strength of our community comes from its diversity, people from a wide range of backgrounds. Different people have different perspectives on issues. Being unable to understand why someone holds a viewpoint doesn’t mean that they’re wrong. Don’t forget that it is human to err and blaming each other doesn’t get us anywhere. Instead, focus on helping to resolve issues and learning from mistakes. 38 | 39 | This code is not exhaustive or complete. It serves to distill our common understanding of a collaborative, shared environment, and goals. We expect it to be followed in spirit as much as in the letter. 40 | 41 | ## Diversity Statement 42 | 43 | We encourage everyone to participate and are committed to building a community for all. Although we may not be able to satisfy everyone, we all agree that everyone is equal. Whenever a participant has made a mistake, we expect them to take responsibility for it. If someone has been harmed or offended, it is our responsibility to listen carefully and respectfully, and do our best to right the wrong. 44 | 45 | Although this list cannot be exhaustive, we explicitly honor diversity in age, gender, gender identity or expression, culture, ethnicity, language, national origin, political beliefs, profession, race, religion, sexual orientation, socioeconomic status, and technical ability. We will not tolerate discrimination based on any of the protected characteristics above, including participants with disabilities. 46 | 47 | ## Reporting Issues 48 | 49 | If you experience or witness unacceptable behavior—or have any other concerns—please report it by contacting us via `opensource@moduscreate.com`. All reports will be handled with discretion. In your report please include: 50 | 51 | - Your contact information. 52 | - Names (real, nicknames, or pseudonyms) of any individuals involved. If there are additional witnesses, please include them as well. Your account of what occurred, and if you believe the incident is ongoing. If there is a publicly available record (e.g. a mailing list archive or a public IRC logger), please include a link. 53 | - Any additional information that may be helpful. 54 | 55 | After filing a report, a representative will contact you personally. If the person who is harassing you is part of the response team, they will recuse themselves from handling your incident. A representative will then review the incident, follow up with any additional questions, and make a decision as to how to respond. We will respect confidentiality requests for the purpose of protecting victims of abuse. 56 | 57 | Anyone asked to stop unacceptable behavior is expected to comply immediately. If an individual engages in unacceptable behavior, the representative may take any action they deem appropriate, up to and including a permanent ban from our community without warning. 58 | 59 | This Code Of Conduct follows the [template](http://todogroup.org/opencodeofconduct/) established by the [TODO Group](http://todogroup.org/). 60 | --------------------------------------------------------------------------------