1
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

メモ:nuxt/imageでSSGする際に処理する画像が多いとipxがエラー吐きまくる問題

Last updated at Posted at 2021-04-05

画像が多いサイトで、nuxt/imageでSSG(静的サイトジェネレーター)で書き出ししようとするとエラーが出て、ネット上に解決方法が見つからなかったのでメモ。

nuxt/imageとは?

nuxtの公式の画像最適化用のコンポーネントで、next.jsでいう next/image と同じような位置付けのコンポーネントです。

エラーの詳細

画像の多いサイトで、以下のコマンドで書き出ししようとすると

yarn generate

このようなエラーがたくさん出て画像の書き出しに失敗します。

ERROR  request to http://localhost:57406/_ipx/images/hoge.jpg?s=640_298 failed, reason: connect ECONNRESET 127.0.0.1:57406

Githubにこのようなissueがありましたが、ちゃんと解決に至っていません。
https://github.com/nuxt/image/issues/198

原因を探ってみると画像変換に使っている ipx というローカルサーバへのアクセス過多でエラー吐いているようだったので、とりあえず応急処置的に対応しました。画像ファイルの処理を一斉に行わず少しずつ遅延させながら処理するようにしています。

@nuxt/image の /src/generate.ts を以下のように修正しました。


export function setupStaticGeneration (nuxt: any, options: ModuleOptions) {
  const staticImages = {} // url ~> hashed file name

  nuxt.hook('vue-renderer:ssr:prepareContext', (renderContext) => {
    renderContext.image = renderContext.image || {}
    renderContext.image.mapToStatic = <MapToStatic> function ({ url, format }: ResolvedImage) {
      if (!staticImages[url]) {
        const ext = (format && `.${format}`) || extname(parseURL(url).pathname) || '.png'
        staticImages[url] = hash(url) + ext
      }
      return staticImages[url]
    }
  })

  nuxt.hook('generate:done', async () => {
    const { dir: generateDir } = nuxt.options.generate
    let delay = 0 // ← この行を追加
    const downloads = Object.entries(staticImages).map(([url, name]) => {
      if (!hasProtocol(url)) {
        url = joinURL(options.internalUrl, url)
      }
      delay += delayOffset // ← この行を追加
      return downloadImage({
        url,
        name,
        outDir: resolve(generateDir, '_nuxt/image' /* TODO: staticImagesBase */),
        delay // ← この行を追加
      })
    })
    await Promise.all(downloads)
  })
}

async function downloadImage ({ url, name, outDir, delay }) { // 引数にdelayを追加
  try {
    await new Promise(resolve => setTimeout(resolve, delay)) // ← この行を追加
    const response = await fetch(url)
    if (!response.ok) { throw new Error(`Unexpected response ${response.statusText}`) }
    const dstFile = join(outDir, name)
    await mkdirp(dirname(dstFile))
    await pipeline(response.body, createWriteStream(dstFile))
    logger.success('Generated static image ' + relative(process.cwd(), dstFile))
  } catch (error) {
    logger.error(error.message)
  }
}

本当は上記のissueにもコメントされてますが、本当は最大の並行処理数を決めて、処理の完了を監視して次の処理をやるみたいなことをやるべきですが、とりあえず動けば良いという雑なやり方です。

一応GithubでForkしています。

追記:
nuxtを使ったプロジェクトの package.json の @nuxt/image を以下のように書き換えるとこちらのForkを読み込むようになりますが、設定が足りていないのか、普通に yarn install しても buildコマンドが走らずdistディレクトリが生成されないです。

"dependencies": {
  "@nuxt/image": "git+https://github.com/kjkmr/nuxt-image.git#main"
}	

とりあえずForkしたプロジェクトを npm run build することで吐き出されるdistディレクトリを nuxtのプロジェクトの node_modules/@nuxt/image 以下にコピーして無理矢理解決しています。(今度ちゃんとやり方調べたい。。。)

1
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?