1. Project Setup

The initial setup steps to create a new project using JAMStart are:
- Choose a project name and domain name
- Start the new project by cloning JAMStart repo
- Update your Project to your requirements, replacing all the placeholder names and values with your project specific information.
- Become familiar with built-in NPM dependencies
Philosophy
JAMStart is not meant to be an evergreen foundation layer for your web sites. Instead is a quick starting point for creating the scaffolding and framework for a new Nuxt Markdown static site. No need to 'synch' to the JAMStart repo later. You own your code going forward, warts 😦 and wonders 😍 both.
Project Name
You should decide on your project name early. The project name that will be used in your git repo, the package.json, README.md, and other places in the code. It should be a short, memorable name that reflects the purpose of your project, ideally you want it to be unique and available as a domain name as well.
Project Domain Name
You should also obtain your project web domain early. The domain name is the web address that users will use to access your site. Further you will want to create unique email names based on that domain to service each site. If you obtain the foobar.biz domain name, you will want to create email accounts like info@foobar.biz and help@foobar.biz, etc. It should be easy to remember, spell, and type. While you can use any domain registrar to purchase a domain name, I recommend using AWS Route 53 since the JAMStart project will discuss how to build, deploy, host, and manage your site on AWS as well and having it already in Route 53 makes it easier. If you don't have an AWS account, you should create one. If you already have a domain from somewhere else, you should transfer it into Route 53 as well.
Clone Start
In the following steps, NewProject is the name of your new repo but you would substitute your real project name instead.
- Create
NewProjectrepo at GitHub, GitLab, BitBucket, etc.- do not create any files, READMEs, etc. Leave blank.
- collect your new repo url to your repo =>
<NewProject git_url>
- Clone from the JAMStart repo
git clone https://github.com/PennockProjects/JAMStart.git {NewProject DirName}- the
NewProjectdirectory, will get created during this step.
- the
- Change into your
{NewProject DirName}directorycd {NewProject DirName}
- Install Dependencies
npm installoryarn installdepending on your package manager
- Run the project locally to verify it works
npm run devoryarn dev- open browser to
http://localhost:3000to verify it works
- Set your remote to your
<NewProject git_url>git remote set-url origin <NewProject git_url>
- Push it
git push
Example
As an example, here is the command-line for how I did this for a new Repo called TestCloneCopy. The GitHub url I created looked like this https://github.com/PennockProjects/TestCloneCopy.git
PS C:\dev> git clone https://github.com/PennockProjects/JAMStart.git TestCloneCopy
Cloning into 'TestCloneCopy'...
remote: Enumerating objects: 668, done.
remote: Counting objects: 100% (668/668), done.
remote: Compressing objects: 100% (329/329), done.
remote: Total 668 (delta 323), reused 653 (delta 311), pack-reused 0 (from 0)
Receiving objects: 100% (668/668), 7.97 MiB | 10.13 MiB/s, done.
Resolving deltas: 100% (323/323), done.
PS C:\dev> cd .\TestCloneCopy\
PS C:\dev\TestCloneCopy> git remote set-url origin https://github.com/PennockProjects/TestCloneCopy.git
PS C:\dev\TestCloneCopy> git push
Enumerating objects: 668, done.
Counting objects: 100% (668/668), done.
Delta compression using up to 8 threads.
Compressing objects: 100% (317/317), done.
Writing objects: 100% (668/668), 7.97 MiB | 3.27 MiB/s, done.
Total 668 (delta 323), reused 668 (delta 323)
remote: Resolving deltas: 100% (323/323), done.
To https://github.com/PennockProjects/TestCloneCopy.git
* [new branch] main -> main
PS C:\dev\TestCloneCopy>
Customize Your Project
Now that you have cloned the repo, you should update the placeholder names, such as a project name, copyright year, etc. to reflect your new project.
Global
This placeholders are found in various files throughout the project. They should be updated using a global find and replace in your text editor or IDE. You can go through them manually, but a global find and replace is much faster.
| Placeholder | Description | Files | Method of Change |
|---|---|---|---|
| JAMStart | Your new Project Name in PascalCase | various | global find and replace |
| jamstart | Your new project name in lowercase | various | global find and replace |
package.json file
Now that you have cloned the repo, you should update the package.json file in the root of your repo to reflect your new project. Typically, I keep my package.json file simple since most of my content sites are held in private repos and not published to NPM. At a minimum, you should update the following fields:
Description Fields
| JSON Field | Description |
|---|---|
| name | Name of the package, all lowercase |
| version | Version of the package |
| description | Short description of the package |
| license | License type for the package, e.g. MIT or UNLICENSED |
| homepage | URL of the project homepage |
| repository | Repository URL (use<NewProject git_url> ) from your git project creation |
| author | Replace with the Author of the package |
| keywords | Keywords for package discovery |
See Cheat sheet: NPM package.json for more details on each field and an example to use.
Project Scripts
In the scripts section of the package.json file, there are some project specific scripts that have placeholders that you you will need to update, although it is probably best to wait to replace them during the Build Deploy Pipeline setup. The placeholders to replace are:
| Scripts Placeholder | Description |
|---|---|
JMSTprodS3 | Replace with your project production S3 bucket, this will be the same as your Domain Name, e.g., yourdomain.com |
JMSTdevS3 | Replace with your project staging S3 bucket name, e.g., dev.yourdomain.com |
JMSTstageS3 | Replace with your project staging S3 bucket name, e.g., stage.yourdomain.com |
JMSTCloudFrontId | Replace with your CloudFront Distribution ID for your production site. This is used to invalidate the CloudFront cache after deployment to prod. |
nuxt.config.ts file
There are several placeholders in the nuxt.config.ts file that you should be updated to reflect your new project.
The site and socialShare sections should be updated to reflect your new project URL and name. These are used for SEO and social sharing metadata.
site: {
url: 'https://JMSTprodURL',
name: 'JMSTprodName'
},
socialShare: {
baseUrl: 'https://JMSTprodURL'
}
README.md file
Replace the contents of README.md with your new project information.
SEO and Metadata
In the app.vue file, there are several placeholders that you should be updated to reflect your new project. You should replace all the placeholders in the metaDefaults object that have JMST in the name. This variable is used to set the default SEO and social sharing metadata for your site.
const metaDefaults = {
isProdEnv: process.env.NODE_ENV === "production",
siteName: 'JAMStart',
title: 'JMSTseoTitle',
description: 'JMSTseoDescription',
author: 'JMSTseoAuthor',
creator: 'JMSTseoCreator',
rootUrl: "https://JMSTsiteURL.com",
robots: 'index, follow',
copyright: '© [JMSTcopyrightYears] [JMSTcopyrightName]',
ogType: 'article',
imageRoot: '/images',
image2x1: '/images/JMSTimage2x1.jpg',
image2x1Width: 1200,
image2x1Height: 600,
image1x1: '/images/JMSTimage1x1.png',
image1x1Width: 1024,
image1x1Height: 1024,
imageAlt: 'JMSTsocialShareImageAlt',
twitterCard: 'summary_large_image',
twitterSiteHandle: '@JMSTsiteHandleX',
twitterCreatorHandle: '@JMSTcreateHandleX'
}
There are two images used for social sharing, image2x1 and image1x1. You should replace these images in the /public/images folder with your own images that represent your project. The recommended sizes are:
| Image | Size (pixels) | Aspect Ratio | Description |
|---|---|---|---|
image2x1 | 1200 x 600 | 2:1 | Used for Facebook, LinkedIn sharing |
image1x1 | 1024 x 1024 | 1:1 | Used for Twitter sharing |
Default Font
In the app.vue file, the Google font 'Rubik' is set to be the default font. To replace it, choose a font from Google Fonts or another font provider. Look for the embed codes or similar from the font provider. The head links are set using the Nuxt.js useHead composable. This means you will need to translate the html embed codes into the useHead format.
For example, the embed code from Google Fonts for Open Sans font looks like this:
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Open+Sans:ital,wght@0,300..800;1,300..800&display=swap" rel="stylesheet">
in the app.vue file in the useHead composable you would replace the 'Rubik' font href objects, demarcated by 'JMSTfont', to look like this:
useHead({
link: [
// JMSTfont start default Font
{ rel: 'preconnect', href: 'https://fonts.googleapis.com' },
{ rel: 'preconnect', href: 'https://fonts.gstatic.com', crossorigin: '' },
{ rel: 'stylesheet', href: 'https://fonts.googleapis.com/css2?family=Open+Sans:ital,wght@0,300..800;1,300..800&display=swap' }
// JMSTfont end default Font
]
})
Next replace the global CSS font-family in the <style> section of app.vue file, marked with 'JMSTfont' to use your new font. For Open Sans, you would change the font-family line to look like this:
<style>
body {
font-family: 'Open Sans', sans-serif;
}
</style>
FavIcon Images
Further there is a set of FavIcon images in the /public folder that you should replace with your own FavIcon images. Create an icon for your site and then you can use a tool like Fav Icon Suite generator - favicon.io or RealFaviconGenerator to generate a set of FavIcon images for your project.
- Remove these files at
/public:- android-chrome-192x192.png
- android-chrome-512x512.png
- apple-touch-icon.png
- favicon-16x16.png
- favicon-32x32.png
- favicon.ico
- site.webmanifest
- Add your new FavIcon files to the
/publicfolder. For example, when I usedhttps://realfavicongenerator.netto create my FavIcons, I downloaded a zip file that contained all the FavIcon files. I extracted the files and copied them into the/publicfolder (which should be empty after you removed the previous FavIcon files). The files I added were:- favicon.ico
- favicon.svg
- favicon-96x96.png
- site.webmanifest
- web-app-manifest-192x192.png
- web-app-manifest-512x512.png
- apple-touch-icon.png
- Your FontProvider should also provide you with some a set of
<head><link>elements . In my example, it was:
<link rel="icon" type="image/png" href="/favicon-96x96.png" sizes="96x96" />
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
<link rel="shortcut icon" href="/favicon.ico" />
<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png" />
<link rel="manifest" href="/site.webmanifest" />
- Within the
app.vuefile in theuseHead()composable, replace current links, bracketed withJMSTfavIconcomments, with the equivalent links provided by your FontProvider. For example, you would replace the current FavIcon links inapp.vuewith the above links from your FontProvider, like this:
useHead({
link: [
{ rel: 'icon', type: 'image/png', href: '/favicon-96x96.png', sizes: '96x96' },
{ rel: 'icon', type: 'image/svg+xml', href: '/favicon.svg' },
{ rel: 'shortcut icon', href: '/favicon.ico' },
{ rel: 'apple-touch-icon', sizes: '180x180', href: '/apple-touch-icon.png' },
{ rel: 'manifest', href: '/site.webmanifest' }
]
})
Copyright Notices
In JAMStart there are several copyright notices. The specific license notice used depend on the type of project you are creating. See this blog post for more details on how I handle copyright and licensing notices for my projects: Copyright and Licensing for Code and Content Projects
| File | Type | Description |
|---|---|---|
./LICENSE.txt | Git Project Notice | This is the main notice that governs the code in the repository |
./package.json | NPM package Notice | This is the notice if the project is published as an NPM package. |
./app.vue | SEO Copyright Notice | This is the copyright notice is embedded in the meta tags of each generated web page. |
./content/license.md | Generated web site license page | This is the notice that is shown for the /license page on the generated web site, which provides more details about the specific copyright and license used for the content and code on the site. |
.components/Footer.vue | Generated web site footer | This is the notice that is shown in the footer of each page on the generated web site and links to the /license page. |
Choosing a License
You can use a tool like Choose a License to help you choose a license and get the text for it.
LICENSE.txt file
The LICENSE.txt file in the root of your git repository should be updated to reflect the license you want to use for your git project. The JAMStart git project is open source and released under the MIT license and you will find the MIT license text in the LICENSE.txt file.
If your repo is also open source, you can keep the MIT license and just update the copyright notice in the license text to reflect your name and the current year, or if you want to use a different license, you should replace the contents of the LICENSE.txt file with the text of the license you want to use.
If your repo is private, I would replace the license text with a simple notice that states that the code is proprietary and owned by you, and that all rights are reserved. In case the code gets out in the wild, the notice should make it clear that the code is not licensed for public use. For example:
Copyright (c) 2024-2026 John P. Pennock. All Rights Reserved. Unlicensed.
This code is proprietary and owned by John P. Pennock. Unauthorized
copying, distribution, modification, or use of this code is strictly
prohibited.
package.json NPM Notice
If you plan to publish your project as an NPM package, you should also include a license field in your package.json file that specifies the license for your package (same as LICENSE.txt). This is important for users who want to use your package and need to know the terms under which it is licensed. If you are using an open source license, you can specify the license type (e.g., MIT, GPL-3.0, etc.) in the license field of your package.json file.
{
"license": "MIT"
}
If your project is private and is not meant to be released as a package, you can specify UNLICENSED in the license field of your package.json file to indicate that the package is not licensed for public use.
{
"license": "UNLICENSED"
}
app.vue SEO Notice
Search and replace "[JMSTcopyrightYears] [JMSTcopyrightName]" in the license field of the metaDefaults object in the app.vue file with your copyright notice. This will ensure that the correct copyright information is included in the meta tags of each generated web page for SEO and social sharing purposes. For example, if your name is John P. Pennock and the current year is 2026, you would replace it with © 2026 John P. Pennock like this:
const metaDefaults = {
// ...
copyright: '© 2026 John P. Pennock',
// ...
}
Web Site Footer footer.vue
In the footer.vue file, there is a copyright notice in the footer of each page on the generated web site that links to the /license page. You should replace the placeholder text "[JMSTcopyrightYears] [JMSTcopyrightName]" in the footer with your own copyright noticeFor example, if your name is John P. Pennock and the current year is 2026, you would replace it with 2026 John P. Pennock like this:
<template>
<footer class="text-center prose dark:prose-invert lg:prose-xl">
© 2026 John P. Pennock.
<span class="hidden lg:inline-block lg:mr-2">See</span>
<NuxtLink to="/license">License</NuxtLink>
<span class="hidden lg:inline-block lg:ml-2">for details.</span>
</footer>
</template>
License Page license.md
In the license.md file, the site copyright notice details are shown on the /license page of the generated web site. You should replace the placeholder text "[JMSTcopyrightYears] [JMSTcopyrightName]" in the license page with your own name and year. Further, you should update the license text to reflect the specific license you are using for your project. For example, if you are using the MIT License, you would replace the text in license.md with the text of the MIT License and update the copyright notice at the top to reflect your name and the current year.
Examine NPM Dependencies
Knowing the the NPM dependencies in the package.json file will help you understand the libraries and tools your project relies on. The dependencies in the JAMStart repo are the ones that I use for my projects, but you may want to add or remove dependencies based on your specific project requirements. You should also check for any outdated dependencies and update them to the latest versions to ensure that your project is using the most secure and stable versions of the packages. You can use a tool like npm outdated or yarn outdated to check for outdated dependencies. For updating dependencies I recommend using npm install <package>@<version> to make sure you are getting the exact version you want. npm update will also update dependencies but it will update to the latest version that satisfies the version range specified in your package.json file, which may not always be what you want.
| Dependency | Description |
|---|---|
nuxt | The Nuxt.js framework, which is the foundation of the JAMStart project. |
vue,vue-router | The Vue.js framework, which Nuxt.js uses for the user interface of the JAMStart project. |
@nuxt/content | The Nuxt Content module, which allows you to write your content as Markdown files. |
remark-unwrap-images | A plugin for the Nuxt Content module to undo the default image markdown to html conversion. The default is <p><img /></p>, but with the plugin images become <img />. |
@nuxt/image | Provides optimized image handling for your Nuxt.js application. |
@nuxtjs/sitemap | The Nuxt Sitemap module, which generates a sitemap for your Nuxt.js application to improve SEO and deployment |
@stefanobartoletti/nuxt-social-share | A Nuxt module for adding social sharing buttons to your application. |
better-sqlite3 | A performant SQLite3 library required for @nuxt/content. |
nuxt-cloudflare-analytics | A Nuxt module for integrating Cloudflare Analytics into your application. |
@nuxtjs/color-mode | A Nuxt module for handling color modes (e.g., dark mode) in your application. |
@nuxtjs/tailwindcss | A Nuxt module for integrating Tailwind CSS into your application. |
@tailwindcss/typography | A Tailwind CSS plugin for adding typography styles to your application. |
@pennockprojects/nuxtss-s3-fix | A deployment tool for fixing Nuxt static sites on AWS S3. |
@pennockprojects/sitemap-diff | A deployment tool for generating sitemap differences between deployments. |
Summary
You have now created your new project by cloning the JAMStart repo and updating the project names and files to reflect your new project.
You have provided the following inputs to customize your project:
- Your Project Name
- Your Project Domain Name
- Your Project Git Repository
- Your Project FavIcons
- Your Project Default Social Sharing Images - 2x1 and 1x1 images.
- Your Project Default Font
- Your Project Copyright and License information
You have updated the following placeholders in your project files:
- JAMStart to your Project Name in PascalCase
- jamstart to your Project Name in lowercase
- all placeholders that start with JMST in
package.json,nuxt.config.ts, andapp.vuefiles (except for build deploy placeholders inpackage.json)
You should smoke test your project again to verify it still runs locally.
> npm run dev
You are now ready to move on to the next step of using Nuxt.js features in your JAMStart project.
Next Using Nuxt
Learn how to use Nuxt.js framework features in your JAMStart project.