Начнем с создания нового приложения Next.js:

$ yarn create next-app — typescript

В корне проекта Next.js на TypeScript будут созданы файлы next-env.d.ts и tsconfig.json. Файл next-env.d.ts делает так, чтобы типы Next.js были подобраны компилятором TypeScript. Его не нужно удалять или редактировать.

Файл tsconfig.json  —  это пользовательская конфигурация компилятора TypeScript. Если понадобятся дополнительные типы, нужно создать *.d.ts в корне и сослаться на него в массиве include файла tsconfig.json.

Более подробную информацию можно найти в официальной документации.

Добавление файлов favicon

Наведем порядок и добавим подписи к проекту. Например, удалим ненужные компоненты и добавим иконку приложения. favicon.io  —  эффективный инструмент для создания файлов иконок веб-приложений.

public/
├── android-chrome-192x192.png
├── android-chrome-512x512.png
├── apple-touch-icon.png
├── favicon-16x16.png
├── favicon-32x32.png
├── favicon.ico
└── site.webmanifest

Файлы иконок должны быть помещены в общедоступную папку. Также нужно добавить свойства в site.webmanifest, чтобы дополнить его и привести к стандартам прогрессивного веб-приложения.

  • ./public/site.webmanifest:
{
"name": "Next.js 100 - TypeScript",
"app_name": "Next.js 100 - TypeScript",
"short_name": "Next.js 100 - TypeScript",
"description": "Build a PWA to achieve 100% in Google Lighthouse and Next.js Analytics",
"icons": [
{
"src": "/android-chrome-192x192.png",
"sizes": "192x192",
"type": "image/png",
"purpose": "any maskable"
},
{
"src": "/android-chrome-512x512.png",
"sizes": "512x512",
"type": "image/png",
"purpose": "any maskable"
},
{
"src": "/favicon-32x32.png",
"sizes": "32x32",
"type": "image/png",
"purpose": "any maskable"
},
{
"src": "/favicon-16x16.png",
"sizes": "16x16",
"type": "image/png",
"purpose": "any maskable"
}
],
"theme_color": "#ffffff",
"background_color": "#ffffff",
"display": "standalone",
"scope": "/",
"start_url": "/"
}
  • ./pages/_document.tsx:
import { Head, Html, Main, NextScript } from 'next/document'

const Document = () => (
<Html>
<Head>
<link rel="icon" type="image/x-icon" href="/favicon.ico" />
<link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
<link
href="/favicon-16x16.png"
rel="icon"
type="image/png"
sizes="16x16"
/>
<link
href="/favicon-32x32.png"
rel="icon"
type="image/png"
sizes="32x32"
/>
<link rel="apple-touch-icon" href="/apple-touch-icon.png"></link>

<link rel="manifest" href="/site.webmanifest" />
</Head>
<body>
<Main />
<NextScript />
</body>
</Html>
)

export default Document

Когда файлы будут готовы, добавьте метатеги в элемент <head> файла _document.tsx.

manifest.json и site.webmanifest

Согласно w3.org, разработчики могут использовать различные расширения, такие как manifest.json и site.webmanifest. Однако зарегистрированным в системе IANA расширением файла для manifest является .webmanifest. Мы будем использовать site.webmanifest в этом репозитории.

Фото 1. Отчет о производительности от Lighthouse — сборка разработки

Производственная сборка  —  это оптимизированная версия приложения. Сгенерированный код в .next компилируется и минифицируется. Обычно производственная версия выкладывается с целью оптимизации производительности.

Фото 2. Отчет о производительности от Lighthouse — производственная сборка

Продолжим, чтобы окрасить все оставшиеся показатели отчета в зеленый цвет.

Добавляем метатеги title и description

Исходя из отчета Lighthouse, добавление элементов title и description может улучшить как уровень доступности, так и показатели SEO.

Фото 3. Диагностика от Lighthouse — элемент title
Фото 4. Диагностика от Lighthouse — элемент title и meta description

В Next.js мы можем разместить метатег description в файле _document.tsx. Однако элемент <title> нужно добавить на каждую страницу.

  • ./pages/_document.tsx:
import { Head, Html, Main, NextScript } from 'next/document'

const Document = () => (
<Html>
<Head>
+ <meta
+ name="description"
+ content="Build a PWA to achieve 100% in Google Lighthouse and Next.js Analytics"
+ />
+
<link rel="icon" type="image/x-icon" href="/favicon.ico" />
<link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
  • ./pages/index.tsx:
import type { NextPage } from 'next'
+ import Head from 'next/head'

const Index: NextPage = () => {
return (
<div>
+ <Head>
+ <title>Next.js 100 - TypeScript</title>
+ </Head>
+
<main>
<h1>Next.js 100 - TypeScript</h1>
</main>

Добавление атрибута lang к элементу HTML

Начиная с версии 10, Next.js поддерживает интернационализированную маршрутизацию. Next.js будет автоматически добавлять атрибут lang в зависимости от языка пользователя.

  • ./next.config.js:
const nextConfig = {
reactStrictMode: true,
+ i18n: {
+ locales: ['en', 'nl'],
+ defaultLocale: 'en',
+ localeDetection: false,
+ },
})

module.exports = nextConfig

Добавим конфигурацию i18n в next.config.js, чтобы указать поддерживаемые языки. Мы увидим, что автоматически определяемый атрибут lang добавлен к элементу HTML.

Фото 5. Отчет о производительности от Lighthouse — все показатели зеленые

Теперь в отчете от Lighthouse все четыре показателя окрашены в зеленый цвет (100). Тем не менее на кружке PWA все еще видим минус.

Прогрессивное веб-приложение (PWA)

Довольно удобно превратить простое приложение Next.js в прогрессивное веб-приложение, добавив пакет next-pwa:

$ yarn add next-pwa

Импортируйте пакет next-pwa в next.config.js и добавьте конфигурации. Желательно, чтобы service worker не функционировал во время процесса разработки.

  • ./next.config.js:
/** @type {import('next').NextConfig} */
+ const withPWA = require('next-pwa')
+ const runtimeCaching = require('next-pwa/cache')
+
const nextConfig = withPWA({
reactStrictMode: true,
i18n: {
locales: ['en', 'nl'],
defaultLocale: 'en',
localeDetection: false,
},
+ pwa: {
+ disable: process.env.NODE_ENV !== 'production',
+ dest: 'public',
+ runtimeCaching,
+ buildExcludes: [/middleware-manifest.json$/],
+ },
})

module.exports = nextConfig

Для настройки PWA также необходимы метатеги theme-color и referrer.

  • ./pages/_document.tsx:
import { Head, Html, Main, NextScript } from 'next/document'

const Document = () => (
<Html>
<Head>
<meta
name="description"
content="Build a PWA to achieve 100% in Google Lighthouse and Next.js Analytics"
/>
+ <meta name="theme-color" content="#333333" />
+ <meta name="referrer" content={'strict-origin'} />

<link rel="icon" type="image/x-icon" href="/favicon.ico" />

manifest.json и проблема предварительного кэширования

После развертывания в Vercel мы столкнемся с проблемой предварительного кэширования. Поэтому в следующей сборке PWA кэш времени выполнения добавлен, а файл middleware-manifest.json исключен.

После выполнения вышеуказанных манипуляций, магическим образом в кружке PWA в отчете от Lighthouse появляется зеленая галочка!

Фото 6. Отчет о производительности от Lighthouse — все показатели зеленые, включая PWA

Проверка безопасности

Несмотря на то, что мы достигли 100% в отчете от Lighthouse, этого недостаточно. Надо также подумать и о безопасности, поэтому проверим соответствующий показатель.

Фото 7. Отчет о безопасности с сайта webpagetest.org — оценка безопасности E

По данным webpagetest.org, оценка безопасности находится в группе E. Это означает, что нам предстоит решить ряд проблем.

Фото 8. Диагностика на сайте webpagetest.org —параметр X Content Type Options
Фото 9. Диагностика на сайте webpagetest.org — параметр X Frame Options
Фото 10. Диагностика на сайте webpagetest.org — параметр X XSS Protection.

Добавляем заголовки безопасности

Мы можем исправить эти проблемы, добавив заголовки безопасности в next.config.js:

/** @type {import('next').NextConfig} */
const withPWA = require('next-pwa')
const runtimeCaching = require('next-pwa/cache')

+ const securityHeaders = () => [
+ {
+ key: 'X-Content-Type-Options',
+ value: 'nosniff',
+ },
+ {
+ key: 'X-Frame-Options',
+ value: 'SAMEORIGIN',
+ },
+ {
+ key: 'X-XSS-Protection',
+ value: '1; mode=block',
+ },
+ ]
+
const nextConfig = withPWA({
reactStrictMode: true,
i18n: {
locales: ['en', 'nl'],
defaultLocale: 'en',
localeDetection: false,
},
pwa: {
disable: process.env.NODE_ENV !== 'production',
dest: 'public',
runtimeCaching,
buildExcludes: [/middleware-manifest.json$/],
},
+ async headers() {
+ return [
+ {
+ source: '/:path*',
+ headers: securityHeaders(),
+ },
+ ]
+ },
})

module.exports = nextConfig

Добавляем политику безопасности контента

Для обеспечения политики безопасности контента мы должны добавить vitals.vercel-insights.com для Vercel Analytics:

/** @type {import('next').NextConfig} */
const withPWA = require('next-pwa')
const runtimeCaching = require('next-pwa/cache')

+ const ContentSecurityPolicy = `
+ default-src 'self';
+ script-src 'self';
+ connect-src 'self' vitals.vercel-insights.com;
+ style-src 'self';
+ font-src 'self';
+ `
+
const securityHeaders = () => [
{
key: 'X-Content-Type-Options',
value: 'nosniff',
},
{
key: 'X-Frame-Options',
value: 'SAMEORIGIN',
},
{
key: 'X-XSS-Protection',
value: '1; mode=block',
},
+ {
+ key: 'Content-Security-Policy',
+ value: ContentSecurityPolicy.replace(/\s{2,}/g, ' ').trim(),
+ },
]

Пройдем еще одну проверку на webpagetest.org для получения лучшей оценки.

Фото 11. Отчет о безопасности от webpagetest.org — оценка безопасности A+

Наконец-то мы получили группу А+ по уровню безопасности.

Vercel Analytics

Google Lighthouse  —  почти стандартный инструмент для проверки основных показателей сайта. Но эта оценка предназначена для одной точки данных. Чтобы оценить веб-показатели с точки зрения реального опыта, нужно воспользоваться Vercel analytics. Этот инструмент позволяет измерять производительность сайта путем сбора метрик при посещении пользователями его страниц.

Фото 12. Включение Vercel Analytics

Настройка Vercel Analytics в Vercel довольно проста, мы просто включаем его на вкладке Analytics целевого проекта.

Фото 13. Отчет о производительности от Vercel Analytics

Поскольку Vercel Analytics собирает показатели производительности по мере посещения пользователями сайта, нужно зайти на страницу несколько раз, прежде чем данные появятся на дашборде.

Вывод

В этой статье мы проследили весь путь создания прогрессивного веб-приложения с Next.js и получения 100-процентного результата от Google Lighthouse, Next.js Analytics и уровня безопасности A+ на webpagetest.org. Надеюсь, этот материал послужит трамплином для ваших потрясающих проектов!

Исходный код можно найти в этом репозитории.

Читайте также:

Читайте нас в TelegramVK и Яндекс.Дзен


Перевод статьи Rocky Li: How to Set Up Next.js with TypeScript to Get a 100% Score in Google Lighthouse and Vercel Analytics

Предыдущая статьяКак быстро создать и развернуть веб-приложение на Python
Следующая статьяArduino и Visual Studio Code