Next.js: Rute (dan halaman) API Next.js harus mendukung membaca file

Dibuat pada 5 Agu 2019  ·  87Komentar  ·  Sumber: vercel/next.js

Permintaan fitur

Apakah permintaan fitur Anda terkait dengan masalah? Tolong jelaskan.

Saat ini tidak mungkin untuk membaca file dari rute atau halaman API.

Jelaskan solusi yang Anda inginkan

Saya ingin dapat memanggil fs.readFile dengan jalur __dirname dan membuatnya "berfungsi".

Ini harus bekerja dalam mode Pengembangan dan Produksi.

Jelaskan alternatif yang telah Anda pertimbangkan

Ini mungkin perlu diintegrasikan dengan @zeit/webpack-asset-relocator-loader dalam beberapa kapasitas. Plugin ini menangani jenis kebutuhan ini.

Namun, itu bukan keharusan. Saya akan baik-baik saja dengan sesuatu yang _only_ berfungsi dengan __dirname dan __filename (tidak ada jalur relatif atau berbasis cwd).

Konteks tambahan

Contoh:

// pages/api/test.js
import fs from 'fs'
import path from 'path'

export default (req, res) => {
  const fileContent = fs.readFileSync(
    path.join(__dirname, '..', '..', 'package.json'), 
    'utf8'
  )
  // ...
}

Catatan: Saya tahu Anda dapat menipu contoh di atas ️ dengan require , tapi bukan itu intinya. 😄

story feature request

Komentar yang paling membantu

Solusi yang saya gunakan:

# next.config.js
module.exports = {
    serverRuntimeConfig: {
        PROJECT_ROOT: __dirname
    }
}

dan di lokasi Anda membutuhkan jalan

import fs from 'fs'
import path from 'path'
import getConfig from 'next/config'
const { serverRuntimeConfig } = getConfig()

fs.readFile(path.join(serverRuntimeConfig.PROJECT_ROOT, './path/to/file.json'))

Saya tahu ini tidak menyelesaikan kebutuhan untuk mereferensikan file dengan jalur relatif ke file saat ini, tetapi ini menyelesaikan kasus penggunaan saya yang sangat terkait (membaca file gambar dari folder /public/images ).

Semua 87 komentar

Hanya ingin yang kedua, mencoba mengimplementasikan pengunggahan file menggunakan rute API. Saya bisa mendapatkan file untuk diunggah tetapi kemudian harus dapat mengaksesnya lagi untuk mengunggahnya ke ember S3.

Saya kedua ini! Juga, dapat membaca direktori sangat penting untuk penggunaan perusahaan saya karena kami menyimpan data kami seperti anggota tim dan posting blog di direktori konten jadi kami mencari cara untuk meminta semua file di direktori.

PR di atas akan memperbaikinya! ️ 🙏

Bagaimana dengan fs.writeFile apakah itu mungkin? Misalnya, buat dan simpan file JSON berdasarkan webhook yang diposting di /api/route

Hai @marlonmarcello , ini akan menjadi mungkin. Tetap disini

Ini sudah terpecahkan?

Belum, Anda dapat berlangganan #8334

@huv1k Terima kasih banyak!

Apakah ada cara untuk membantu kemajuan ini lebih cepat?

Perlu diperhatikan: jika Anda menggunakan TypeScript, Anda sudah dapat mengimpor file JSON sebagai modul secara langsung (pastikan resolveJsonModule adalah true di tsconfig.json ). Misalnya:

import myJson from '../../../some/path/my.json';

Bentuk objek JSON juga otomatis digunakan sebagai tipenya, jadi pelengkapan otomatis sangat bagus.

Solusi yang saya gunakan:

# next.config.js
module.exports = {
    serverRuntimeConfig: {
        PROJECT_ROOT: __dirname
    }
}

dan di lokasi Anda membutuhkan jalan

import fs from 'fs'
import path from 'path'
import getConfig from 'next/config'
const { serverRuntimeConfig } = getConfig()

fs.readFile(path.join(serverRuntimeConfig.PROJECT_ROOT, './path/to/file.json'))

Saya tahu ini tidak menyelesaikan kebutuhan untuk mereferensikan file dengan jalur relatif ke file saat ini, tetapi ini menyelesaikan kasus penggunaan saya yang sangat terkait (membaca file gambar dari folder /public/images ).

Melihat di PR ini telah sedikit berubah - ada pembaruan tentang apa rencana saat ini (atau tidak)? Kedengarannya seperti ada beberapa strategi yang tidak ingin Anda lakukan, pertimbangkan untuk mencantumkannya + mengapa kontributor dapat mencobanya?

Ini memblokir penggunaan nexus dengan Next.js. Akan sangat bagus untuk melihat ini diprioritaskan lagi.

Solusi yang saya gunakan:

# next.config.js
module.exports = {
    serverRuntimeConfig: {
        PROJECT_ROOT: __dirname
    }
}

dan di lokasi Anda membutuhkan jalan

import fs from 'fs'
import path from 'path'
import getConfig from 'next/config'
const { serverRuntimeConfig } = getConfig()

fs.readFile(path.join(serverRuntimeConfig.PROJECT_ROOT, './path/to/file.json'))

Saya tahu ini tidak menyelesaikan kebutuhan untuk mereferensikan file dengan jalur relatif ke file saat ini, tetapi ini menyelesaikan kasus penggunaan saya yang sangat terkait (membaca file gambar dari folder /public/images ).

Pria Luar Biasa. Bekerja untuk saya.

Saya telah menggunakan metode getStaticProps untuk ini (di #9524). Metode saat ini ditandai sebagai tidak stabil tetapi tampaknya ada dukungan yang baik dari tim Next.js untuk mengirimkannya secara resmi.

misalnya:

export async function unstable_getStaticProps() {
  const siteData = await import("../data/pages/siteData.json");
  const home = await import("../data/pages/home.json");

  return {
    props: { siteData, home }
  };
}

@ ScottSmith95 Apakah Anda memiliki proyek sumber publik tempat Anda menggunakan ini? Penasaran seperti apa bentuknya.

Proyek ini bukan open source, tetapi saya senang untuk membagikan lebih banyak konfigurasi saya jika Anda memiliki lebih banyak pertanyaan.

@ScottSmith95 Saya punya _semua_ pertanyaan

  1. Di mana dalam proyek Anda, Anda menyimpan file data? (di luar/dalam src ?)
  2. Seperti apa komponen halaman next.js yang menggunakannya?
  3. Apakah hanya jalur hard-coded, atau dapatkah Anda memuat file berdasarkan parameter jalur?
  4. Bagaimana cara kerja build/deployment, terutama jika itu bukan jalur hard-code?

@Svish Kami menyimpan file data di /data dalam proyek kami. (Halaman ada di /pages, bukan /src/prages.) Komponen halaman ini terlihat seperti ini (props dikirim ke komponen Home yang merupakan ekspor default):

// /pages/index.js
const Home = ({ siteData, home }) => {
  return (
    <>
      <Head>
        <meta name="description" content={siteData.siteDescription} />
        <meta name="og:description" content={siteData.siteDescription} />
        <meta
          name="og:image"
          content={getAbsoluteUrl(siteData.siteImage, constants.siteMeta.url)}
        />
      </Head>
      <section className={`container--fluid ${styles.hero}`}>
        <SectionHeader section={home.hero} heading="1">
          <div className="col-xs-12">
            <PrimaryLink
              href={home.hero.action.path}
              className={styles.heroAction}
            >
              {home.hero.action.text}
            </PrimaryLink>
          </div>
        </SectionHeader>
        <div className={styles.imageGradientOverlay}>
          <img src={home.hero.image.src} alt={home.hero.image.alt} />
        </div>
      </section>
    </>
  );
};

Untuk halaman yang lebih maju, yang memiliki rute dinamis, kami mengambil data ini seperti:

// /pages/studio/[member.js]
export async function unstable_getStaticProps({ params }) {
  const siteData = await import("../../data/pages/siteData.json");
  const member = await import(`../../data/team/${params.member}.json`);

  return {
    props: { siteData, member }
  };
}

Deployment berjalan sangat lancar, dengan rute dinamis, getStaticPaths() menjadi perlu. Saya mendorong Anda untuk memeriksa RFC untuk dokumentasi tentang itu, tetapi inilah contoh bagaimana kami menanganinya dengan mengumpulkan semua data anggota tim kami dan meneruskannya ke Next.js.

// /pages/studio/[member.js]
export async function unstable_getStaticPaths() {
  const getSingleFileJson = async path => await import(`../../${path}`);

  // These utility functions come from `@asmallstudio/tinyutil` https://github.com/asmallstudio/tinyutil
  const directoryData = await getDirectory(
    "./data/team",
    ".json",
    getSingleFileJson,
    createSlugFromTitle
  );
  const directoryPaths = directoryData.reduce((pathsAccumulator, page) => {
    pathsAccumulator.push({
      params: {
        member: page.slug
      }
    });

    return pathsAccumulator;
  }, []);

  return directoryPaths;
}

@ScottSmith95 Terlihat menjanjikan! Beberapa pertanyaan lanjutan jika Anda punya waktu:

  1. Apa yang Anda lakukan di sini adalah untuk pembuatan situs statis? Yaitu ketika menggunakan next export ?
  2. Sudahkah saya memahaminya dengan benar, bahwa getStaticPaths mengembalikan daftar parameter jalur, yang kemudian (berikutnya) diumpankan, satu per satu, ke getStaticProps untuk setiap render?
  3. Bisakah Anda menggunakan getStaticProps tanpa getStaticPaths , misalnya untuk halaman tanpa parameter apa pun?
  4. Bisakah Anda menggunakan getStaticProps di _app ? Misalnya jika Anda memiliki beberapa konfigurasi situs yang ingin Anda muat atau sesuatu seperti itu?

Bagaimana dengan apinya?? Kait itu untuk halaman, tetapi bagaimana dengan apis?

Saya bingung. Saya dapat mengatur _dirname sebagai variabel env di konfigurasi berikutnya. Oleh karena itu saya dapat mengakses sistem file dari API, tetapi hanya berfungsi secara lokal. Setelah menyebarkannya ke sekarang, saya mendapat kesalahan. Adakah ide mengapa itu tidak berfungsi setelah penerapan?

@josias-r masalah utamanya biasanya bahwa file yang akan dibaca tidak termasuk penyebaran, tetapi itu tergantung pada bagaimana Anda memasukkannya dan jenis file apa ( js / json biasanya baik-baik saja, tetapi jenis file lain seperti .jade akan memerlukan cara alternatif untuk menanganinya, seperti menggunakan @now/node lambda/deployment terpisah untuk membaca/menangani file tersebut).

Jika Anda dapat menjelaskan lebih lanjut tentang kesalahan tersebut, mungkin seseorang dapat membantu Anda.

@BrunoBernardino Itu sebenarnya merujuk ke file JSON di dalam folder src saya. Tetapi sebenarnya bahkan metode fs.readdirSync(my_dirname_env_var) yang sudah gagal dalam penerapan. Jadi dir itu sepertinya tidak ada sama sekali setelah penyebaran. Inilah yang saya dapatkan ketika saya mencoba mengakses path lengkap ke json vis API saya:

ERROR   Error: ENOENT: no such file or directory, open '/zeit/3fc37db3/src/content/somejsonfilethatexists.json'

Dan seperti yang saya sebutkan, ini berfungsi secara lokal ketika saya membangun dan kemudian menjalankan npm start .

@josias-r Terima kasih! Sudahkah Anda mencoba melakukan fs.readdirSync dengan jalur relatif (tanpa variabel) sebagai gantinya (hanya untuk men-debug penerapan)? Saya telah menemukan bahwa biasanya berfungsi, dan jika demikian, Anda dapat menulis potongan kode itu (hanya membaca file, tidak menyimpannya di mana pun) di suatu tempat dalam proses inisialisasi ( getInitialProps atau sesuatu), sehingga proses penyebaran mengambil bahwa itu membutuhkan file itu, dan kemudian terus membacanya dengan var dalam kode/logika yang sebenarnya. Ini tidak rapi, tetapi berfungsi sampai ini didukung. Saya percaya bahwa menggunakan __dirname berfungsi dalam beberapa kasus.

@BrunoBernardino Saya dapat membangun pohon file mulai dari jalur relatif root ./ . Apa yang saya dapatkan adalah JSON berikut (tanpa modul simpul yang terdaftar):

{
  "path": "./",
  "name": ".",
  "type": "folder",
  "children": [
    {
      "path": ".//.next",
      "name": ".next",
      "type": "folder",
      "children": [
        {
          "path": ".//.next/serverless",
          "name": "serverless",
          "type": "folder",
          "children": [
            {
              "path": ".//.next/serverless/pages",
              "name": "pages",
              "type": "folder",
              "children": [
                {
                  "path": ".//.next/serverless/pages/api",
                  "name": "api",
                  "type": "folder",
                  "children": [
                    {
                      "path": ".//.next/serverless/pages/api/posts",
                      "name": "posts",
                      "type": "folder",
                      "children": [
                        {
                          "path": ".//.next/serverless/pages/api/posts/[...id].js",
                          "name": "[...id].js",
                          "type": "file"
                        }
                      ]
                    }
                  ]
                }
              ]
            }
          ]
        }
      ]
    },
    {
      "path": ".//node_modules",
      "name": "node_modules",
      "type": "folder",
      "children": ["alot of children here ofc"]
    },
    { "path": ".//now__bridge.js", "name": "now__bridge.js", "type": "file" },
    {
      "path": ".//now__launcher.js",
      "name": "now__launcher.js",
      "type": "file"
    }
  ]
}

File JSON Anda sepertinya hilang di sana, apakah Anda mencoba memasukkannya melalui kode seperti yang saya sarankan di atas? Masalah utama adalah bahwa pengoptimalan yang dijalankan penyebaran tidak selalu mengambil jalur dinamis, saya percaya, jadi memaksa jalur statis telah berhasil untuk saya di masa lalu (tidak harus untuk kode aktual yang berjalan, tetapi untuk memastikan file yang relevan sudah termasuk). Apakah itu masuk akal?

@BrunoBernardino Saya telah beralih ke solusi non API. Karena saya secara dinamis ingin meminta file dari folder dan saya hanya membutuhkan konten file-file ini, saya dapat menggunakan metode import() . Saya hanya tidak ingin melakukannya dengan cara ini, karena tampaknya hacky, tetapi pada dasarnya melakukan hal yang sama yang akan dilakukan titik akhir API saya.
... Saya mencoba memasukkan file ke dalam folder statis tetapi tidak berhasil juga. Tapi saya berharap mengakses sistem file akan memungkinkan di masa depan.

Saya juga harus menggunakan solusi peretasan, tetapi mudah-mudahan ini akan segera mendarat dan lebih banyak orang akan mulai melihat Next sebagai siap produksi karena kasus penggunaan ini didukung "seperti yang diharapkan".

Solusi yang saya gunakan:

# next.config.js
module.exports = {
    serverRuntimeConfig: {
        PROJECT_ROOT: __dirname
    }
}

dan di lokasi Anda membutuhkan jalan

import fs from 'fs'
import path from 'path'
import getConfig from 'next/config'
const { serverRuntimeConfig } = getConfig()

fs.readFile(path.join(serverRuntimeConfig.PROJECT_ROOT, './path/to/file.json'))

Saya tahu ini tidak menyelesaikan kebutuhan untuk mereferensikan file dengan jalur relatif ke file saat ini, tetapi ini menyelesaikan kasus penggunaan saya yang sangat terkait (membaca file gambar dari folder /public/images ).

Pria Luar Biasa. Bekerja untuk saya.

Ini berfungsi dengan baik pada pengembangan lokal, meskipun tampaknya tidak berfungsi saat digunakan ke now .

ENOENT: no such file or directory, open '/zeit/41c233e5/public/images/my-image.png'
    at Object.openSync (fs.js:440:3)
    at Object.readFileSync (fs.js:342:35)
    at getEmailImage (/var/task/.next/serverless/pages/api/contact/demo.js:123:52)
    at module.exports.7gUS.__webpack_exports__.default (/var/task/.next/serverless/pages/api/contact/demo.js:419:87)
    at processTicksAndRejections (internal/process/task_queues.js:93:5)
    at async apiResolver (/var/task/node_modules/next/dist/next-server/server/api-utils.js:42:9) {
  errno: -2,
  syscall: 'open',
  code: 'ENOENT',
  path: '/zeit/41c233e5/public/images/my-image.png'
}

Saya mengerti bahwa folder publik dipindahkan ke rute jadi saya mencoba memaksanya untuk mencari di folder dasar saat produksi tetapi masih mendapatkan hasil yang sama:

ENOENT: no such file or directory, open '/zeit/5fed13e9/images/my-image.png'
    at Object.openSync (fs.js:440:3)
    at Object.readFileSync (fs.js:342:35)
    at getEmailImage (/var/task/.next/serverless/pages/api/contact/demo.js:124:52)
    at module.exports.7gUS.__webpack_exports__.default (/var/task/.next/serverless/pages/api/contact/demo.js:331:87)
    at processTicksAndRejections (internal/process/task_queues.js:93:5)
    at async apiResolver (/var/task/node_modules/next/dist/next-server/server/api-utils.js:42:9) {
  errno: -2,
  syscall: 'open',
  code: 'ENOENT',
  path: '/zeit/5fed13e9/images/my-image.png'
}

@PaulPCIO masalah yang Anda alami adalah karena itu bukan file .json , .js , atau .ts . File di bawah /public "disebarkan" ke CDN tetapi tidak ke lambda (AFAIK), jadi untuk itu Anda memerlukan penyebaran lambda ( @now/node ) khusus dengan includeFiles , atau, jika Anda hanya membutuhkan satu file itu, ubah menjadi base64 dan gunakan itu sebagai var (dalam file khusus atau tidak).

Terima kasih @BrunoBernardino sudah berharap banyak, saya akan menggunakan metode base64

Ada beberapa resolusi untuk __dirname di lingkungan yang digunakan ??

@NicolasHz dapatkah Anda menguraikannya? Saya tidak begitu mengerti pertanyaan Anda.

@BrunoBernardino Melihat komentar terakhir, termasuk komentar saya, saya cukup yakin bahwa peretasan "map _dirname di konfigurasi berikutnya" tidak berfungsi dalam penerapan. Bahkan file w/ js dan JSON. Setidaknya untuk penerapan now , itu mungkin tidak dihitung untuk penerapan khusus.

@BrunoBernardino Saya tidak dapat menggunakan beberapa variabel yang mengarah ke jalur lokal di env yang digunakan. __dirname itu tidak terdefinisi setelah digunakan, dan saya tidak dapat membaca file dari skrip apis saya.

Mengerti @NicolasHz . Ya, Anda harus menggunakan salah satu solusi di atas, tergantung pada jenis file yang perlu Anda baca/akses.

Hanya mengonfirmasi, config.js tidak berfungsi pada penerapan.

Solusi yang saya gunakan:

# next.config.js
module.exports = {
  env: {
    PROJECT_DIRNAME: __dirname,
  },
}

dan dalam definisi api di mana saya memerlukan path (folder allPosts berisi semua blog dalam format penurunan harga dan terletak di root proyek)

import fs from 'fs'
import { join } from 'path'

const postsDirectory = join(process.env.PROJECT_DIRNAME, 'allPosts')

Ini bekerja dengan sempurna pada pembangunan lokal.
Tapi itu memberikan kesalahan ini saat menyebarkan ke zeit sekarang.

[POST] /api/postsApi
11:00:13:67
Status:
500
Duration:
8.1ms
Memory Used:
76 MB
ID:
kxq8t-1585546213659-5c3393750f30
User Agent:
axios/0.19.2
{
  fields: [ 'title', 'date', 'slug', 'author', 'coverImage', 'excerpt' ],
  page: 1
}
2020-03-30T05:30:13.688Z    572075eb-4a7a-47de-be16-072a9f7005f7    ERROR   Error: ENOENT: no such file or directory, scandir '/zeit/1cc63678/allPosts'
    at Object.readdirSync (fs.js:871:3)
    at getPostSlugs (/var/task/.next/serverless/pages/api/postsApi.js:306:52)
    at module.exports.fZHd.__webpack_exports__.default (/var/task/.next/serverless/pages/api/postsApi.js:253:86)
    at apiResolver (/var/task/node_modules/next/dist/next-server/server/api-utils.js:48:15)
    at processTicksAndRejections (internal/process/task_queues.js:97:5) {
  errno: -2,
  syscall: 'scandir',
  code: 'ENOENT',
  path: '/zeit/1cc63678/allPosts'
}

@sjcodebook seperti yang dikatakan @BrunoQuaresma , solusi itu hanya berfungsi secara lokal. Saya masih menggunakan penyebaran @now/node untuk lambdas untuk mengakses sistem file, dan memanggil file itu melalui permintaan dari aplikasi itu sendiri (atau menghasilkan hasil statis apa pun yang saya perlukan sebelum menerapkan). Agak gila, tapi berhasil.

Hai @BrunoBernardino... Apakah maksud Anda proyek terpisah dengan server simpul khusus?

Namun saya tidak mengerti mengapa ada pengaturan " includeFiles " jika tidak mungkin untuk mengaksesnya

@valse bisa di proyek yang sama. Berikut cuplikan dari now.json :

{
  "builds": [
    {
      "src": "next.config.js",
      "use": "@now/next"
    },
    {
      "src": "lambdas/**/*.ts",
      "use": "@now/node",
      "config": {
        "includeFiles": ["email-templates/**"]
      }
    }
  ],
  "routes": [
    {
      "src": "/lambdas/(.+)",
      "dest": "/lambdas/$1.ts"
    }
  ]
}

Dengan begitu saya dapat memanggil mereka melalui sesuatu seperti:

await ky.post(`${hostUrl}/lambdas/email?token=${someToken}`);

dari dalam halaman api berikutnya, dengan asumsi saya memiliki file lambdas/email.ts yang menangani pengiriman email dan membaca dari file template seperti pug .

Saya harap itu membantu!

Juga, "includeFiles" hanya berfungsi untuk @now/node (mungkin yang lain, tetapi tidak @now/next )

@BrunoBernardino sepertinya jika menggunakan fungsi node , sekarang tidak dapat membaca ESM!

inilah yang terjadi ketika saya mencoba mengimpor daftar halaman mdx:

kode

import { NextApiRequest, NextApiResponse } from 'next'
import { promises as fs } from 'fs'
import { join } from 'path'
const { readdir } = fs

export default async (req: NextApiRequest, res: NextApiResponse) => {
  const postFiles = await readdir(join(process.cwd(), 'pages', 'blog'))

  const postNames: string[] = postFiles.filter((page: string) => page !== 'index.tsx')

  const posts = []

  for (const post of postNames) {
    const mod = await import(`../pages/blog/${post}`)

    posts.push({ ...mod, link: post.slice(0, post.indexOf('.')) })
  }

  res.status(200).json([])
}

kesalahan yang saya dapatkan:

export const title = 'My new website!'
^^^^^^

SyntaxError: Unexpected token 'export'

@talentlessguy Saya tidak berada di tim Zeit/Vercel, hanya pelanggan yang senang. Sepertinya itu mungkin lebih cocok untuk dukungan pelanggan mereka, karena saya melihat beberapa potensi masalah hanya dari cuplikan itu:

  1. Anda mungkin ingin menggunakan apa-apa atau __dirname alih-alih process.cwd() untuk jalur dasar. Saya belum pernah menggunakan yang terakhir di lambdas, tetapi yang lain, jadi saya tidak yakin apakah itu masalah atau tidak
  2. Anda mengimpor NextApiRequest dan NextApiResponse sebagai tipe, tetapi ini harus dijalankan dari @now/node" , bukan? Jadi jenisnya harus diimpor seperti:
import { NowRequest, NowResponse } from '@now/node';
  1. Anda mengimpor/membaca dari pages/... tetapi apakah Anda menyertakannya melalui includeFiles ? Seperti apa tampilan now.json ?

@BrunoBernardino

Saya tidak dapat menggunakan __dirname karena selalu / , process.cwd() sebagai gantinya, menunjukkan jalur yang sebenarnya

Saya menerima perbaikan Anda dan berhasil:

lambdas/posts.ts

import { NowResponse, NowRequest } from '@now/node'
import { promises as fs } from 'fs'
import { join } from 'path'
const { readdir } = fs

export default async (req: NowRequest, res: NowResponse) => {
  const postFiles = await readdir(join(process.cwd(), 'pages', 'blog'))

  const postNames: string[] = postFiles.filter((page: string) => page !== 'index.tsx')

  const posts = []

  for (const post of postNames) {
    const mod = await import(`../pages/blog/${post}`)

    posts.push({ ...mod, link: post.slice(0, post.indexOf('.')) })
  }

  res.status(200).json([])
}

sekarang.json

{
  "builds": [
    {
      "src": "next.config.js",
      "use": "@now/next"
    },
    {
      "src": "lambdas/**/*.ts",
      "use": "@now/node",
      "config": {
        "includeFiles": ["pages/blog/*.mdx"]
      }
    }
  ],
  "routes": [
    {
      "src": "/lambdas/(.+)",
      "dest": "/lambdas/$1.ts"
    }
  ]
}

kesalahan yang saya dapatkan:

import Meta from '../../components/Article/Meta.tsx'
^^^^^^

SyntaxError: Cannot use import statement outside a module

Sepertinya fungsi simpul TypeScript tidak dapat memperlakukan .mdx sebagai modul :(

Baiklah, jadi sepertinya Anda menemukan masalahnya. Coba baca konten file dan parsing alih-alih mengimpor secara langsung. Saya belum pernah melihat impor seperti itu berfungsi, dan sepertinya sesuatu yang hanya akan berfungsi dengan sihir Babel, yang juga dapat Anda gunakan sebagai ganti TS biasa.

@BrunoBernardino Anda benar, tapi itu tidak biasa ... Saya memiliki target yang ditetapkan ke esnext dan modul ke esnext juga, itu harus dapat mengimpor semuanya ... tapi entah bagaimana tidak

lagian itu tidak terkait dengan masalah, akan google di suatu tempat

Jangan khawatir. Beberapa tips mungkin ada di https://mdxjs.com/advanced/typescript dan https://mdxjs.com/getting-started/webpack yang mungkin membuatnya jadi penyebaran @now/node perlu disesuaikan Gunakan. Bagaimanapun, dukungan mereka harus membantu.

ada gerakan ini? Akan sangat bagus jika dapat menyertakan template email html untuk digunakan di Rute API. Saat ini saya memasukkannya ke dalam file JS tetapi saya bukan penggemar khusus peretasan ini.

Peretasan lain adalah menggunakan webpack raw-loader untuk menyematkannya ke js.

yarn add --dev raw-loader
const templates = {
    verify: require("raw-loader!../template/email/verify.hbs").default,
};

Kemudian gunakan templates.verify sebagai string.

Ada masalah yang terjadi dengan next-i18next yang tampaknya terkait dengan yang ini ( vercel/vercel#4271 ) . Pada dasarnya now tidak menempatkan file .json terletak di dalam /public/static/locales/ ke dalam fungsi tanpa server. Adakah yang bisa memberikan solusi sampai fitur yang dibahas di sini ditambahkan ke berikutnya?

@borispoehland sudahkah Anda mencoba impor/memerlukan solusi dari atas? Itu harus bekerja.

@borispoehland sudahkah Anda mencoba impor/memerlukan solusi dari atas? Itu harus bekerja.

@BrunoBernardino Saya tidak tahu persis komentar apa yang Anda maksud.

Bisakah Anda memberi saya contoh cara mengimpor semua file .json di dalam public/static/locales ke dalam fungsi tanpa server? Dan di mana melakukan ini (dalam file apa)?

Saya menggunakan next (seperti yang Anda nyatakan sebelumnya, includeFiles tidak kompatibel dengan @now/next , idk apakah ini berdampak pada masalah saya).

Selain itu, karena next-i18next adalah semacam kotak hitam bagi saya (jadi saya tidak ingin mengimpor file dari sana), saya mencari cara untuk sepenuhnya mengimpornya sehingga next-i18next dapat langsung mengaksesnya (dalam komentar lain di atas, terkadang hanya PROJECT_DIRNAME yang didefinisikan di dalam next.config.json dan impor harus dilakukan secara manual. Ini bukan yang saya coba jangkau). Seperti di vercel/vercel#4271 , saya hanya ingin now mengambil file .json ke fungsi tanpa server.

@borispoehland dalam file _any_ di dalam pages/api (atau yang dipanggil oleh salah satu di sana), lakukan sesuatu seperti https://github.com/vercel/next.js/issues/8251#issuecomment -544008976

Anda tidak perlu melakukan apa pun dengan impor. Intinya adalah bahwa webpack vercel berjalan kemudian akan melihat file-file itu perlu dimasukkan, dan itu akan berfungsi.

Saya harap itu masuk akal.

@borispoehland di _any_ file di dalam pages/api (atau yang dipanggil oleh salah satu di sana), lakukan sesuatu seperti #8251 (komentar)

Anda tidak perlu melakukan apa pun dengan impor. Intinya adalah bahwa webpack vercel berjalan kemudian akan melihat file-file itu perlu dimasukkan, dan itu akan berfungsi.

Saya harap itu masuk akal.

@BrunoBernardino masalah dengan pendekatan ini adalah saya memiliki banyak file json. Melakukan impor secara manual untuk setiap file agak rumit. Apakah ada cara yang lebih mudah untuk memberitahu now : "Hei, tolong ambil semua file json di dalam direktori itu secara rekursif"? Terima kasih sebelumnya

Sunting: Bahkan mengimpor file json secara manual menghasilkan kesalahan yang sama dari sebelumnya. Saya akan membuka masalah baru untuk ini, saya kira

Saya membuka masalah baru untuk masalah saya , jika seseorang tertarik untuk bergabung dalam diskusi. Terima kasih untuk saat ini, @BrunoBernardino !

Opsi/solusi lain untuk mengaktifkan kemampuan menggunakan __dirname seperti yang biasanya Anda harapkan untuk berperilaku adalah dengan menyesuaikan konfigurasi webpack.

Secara default, webpack akan membuat alias berbagai global Node dengan polyfill kecuali Anda melarangnya:
https://webpack.js.org/configuration/node/
Dan pengaturan default webpack adalah membiarkan __dirname dan __filename saja, yaitu tidak melakukan polyfill dan membiarkan node menanganinya seperti biasa.

Namun, konfigurasi webpack Next.js tidak menggunakan/mencerminkan default webpack https://github.com/vercel/next.js/blob/bb6ae2648ddfb65a810edf6ff90a86201d52320c/packages/next/build/webpack-config.ts#L661 -L663

Semua itu dikatakan, saya telah menggunakan plugin konfigurasi Berikutnya kustom di bawah ini untuk menyesuaikan konfigurasi webpack.

PENTING: ini berfungsi untuk kasus penggunaan saya. Ini belum diuji di berbagai lingkungan/konfigurasi dan juga belum diuji terhadap semua pengujian unit/integrasi Next.js. Menggunakannya mungkin memiliki efek samping yang tidak diinginkan di lingkungan Anda.
Selain itu, Next mungkin memiliki alasan khusus untuk tidak menggunakan pengaturan default webpack untuk __dirname dan __filename . Jadi sekali lagi, kode di bawah ini mungkin memiliki efek samping yang tidak diinginkan dan harus digunakan dengan hati-hati.

Juga, plugin di bawah ini telah dirancang untuk digunakan dengan paket next-compose-plugins : https://github.com/cyrilwanner/next-compose-plugins

Tetapi harus berfungsi sebagai plugin normal juga: https://nextjs.org/docs/api-reference/next.config.js/custom-webpack-config

const withCustomWebpack = (nextCfg) => {
  return Object.assign({}, nextCfg, {
    webpack(webpackConfig, options) {
      // We only want to change the `server` webpack config.
      if (options.isServer) {
        // set `__dirname: false` and/or `__filename: false` here to align with webpack defaults:
        // https://webpack.js.org/configuration/node/
        Object.assign(webpackConfig.node, { __dirname: false });
      }

      if (typeof nextCfg.webpack === 'function') {
        return nextCfg.webpack(webpackConfig, options);
      }

      return webpackConfig;
    },
  });
};

Saya mengimplementasikan solusi oleh @jkjustjoshing , dan meskipun berfungsi dengan baik secara lokal, itu tidak berfungsi ketika saya menyebarkan aplikasi ke Vercel.

Saya mendapatkan kesalahan berikut:

Error: GraphQL error: ENOENT: no such file or directory, open '/vercel/37166432/public/ts-data.csv'

Kode saya:

const content = await fs.readFile(
  path.join(serverRuntimeConfig.PROJECT_ROOT, "./public/ts-data.csv")
);

Berikut tautan ke file: https://github.com/bengrunfeld/trend-viewer/blob/master/pages/api/graphql-data.js

@bengrunfeld ya, solusi Anda hanya berfungsi secara lokal.

Saya memiliki masalah yang sama akhir-akhir ini (ingin membaca file dalam rute API) dan solusinya lebih mudah dari yang diharapkan.

Coba path.resolve('./public/ts-data.csv')

@borispoehland Terima kasih banyak!! Solusi Anda bekerja dengan indah!

@bengrunfeld tidak masalah, saya juga menemukannya secara kebetulan ( @BrunoBernardino ;)). Ini adalah solusi untuk masalah semua orang di sini, saya kira.

Harap dicatat, Anda masih perlu mengatur next.config.js . Saya menghapus file setelah saya melihat bahwa solusi @borispoehland berfungsi, dan menerima kesalahan serupa.

Kemudian saya meresetnya ke solusi @jkjustjoshing di atas, dikerahkan lagi ke Vercel, dan berhasil.

# next.config.js
module.exports = {
    serverRuntimeConfig: {
        PROJECT_ROOT: __dirname
    }
}

Harap dicatat, Anda masih perlu mengatur next.config.js . Saya menghapusnya setelah saya melihat bahwa solusi @borispoehland berfungsi, dan menerima kesalahan serupa.

Saya mengatur ulang ke solusi @jkjustjoshing di atas, dikerahkan lagi ke Vercel, dan berhasil.

# next.config.js
module.exports = {
    serverRuntimeConfig: {
        PROJECT_ROOT: __dirname
    }
}

@bengrunfeld Benarkah? Mungkin Anda masih menggunakan pendekatan PROJECT_ROOT pada titik lain dalam kode, karena dalam proyek saya ini berfungsi tanpa itu. Bagaimana tampilan kesalahannya?

Saat menerapkan ke Vercel, bagaimana cara menulis readFile di Halaman yang akan berfungsi baik dalam mode SSG dan SSR/Pratinjau?

Repositori demo yang tidak berfungsi: https://github.com/mathdroid/blog-fs-demo

https://blog-fs-demo.vercel.app/

@mathdroid coba pindahkan readFile dan readdir di dalam fungsi getStaticProps dan getStaticPaths , jika tidak kode mungkin berjalan di browser.

Mengimpor fs seharusnya tidak masalah.

Beri tahu kami cara kerjanya.

@borispoehland Terima kasih atas solusi yang luar biasa. Tidak menyangka path.resolve() hingga /public akan berfungsi baik secara lokal maupun di Vercel :eyes:! Anda adalah penyelamat saya untuk hari ini. :+1:

@borispoehland saya mencoba solusi Anda di dalam fungsi tanpa servertetapi masih mendapatkan:
ENOENT: tidak ada file atau direktori seperti itu, buka '/var/task/public/posts.json'

const postsFile = resolve('./public/posts.json');

const updateCache = async (posts: IPost[]): Promise<IPost[]> => {
    postCache = posts;
    fs.writeFileSync(postsFile, JSON.stringify(postCache)); // <====
    return postCache;
}

saya mencoba dengan kami tanpa next.config.js

module.exports = {
    serverRuntimeConfig: {
        PROJECT_ROOT: __dirname
    }
}

Mungkin solusi Anda tidak berfungsi pada fungsi tanpa server?

@borispoehland saya mencoba solusi Anda di dalam fungsi tanpa servertetapi masih mendapatkan:
ENOENT: tidak ada file atau direktori seperti itu, buka '/var/task/public/posts.json'

const postsFile = resolve('./public/posts.json');

const updateCache = async (posts: IPost[]): Promise<IPost[]> => {
    postCache = posts;
    fs.writeFileSync(postsFile, JSON.stringify(postCache)); // <====
    return postCache;
}

saya mencoba dengan kami tanpa next.config.js

module.exports = {
    serverRuntimeConfig: {
        PROJECT_ROOT: __dirname
    }
}

Mungkin solusi Anda tidak berfungsi pada fungsi tanpa server?

Saya tidak tahu mengapa itu tidak berhasil di pihak Anda ... Maaf

Ok saya membuatnya berfungsi untuk dibaca menggunakan kode @bengrunfeld tetapi sayangnya Anda tidak dapat menulis:
[Kesalahan: EROFS: sistem file read-only, buka '/var/task/public/posts.json']
Jadi tidak ada cara untuk memperbarui cache untuk menghindari terlalu banyak panggilan database :(

@neckaros sudahkah Anda mencoba menggunakan pendekatan saya untuk membaca file selain .json , misalnya file .jpg ?

Ok saya membuatnya berfungsi untuk dibaca menggunakan kode @bengrunfeld tetapi sayangnya Anda tidak dapat menulis:

[Kesalahan: EROFS: sistem file read-only, buka '/var/task/public/posts.json']

Jadi tidak ada cara untuk memperbarui cache untuk menghindari terlalu banyak panggilan database :(

@neckaros Anda harus dapat menulis dan membaca dari S3 (atau sistem file eksternal lainnya), tetapi saya biasanya menggunakan redis untuk hal-hal yang cepat dan di-cache yang dapat berubah-ubah. https://redislabs.com menyimpannya "tanpa server", dan saya punya contoh kode siap produksi di https://nextjs-boilerplates.brn.sh jika Anda mau.

@borispoehland saya bisa membaca tetapi tidak menulis dari fungsi tanpa server. Tetapi saya akhirnya membuatnya berfungsi dengan menyegarkan cache saya di build tambahan (validasi ulang) alih-alih menambahkan konten baru. Yang saya kira bukan pola yang buruk. Terima kasih atas bantuan Anda!

@BrunoBernardino terima kasih saya akan melihatnya. Benar-benar mencari solusi penghobi gratis yang tidak rusak setelah Anda memiliki beberapa pengguna :)

Benar-benar mencari solusi penghobi gratis yang tidak rusak setelah Anda memiliki beberapa pengguna :)

Dimengerti. RedisLabs dan Vercel melakukannya untuk saya. 💯

Setelah beberapa penggalian, saya berhasil menulis file dengan paket os yang diperluas ...

import { tmpdir } from "os";
const doc = new PDFDocument()
const pdfPath = path.join(tmpdir(), `${store.id}${moment().format('YYYYMMDD')}.pdf`)
const writeStream = doc.pipe(fs.createWriteStream(pdfPath)

membaca file berfungsi dengan solusi @subwaymatch
const logoPath = path.resolve('./public/logo.png')

Setelah beberapa penggalian, saya berhasil menulis file dengan paket os yang diperluas ...

import { tmpdir } from "os";
const doc = new PDFDocument()
const pdfPath = path.join(tmpdir(), `${store.id}${moment().format('YYYYMMDD')}.pdf`)
const writeStream = doc.pipe(fs.createWriteStream(pdfPath)

membaca file berfungsi dengan solusi @subwaymatch
const logoPath = path.resolve('./public/logo.png')

Bagus, apakah Anda dapat membaca kembali isi file ini? Apakah direktori dapat diakses dan permanen?

@marklundin Dengan fungsi bernama tmpdir Saya ragu itu permanen, tetapi jika ini berhasil, maka akan lebih baik untuk mengetahui seberapa sementara sebenarnya tmpdir itu, ya...

Ada pembaruan tentang ini? Saya bertanya-tanya mengapa ini berfungsi di getInitialProps, tetapi tidak di rute API ️

Solusi saya saat ini

const data = await import(`../../../../data/de/my-nice-file.json`);
res.json(data.default);

saat ini mengalami masalah ini di rute API juga

saat ini mengalami masalah ini di rute API juga

Ada beberapa solusi yang berfungsi di sini, masalah apa yang Anda alami, khususnya?

Saya berjuang untuk membuatnya berfungsi bahkan dengan saran dari utas ini. Kasus penggunaan saya adalah saya sedang menulis panduan dan ingin menunjukkan kode sumber untuk komponen di samping komponen itu sendiri. Metode saya untuk melakukan ini adalah menggunakan fs untuk memuat file jsx komponen di dalam getServerSideProps dan meneruskan nilai string dari konten file sebagai prop.

Saya merasa senang karena membuatnya bekerja secara lokal, tetapi kemudian ketika saya menggunakannya, kegembiraannya telah hilang :(

Silakan lihat: https://github.com/ElGoorf/i18next-guide/blob/fix-example-components/pages/plurals.jsx

@ElGoorf masalah Anda adalah bahwa file public ada di tepi, dan fungsinya ada di lambda. Sekarang, @vercel/next masih tidak mengizinkan includeFiles , jadi cara termudah bagi Anda untuk membuatnya berfungsi adalah dengan menggunakan fungsi lambda dengannya.

Berikut beberapa contoh kode yang membantu orang lain di sini: https://github.com/vercel/next.js/issues/8251#issuecomment -614220305

Terima kasih @BrunoBernardino Saya tidak menyadari bahwa saya melewatkan "x item tersembunyi memuat lebih banyak ..." dan berpikir saya menjadi gila karena utas kehilangan makna!

Sayangnya, saya kesulitan dengan solusi Anda, karena ini adalah pertama kalinya saya mendengar tentang Edge/Lambda, namun, saya menemukan solusi @balthild lebih dekat dengan apa yang saya cari sebelumnya sebelum mencoba metode node.fs: https:/ /github.com/vercel/next.js/issues/8251#issuecomment -634829189

Besar! Apakah Anda membuatnya bekerja? Atau apakah Anda masih memiliki masalah?

Saya tidak yakin Vercel bahkan menggunakan terminologi itu, tetapi dengan Edge maksud saya CDN, dari mana file statis disajikan, dan dengan lambda maksud saya fungsi "backend" yang dipanggil dari rute API, yang diisolasi seperti fungsi AWS Lambda .

Hai,

Adakah pembaruan tentang penulisan ke file menggunakan next.js di vercel? Saya bisa membaca tidak ada masalah. Menggunakan const logoPath = path.resolve('./public/logo.png')

Saya mencoba untuk menimpa file public/sitemap.xml (karena batas ukuran pada vercel) saya hanya dapat mengembalikannya tanpa kesalahan sebagai file statis di folder publik. Saya sebelumnya telah menerapkan peta situs dengan zlib dan mengalirkan respons tetapi tampaknya menunggu hingga aliran selesai dan kemudian mengembalikannya. Ini tidak mengenai kesalahan batasan ukuran, tetapi sayangnya sangat lambat. Saya terbuka untuk saran yang mungkin dimiliki orang. Peta situs dibuat dari panggilan API ke backend terpisah dan perlu diperbarui secara berkala.

Hal-hal yang saya coba:

  • Zipping dan streaming xml - berfungsi tetapi sangat lambat.
  • Membangun dan mengembalikan peta situs dari fungsi api, sayangnya ini mencapai batas ukuran.
  • Membaca file xml statis dari folder publik (berfungsi) terlepas dari ukurannya, tetapi tidak dapat diperbarui.
  • Tes menulis ke file ini, tidak berhasil. Tes menulis ke file/folder apa pun tidak berfungsi
  • Uji pengembalian file xml statis dari fungsi "api", kesalahan ukuran. Ini bekerja secara lokal.
  • Uji pengembalian file xml statis dari kesalahan ukuran getServerSideProp "halaman". Ini bekerja secara lokal.
  • Akan menghargai ide sama sekali?

Hei @emomooney , saya tidak membayangkan Vercel pernah mengizinkan untuk menulis file dalam suatu fungsi (bahkan untuk caching), karena "keuntungan" utama dari tanpa server adalah statusnya, dan itu akan menambah statusnya, jadi saya pikir Anda akan melakukannya perlu menggunakan Edge/cdn untuk itu.

Saya sebelumnya telah menerapkan peta situs dengan zlib dan mengalirkan respons tetapi tampaknya menunggu hingga aliran selesai dan kemudian mengembalikannya.

Saya ingin tahu apakah Anda hanya mengalami kelambatan ini untuk panggilan berikutnya, atau hanya yang pertama, untuk awal yang dingin? Saya membayangkan ini adalah panggilan API ke Vercel melalui fungsi api next.js, atau lambda khusus, mirip dengan yang saya lakukan di sini .

Jika ya dan masih terlalu lambat, apakah "backend terpisah" Anda di luar Vercel? Jika demikian, Anda berpotensi dapat menggunakannya untuk membuat file sitemap.xml dan vercel --prod menjadi domain, pada dasarnya "caching" file agar dapat dibaca dan diakses, dan Anda hanya perlu memperbarui robots.txt untuk menautkan peta situs ke domain/subdomain lain.

Apakah halaman ini membantu?
0 / 5 - 0 peringkat