NuxtPress

Guide

NuxtPress is a microframework that leverages the Nuxt module system.

It will automatically register routes, templates and configuration options in your Nuxt application. It also takes care of loading Markdown files and making pre-rendered static files automatically available.

Setup

Install via npm or yarn:

$ npm install nuxt @nuxt/press
$ yarn add nuxt @nuxt/press

Note that you must also install Nuxt if you haven't already.

Configuration

First, NuxtPress needs to be enabled via nuxt.config.js:

export default {
  modules: ['@nuxt/press']
}

In a freshly started project, npm install (or yarn add) will automatically create that nuxt.config.js file for you if you haven't already.

Default mode

The above nuxt.config.js file would set NuxtPress to run in its default mode, which enables support for Markdown pages/, and automatic full static nuxt generate for them.

In default mode, bundled apps can also be enabled based on the presence of the docs/, blog/ and slides/ directories. The URL prefix for each bundled app matches these directories, .e.g, blog will be able available at /blog.

Standalone mode

Alternatively, you can also do:

export default {
  modules: [
    ['@nuxt/press', '<mode>']
  ]
}

This would set NuxtPress to run in docs standalone mode:

export default {
  modules: [
    ['@nuxt/press', 'docs']
  ]
}

In docs standalone mode, there's no URL prefix, so here docs will be available at /, not /docs, and Markdown files can be placed directly on <srcDir>.

Standalone mode works similarly for blog and slides, as will be shown later.

On nuxt.press.json

With the exception of the single string parameter that can be passed directly via nuxt.config.js (enabling standalone mode for any of the available bundled apps), all NuxtPress configuration must take place in either nuxt.press.json or nuxt.press.js. The JSON variant of the config is automatically generated the first time you run Nuxt with NuxtPress. If you decide to use nuxt.press.js instead (with a default export), nuxt.press.json is ignored.

The nuxt.press.json file autogenerated for this documentation can be seen below. The nav key is initially empty and must be filled out.

{
  "docs": {
    "dir": "docs",
    "prefix": "/",
    "title": "NuxtPress documentation",
    "nav": [
      { "Home": "/" },
      { "Internals": "/internals" },
      { "GitHub": "https://github.com/nuxt/press" }
    ],
    "sidebar": [
      "/",
      "/guide"
    ]
  }
}

Deployment

Follow Nuxt's guide for all deployment details.

NuxtPress is tested with static builds (nuxt generate.) and live builds (universal mode).

Nuxt's spa mode support is not fully tested yet (as of 0.1-beta.4).

Markdown pages

At its core, NuxtPress enables you to use Markdown files as Nuxt pages:

pages/index.md /
pages/foo/index.md /foo
pages/foo/bar.md /foo/bar

Not only will NuxtPress transform Markdown files into working routes, it will also parse YAML metadata via gray-matter, if available.

Here's a snippet from examples/pages:

---
someText: hey, this works
someOtherText: hey, this works too
---

### Hello world

Go to [/subpage](/subpage)

Go to [/subpage/other](/subpage/other)

Msg: {​{ $press.source.someText }}

Msg: **{​{ $press.source.someOtherText }}**

You can also use the YAML metadata to specify the Nuxt layout:

---
layout: yourLayout
---

The common bundle

NuxtPress makes this possible by adding the common app bundle to your Nuxt app. This bundle will register a middleware that will automaticaly retrieve JSON sources for every requested route. Once a source request is detected and loaded, it's passed on to the press source route. This is the source route registered for this documentation suite, which has i18n enabled:

{
  path: "/:locale/:source(.*)",
  component: _e1c6a3e4,
  name: "source-locale"
}

Later in this guide you'll learn how to completely eject the source code for the common bundle, which can give you complete control over how NuxtPress works in any given Nuxt app.

Learning internals

See the introductory blog post to learn about the architectural decisions that are behind NuxtPress, including blueprint modules which are the mechanism used to register its built-in apps.

Contributing is extremely easy, just pull the nuxt/press repository, install NPM dependencies and use the dev script to test your changes directly in the bundled examples. If you change something in src/blueprints/blog, you'll want to test with your changes with:

$ npm run dev examples/blog

Beyond pages

Before we move on, keep in mind that NuxtPress can be added to and seamlessly extend any existing Nuxt application.

A NuxtPress app is a Nuxt app. As long as it's the last enabled module, it won't interfere with existing functionality.

In default mode, in addition to now being able to add Markdown files directly to pages/, you have three new route folders to work with: docs/, blog/ and slides/. The presence of any of these directories in the srcDir of a Nuxt project will enable their corresponding NuxtPress modes.

You can customize these directories as follows:

{
  "docs": {
    "dir": "my-custom-docs-dir"
  },
  "blog": {
    "dir": "my-custom-blog-dir"
  },
  "slides": {
    "dir": "my-custom-slides-dir"
  }
}

You can run multiple NuxtPress modes in the same Nuxt app.

Standalone mode

You've seen briefly how to specify which bundled app should be loaded by passing a mode parameter to the @nuxt/press definition in nuxt.config.js.

Standalone mode basically tells NuxtPress two things: you're only using one of the available bundled apps and the URL prefix for the URLs generated by the app bundle should be /, i.e., mixed with those that result from files being placed under the pages/ directory.

That means if you're running blog in standalone mode:

export default {
  modules: [
    ['@nuxt/press', 'blog']
  ]
}

And you have a pages/index.vue file, that is effectively overriding the index blog view. On the other hand, if you have pages/about.md, that will be available as /about and the blog index will be available at /.

Depending on the standalone mode you choose, Markdown files are searched for in different directories, as detailed below:

Standalone modeLookup directories
docs<srcDir> or <srcDir>/docs
blog<srcDir>/entries or <srcDir>/posts
slides<srcDir> or <srcDir>/slides

You can also set the standalone app via nuxt.press.json:

{
  "mode": "slides"
}

Or via nuxt.press.js:

export default {
  mode: 'slides'
}

Publishing blogs

You can structure Markdown files for the blog mode (under the configured lookup directory) in however many subdirectories you want (for grouping posts by year of publication for, for instance). What determines the publishing date of each blog entry is actually their Markdown source header.

By default, NuxtPress uses a simple format where the first line is parsed out as the publication date. Titles and slugs are automatically generated from the first heading (#) of your Markdown sources:

June 20, 2019

# Blog Entry's Title

If your Markdown sources however start with a ---, NuxtPress will try and parse it via gray-matter and will look for title, slug and date.

---
title: Blog Entry's Title
date: June 20, 2019
slug: blog-entry-slug
---

# This Heading Is Not Used As Title

NuxtPress' default blog template makes it easy to automatically include sidebar text links.

Here's nuxt.press.json from examples/blog.

{
  "blog": {
    "links": [
      {"Home": "/blog"},
      {"Archive": "/blog/archive"},
      {"About": "/blog/about"},
    ]
  }
}

This feature is mostly illustrative. You're likely to benefit more from ejecting the entire app bundle and adding your code for the sidebar component. Your component can still have access to these options you define under the blog configuration key in nuxt.press.json or nuxt.press.js, making it extremely to customize templates even with your own configuration options.

Publishing docs

The docs mode of NuxtPress provides similar functionality as VuePress. NuxtPress even borrows config syntax and some components from VuePress, but although NuxtPress aims to provide similar functionality its not meant to be a one to one replacement.

Path prefix

As you saw before, the URL prefix is automaticaly determined by whether you're running docs mode in NuxtPress standalone or default mode (/ vs /docs). You can override this by manually setting docs.prefix in the configuration:

{
  "docs": {
    "prefix": "/custom-docs-prefix/"
  }
}

NuxtPress has full support for Markdown via @nuxt/markdown.

Home page

NuxtPress will automatically detect the presence of a README.md file or an index.md file in the configured lookup directory and make that the introductory page of your docs suite.

NuxtPress provides a default home page layout similar to VuePress which can be configured by a YAML meta data section in your markdown index.

---
home: true
heroImage: /hero.png
actionText: Get Started →
actionLink: /guide/
features:
- title: Simplicity First
  details: Minimal setup with markdown-centered project structure helps you focus on writing.
- title: Nuxt-Powered
  details: Enjoy the dev experience of Nuxt.js and Vue
- title: Performant
  details: Because Nuxt.js
footer: MIT Licensed
---

All additional markdown content will be rendered after the features sections (but before the footer).

Currently the NuxtPress navbar only supports a links section. E.g. the links you see on the top right corner of this page are added via NuxtPress configuration. Use the docs.nav configuration key, as follows:

NuxtPress does not (yet) support dropdown menus.

{
  "docs": {
    "nav": [
      {
        "text": "Home",
        "link": "/"
      },
      {
        "text": "Internals",
        "link": "/internals"
      },
      {
        "text": "GitHub",
        "link": "https://github.com/nuxt/press"
      }
    ]
  }
}

You can also use a shorthand syntax as follows:

{
  "docs": {
    "nav": [
      {"Home": "/"},
      {"Internals": "/internals"},
      {"GitHub": "https://github.com/nuxt/press"}
    ]
  }
}

The docs bundled app also includes a sidebar component that can automatically scroll topics into view when you click them, and highlights which topic is currently into view. A basic sidebar expects an Array of links:

{
  "docs": {
    "sidebar": [
      "/",
      "/guide",
      ["/customize", 'Customize the app']
    ]
  }
}

You can omit the .md extension, and paths ending with / are inferred as /README.md or /index.md. The text for the link is automatically inferred (either from the first header in the page or explicit title in YAML meta data). If you wish to explicitly specify the link text, use an Array in form of [link, text].

The sidebar automatically displays links for headers in the current active page, nested under the link for the page itself. You can customize this behavior using docs.sidebarDepth. The default depth is 1, which extracts the h2 headers. Setting it to 0 disables the header links, and the max value is 2 which extracts both h2 and h3 headers.

A page can also override this value via YAML front matter:

---
sidebarDepth: 2
---

You can divide sidebar links into multiple groups by using objects:

{
  "docs": {
    "sidebar": [
      {
        "title": "Group 1",
        "children": [
          "/"
        ]
      },
      {
        "title": "Group 2",
        "children": [ /* ... */ ]
      }
    ]
  }
}

Multiple Sidebars

If you wish to display different sidebars for different sections of content, first organize your pages into directories for each desired section:

.
├─ README.md
├─ contact.md
├─ about.md
├─ foo/
│  ├─ README.md
│  ├─ one.md
│  └─ two.md
└─ bar/
   ├─ README.md
   ├─ three.md
   └─ four.md

Then, update your configuration to define your sidebar for each section.

{
  "docs": {
    "sidebar": {
      "/": [
        "",        /* / */
        "contact", /* /contact.html */
        "about"    /* /about.html */
      ],

      "/foo/": [
        "",     /* /foo/ */
        "one",  /* /foo/one.html */
        "two"   /* /foo/two.html */
      ],

      "/bar/": [
        "",      /* /bar/ */
        "three", /* /bar/three.html */
        "four"   /* /bar/four.html */
      ]
    }
  }
}

Single Page Auto Sidebar

If you wish to automatically generate a sidebar that contains only the header links for the current page, you can use YAML meta data for that page:

---
sidebar: auto
---

Internationalization

NuxtPress includes limited support to i18n via nuxt-i18n. If you set the i18n top-level key in nuxt.press.json with locales and messages, these are used to populate VueI18n.

"i18n": {
  "locales": [
    {
      "code": "en",
      "name": "English"
    },
    {
      "code": "pt-BR",
      "name": "Português (BR)"
    }
  ]
}

NuxtPress will then load content from directories named after each locale.

Internally, $press.locale and $press.locales are exposed. The language select box on NuxtPress' landing page is rendered with the following:

<div class="lang-select">
  <select
    v-if="$press.locales"
    v-model="lang"
    @change="(e) => $router.push(`/${e.target.value}/`)">
    <option
      v-for="locale in $press.locales"
      :key='`locale-${locale.code}`'
      :value="locale.code">{​{ locale.name }}</option>
  </select>
</div>

See the full configuration for this documentation suite here.

Publishing slides

NuxtPress will parse each slide from Markdown using # as the delimiter. If text follows #, it's appended as a <h1> tag. If not, it's simply used as the delimiter and no <h1> tag is added.

The following example represents four slides. It is a single file, but here it is shown divided in sections to illustrate the processing.

My Presentation
(opener, slide 1)
# Slide 2 header

Slide 2 text
#

Slide 3 text
(slide with no header)
# Slide 4 header

Slide 4 text

This is a simplification from MDX, which uses --- as delimiter.

Convenience classes

NuxtPress adds classes to slides to make styling easier.

.slides-<fileName> .slide-<slideNumber> {
  ...
}

Use the above CSS selector pattern to style the entire presentation or any specific slide. You can also inline <style> tags with such selectors in the slides Markdown source. Take a slides/hello.md file, for example:

# Presentation

<style>
.slides-hello .slide-1 h1 {
  font-size: 2rem;
}
</style>

This would modify the styles for the first slide.