diff --git a/docs/.vitepress/config.js b/docs/.vitepress/config.js index ced5625..ebff526 100644 --- a/docs/.vitepress/config.js +++ b/docs/.vitepress/config.js @@ -8,6 +8,7 @@ export default { sidebar: { '/python/': require('../python/sidebar.json'), '/rust/': require('../rust/sidebar.json'), + '/nuxt/': require('../nuxt/sidebar.json'), '/': [ { text: 'Home', diff --git a/docs/frameworks.md b/docs/frameworks.md index e69de29..7e9536e 100644 --- a/docs/frameworks.md +++ b/docs/frameworks.md @@ -0,0 +1,3 @@ +# Frameworks + +[Nuxtjs](/nuxt/) \ No newline at end of file diff --git a/docs/nuxt/datafetching.md b/docs/nuxt/datafetching.md new file mode 100644 index 0000000..6b260f1 --- /dev/null +++ b/docs/nuxt/datafetching.md @@ -0,0 +1,103 @@ +# Data Fetching + +## useFetch + +This is the main form of fetching data from the backend. This can only be used in pages. Can be awaited. + +```vue + + + +``` + +## useLazyFetch + +This is the same as useFetch but does not block navigation, so you need to handle the case where data is null while still fetching. It does also provide a pending flag to know when the data is loading. + +```js +const { pending, data: posts } = useLazyFetch('/api/posts') +``` + +## useAsyncData + +Can be used in a component, composable, or page. The first argument is a key for the data. The main different between this and useFetch is that this provides some more control for the developer. + +```js +const { data } = await useAsyncData('count', () => $fetch('/api/count')) +``` + +## useAsyncLazyData + +Again, same as useAsyncData but you need to handle the case where the data is null. + +```js +const { pending, data: count } = useLazyAsyncData('count', () => $fetch('/api/count')) +``` + +## Refreshing data + +All of these functions also return a `refresh` property that can be called to refetch the data. + +```js +const { data: users, pending, refresh, error } = await useFetch(() => `users?page=${page.value}&take=6`, { baseURL: config.API_BASE_URL } + +function previous(){ + page.value--; + refresh(); +} + +function next() { + page.value++; + refresh(); +} +``` + +You can also refresh all data for a given key with `refreshNuxtData`. If no key is specified, it will refresh all queries. + +```jsx +const { pending, data: count } = useLazyAsyncData('count', () => $fetch('/api/count')) + +const refresh = () => refreshNuxtData('count') +``` + +## Trimming data + +You can use the `pick` option to limit what pieces of data get returned on the request so you only get the fields you need. + +```js +const { data: mountain } = await useFetch('/api/mountains/everest', { pick: ['title', 'description'] }) +``` + +## More useFetch documentation + +```ts +function useFetch( + url: string | Request, + options?: UseFetchOptions +): Promise + +type UseFetchOptions = { + key?: string, + method?: string, + params?: SearchParams, + body?: RequestInit['body'] | Record + headers?: {key: string, value: string}[], + baseURL?: string, + server?: boolean + lazy?: boolean + default?: () => DataT + transform?: (input: DataT) => DataT + pick?: string[] +} + +type DataT = { + data: Ref + pending: Ref + refresh: () => Promise + error: Ref +} +``` \ No newline at end of file diff --git a/docs/nuxt/dir.md b/docs/nuxt/dir.md new file mode 100644 index 0000000..f8d0972 --- /dev/null +++ b/docs/nuxt/dir.md @@ -0,0 +1,35 @@ +# Directory Structure + +## Pages + +Contains all of our vue files that make up our main page layout. The directory structure also determines the routes (see [routing](/nuxt/routing)). + +## Components + +Contains all of the vue components that you want to use in multiple places in your application. These components get auto imported into all of your other files and are treeshaken to remove unused ones. The component name is dependent on the file location, so `components/base/foo/Button.vue` will be `BaseFooButton`. Then can also be chosen dynamically like below. + +```vue + + + +``` + +## Composables + +Contains javascript files that are auto imported, although only files at the `composable` root level and index files in subdirectories and only exported named functions are available. This is also where you would define your [state](/nuxt/state). + +## Server + +See [Server Routes](/nuxt/server/) + +## Assets + +Contains styles, images, and fonts. + +## Static + +This is directory mapped to the server root and contains files that have to keep their names (like images, etc) or likely won't change (favicon). \ No newline at end of file diff --git a/docs/nuxt/index.md b/docs/nuxt/index.md new file mode 100644 index 0000000..7397a07 --- /dev/null +++ b/docs/nuxt/index.md @@ -0,0 +1,11 @@ +# Nuxt.js + +Nuxt is a server side rendering framework for Node and Vue. + +## Creating a Project + +```bash +npx nuxi init +cd +npm run dev +``` \ No newline at end of file diff --git a/docs/nuxt/routing.md b/docs/nuxt/routing.md new file mode 100644 index 0000000..5cb9be0 --- /dev/null +++ b/docs/nuxt/routing.md @@ -0,0 +1,41 @@ +# Routing + +Routing in Nuxt is file based. The file structure within the `pages` directory determines the routes for the front end application. + +Files with `index.vue` within a directory will route to that directories name, while files with other names will append that file name onto the route. + +Dynamic routes are denoted by square brackets surrounding the file name. These can be accessed with `this.$route.params.{parameterName}`. You can also have a catchall route with`[...slug].vue`. This will hit if the url matches no other routes. If multiple unknown routes are provided, they will come in as an array `/hello/world -> ['hello', 'world']`. You can also denote optional parameters by wrapping it in two sets of brackets. + +- `pages/index.vue` -> / +- `pages/about/index.vue` -> /about +- `pages/about/me.vue` -> /about/me +- `pages/profile/[id].vue` -> /profile/foo +- `pages/users-[group]/[id].vue` -> /users-foo/bar +- `pages/[...slug].vue` -> /foobar (catchall) + +## Accessing Route in Vue files + +```vue + + + +``` + +## Navigation + +```vue + +``` \ No newline at end of file diff --git a/docs/nuxt/server.md b/docs/nuxt/server.md new file mode 100644 index 0000000..9cc2685 --- /dev/null +++ b/docs/nuxt/server.md @@ -0,0 +1,61 @@ +# Server Routes + +Server routes are defined in the `server` directory, and can be divided into `server/api`, `server/routes`, and `server/middleware`. Each file needs to export a default function `defineEventHandler` which takes an event object and can return either JSON, a promise, or use `event.res.send()` to return data. + +```tsx +// ~/server/api/hello.ts +export default defineEventHandler((event) => { + return { + api: 'works' + } +}) +``` + +Routes in the api subdirectory will be at a route `/api`, routes defined in the routes subdirectory will be accessible without `/api`. + +You can also name files with a suffix to specify which request type hits which route. If not all methods are defined, methods without a matching handler will 404. + +```tsx +// ~/server/api/test.get.ts +export default defineEventHandler(() => 'Test get handler') + +// ~/server/api/test.post.ts +export default defineEventHandler(() => 'Test post handler') +``` + +## Dynamic server routes + +These can be defined the same way we define dynamic navigation with brackets surrounding the variable in the file name. Catch all routes can be defined with a `[...].ts`. + +```tsx +// ~/server/api/[name].ts +export default defineEventHandler(event => `Hello, ${event.context.params.name}!`) +``` + +## Getting Data from Request + +```tsx +// Request body +export default defineEventHandler(async (event) => { + const body = await useBody(event) + return { body } +}) + +// Query params +export default defineEventHandler((event) => { + const query = useQuery(event) + return { a: query.param1, b: query.param2 } +}) + +// Access runtime config +export default defineEventHandler((event) => { + const config = useRuntimeConfig() + return { key: config.KEY } +}) + +// Accessing cookies +export default defineEventHandler((event) => { + const cookies = useCookies(event) + return { cookies } +}) +``` \ No newline at end of file diff --git a/docs/nuxt/sidebar.json b/docs/nuxt/sidebar.json new file mode 100644 index 0000000..c89f348 --- /dev/null +++ b/docs/nuxt/sidebar.json @@ -0,0 +1,13 @@ +[ + { + "text": "Nuxt Basics", + "items": [ + {"text": "Introduction", "link": "/nuxt/"}, + {"text": "Directory Structure", "link": "/nuxt/dir"}, + {"text": "Routing", "link": "/nuxt/routing"}, + {"text": "Data Fetching", "link": "/nuxt/datafetching"}, + {"text": "State", "link": "/nuxt/state"}, + {"text": "Server Routes", "link": "/nuxt/server"} + ] + } +] \ No newline at end of file diff --git a/docs/nuxt/state.md b/docs/nuxt/state.md new file mode 100644 index 0000000..9353a7a --- /dev/null +++ b/docs/nuxt/state.md @@ -0,0 +1,19 @@ +# State Management + +State is created using the `useState` function. Any component that calls `useState` with the same key will share the state for that variable. + +```jsx +const counter = useState('counter', () => Math.round(Math.random() * 1000)) + +function increment() { + counter++; +} +``` + +You can also create shared state by creating a composable that returns state functions. If using `useState` outside of a setup function, they must be created this way otherwise they will be shared by every user of the application, not just the current one. + +```tsx +// composables/states.ts +export const useCounter = () => useState('counter', () => 0) +export const useColor = () => useState('color', () => 'pink') +``` \ No newline at end of file