Here are some notes on how Dev.java pages are organized and how the system sorts the pages to render them into HTML.
Working on content should be mostly done in Markdown files under the /app/pages directory.
A single-page tutorial, probably the most common on the site, although tutorial series are also popular.
Example: Getting Started with Java
A multi-tutorial series with a guide at the top that walks you through the series.
There are two components to a series, the series page, and the actual tutorial pages.
Tutorial series example: Language Basics Folder
Series page example: Language Basics
First tutorial in series: Language Basics: Creating Variables
Second tutorial in series: Language Basics: Primitive Types
- All tutorials in a series have the
group
field in the markdown - The series page is of type and layout
tutorial
- The actual tutorials in the series are type and layout of
tutorial-group
.
Example: Duke Home
Frontmatter is the heart of how content is processed. Here is an example of a pages frontmatter with descriptions below.
---
id: lang.lambda.comparators
title: Writing and Combining Comparators
slug: learn/lambdas/writing-comparators
slug_history:
- learn/writing-and-combining-comparators
type: tutorial-group
group: lambdas
layout: learn/tutorial-group.html
subheader_select: tutorials
main_css_id: learn
more_learning:
youtube:
- lFbBI85oTnY
toc:
- Implementing a Comparator with a Lambda Expression {implementing}
- Using a Factory Method to Create a Comparator {creating-comparators-with-a-factory}
description: "Creating and Combining Comparators Using Lambda Expressions."
last_update: 2021-10-26
---
title
: this is the title displayed at the top of the pagetype
: this has to have the valuetutorial
. If it does not, then this page will not appear under any category.category
: the name of the category this page belongs to.layout
: this has to have the valuelearn/tutorial.html
.sidemenu
andmain_css_id
: you do not need to touch these.description
: the description displayed on the main page.slug
[optional]: (see below)slug_history
: Slug history can now be used to ensure we don't break Internet links.For each item in the slug_history, a redirect to the current slug will be created.more_learning
[optional]:toc
[optional]: The table of contents used for the sidebar on tutorial pages. If you do not include this, the system will try and autobuild it from the content.last_update
: (see below)last_review
: (see below)
It is alphanumeric, and can contain .
. Meaning, any sequence of characters, as opposed to just a number. The problem with a number is finding the last number and incrementing it would be next to impossible, so when you create a new page, just give it something random. Because you can put .
in it, you can also create IDs with a namespace, like stream.intro
. I tried to use the first few characters of the page title followed by some randoms stuff, to give it a little more randomness. We can probably improve this, but once id's are set, any subsequent links will also be set.
Page by default will generate their URL using the frontmatter title
tag. So. If the title is "Getting Started with Java" this will turn into https://dev.java/learn/getting-started-with-java. There's some added magic to clean up extraneous characters [,?``]
.
If they have the slug tag, that'll take precedence.
Note: Currently we are using ahrefs.com to generate a daily report that includes broken links on the deployed site. This should be sufficient for awhile until we add a custom CI step in. That said, ahrefs has a lot of other nice stuff so we might just keep using it.
We want readers to see that the articles are well-maintained and up to date.
To that end, there are two relevant frontmatter entries that both take dates in the format YYYY-MM-DD
:
last_review
: most recent date when the article was read (at least mostly) and possibly slightly editedlast_update
: most recent date when the article's content got updated or expanded (including creation)
Please update these entries accordingly.
That means, when reading an article and either nodding along or doing some slight edits, update last_review
.
When writing a new article or changing an article's content, for example to update a section to a new feature or add a new section, update last_update
.
The most recent of the two dates is picked to be displayed below the article.
Furthermore, the last_update
entry is used to populate the "Recently Updated Articles" section on the landing page.
So when new articles get added, make sure to set the current date, so they show up there and get some exposure. :)
There are 7 entries on the tutorial welcome page:
- Running Your First Java Application
- Staying Aware of New Features
- Getting to Know the Language
- Mastering the API
- Organizing your Application
- Getting to know the JVM
- References
These 7 entries are hard-coded in the template/pages/learn/index.html
page. A page is displayed under an entry on this page if it is a tutorial
page that has the right category
defined in its front matter.
Entry | category |
---|---|
Running Your First Java Application | learn |
Staying Aware of New Features | awareness |
Getting to Know the Language | language |
Mastering the API | api |
Organizing your Application | organizing |
Getting to know the JVM | jvm |
Note that the Reference part is not a category. It is written in the index.md
file, under the learn
directory. Making it a category would also make it a separate page, and the links currently displayed directly on this page would be on this other page.
There are two types of categories:
- Categories that are made of just one page, like Getting Started with Java.
- Categories that are made of several, linked pages, like Getting to Know the Language/Basics.
This is the simplest case: you just need to create a basic .md
file an add a frontmatter to it. In fact you do not need to do that, just copy / paste and existing one and apply the modifications you need.
Here is the front matter of the Getting Started with Java page (just the first two entries of the table of content have been reproduced).
---
title: Getting Started with Java
type: tutorial
category: start
layout: learn/tutorial.html
subheader_select: tutorials
main_css_id: learn
toc:
- Elements of a Java Application
- Compiling and Executing a Java Code
description: "Creating your first Java application."
---
Then the table of content follows. You can put any level of section or subsection there. This will create a navigation menu on the right of the page. You need to add anchors to the section of the table of content for the links of this menu to work. Make sure the anchors are correctly numbered or the menu will not work.
A category made of several pages is a group category. It is displayed as a single link under the entry. This link leads to a page with all the pages of the group.
There is a specific navigation on a page that it part of a group: you can navigate to the next and previous pages directly.
You can put all the markdown files of a category under the same folder. This folder must contain a technical page that holds all the links to the pages of the group, and that has a special front matter.
A group of pages in linked from a group page markdown page that has specific elements in its front matter.
Here is the front matter for the page 00_language-basics.md
:
---
title: "Java Language Basics"
category: language
type: tutorial
group: language-basics
layout: learn/tutorial-group-top.html
category_order: 1
subheader_select: tutorials
main_css_id: learn
description: "Getting to know the basics of the Java language."
---
This part of the tutorial covers the basics of the language, including: variables, operators, expressions, statements, blocks and control flow statements.
The type
of this page is tutorial
, so it will be displayed on the learn
page under the entry Getting to Know the Language.
It defines a group
named language-basics
.
Its description
is displayed on the learn
page. The text is displayed on the page it links to, along with links to all the pages of this category.
Note that the layout
of this page is learn/tutorial-group-top.html
.
To make a page part of a group, you need three elements in the front matter:
type: tutorial-group
group: language-basics
layout: learn/tutorial-group.html
The value of the group
is of course the name of the group this page belongs to.
Because the type
is tutorial-group
, this page is not displayed on the Learn page.
If a category is composed of single pages, then the order of the pages on the file system is the order of the pages in the category. See also the section on URL Generation.
If you have groups of several pages in a category, then the order may vary with the file system: you may end up with the directories, then the files.
You can force the order of pages and group of pages by using a field in the front matter: category_order
. If this field is present in the single pages and in the group page, then it will be used to sort the elements.
Once an ID exists, that page can be linked to from other markdown files using the standard markdown approach with a little magic... instead of Here is a [link](/learn/tutorials/some/long/url/)
, you do it like this: Here is a [link](id:abc123)
where abc123
is the id tag associated with the destination page.
The Markdown processor automatically adds IDs to the headers by "slugifying" their name (i.e. all lower case, spaces replaced by -
, most other special characters removed).
To customize that ID, you can append the header text with curly braces that contain the custom slug, which must start with a #
, for example:
## This is a header {#header}
While the header text can still contain curly braces, it can't end with a closing curly brace, or that will be interpreted as an effort to override the anchor, which is only legal if it strictly adheres by the syntax above. Otherwise an author mistake is assumed and an error thrown.
To link to a header, attach #
followed by the header's ID to the link, be it a regular one or one that uses the ID approach described above.
("Slugified" means all lower case as well as spaces and most other special characters replaced by -
.)
For example, to link to the The Unary Operators header in the article Using Operators in Your Programs, which has the ID lang.basics.operators
, write ++ is probably Java's most famous [unary operator](id:lang.basics.operators#the-unary-operators).
The available links to the Javadoc must be declared in the javadoc.json
file. This file contains key/value pairs, with keys rendered as values in the URL generation mechanism.
To create a link to a specific Javadoc page, you can use the following:
You should read the page about the [`File`](javadoc:File) class.
A key named File
must be present in the javadoc.json
file for the link to be properly rendered.
We could create more sets of links to other resources on this model, with some other prefix.
This is truly glorious. In my most humble opinion.
You can see that the sorting of the pages on the site may rely on the order of the corresponding files on the file system, or can be overridden with the category_order
front matter field.
So far, the markdown pages have been arranged on the file system as they appear on the site, by using a numeric prefix on the folder and file names.
The system generates URL from the paths of the markdown files, removing everything that is before the _
character. So the file learn/01_your-first-java-app/03_jshell.md
is available under the URL learn/your-first-java-app/jshell.html
.
The overview pages have a special status among the pages. They are marked with the type: tutorial
frontmatter field. These pages are used to generate a table of content per group. The group of that page is marked with the group: group-name
frontmatter field.
When the analyzer sees such a page, it does two things.
- It gathers all the pages that belong to the group of this page.
- It generates a table of content page, containing links to all the pages that belongs to that group. These pages are sorted following the order they have in their directory.
If there is a doc_links:
frontmatter section, then the links of this section will be added. They are two kinds of links:
- The links specified as
doc:gc-tuning
will reuse links from thedata/javadocs.json
file. But PLEASE NOTE, When using this functionality, you must add an additional "text" field to the JSON so the link can be displayed. See thegc-tuning
entry as an example. - You can also add
related_page:jvm.monitoring.jstat
which creates links that point to pages inside the Dev.java website. The page_id (iejvm.monitoring.jstat
) has to be a valid page ID. The link will open in the same tab.
Here is an example of a complete frontmatter:
---
id: gc.overview
title: "The Article Title"
type: tutorial
layout: learn/tutorial-group-top.html
category: jvm
category_order: 6
group: gc-overview
slug: garbage-collection
slug_history:
- old_path/garbage-collection
doc_links:
- doc:gc-tuning
- related_page:jvm.monitoring.jstat
toc:
- Chaining Predicates with Default Methods {chaining-predicates}
- Creating Predicates with Factory Methods {creating-predicates}
- Chaining Consumers with Default Methods {chaining}
main_css_id: learn
description: "Understanding the key aspects of how garbage collection works in Java and how to tune garbage collection."
---
The generated page will contain the following links:
- two links to the Introduction to Garbage Collection and Garbage Collection in Java pages
- a link to the Hotspot JVM Garbage Collection Tuning Guide
- a link to the Jstat page on Dev.java.
To embed YouTube videos, include the partial app/templates/partials/_youtube_embed.html
- depending on where in the file tree the source file is, you may unfortunately need to go up a few directories.
Given the video slug (the part after ?v=
in the YouTube URL), it will create a responsive embed that takes up the all available horizontal space.
{% set embed = { slug: 'VziRKd8lLug' } %}
{% include "../../../templates/partials/_youtube_embed.html" %}
If you don't want to embed the video (or can't because the channel turned that option off), you can provide the thumbnail instead (get it e.g. with https://www.get-youtube-thumbnail.com/) and you'll get a linked image.
{% set embed = { slug: '2y5Pv4yN0b0', image: '/assets/images/stewardship_youtube_thumb.jpg' } %}
{% include "../../../templates/partials/_youtube_embed.html" %}