Encodera

Thanks for reading!

Donate to the site — we work hard for you.

Contents

Images, files and styles

Images and styles in Nuxt live in two places. The public/ folder is served to the browser as is, while files in app/assets/ are processed by the Vite bundler: it compresses them, adds a version tag to the name and checks that the file exists. The folder you choose decides how you refer to the file.

The public folder

Put an image into public/images/cover.jpg. The link to it starts from the site root, without the word public:

<!-- app/pages/index.vue -->
<template>
  <section>
    <img src="/images/cover.jpg" alt="Blog cover">
  </section>
</template>

The file also opens directly at http://localhost:3000/images/cover.jpg. This is the place for favicon.ico, robots.txt and files whose address must stay the same.

The app/assets folder

Put a logo into app/assets/images/logo.svg and refer to it through ~:

<!-- app/layouts/default.vue -->
<template>
  <header>
    <img src="~/assets/images/logo.svg" alt="My blog" width="40">
  </header>
</template>

Vite finds the file at build time and puts in an address like /_nuxt/logo.Bx3k9.svg. The tag in the name changes whenever the file changes, so the browser never shows a stale cached version. If the path has a typo, the build reports an error.

Which folder to choose

public/app/assets/
The file is served as isThe file is processed by the bundler
Link from the root: /images/cover.jpgLink through ~/assets/...
The address stays the sameThe address changes when the file changes
Icons, robots.txt, downloadable filesStyles, fonts, interface images

A global stylesheet

Create app/assets/css/main.css:

/* app/assets/css/main.css */
body {
  margin: 0 auto;
  max-width: 720px;
  font-family: system-ui, sans-serif;
  line-height: 1.6;
}

And connect it to every page in nuxt.config.ts:

// nuxt.config.ts
export default defineNuxtConfig({
  css: ['~/assets/css/main.css']
})

After restarting npm run dev, all pages get the same font and width.

Component styles

Styles for one component go into its <style scoped> block:

<!-- app/components/PostCard.vue -->
<style scoped>
.post-card {
  padding: 16px;
  border: 1px solid #ddd;
  border-radius: 8px;
}
</style>

The word scoped limits the styles to this component: a .post-card class elsewhere on the site is not affected. For preprocessors like Sass, install the package (npm install -D sass) and set lang="scss" on the <style> block.

Common mistake

Writing src="/public/images/cover.jpg" or src="/assets/images/logo.svg". The word public is not part of the address, and files from app/assets/ are not available at a direct address. For public/ write the path from the root (/images/cover.jpg), for app/assets/ go through ~/assets/.

Thanks for reading!

Donate to the site — we work hard for you.