Project Structure ๐Ÿ’ป

In this section, we'll cover the basics to start building an รฎles application.

Default App Structure ๐Ÿ“‚

src/
โ”œโ”€โ”€ components/
โ”‚    โ”œโ”€โ”€ ReadingTime.vue
โ”‚    โ””โ”€โ”€ Author.vue
โ”‚
โ”œโ”€โ”€ layouts/
โ”‚    โ”œโ”€โ”€ default.vue
โ”‚    โ””โ”€โ”€ post.vue
โ”‚
โ”œโ”€โ”€ pages/
โ”‚    โ”œโ”€โ”€ posts/
โ”‚    โ”‚    โ”œโ”€โ”€ intro.mdx
โ”‚    โ”‚    โ””โ”€โ”€ goodbye.mdx
โ”‚    โ”œโ”€โ”€ about.vue
โ”‚    โ””โ”€โ”€ index.mdx
โ”‚
โ”œโ”€โ”€ site.ts
โ””โ”€โ”€ app.ts

Aliases and Auto-Imports โœจ

Aliases

srcDir is the src directory at your project root, and is aliased as ~/ or @/.

For example:

// Named import from `src/utils/index.ts`
import { camelize } from '~/utils'
<!-- Asset import of src/assets/logo.svg -->
<img src="@/assets/logo.svg"/>

Auto Imports

รŽles auto-imports APIs on-demand, powered by unplugin-auto-import in the following file extensions.

  • .vue, .md, .mdx, .ts, .tsx, .js, .jsx, .svelte

The auto-imported APIs includes:

  • vue APIs: ref, computed, reactive, etc.
  • รŽles composables: usePage, useRoute, definePageComponent, useDocuments.
  • @unhead/vue composables: useHead, useSeoMeta, useScript, etc.
  • Any composables in your src/composables folder.

To illustrate, the imports in the below example are not required.

<script setup lang="ts">
import { computed } from 'vue' // not required
import { usePage } from 'iles' // not required
import { useHead } from '@unhead/vue' // not required
import { isDark, toggleDark } from '@/composables/dark' // not required

const toggleTheme = () => {
  // Trigger with button click in the template
  toggleDark() 
}

const { frontmatter, site, route } = usePage()
const { title: pageTitle, description } = frontmatter
const { title: siteTitle, titleSeparator } = site
const canonicalUrl = new URL(route.path, site.url)

useHead({
  title: pageTitle
    ? `${pageTitle} ${titleSeparator} ${siteTitle}`
    : siteTitle,
  meta: [
    {
      name: 'description',
      content: description,
    },
  ],
  link: [
    {
      rel: 'canonical',
      href: canonicalUrl.href,
    },
  ],
})

const navs = [
  { title: 'Home', to: '/' },
  { title: 'About', to: '/about' },
]
const currentPath = computed(() => {
  return route.path
})

</script>

Use the autoImport key in iles.config.ts to customize Auto Import configurations.

Auto Import also supports presets and resolvers for popular libraries such as vue-i18n, @vueuse/core, pinia, primevue, etc.

Components ๐Ÿงฑ

Components in the src/components directory will be auto-imported on-demand, powered by unplugin-vue-components.

รŽles extends this so that you don't need to import components in MDX files.

Use the components key in iles.config.ts to customize Auto Import configurations for components.

Auto Import configurations for components also includes options such as extensions, directories to scan, resolvers etc.

Layouts ๐Ÿ“

Components in the src/layouts directory will be available as layouts, and they should provide a default <slot/>.

Pages may specify a layout using the layout property in frontmatter:

---
layout: post
---

Layouts and Vue pages can also specify a parent layout using a layout attribute in the template:

<template layout="post">

Layouts are optional; however, having a default layout is highly recommended.

The default layout will be used for all pages unless specified.

Pages may opt-out by specifying layout: false

Layout files must be in lowercase, as in post.vue or default.vue.

Pages ๐Ÿ›ฃ

Routes will be auto-generated for files in the src/pages directory with the same file structure.

Pages can be Vue components or MDX files, and may specify frontmatter and route metadata.

You may use components inside MDX, and access any properties defined in the frontmatter:

---
title: Song for You
audio: /song-for-you.mp3
---

I've recently recorded a song, listen:

<Song title={title} src={audio}/>

In Vue single-file components you can use a <page> block to define frontmatter:

<page>
title: Song for You
audio: /song-for-you.mp3
</page>

<template>
  <p>I've recently recorded a song, listen:</p>

  <Song :title="$frontmatter.title" :src="$frontmatter.audio"/>
</template>
Page Hooks ๐ŸŽฃ

You can customize all pages using the extendFrontmatter and extendRoute hooks.

Using Page Data

You may access information about the current page using the usePage composition API helper, or by using the $frontmatter or $meta global properties.

  • frontmatter: The frontmatter of an MDX document or Vue component (in <page>)
  • meta: Information about the page, including href, filename, and lastUpdated
<script setup>
import { usePage } from 'iles' // not required

const { frontmatter, meta } = usePage()
</script>
Auto-imported APIs and Composables
You don't need to import ref, computed, reactive, usePage, useRoute, definePageComponent, useDocuments, useHead, useSeoMeta, useScript.

Glob Imports

When rendering collections or index pages, you can leverage useDocuments to conveniently access multiple page components and their data.


 


export function usePosts () {
  const posts = useDocuments('~/pages/posts')
  return computed(() => posts.value.sort(byDate))
}

Page data is available directly in the component modules:

<script setup lang="ts">
import { usePosts } from '~/composables/posts'

const posts = usePosts()
</script>

<template>
  <h1>Posts</h1>
  <article v-for="post of posts" :key="post.href">
    <time :datetime="post.date.toISOString()">{{ formatDate(post.date) }}</time>
    <h2>
      <a :href="post.href">{{ post.title }}</a>
    </h2>
    <component :is="post" excerpt/>
  </article>
</template>

Site ๐ŸŒ

src/site.ts can be used to provide site-wide information such as title, description, etc.

export default {
  title: 'About',
  description: 'Learn more about what we do',
}

It can be accessed as $site in component instances, or by using usePage.

<script setup>
import { usePage } from 'iles' // not required

const { site } = usePage()
</script>

It's also displayed in the page information in Islands devtools.

Adding src/site.ts to your project is optional.

Alternatively, you can use composables from @unhead/vue to manage the head and meta tags of your page.

App ๐Ÿ“ฑ

รฎles will pre-configure a Vue 3 shell that, during development, will load your site comprising of your layouts and pages within it.

src/app.ts can be used to provide additional configurations with the defineApp helper, allowing you to customize:

  • using enhanceApp, the development and build logic of this "outer" shell.
  • using enhanceIslands, add Vue plugins and top level runtime logic in your Vue Islands.
  • your site's head and meta tags, scroll behavior, etc.

This "outer" shell is loaded only during development and is not included in your built site.

Adding src/app.ts to your project is optional.

import { defineApp } from 'iles'

export default defineApp({
  enhanceApp ({ app, head, router }) {
    // Configure the "outer" shell to customize it's development/build logic
  },
  enhanceIslands ({ app }) {
    // Configure Vue Islands with plugins and other top level runtime logic
  },
  head ({ frontmatter, site }) {
    return {
      meta: [
        { property: 'author', content: site.author },
        { property: 'keywords', content: computed(() => frontmatter.tags) },
      ]
    }
  },
  router: {
    scrollBehavior (current, previous, savedPosition) {
      // Configure the scroll behavior
    }, 
  },
  mdxComponents: {
      // Options for tag mapping in MDX
  },
  socialTags: true // default
})

enhanceApp (Development only)

  • Type: (context: AppContext) => void | Promise<void>

A hook that allows you to add additional development/build logic. See this discussion thread for few suggestions.

enhanceIslands (Vue Islands only)

  • Type: (context: IslandContext) => void | Promise<void>

A hook that allows you to extend your Vue Islands with plugins such as Pinia, i18n, Vuetify, and more, along with any other top-level runtime logic on your site.

The hook will be invoked for every Vue Island in your site.

import { defineApp } from 'iles'
import { createI18n } from 'vue-i18n'
import { createPinia } from 'pinia'
import { createVuetify } from 'vuetify'

const i18n = createI18n({
  // vue-i18n options ...
})
const pinia = createPinia()
const vuetify = createVuetify({
  // vuetify options ...
})

export default defineApp({
  enhanceIslands({ app }) {
    app.use(i18n)
    app.use(pinia)
    if(app._component.name === 'Island: ChatboxIsland') {
      // To initialise Vuetify only within ChatboxIsland.vue
      app.use(vuetify)
    }
  },
})
  • Type: HeadObject | (context: AppContext) => HeadObject

Set the head and meta tags, additional CSS, or scripts using @unhead/vue.

router

  • Type: RouterOptions

Configure vue-router by providing options such as scrollBehavior and linkActiveClass.

mdxComponents

  • Type: MDXComponents | (context: AppContext) => MDXComponents

Provide an object that maps tag names in MDX to components to render.

import { defineApp } from 'iles'
import Image from '~/components/Image.vue'

export default defineApp({
  mdxComponents: {
    b: 'strong',
    img: Image,
  },
})

socialTags

  • Type: boolean
  • Default: true

Some social tags can be inferred from the site.

Set it to false to avoid adding social tags such as og:title and twitter:description.

Devtools ๐Ÿ› 

Page information is available in a debug panel, similar to VitePress, but you may also access an Islands inspector in Vue devtools.

This can be useful when debugging islands hydration.

Iles Configuration โš™๏ธ

You may provide a iles.config.ts configuration file at your project root to customize the various รฎles-specific features.

You may also provide a vite.config.ts configuration file (or use the vite key in iles.config.ts) to add vite plugins and customize the various vite-specific features.

Sitemap ๐Ÿ—บ

A sitemap can be automatically generated when you build your site, all you need to do is configure siteUrl in your iles.config.ts configuration file.

If configured, siteUrl will also make it available as site.url and site.canonical.

import { defineConfig } from 'iles'

export default defineConfig({
  siteUrl: 'https://nuraui.com',
})

If you would like to opt-out, you can disable it explicitly:

export default defineConfig({
  ssg: {
    sitemap: false
  },
})

To learn more about further Iles and Vite configurations, refer to the config page.

Last Updated: