mirror of
https://github.com/jakejarvis/jarv.is.git
synced 2025-04-26 08:25:21 -04:00
deploy to Vercel
This commit is contained in:
parent
034babd9af
commit
82c42f8322
@ -11,7 +11,7 @@
|
||||
"es6": true
|
||||
},
|
||||
"overrides": [{
|
||||
"files": ["functions/**/*.js"],
|
||||
"files": ["api/**/*.js"],
|
||||
"parserOptions": {
|
||||
"ecmaVersion": 2018,
|
||||
"sourceType": "module"
|
||||
|
100
.github/workflows/ci.yml
vendored
100
.github/workflows/ci.yml
vendored
@ -1,100 +0,0 @@
|
||||
name: CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
pull_request:
|
||||
|
||||
jobs:
|
||||
deploy:
|
||||
runs-on: ubuntu-latest
|
||||
# "[skip ci]" also causes Netlify to skip, so these are automatically in harmony
|
||||
# https://docs.netlify.com/site-deploys/manage-deploys/#skip-a-deploy
|
||||
if: "github.actor == 'jakejarvis' && !contains(github.event.head_commit.message, '[skip ci]')"
|
||||
timeout-minutes: 20
|
||||
steps:
|
||||
- name: Wait for Netlify
|
||||
# installing via `npx` each run takes a long time, but deploys always take longer
|
||||
run: npx netlify-cli watch
|
||||
env:
|
||||
NETLIFY_SITE_ID: ${{ secrets.NETLIFY_SITE_ID }}
|
||||
NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_AUTH_TOKEN }}
|
||||
|
||||
audit:
|
||||
runs-on: ubuntu-latest
|
||||
needs: deploy
|
||||
env:
|
||||
LHCI_TOKEN: ${{ secrets.LHCI_TOKEN }}
|
||||
LHCI_GITHUB_APP_TOKEN: ${{ secrets.LHCI_GITHUB_APP_TOKEN }}
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
fetch-depth: 2
|
||||
lfs: false
|
||||
- uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: 16.x
|
||||
- name: Install LHCI
|
||||
run: npm install -g @lhci/cli
|
||||
- name: Check LHCI
|
||||
run: |
|
||||
lhci --version
|
||||
lhci healthcheck
|
||||
- name: Audit deploy preview
|
||||
if: "github.event_name == 'pull_request'"
|
||||
continue-on-error: true
|
||||
run: |
|
||||
lhci autorun \
|
||||
--collect.url=https://deploy-preview-${{ github.event.number }}--jakejarvis.netlify.app/ \
|
||||
--collect.url=https://deploy-preview-${{ github.event.number }}--jakejarvis.netlify.app/notes/how-to-pull-request-fork-github/
|
||||
- name: Audit production site
|
||||
if: "github.event_name == 'push' && github.ref == 'refs/heads/main'"
|
||||
continue-on-error: true
|
||||
run: |
|
||||
lhci autorun \
|
||||
--collect.url=https://jarv.is/ \
|
||||
--collect.url=https://jarv.is/notes/how-to-pull-request-fork-github/
|
||||
- name: Upload results as artifact
|
||||
uses: actions/upload-artifact@v2
|
||||
if: success()
|
||||
with:
|
||||
name: lhci-results
|
||||
path: ./.lighthouseci
|
||||
|
||||
lint:
|
||||
runs-on: ubuntu-latest
|
||||
if: "!contains(github.event.head_commit.message, '[skip ci]')"
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
fetch-depth: 1
|
||||
lfs: false
|
||||
- uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: 16.x
|
||||
- name: Get Yarn cache path
|
||||
# https://github.com/actions/cache/blob/master/examples.md#node---yarn
|
||||
# https://github.com/actions/cache/issues/60
|
||||
id: yarn-cache
|
||||
run: echo "::set-output name=dir::$(yarn cache dir)"
|
||||
- name: Cache dependencies
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: ${{ steps.yarn-cache.outputs.dir }}
|
||||
key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-yarn-
|
||||
- name: Install dependencies
|
||||
run: yarn install --no-ignore-optional --frozen-lockfile
|
||||
- name: Audit dependencies
|
||||
run: yarn audit || true
|
||||
continue-on-error: true
|
||||
- name: Build preview
|
||||
run: yarn build:hugo --environment development --baseURL / --buildDrafts --buildFuture
|
||||
- name: Lint
|
||||
run: yarn lint
|
||||
- name: Percy snapshots
|
||||
uses: percy/snapshot-action@v0.1.2
|
||||
env:
|
||||
PERCY_TOKEN: ${{ secrets.PERCY_TOKEN }}
|
71
.github/workflows/codeql-analysis.yml
vendored
71
.github/workflows/codeql-analysis.yml
vendored
@ -1,71 +0,0 @@
|
||||
# For most projects, this workflow file will not need changing; you simply need
|
||||
# to commit it to your repository.
|
||||
#
|
||||
# You may wish to alter this file to override the set of languages analyzed,
|
||||
# or to provide custom queries or build logic.
|
||||
#
|
||||
# ******** NOTE ********
|
||||
# We have attempted to detect the languages in your repository. Please check
|
||||
# the `language` matrix defined below to confirm you have the correct set of
|
||||
# supported CodeQL languages.
|
||||
#
|
||||
name: "CodeQL"
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ main ]
|
||||
pull_request:
|
||||
# The branches below must be a subset of the branches above
|
||||
branches: [ main ]
|
||||
schedule:
|
||||
- cron: '41 7 * * 6'
|
||||
|
||||
jobs:
|
||||
analyze:
|
||||
name: Analyze
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
actions: read
|
||||
contents: read
|
||||
security-events: write
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
language: [ 'javascript' ]
|
||||
# CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ]
|
||||
# Learn more:
|
||||
# https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#changing-the-languages-that-are-analyzed
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v2
|
||||
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v1
|
||||
with:
|
||||
languages: ${{ matrix.language }}
|
||||
# If you wish to specify custom queries, you can do so here or in a config file.
|
||||
# By default, queries listed here will override any specified in a config file.
|
||||
# Prefix the list here with "+" to use these queries and those in the config file.
|
||||
# queries: ./path/to/local/query, your-org/your-repo/queries@main
|
||||
|
||||
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
|
||||
# If this step fails, then you should remove it and run the build manually (see below)
|
||||
- name: Autobuild
|
||||
uses: github/codeql-action/autobuild@v1
|
||||
|
||||
# ℹ️ Command-line programs to run using the OS shell.
|
||||
# 📚 https://git.io/JvXDl
|
||||
|
||||
# ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
|
||||
# and modify them (or add more) to build your code if your project
|
||||
# uses a compiled language
|
||||
|
||||
- run: |
|
||||
yarn install --no-ignore-optional --frozen-lockfile
|
||||
yarn build:functions
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@v1
|
15
.github/workflows/purge-artifacts.yml
vendored
15
.github/workflows/purge-artifacts.yml
vendored
@ -1,15 +0,0 @@
|
||||
name: Purge old artifacts
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: '0 9 * * 3' # every Wednesday at 9 AM UTC == 5 AM EDT
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
purge-artifacts:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: kolpav/purge-artifacts-action@v1
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
expire-in: 0
|
4
.gitignore
vendored
4
.gitignore
vendored
@ -11,8 +11,8 @@ npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
|
||||
# local Netlify config
|
||||
.netlify/
|
||||
# local Vercel config
|
||||
.vercel/
|
||||
|
||||
# Lighthouse CI
|
||||
.lighthouseci/
|
||||
|
@ -16,9 +16,10 @@ postcss.config.js
|
||||
devcontainer.json
|
||||
|
||||
# miscellaneous
|
||||
vercel.json
|
||||
.vercel/
|
||||
.github/
|
||||
.lighthouseci/
|
||||
.netlify/
|
||||
.vscode/
|
||||
LICENSE.md
|
||||
content/notes/dark-mode/example.html
|
||||
|
@ -1,13 +1,12 @@
|
||||
# 🏡 [jarv.is](https://jarv.is/)
|
||||
|
||||
[](https://app.netlify.com/sites/jakejarvis/deploys)
|
||||
[](https://github.com/jakejarvis/jarv.is/actions?query=workflow%3ACI+branch%3Amain)
|
||||
[](https://github.com/gohugoio/hugo)
|
||||
[](LICENSE.md)
|
||||
[](https://github.com/jakejarvis/jarv.is)
|
||||
[](http://jarvis2i2vp4j4tbxjogsnqdemnte5xhzyi7hziiyzxwge3hzmh57zad.onion/)
|
||||
|
||||
Personal website of [@jakejarvis](https://github.com/jakejarvis), created and deployed using [Hugo](https://github.com/gohugoio/hugo), [Netlify](https://www.netlify.com/), [and more](https://jarv.is/uses/).
|
||||
Personal website of [@jakejarvis](https://github.com/jakejarvis), created and deployed using [Hugo](https://github.com/gohugoio/hugo), [Vercel](https://vercel.com/), [and more](https://jarv.is/uses/).
|
||||
|
||||
I keep an ongoing list of [blog post ideas](https://github.com/jakejarvis/jarv.is/issues/1) and [coding to-dos](https://github.com/jakejarvis/jarv.is/issues/11) as issues in this repo.
|
||||
|
||||
|
@ -6,20 +6,16 @@ const numeral = require("numeral");
|
||||
const pluralize = require("pluralize");
|
||||
require("dotenv").config();
|
||||
|
||||
// .....??????
|
||||
// https://github.com/netlify/netlify-lambda/issues/201
|
||||
require("encoding");
|
||||
|
||||
exports.handler = async (event) => {
|
||||
const { slug } = event.queryStringParameters;
|
||||
module.exports = async (req, res) => {
|
||||
const { slug } = req.query;
|
||||
|
||||
try {
|
||||
// some rudimentary error handling
|
||||
if (!process.env.FAUNADB_SERVER_SECRET) {
|
||||
throw new Error("Database credentials aren't set.");
|
||||
}
|
||||
if (event.httpMethod !== "GET") {
|
||||
throw new Error(`Method ${event.httpMethod} not allowed.`);
|
||||
if (req.method !== "GET") {
|
||||
throw new Error(`Method ${req.method} not allowed.`);
|
||||
}
|
||||
if (!slug || slug === "/") {
|
||||
throw new Error("Parameter `slug` is required.");
|
||||
@ -33,32 +29,21 @@ exports.handler = async (event) => {
|
||||
const result = await client.query(q.Call(q.Function("hit"), slug));
|
||||
|
||||
// send client the new hit count
|
||||
return {
|
||||
statusCode: 200,
|
||||
headers: {
|
||||
"Content-Type": "application/json; charset=utf-8",
|
||||
"Cache-Control": "private, no-cache, no-store, must-revalidate",
|
||||
Expires: "0",
|
||||
Pragma: "no-cache",
|
||||
"Access-Control-Allow-Methods": "GET",
|
||||
"Access-Control-Allow-Origin": "*",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
slug: result.data.slug,
|
||||
hits: result.data.hits,
|
||||
pretty_hits: numeral(result.data.hits).format("0,0"),
|
||||
pretty_unit: pluralize("hit", result.data.hits),
|
||||
}),
|
||||
};
|
||||
res.setHeader("Cache-Control", "private, no-cache, no-store, must-revalidate");
|
||||
res.setHeader("Expires", 0);
|
||||
res.setHeader("Pragma", "no-cache");
|
||||
res.setHeader("Access-Control-Allow-Methods", "GET");
|
||||
res.setHeader("Access-Control-Allow-Origin", "*");
|
||||
return res.json({
|
||||
slug: result.data.slug,
|
||||
hits: result.data.hits,
|
||||
pretty_hits: numeral(result.data.hits).format("0,0"),
|
||||
pretty_unit: pluralize("hit", result.data.hits),
|
||||
});
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
|
||||
return {
|
||||
statusCode: 400,
|
||||
body: JSON.stringify({
|
||||
message: error.message,
|
||||
}),
|
||||
};
|
||||
return res.status(400).json({ message: error.message });
|
||||
}
|
||||
};
|
||||
|
@ -64,11 +64,11 @@ async function fetchRepos(sort, limit) {
|
||||
return currentRepos;
|
||||
}
|
||||
|
||||
exports.handler = async (event) => {
|
||||
module.exports = async (req, res) => {
|
||||
try {
|
||||
// some rudimentary error handling
|
||||
if (event.httpMethod !== "GET") {
|
||||
throw new Error(`Method ${event.httpMethod} not allowed.`);
|
||||
if (req.method !== "GET") {
|
||||
throw new Error(`Method ${req.method} not allowed.`);
|
||||
}
|
||||
if (!process.env.GH_PUBLIC_TOKEN) {
|
||||
throw new Error("GitHub API credentials aren't set.");
|
||||
@ -77,27 +77,18 @@ exports.handler = async (event) => {
|
||||
// default to latest repos
|
||||
let sortBy = "PUSHED_AT";
|
||||
// get most popular repos (/projects?top)
|
||||
if (typeof event.queryStringParameters.top !== "undefined") sortBy = "STARGAZERS";
|
||||
if (typeof req.query.top !== "undefined") sortBy = "STARGAZERS";
|
||||
|
||||
const repos = await fetchRepos(sortBy, 16);
|
||||
|
||||
return {
|
||||
statusCode: 200,
|
||||
headers: {
|
||||
"Content-Type": "application/json; charset=utf-8",
|
||||
"Access-Control-Allow-Methods": "GET",
|
||||
"Access-Control-Allow-Origin": "*",
|
||||
},
|
||||
body: JSON.stringify(repos),
|
||||
};
|
||||
// let Vercel edge cache results for 10 mins
|
||||
res.setHeader("Cache-Control", "s-maxage=600, stale-while-revalidate");
|
||||
res.setHeader("Access-Control-Allow-Methods", "GET");
|
||||
res.setHeader("Access-Control-Allow-Origin", "*");
|
||||
return res.json(repos);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
|
||||
return {
|
||||
statusCode: 400,
|
||||
body: JSON.stringify({
|
||||
message: error.message,
|
||||
}),
|
||||
};
|
||||
return res.status(400).json({ message: error.message });
|
||||
}
|
||||
};
|
@ -9,14 +9,14 @@ require("dotenv").config();
|
||||
|
||||
const baseUrl = "https://jarv.is/";
|
||||
|
||||
exports.handler = async (event) => {
|
||||
module.exports = async (req, res) => {
|
||||
try {
|
||||
// some rudimentary error handling
|
||||
if (!process.env.FAUNADB_SERVER_SECRET) {
|
||||
throw new Error("Database credentials aren't set.");
|
||||
}
|
||||
if (event.httpMethod !== "GET") {
|
||||
throw new Error(`Method ${event.httpMethod} not allowed.`);
|
||||
if (req.method !== "GET") {
|
||||
throw new Error(`Method ${req.method} not allowed.`);
|
||||
}
|
||||
|
||||
const parser = new rssParser({
|
||||
@ -73,23 +73,12 @@ exports.handler = async (event) => {
|
||||
stats.total.pretty_hits = numeral(stats.total.hits).format("0,0");
|
||||
stats.total.pretty_unit = pluralize("hit", stats.total.hits);
|
||||
|
||||
return {
|
||||
statusCode: 200,
|
||||
headers: {
|
||||
"Content-Type": "application/json; charset=utf-8",
|
||||
"Access-Control-Allow-Methods": "GET",
|
||||
"Access-Control-Allow-Origin": "*",
|
||||
},
|
||||
body: JSON.stringify(stats),
|
||||
};
|
||||
res.setHeader("Access-Control-Allow-Methods", "GET");
|
||||
res.setHeader("Access-Control-Allow-Origin", "*");
|
||||
return res.json(stats);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
|
||||
return {
|
||||
statusCode: 400,
|
||||
body: JSON.stringify({
|
||||
message: error.message,
|
||||
}),
|
||||
};
|
||||
return res.status(400).json({ message: error.message });
|
||||
}
|
||||
};
|
@ -16,7 +16,7 @@
|
||||
// this will return an error from the API anyways
|
||||
if (!slug || slug === "/") return;
|
||||
|
||||
fetch("/api/hits?slug=" + slug)
|
||||
fetch("/api/hits/?slug=" + slug)
|
||||
.then((response) => response.json())
|
||||
.then((data) => {
|
||||
if (typeof data.hits !== "undefined") {
|
||||
|
@ -3,7 +3,7 @@
|
||||
var wrapper = document.getElementById("github-cards");
|
||||
|
||||
if (wrapper) {
|
||||
fetch("/api/projects?top")
|
||||
fetch("/api/projects/?top")
|
||||
.then((response) => response.json())
|
||||
.then((data) => {
|
||||
data.forEach((repo) => {
|
||||
|
28
config.toml
28
config.toml
@ -21,9 +21,6 @@ disableKinds = ["taxonomy", "term"]
|
||||
# don't worry, inserted manually :)
|
||||
disableHugoGeneratorInject = true
|
||||
|
||||
# prefer Netlify's _redirects file, see outputs below
|
||||
disableAliases = true
|
||||
|
||||
[params]
|
||||
description = "Hi there! I'm a frontend web developer based in Boston, Massachusetts specializing in the JAMstack, modern JavaScript frameworks, and progressive web apps."
|
||||
image = "img/logo.png" # relative to assetDir root
|
||||
@ -96,7 +93,7 @@ disableAliases = true
|
||||
weight = 4
|
||||
|
||||
[outputs]
|
||||
home = ["HTML", "RSS", "ATOM", "MANIFEST", "REDIRECTS", "HEADERS"]
|
||||
home = ["HTML", "RSS", "ATOM", "MANIFEST"]
|
||||
section = ["HTML"]
|
||||
page = ["HTML"]
|
||||
|
||||
@ -116,24 +113,12 @@ disableAliases = true
|
||||
baseName = "site" # /site.webmanifest
|
||||
isPlainText = true
|
||||
notAlternative = true
|
||||
[outputFormats.REDIRECTS]
|
||||
mediaType = "text/netlify"
|
||||
baseName = "_redirects"
|
||||
isPlainText = true
|
||||
notAlternative = true
|
||||
[outputFormats.HEADERS]
|
||||
mediaType = "text/netlify"
|
||||
baseName = "_headers"
|
||||
isPlainText = true
|
||||
notAlternative = true
|
||||
|
||||
[mediaTypes]
|
||||
[mediaTypes."application/atom+xml"]
|
||||
suffixes = ["atom"]
|
||||
[mediaTypes."application/manifest+json"]
|
||||
suffixes = ["webmanifest"]
|
||||
[mediaTypes."text/netlify"]
|
||||
delimiter = "" # no dot/extension for _headers & _redirects files
|
||||
|
||||
[sitemap]
|
||||
filename = "sitemap.xml"
|
||||
@ -183,14 +168,3 @@ disableAliases = true
|
||||
writeStats = true
|
||||
# don't use cache for SCSS compilation, better to throw error than be stale
|
||||
useResourceCacheWhen = "never"
|
||||
|
||||
[server]
|
||||
# proxy /api requests to netlify-lambda's local server (port 9337) for each function
|
||||
[[server.redirects]]
|
||||
from = "/api/**"
|
||||
to = "http://localhost:9337/"
|
||||
status = 200
|
||||
[[server.headers]]
|
||||
for = "/**"
|
||||
[server.headers.values]
|
||||
Access-Control-Allow-Origin = "*"
|
||||
|
@ -30,8 +30,7 @@
|
||||
# TECHNOLOGY
|
||||
|
||||
Hugo
|
||||
Netlify
|
||||
GitHub Actions
|
||||
Vercel
|
||||
...and much more: https://jarv.is/uses/
|
||||
|
||||
# VIEW SOURCE
|
||||
|
@ -15,7 +15,7 @@ This website uses a simple hit counter on each post to tally an aggregate number
|
||||
|
||||
## Hosting
|
||||
|
||||
Pages and first-party assets on this website are served by [**Netlify**](https://www.netlify.com/). Refer to their [privacy policy](https://www.netlify.com/privacy/) and [GDPR statement](https://www.netlify.com/gdpr/) for more information.
|
||||
Pages and first-party assets on this website are served by [**Vercel**](https://vercel.com/). Refer to their [privacy policy](https://vercel.com/legal/privacy-policy) for more information.
|
||||
|
||||
For a likely excessive level of privacy and security, this website is also mirrored on the [🧅 Tor network](https://www.torproject.org/) at: [**jarvis2i2vp4j4tbxjogsnqdemnte5xhzyi7hziiyzxwge3hzmh57zad.onion**](http://jarvis2i2vp4j4tbxjogsnqdemnte5xhzyi7hziiyzxwge3hzmh57zad.onion).
|
||||
|
||||
|
@ -172,7 +172,7 @@ I've been making recent efforts to [de-Google](https://www.stallman.org/google.h
|
||||
Other geeky stuff:
|
||||
|
||||
- [**DNSimple**](https://dnsimple.com/) [(referral link)](https://dnsimple.com/r/eb6ced548f1e0a) & [**Cloudflare**](https://www.cloudflare.com/) for domain DNS.
|
||||
- [**Netlify**](https://www.netlify.com/) for static sites.
|
||||
- [**Netlify**](https://www.netlify.com/) and [**Vercel**](https://vercel.com/) for static sites.
|
||||
- [**Linode**](https://www.linode.com/) [(referral link)](https://www.linode.com/?r=0c5aeace9bd591be9fbf32f96f58470295f1ee05) and [**DigitalOcean**](https://www.digitalocean.com/) [(referral link)](https://m.do.co/c/afcf288a7dac) for virtual Linux servers.
|
||||
- [**Backblaze**](https://www.backblaze.com/) [(referral link)](https://secure.backblaze.com/r/00x84e) for off-site MacBook backups.
|
||||
- [**Gitea**](https://gitea.io/en-us/) as a [self-hosted](https://code.jarv.is/) Git backup/mirror.
|
||||
|
@ -1,16 +0,0 @@
|
||||
# Cache static assets (webfonts, emojis, etc.) for a long time (1 month)
|
||||
/vendor/*
|
||||
Cache-Control: max-age=2628000
|
||||
|
||||
# Recommended MIME type for PWA manifests:
|
||||
# https://github.com/w3c/manifest/issues/689
|
||||
/site.webmanifest
|
||||
Content-Type: application/manifest+json
|
||||
|
||||
# Set matching Onion-Location headers for each permalink
|
||||
{{- range $page := .Site.Pages }}
|
||||
{{- range .AlternativeOutputFormats }}
|
||||
{{ .RelPermalink }}
|
||||
Onion-Location: {{ $.Site.Params.baseOnionURL }}{{ .RelPermalink }}
|
||||
{{ end -}}
|
||||
{{ end -}}
|
@ -1,26 +0,0 @@
|
||||
/index.php* / 301
|
||||
/feed /feed.xml 301
|
||||
/rss /feed.xml 301
|
||||
/index.xml /feed.xml 301
|
||||
|
||||
{{- with .Site.Params.social.webmentionIO }}
|
||||
/xmlrpc.php https://webmention.io/{{ . }}/xmlrpc 302
|
||||
{{ end -}}
|
||||
|
||||
/favicon.ico /img/favicon.ico 200
|
||||
/favicon-* /img/favicon-:splat 200
|
||||
/apple-touch-icon.png /img/apple-touch-icon.png 200
|
||||
/apple-touch-icon-precomposed.png /img/apple-touch-icon.png 200
|
||||
/safari-pinned-tab.svg /img/safari-pinned-tab.svg 200
|
||||
|
||||
# Hugo aliases: prefer HTTP 301 redirects over meta tags
|
||||
{{- range $page := .Site.Pages }}
|
||||
{{- range .Aliases }}
|
||||
{{ . }} {{ $page.RelPermalink }} 301
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
||||
# Redirect old AMP URLs to the normal HTML page
|
||||
{{- range $page := .Site.Pages }}
|
||||
{{ print .RelPermalink "amp.html" }} {{ .RelPermalink }} 301!
|
||||
{{ end -}}
|
@ -1,4 +1,4 @@
|
||||
{{ if .Site.Params.social.webmentionIO }}
|
||||
<link rel="pingback" href="{{ "api/ping" | absURL }}">
|
||||
<link rel="webmention" href="{{ "api/mention" | absURL }}">
|
||||
{{ with .Site.Params.social.webmentionIO }}
|
||||
<link rel="webmention" href="https://webmention.io/{{ . }}/webmention">
|
||||
<link rel="pingback" href="https://webmention.io/{{ . }}/xmlrpc">
|
||||
{{ end }}
|
||||
|
253
netlify.toml
253
netlify.toml
@ -1,253 +0,0 @@
|
||||
[build]
|
||||
command = "yarn build"
|
||||
publish = "public"
|
||||
functions = ".netlify/functions"
|
||||
|
||||
[build.environment]
|
||||
NODE_VERSION = "16"
|
||||
YARN_VERSION = "1.22.10"
|
||||
YARN_FLAGS = "--no-ignore-optional --frozen-lockfile"
|
||||
|
||||
# Ensure *only* Pretty URLs are enabled, even though this is already set up in
|
||||
# the Netlify dashboard.
|
||||
[build.processing]
|
||||
skip_processing = false
|
||||
[build.processing.css]
|
||||
bundle = false
|
||||
minify = false
|
||||
[build.processing.js]
|
||||
bundle = false
|
||||
minify = false
|
||||
[build.processing.html]
|
||||
pretty_urls = true
|
||||
[build.processing.images]
|
||||
compress = false
|
||||
|
||||
[context.deploy-preview]
|
||||
command = "yarn build:functions && yarn build:hugo --environment development --baseURL $DEPLOY_PRIME_URL --buildDrafts --buildFuture"
|
||||
|
||||
[context.branch-deploy]
|
||||
command = "yarn build:functions && yarn build:hugo --environment development --baseURL $DEPLOY_PRIME_URL --buildDrafts --buildFuture"
|
||||
|
||||
# https://github.com/netlify/cli/blob/master/docs/netlify-dev.md#netlifytoml-dev-block
|
||||
[dev]
|
||||
framework = "#custom"
|
||||
# only start Hugo, `netlify dev` builds/serves functions itself
|
||||
command = "yarn start:hugo --port=1338 --baseURL=/ --appendPort=false --disableLiveReload"
|
||||
# swap ports to keep consistent w/ normal local server
|
||||
targetPort = 1338
|
||||
port = 1337
|
||||
# don't launch browser automatically
|
||||
autoLaunch = false
|
||||
|
||||
# Enable local Netlify build plugins:
|
||||
[[plugins]]
|
||||
package = "@netlify/plugin-local-install-core"
|
||||
# Cache resoures between builds:
|
||||
# https://github.com/jakejarvis/netlify-plugin-cache
|
||||
[[plugins]]
|
||||
package = "netlify-plugin-cache"
|
||||
[plugins.inputs]
|
||||
paths = ["public", "builds", "_vendor"]
|
||||
# List cached resources for debugging:
|
||||
# [[plugins]]
|
||||
# package = "netlify-plugin-debug-cache"
|
||||
|
||||
# The most important headers and redirects are specified in the _headers and
|
||||
# _redirects files generated by Hugo. These are additional custom rules, mostly
|
||||
# unrelated to the actual website.
|
||||
|
||||
# Global security headers:
|
||||
[[headers]]
|
||||
for = "/*"
|
||||
[headers.values]
|
||||
Content-Security-Policy = '''
|
||||
default-src 'self';
|
||||
base-uri 'none';
|
||||
connect-src 'self' api.github.com platform.twitter.com;
|
||||
font-src 'self';
|
||||
form-action 'none';
|
||||
frame-ancestors 'self';
|
||||
frame-src 'self' jakejarvis.github.io buttons.github.io codepen.io cdpn.io platform.twitter.com www.youtube-nocookie.com;
|
||||
img-src 'self' data: https:;
|
||||
manifest-src 'self';
|
||||
media-src 'self' data: https:;
|
||||
object-src 'none';
|
||||
script-src 'self' buttons.github.io gist.github.com syndication.twitter.com platform.twitter.com 'sha256-1j1MKfE70TTCp5KmiC2YImxw2RMS52uCH5yXl1heG9U=' 'sha256-y3Xr/40/KQnUvqk/kZO5us6t3i/I49BsbYjsH8ELhVg=' 'sha256-JGG0npUp+0ABq/NY1azjpQ0WBtm+m5gU58mzF+2DCXY=';
|
||||
style-src 'self' 'unsafe-inline' github.githubassets.com;
|
||||
worker-src 'self';
|
||||
block-all-mixed-content;
|
||||
report-uri https://jarv.is/api/csp_wizard;
|
||||
report-to default'''
|
||||
NEL = '''
|
||||
{"report_to":"default","max_age":604800}'''
|
||||
Report-To = '''
|
||||
{"group":"default","max_age":604800,"endpoints":[{"url":"https://jarv.is/api/report"}],"include_subdomains":false}'''
|
||||
# More generic security headers:
|
||||
Feature-Policy = "accelerometer 'none'; camera 'none'; geolocation 'none'; gyroscope 'none'; magnetometer 'none'; microphone 'none'; payment 'none'; usb 'none'"
|
||||
Permissions-Policy = "accelerometer=(), camera=(), geolocation=(), gyroscope=(), magnetometer=(), microphone=(), payment=(), usb=(), interest-cohort=()"
|
||||
Referrer-Policy = "no-referrer-when-downgrade"
|
||||
X-Content-Type-Options = "nosniff"
|
||||
X-Frame-Options = "SAMEORIGIN"
|
||||
X-XSS-Protection = "1; mode=block"
|
||||
X-Got-Milk = "2%"
|
||||
X-View-Source = "https://github.com/jakejarvis/jarv.is"
|
||||
# PGP key: open in browser, download correctly
|
||||
[[headers]]
|
||||
for = "/pubkey.asc"
|
||||
[headers.values]
|
||||
Cache-Control = "no-cache"
|
||||
Content-Type = "text/plain; charset=UTF-8"
|
||||
Content-Disposition = "inline; filename=\"pubkey.asc\""
|
||||
|
||||
# Redirect Netlify and www subdomains to primary domain:
|
||||
[[redirects]]
|
||||
from = "https://jakejarvis.netlify.com/*"
|
||||
to = "https://jarv.is/:splat"
|
||||
status = 301
|
||||
force = true
|
||||
[[redirects]]
|
||||
from = "https://jakejarvis.netlify.app/*"
|
||||
to = "https://jarv.is/:splat"
|
||||
status = 301
|
||||
force = true
|
||||
[[redirects]]
|
||||
from = "https://www.jarv.is/*"
|
||||
to = "https://jarv.is/:splat"
|
||||
status = 301
|
||||
force = true
|
||||
|
||||
# External API redirects/mirrors:
|
||||
# Must set `force = true` and wildcard /api/* rule goes last.
|
||||
## Report URI endpoints
|
||||
[[redirects]]
|
||||
from = "/api/report"
|
||||
to = "https://jarvis.report-uri.com/a/d/g"
|
||||
status = 200
|
||||
force = true
|
||||
[[redirects]]
|
||||
from = "/api/csp_wizard"
|
||||
to = "https://jarvis.report-uri.com/r/d/csp/enforce"
|
||||
status = 200
|
||||
force = true
|
||||
## Webmention.io endpoints
|
||||
[[redirects]]
|
||||
from = "/api/mention"
|
||||
to = "https://webmention.io/jarv.is/webmention"
|
||||
status = 200
|
||||
force = true
|
||||
[[redirects]]
|
||||
from = "/api/ping"
|
||||
to = "https://webmention.io/jarv.is/xmlrpc"
|
||||
status = 200
|
||||
force = true
|
||||
## Prettier URLs for Netlify Functions
|
||||
[[redirects]]
|
||||
from = "/api/*"
|
||||
to = "/.netlify/functions/:splat"
|
||||
status = 200
|
||||
|
||||
# More miscellaneous mirrors/redirects:
|
||||
[[redirects]]
|
||||
from = "/blog/*"
|
||||
to = "/notes/"
|
||||
status = 301
|
||||
[[redirects]]
|
||||
from = "/archives/*"
|
||||
to = "/notes/"
|
||||
status = 301
|
||||
[[redirects]]
|
||||
from = "/resume"
|
||||
to = "/resume.pdf"
|
||||
status = 302
|
||||
|
||||
# Fix some 404s after moving files around somewhat recklessly:
|
||||
[[redirects]]
|
||||
from = "/keybase.txt"
|
||||
to = "/.well-known/keybase.txt"
|
||||
status = 301
|
||||
[[redirects]]
|
||||
from = "/jarvis.asc"
|
||||
to = "/pubkey.asc"
|
||||
status = 301
|
||||
[[redirects]]
|
||||
from = "/img/logo.svg"
|
||||
to = "/img/favicon.svg"
|
||||
status = 302
|
||||
[[redirects]]
|
||||
from = "/img/me_large.jpg"
|
||||
to = "/img/me.jpg"
|
||||
status = 301
|
||||
[[redirects]]
|
||||
from = "/me.jpg"
|
||||
to = "/img/me.jpg"
|
||||
status = 301
|
||||
[[redirects]]
|
||||
from = "/me_large.jpg"
|
||||
to = "/img/me.jpg"
|
||||
status = 301
|
||||
[[redirects]]
|
||||
from = "/img/me_hu1c1a997e30e234e83718deb8b3f52283_130509_320x320_resize_q90_lanczos.jpg"
|
||||
to = "/img/me.jpg"
|
||||
status = 301
|
||||
[[redirects]]
|
||||
from = "/twemoji/svg/*"
|
||||
to = "/vendor/emoji/svg/:splat"
|
||||
status = 301
|
||||
[[redirects]]
|
||||
from = "/vendor/inter/*"
|
||||
to = "/vendor/fonts/:splat"
|
||||
status = 301
|
||||
|
||||
# Moved these random sites/projects elsewhere (mostly GitHub Pages) to keep
|
||||
# this repo and domain squeaky clean:
|
||||
[[redirects]]
|
||||
from = "/y2k/*"
|
||||
to = "https://jakejarvis.github.io/my-first-website/:splat"
|
||||
status = 302
|
||||
[[redirects]]
|
||||
from = "/ios-trackers/*"
|
||||
to = "https://jakejarvis.github.io/ios-trackers/:splat"
|
||||
status = 302
|
||||
[[redirects]]
|
||||
from = "/awesome/*"
|
||||
to = "https://synonymsforawesome.com/"
|
||||
status = 302
|
||||
[[redirects]]
|
||||
from = "/hugo-node/*"
|
||||
to = "https://github.com/jakejarvis/hugo-extended"
|
||||
status = 302
|
||||
[[redirects]]
|
||||
from = "/comp20/*"
|
||||
to = "https://jakejarvis.github.io/comp20/:splat"
|
||||
status = 302
|
||||
[[redirects]]
|
||||
from = "/scrabble/*"
|
||||
to = "https://jakejarvis.github.io/scrabble/:splat"
|
||||
status = 302
|
||||
|
||||
# H A C K E R M A N ( ͡° ͜ʖ ͡°)
|
||||
[[redirects]]
|
||||
from = "*/wp-admin/*"
|
||||
to = "/403.html"
|
||||
status = 403
|
||||
[[redirects]]
|
||||
from = "*/admin/*"
|
||||
to = "/403.html"
|
||||
status = 403
|
||||
[[redirects]]
|
||||
from = "*/wp-login.php"
|
||||
to = "/403.html"
|
||||
status = 403
|
||||
[[redirects]]
|
||||
from = "*/login.php"
|
||||
to = "/403.html"
|
||||
status = 403
|
||||
[[redirects]]
|
||||
from = "*/wlwmanifest.xml"
|
||||
to = "/403.html"
|
||||
status = 403
|
||||
[[redirects]]
|
||||
from = "*/.git/*"
|
||||
to = "/403.html"
|
||||
status = 403
|
14
package.json
14
package.json
@ -14,13 +14,10 @@
|
||||
"url": "git+https://github.com/jakejarvis/jarv.is.git"
|
||||
},
|
||||
"scripts": {
|
||||
"clean": "rimraf public/ resources/ builds/ _vendor/ .netlify/{cache,functions}/ $TMPDIR/hugo_cache/ hugo_stats.json",
|
||||
"start": "run-p start:**",
|
||||
"start:hugo": "hugo server --disableFastRender --buildDrafts --buildFuture --port=1337 --baseURL=/ --appendPort=false --bind=0.0.0.0 --verbose",
|
||||
"start:functions": "netlify-lambda serve --port 9337 functions",
|
||||
"clean": "rimraf public/ resources/ builds/ _vendor/ .vercel/cache/ $TMPDIR/hugo_cache/ hugo_stats.json",
|
||||
"start": "hugo server --buildDrafts --buildFuture --port=${PORT:-1337} --baseURL=/ --appendPort=false --bind=0.0.0.0 --verbose",
|
||||
"build": "run-s build:** minify:**",
|
||||
"build:hugo": "hugo --gc --cleanDestinationDir --verbose",
|
||||
"build:functions": "netlify-lambda build functions",
|
||||
"minify:html": "html-minifier --html5 --collapse-whitespace --collapse-boolean-attributes --preserve-line-breaks --minify-css --remove-comments --file-ext html --input-dir public --output-dir public **/*.html",
|
||||
"minify:js": "terser --compress passes=3,negate_iife=false,keep_fargs=false,sequences=false,reduce_vars=false --mangle reserved=['sa','sa_event'] --output public/js/app.js -- public/js/app.js",
|
||||
"minify:img": "glob-exec --parallel --foreach 'public/**/{img,images}/' -- imagemin '{{file.path}}*' --plugin=mozjpeg --plugin.mozjpeg.progressive --plugin.mozjpeg.quality=85 --plugin=pngquant --plugin.pngquant.quality={0.1,0.3} --plugin.pngquant.speed=1 --plugin.pngquant.strip --plugin=gifsicle --plugin=svgo --out-dir='{{file.path}}'",
|
||||
@ -37,7 +34,6 @@
|
||||
"@fontsource/inter": "4.4.2",
|
||||
"@fontsource/roboto-mono": "4.4.2",
|
||||
"dotenv": "^10.0.0",
|
||||
"encoding": "^0.1.13",
|
||||
"faunadb": "fauna/faunadb-js#master",
|
||||
"graphql": "^15.5.0",
|
||||
"graphql-request": "^3.4.0",
|
||||
@ -63,8 +59,6 @@
|
||||
"imagemin-cli": "^6.0.0",
|
||||
"lint-staged": "^11.0.0",
|
||||
"markdownlint-cli": "~0.27.1",
|
||||
"netlify-lambda": "^2.0.8",
|
||||
"netlify-plugin-cache": "^1.0.3",
|
||||
"npm-run-all": "^4.1.5",
|
||||
"postcss": "^8.3.0",
|
||||
"postcss-clean": "jakejarvis/postcss-clean#master",
|
||||
@ -93,10 +87,6 @@
|
||||
"imagemin-pngquant": "^9.0.2",
|
||||
"imagemin-svgo": "^9.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^10 || ^12 || >=14",
|
||||
"yarn": "^1.22.4"
|
||||
},
|
||||
"simple-git-hooks": {
|
||||
"pre-commit": "npx lint-staged"
|
||||
},
|
||||
|
110
vercel.json
Normal file
110
vercel.json
Normal file
@ -0,0 +1,110 @@
|
||||
{
|
||||
"public": false,
|
||||
"trailingSlash": true,
|
||||
"rewrites": [
|
||||
{ "source": "/favicon.ico", "destination": "/img/favicon.ico" },
|
||||
{ "source": "/favicon-(.*)", "destination": "/img/favicon-$1xxxxxxxx" },
|
||||
{ "source": "/apple-touch-icon.png", "destination": "/img/apple-touch-icon.png" },
|
||||
{ "source": "/apple-touch-icon-precomposed.png", "destination": "/img/apple-touch-icon.png" },
|
||||
{ "source": "/safari-pinned-tab.svg", "destination": "/img/safari-pinned-tab.svg" }
|
||||
],
|
||||
"redirects": [
|
||||
{ "source": "/notes/:slug/amp.html", "destination": "/notes/:slug/", "statusCode": 301 },
|
||||
{ "source": "/blog/(.*)", "destination": "/notes/" },
|
||||
{ "source": "/archives/(.*)", "destination": "/notes/" },
|
||||
{ "source": "/feed", "destination": "/feed.xml" },
|
||||
{ "source": "/rss", "destination": "/feed.xml" },
|
||||
{ "source": "/index.xml", "destination": "/feed.xml" },
|
||||
{ "source": "/resume/", "destination": "/resume.pdf" },
|
||||
{ "source": "/keybase.txt", "destination": "/.well-known/keybase.txt" },
|
||||
{ "source": "/jarvis.asc", "destination": "/pubkey.asc" },
|
||||
{ "source": "/img/logo.svg", "destination": "/img/favicon.svg" },
|
||||
{ "source": "/img/me_large.jpg", "destination": "/img/me.jpg" },
|
||||
{ "source": "/me.jpg", "destination": "/img/me.jpg" },
|
||||
{ "source": "/me_large.jpg", "destination": "/img/me.jpg" },
|
||||
{ "source": "/img/me_hu1c1a997e30e234e83718deb8b3f52283_130509_320x320_resize_q90_lanczos.jpg", "destination": "/img/me.jpg" },
|
||||
{ "source": "/y2k/(.*)", "destination": "https://jakejarvis.github.io/my-first-website/$1" },
|
||||
{ "source": "/ios-trackers/(.*)", "destination": "https://jakejarvis.github.io/ios-trackers/$1" },
|
||||
{ "source": "/awesome/", "destination": "https://synonymsforawesome.com/" },
|
||||
{ "source": "/hugo-node/", "destination": "https://github.com/jakejarvis/hugo-extended" },
|
||||
{ "source": "/comp20/(.*)", "destination": "https://jakejarvis.github.io/comp20/$1" },
|
||||
{ "source": "/scrabble/(.*)", "destination": "https://jakejarvis.github.io/scrabble/$1" }
|
||||
],
|
||||
"headers": [
|
||||
{
|
||||
"source": "/vendor/(.*)",
|
||||
"headers": [
|
||||
{
|
||||
"key": "Cache-Control",
|
||||
"value": "public, max-age=2628000"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"source": "/pubkey.asc",
|
||||
"headers": [
|
||||
{
|
||||
"key": "Cache-Control",
|
||||
"value": "private, no-cache, no-store, must-revalidate"
|
||||
},
|
||||
{
|
||||
"key": "Content-Type",
|
||||
"value": "text/plain; charset=utf-8"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"source": "/(.*)",
|
||||
"headers" : [
|
||||
{
|
||||
"key": "Onion-Location",
|
||||
"value": "http://jarvis2i2vp4j4tbxjogsnqdemnte5xhzyi7hziiyzxwge3hzmh57zad.onion/$1"
|
||||
},
|
||||
{
|
||||
"key": "Content-Security-Policy",
|
||||
"value": "default-src 'self'; base-uri 'none'; connect-src 'self' api.github.com platform.twitter.com; font-src 'self'; form-action 'none'; frame-ancestors 'self'; frame-src 'self' jakejarvis.github.io buttons.github.io codepen.io cdpn.io platform.twitter.com www.youtube-nocookie.com; img-src 'self' data: https:; manifest-src 'self'; media-src 'self' data: https:; object-src 'none'; script-src 'self' buttons.github.io gist.github.com syndication.twitter.com platform.twitter.com 'sha256-1j1MKfE70TTCp5KmiC2YImxw2RMS52uCH5yXl1heG9U=' 'sha256-y3Xr/40/KQnUvqk/kZO5us6t3i/I49BsbYjsH8ELhVg=' 'sha256-JGG0npUp+0ABq/NY1azjpQ0WBtm+m5gU58mzF+2DCXY='; style-src 'self' 'unsafe-inline' github.githubassets.com; worker-src 'self'; block-all-mixed-content; report-uri https://jarvis.report-uri.com/r/d/csp/enforce; report-to default"
|
||||
},
|
||||
{
|
||||
"key": "Report-To",
|
||||
"value": "{\"group\":\"default\",\"max_age\":604800,\"endpoints\":[{\"url\":\"https://jarvis.report-uri.com/a/d/g\"}],\"include_subdomains\":false}"
|
||||
},
|
||||
{
|
||||
"key": "NEL",
|
||||
"value": "{\"report_to\":\"default\",\"max_age\":604800}"
|
||||
},
|
||||
{
|
||||
"key": "Feature-Policy",
|
||||
"value": "accelerometer 'none'; camera 'none'; geolocation 'none'; gyroscope 'none'; magnetometer 'none'; microphone 'none'; payment 'none'; usb 'none'"
|
||||
},
|
||||
{
|
||||
"key": "Permissions-Policy",
|
||||
"value": "accelerometer=(), camera=(), geolocation=(), gyroscope=(), magnetometer=(), microphone=(), payment=(), usb=(), interest-cohort=()"
|
||||
},
|
||||
{
|
||||
"key": "Referrer-Policy",
|
||||
"value": "no-referrer-when-downgrade"
|
||||
},
|
||||
{
|
||||
"key": "X-Content-Type-Options",
|
||||
"value": "nosniff"
|
||||
},
|
||||
{
|
||||
"key": "X-Frame-Options",
|
||||
"value": "SAMEORIGIN"
|
||||
},
|
||||
{
|
||||
"key": "X-XSS-Protection",
|
||||
"value": "1; mode=block"
|
||||
},
|
||||
{
|
||||
"key": "x-view-source",
|
||||
"value": "https://github.com/jakejarvis/jarv.is"
|
||||
},
|
||||
{
|
||||
"key" : "x-got-milk",
|
||||
"value" : "2%"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user