Next.js PWA(Service Worker + Manifest.json)

15

我正在使用Next.js开发一个服务器端渲染的网站,并希望将其变成渐进式Web应用程序,但问题是我找不到正确实现的方法。

当我构建应用程序时,它可以正确地提供服务工作者,但没有manifest.json文件,在一些项目示例中,它可以提供manifest.json文件,但在Lighthouse审计中尝试后,它会显示:

Service worker does not successfully serve the manifest's start_url

我使用的其中一个示例为 Create Next App With Service Worker Precache

我认为问题可能是start_url是"."或"/"而不是有效的文件,因为在Next.js中没有index.html文件可用于从开始提供服务。

总体而言 我正在寻找一个使用Next.js构建到dist文件夹的示例,当我提供它时,它具有有效的服务工作者和有效的Web Manifes。


请查看您的Next.js项目中的/public目录。其中有一些文件是静态提供的,这是manifest.json等文件的“根”URL。 - mtx
2个回答

16

A. 预期在“/”找到某些文件

您出现此错误是因为浏览器预期从服务器的根目录下提供访问某些文件,包括:

  1. /manifest.json
  2. /sitemap.xml
  3. /favicon.ico
  4. /robots.txt
  5. /browserconfig.xml
  6. /site.webmanifest

这些路径中的大多数都可以使用元标记进行设置,但老旧的浏览器会忽略它们,并在未提供这些确切的文件名时出现错误。

B. 配置替代路径并使用NextJS的静态文件

截至撰写本文的时间,NextJS正在进行支持离线功能的工作(请参见此处的工作进展),但还没有完全准备好。

如果您不需要支持老旧浏览器且不需要高级搜索引擎优化,则可以使用NextJS的Head组件(请参见文档)将manifest.json路径定义为任何NextJS静态文件。

import Head from "next/head"

export default () => (
    <Head>
        <link rel="manifest" href="/static/manifest.json" />
        <link rel="manifest" href="/static/site.webmanifest" />
        <link rel="shortcut icon" href="/static/favicon.ico"
    </Head>
)

请注意,robots.txt文件不能从子目录服务 (来源),因此如果您需要定义此文件,则此解决方案不适用。

C. 像预期的那样提供这些文件

正确的解决方案是从您的express服务器上像这样服务这些文件

const { createServer } = require('http')
const { parse } = require('url')
const next = require('next')
const { join } = require('path')

const port = parseInt(process.env.PORT, 10) || 3000
const dev = process.env.NODE_ENV !== 'production'
const app = next({ dev })
const handle = app.getRequestHandler()

app.prepare()
  .then(() => {
    createServer((req, res) => {
      const parsedUrl = parse(req.url, true)
      const rootStaticFiles = [
        '/manifest.json',
        '/sitemap.xml',
        '/favicon.ico',
        '/robots.txt',
        '/browserconfig.xml',
        '/site.webmanifest',
      ]
      if (rootStaticFiles.indexOf(parsedUrl.pathname) > -1) {
        const path = join(__dirname, 'static', parsedUrl.pathname)
        app.serveStatic(req, res, path)
      } else {
        handle(req, res, parsedUrl)
      }
    })
      .listen(port, (err) => {
        if (err) throw err
        console.log(`> Ready on http://localhost:${port}`)
      })
  })

注意:此代码直接来自于NextJS示例存储库


2
以下是关于如何使您的Next.js渐进式的步骤:查看示例
  • npm i next-pwa
  • next.config.json

请注意,这些步骤将帮助您使您的Next.js网站更加现代化和易于使用。
    const withPWA = require("next-pwa");
    module.exports = withPWA({
      pwa: {
        dest: "public",
        
      },
      ...
    });
  • add manifest.json and icons to public folder from the example. However, icons directory is missing "maskable_icon.png". So create a maskable icon from here then add this to "manifest.json".

     {
        "src": "path/to/maskable_icon.png",
        "sizes": "196x196",
        "type": "image/png",
        "purpose": "any maskable"
      }
    
  • add those tags to import Head from "next/head". Head is used for better SEO setting. check the documentation*

      <meta charSet="utf-8" />
      <meta httpEquiv="X-UA-Compatible" content="IE=edge" />
      <meta
        name="viewport"
        content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no"
      />
      <meta name="description" content="Description" />
      <meta name="keywords" content="Keywords" />
      <title>Next.js PWA Example</title>
    
      <link rel="manifest" href="/manifest.json" />
      <link
        href="/icons/favicon-16x16.png"
        rel="icon"
        type="image/png"
        sizes="16x16"
      />
      <link
        href="/icons/favicon-32x32.png"
        rel="icon"
        type="image/png"
        sizes="32x32"
      />
      <link rel="apple-touch-icon" href="/apple-icon.png"></link>
      <meta name="theme-color" content="#317EFB" />
    </Head>
    
  • lastly check if it is working. add Lighhouse extension to chrome dev tools from chrome app store and run start the performance.


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接