Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

perf: conditionally import Telemetry #63574

Merged
merged 4 commits into from
Mar 25, 2024

Conversation

grajen3
Copy link
Contributor

@grajen3 grajen3 commented Mar 21, 2024

What?

Make Telemetry import in packages/next/src/server/lib/router-server.ts lazy and conditional

Why?

Telemetry in that module is only used when opts.dev is truthy, so in production mode the module is imported and used.

Cost of importing that module is quite significant chunk of starting standalone server. Those are example logs I got from https://www.npmjs.com/package/require-times (with updates to make it work as that is pretty old package that wasn't updated and doesn't work as is) on the server:

Before the change:

total: 658ms
646ms node_modules/next/dist/server/lib/start-server.js
  479ms node_modules/next/dist/server/lib/router-server.js
    149ms node_modules/next/dist/telemetry/storage.js
      87ms node_modules/next/dist/compiled/@edge-runtime/ponyfill/index.js
        86ms node_modules/next/dist/compiled/@edge-runtime/primitives/index.js
          1ms node_modules/next/dist/compiled/@edge-runtime/primitives/load.js
            23ms node_modules/next/dist/compiled/@edge-runtime/primitives/fetch.js.text.js
            12ms node_modules/next/dist/compiled/@edge-runtime/primitives/url.js.text.js
            1ms node_modules/next/dist/compiled/@edge-runtime/primitives/events.js.text.js
            1ms node_modules/next/dist/compiled/@edge-runtime/primitives/structured-clone.js.text.js
      41ms node_modules/next/dist/compiled/conf/index.js
        12ms node_modules/next/dist/compiled/semver/index.js
      12ms node_modules/next/dist/telemetry/project-id.js
      3ms node_modules/next/dist/telemetry/post-payload.js
      1ms node_modules/next/dist/compiled/is-docker/index.js
      1ms node_modules/next/dist/telemetry/anonymous-meta.js
        1ms node_modules/next/dist/compiled/is-wsl/index.js
    100ms node_modules/next/dist/server/base-server.js
      17ms node_modules/next/dist/server/future/route-matcher-providers/app-page-route-matcher-provider.js
        7ms node_modules/next/dist/lib/is-app-page-route.js
        7ms node_modules/next/dist/server/future/normalizers/built/app/index.js
          3ms node_modules/next/dist/server/future/normalizers/built/app/app-page-normalizer.js
            2ms node_modules/next/dist/server/future/normalizers/absolute-filename-normalizer.js
              1ms node_modules/next/dist/shared/lib/page-path/absolute-path-to-page.js
            1ms node_modules/next/dist/lib/page-types.js
          2ms node_modules/next/dist/server/future/normalizers/built/app/app-bundle-path-normalizer.js
            1ms node_modules/next/dist/shared/lib/page-path/normalize-page-path.js
          1ms node_modules/next/dist/server/future/normalizers/built/app/app-filename-normalizer.js
          1ms node_modules/next/dist/server/future/normalizers/built/app/app-pathname-normalizer.js
        1ms node_modules/next/dist/server/future/route-matcher-providers/manifest-route-matcher-provider.js
      15ms node_modules/next/dist/server/app-render/strip-flight-headers.js
      13ms node_modules/next/dist/server/future/route-modules/helpers/response-handlers.js
        13ms node_modules/next/dist/server/web/spec-extension/adapters/request-cookies.js
      8ms node_modules/next/dist/server/future/normalizers/locale-route-normalizer.js
      4ms node_modules/next/dist/server/api-utils/index.js
        2ms node_modules/next/dist/server/web/spec-extension/adapters/headers.js
          1ms node_modules/next/dist/server/web/spec-extension/adapters/reflect.js
      4ms node_modules/next/dist/server/render-result.js
        3ms node_modules/next/dist/server/stream-utils/node-web-streams-helper.js
          1ms node_modules/next/dist/lib/scheduler.js
      4ms node_modules/next/dist/server/future/route-matcher-providers/pages-api-route-matcher-provider.js
        3ms node_modules/next/dist/server/future/normalizers/built/pages/index.js
          1ms node_modules/next/dist/server/future/normalizers/built/pages/pages-filename-normalizer.js
          1ms node_modules/next/dist/server/future/normalizers/built/pages/pages-pathname-normalizer.js
        1ms node_modules/next/dist/lib/is-api-route.js
      2ms node_modules/next/dist/server/future/route-matcher-managers/default-route-matcher-manager.js
        1ms node_modules/next/dist/server/future/route-matchers/locale-route-matcher.js
      2ms node_modules/next/dist/server/future/route-matcher-providers/app-route-route-matcher-provider.js
      2ms node_modules/next/dist/server/lib/match-next-data-pathname.js
      2ms node_modules/next/dist/server/future/route-modules/checks.js
      1ms node_modules/next/dist/lib/is-edge-runtime.js
      1ms node_modules/next/dist/shared/lib/runtime-config.external.js
      1ms node_modules/next/dist/server/lib/revalidate.js
      1ms node_modules/next/dist/shared/lib/router/utils/escape-path-delimiters.js
      1ms node_modules/next/dist/server/future/route-matcher-providers/pages-route-matcher-provider.js
        1ms node_modules/next/dist/server/future/route-matchers/pages-route-matcher.js
      1ms node_modules/next/dist/server/send-response.js
      1ms node_modules/next/dist/shared/lib/router/utils/get-route-from-asset-path.js
      1ms node_modules/next/dist/server/lib/server-action-request-meta.js
    83ms node_modules/next/dist/server/lib/router-utils/filesystem.js
      22ms node_modules/next/dist/lib/load-custom-routes.js
        4ms node_modules/next/dist/lib/try-to-parse-path.js
          2ms node_modules/next/dist/lib/is-error.js
            1ms node_modules/next/dist/shared/lib/is-plain-object.js
          1ms node_modules/next/dist/compiled/path-to-regexp/index.js
        2ms node_modules/next/dist/lib/redirect-status.js
          1ms node_modules/next/dist/client/components/redirect-status-code.js
        1ms node_modules/next/dist/shared/lib/escape-regexp.js
      16ms node_modules/next/dist/server/future/normalizers/request/rsc.js
      13ms node_modules/next/dist/shared/lib/router/utils/index.js
        10ms node_modules/next/dist/shared/lib/router/utils/is-dynamic.js
          3ms node_modules/next/dist/server/future/helpers/interception-routes.js
            1ms node_modules/next/dist/shared/lib/router/utils/app-paths.js
              1ms node_modules/next/dist/shared/lib/page-path/ensure-leading-slash.js
        1ms node_modules/next/dist/shared/lib/router/utils/sorted-routes.js
      9ms node_modules/next/dist/shared/lib/page-path/normalize-path-sep.js
      4ms node_modules/next/dist/shared/lib/router/utils/middleware-route-matcher.js
        4ms node_modules/next/dist/shared/lib/router/utils/prepare-destination.js
          1ms node_modules/next/dist/client/components/app-router-headers.js
          1ms node_modules/next/dist/server/api-utils/get-cookie-parser.js
      4ms node_modules/next/dist/lib/metadata/get-metadata-route.js
        2ms node_modules/next/dist/server/server-utils.js
        1ms node_modules/next/dist/lib/metadata/is-metadata-route.js
      1ms node_modules/next/dist/compiled/lru-cache/index.js
      1ms node_modules/next/dist/lib/file-exists.js
      1ms node_modules/next/dist/lib/recursive-readdir.js
      1ms node_modules/next/dist/shared/lib/router/utils/path-match.js
      1ms node_modules/next/dist/shared/lib/router/utils/route-regex.js
      1ms node_modules/next/dist/shared/lib/router/utils/route-matcher.js
      1ms node_modules/next/dist/server/future/normalizers/request/postponed.js
        1ms node_modules/next/dist/shared/lib/page-path/denormalize-page-path.js
      1ms node_modules/next/dist/server/future/normalizers/request/prefetch-rsc.js
    35ms node_modules/next/dist/server/lib/router-utils/resolve-routes.js
      11ms node_modules/next/dist/server/body-streams.js
      1ms node_modules/next/dist/server/lib/server-ipc/utils.js
      1ms node_modules/next/dist/shared/lib/router/utils/relativize-url.js
      1ms node_modules/next/dist/server/future/normalizers/request/next-data.js
      1ms node_modules/next/dist/server/lib/mock-request.js
    22ms node_modules/next/dist/server/serve-static.js
      20ms node_modules/next/dist/compiled/send/index.js
        1ms node_modules/next/dist/compiled/fresh/index.js
    22ms node_modules/next/dist/server/pipe-readable.js
      20ms node_modules/next/dist/server/web/spec-extension/adapters/next-request.js
        18ms node_modules/next/dist/server/web/spec-extension/request.js
          15ms node_modules/next/dist/server/web/next-url.js
            12ms node_modules/next/dist/shared/lib/router/utils/format-next-pathname-info.js
              1ms node_modules/next/dist/shared/lib/router/utils/add-path-prefix.js
            1ms node_modules/next/dist/shared/lib/i18n/detect-domain-locale.js
          2ms node_modules/next/dist/server/web/spec-extension/cookies.js
            1ms node_modules/next/dist/compiled/@edge-runtime/cookies/index.js
      1ms node_modules/next/dist/lib/detached-promise.js
    19ms node_modules/next/dist/compiled/compression/index.js
    16ms node_modules/next/dist/server/lib/dev-bundler-service.js
    4ms node_modules/next/dist/trace/index.js
      3ms node_modules/next/dist/trace/trace.js
        2ms node_modules/next/dist/trace/report/index.js
          1ms node_modules/next/dist/trace/report/to-telemetry.js
          1ms node_modules/next/dist/trace/report/to-json.js
    2ms node_modules/next/dist/server/lib/router-utils/proxy-request.js
      1ms node_modules/next/dist/server/server-route-utils.js
    1ms node_modules/next/dist/server/node-environment.js
    1ms node_modules/next/dist/shared/lib/utils.js
    1ms node_modules/next/dist/lib/find-pages-dir.js
    1ms node_modules/next/dist/server/lib/router-utils/is-postpone.js
  140ms node_modules/next/dist/server/next.js
    84ms node_modules/next/dist/server/config.js
      20ms node_modules/next/dist/shared/lib/match-remote-pattern.js
        18ms node_modules/next/dist/compiled/micromatch/index.js
      17ms node_modules/next/dist/compiled/zod/index.js
      14ms node_modules/next/dist/shared/lib/constants.js
        8ms node_modules/@swc/helpers/cjs/_interop_require_default.cjs
      3ms node_modules/next/dist/compiled/find-up/index.js
        1ms node_modules/next/dist/compiled/p-limit/index.js
      3ms node_modules/next/dist/telemetry/ci-info.js
        1ms node_modules/next/dist/compiled/ci-info/index.js
      2ms node_modules/next/dist/server/config-shared.js
        1ms node_modules/next/dist/shared/lib/image-config.js
      2ms node_modules/@next/env/dist/index.js
      2ms node_modules/next/dist/telemetry/flush-and-exit.js
      2ms node_modules/next/dist/lib/find-root.js
      1ms node_modules/next/dist/server/setup-http-agent-env.js
      1ms node_modules/next/dist/shared/lib/router/utils/path-has-prefix.js
    21ms node_modules/next/dist/server/lib/trace/tracer.js
      5ms node_modules/next/dist/compiled/@opentelemetry/api/index.js
      1ms node_modules/next/dist/server/lib/trace/constants.js
    13ms node_modules/next/dist/shared/lib/router/utils/format-url.js
    12ms node_modules/next/dist/build/output/log.js
      9ms node_modules/next/dist/lib/picocolors.js
    3ms node_modules/next/dist/server/require-hook.js
    1ms node_modules/next/dist/server/node-polyfill-crypto.js
    1ms node_modules/next/dist/lib/constants.js
    1ms node_modules/next/dist/server/lib/utils.js
  14ms node_modules/next/dist/compiled/watchpack/watchpack.js
  3ms node_modules/next/dist/compiled/debug/index.js
  1ms node_modules/next/dist/server/lib/format-hostname.js
  1ms node_modules/next/dist/server/lib/app-info-log.js
  1ms node_modules/next/dist/lib/turbopack-warning.js

And after the change:

total: 516ms
499ms node_modules/next/dist/server/lib/start-server.js
  303ms node_modules/next/dist/server/lib/router-server.js
    103ms node_modules/next/dist/server/base-server.js
      42ms node_modules/next/dist/server/future/route-matcher-providers/app-page-route-matcher-provider.js
        38ms node_modules/next/dist/server/future/normalizers/built/app/index.js
          20ms node_modules/next/dist/server/future/normalizers/built/app/app-page-normalizer.js
            18ms node_modules/next/dist/server/future/normalizers/absolute-filename-normalizer.js
              17ms node_modules/next/dist/shared/lib/page-path/absolute-path-to-page.js
            1ms node_modules/next/dist/lib/page-types.js
          17ms node_modules/next/dist/server/future/normalizers/built/app/app-bundle-path-normalizer.js
            16ms node_modules/next/dist/shared/lib/page-path/normalize-page-path.js
          1ms node_modules/next/dist/server/future/normalizers/built/app/app-pathname-normalizer.js
        1ms node_modules/next/dist/lib/is-app-page-route.js
        1ms node_modules/next/dist/server/future/route-kind.js
        1ms node_modules/next/dist/server/future/route-matcher-providers/manifest-route-matcher-provider.js
      10ms node_modules/next/dist/server/send-response.js
      8ms node_modules/next/dist/server/future/normalizers/locale-route-normalizer.js
      4ms node_modules/next/dist/server/api-utils/index.js
        2ms node_modules/next/dist/server/web/spec-extension/adapters/headers.js
          1ms node_modules/next/dist/server/web/spec-extension/adapters/reflect.js
      3ms node_modules/next/dist/server/render-result.js
        2ms node_modules/next/dist/server/stream-utils/node-web-streams-helper.js
      3ms node_modules/next/dist/server/future/route-matcher-providers/pages-api-route-matcher-provider.js
        2ms node_modules/next/dist/server/future/normalizers/built/pages/index.js
          1ms node_modules/next/dist/server/future/normalizers/built/pages/pages-bundle-path-normalizer.js
        1ms node_modules/next/dist/server/future/route-matchers/pages-api-route-matcher.js
      2ms node_modules/next/dist/server/future/route-matcher-providers/app-route-route-matcher-provider.js
        1ms node_modules/next/dist/lib/is-app-route-route.js
        1ms node_modules/next/dist/server/future/route-matchers/app-route-route-matcher.js
      2ms node_modules/next/dist/server/future/route-modules/helpers/response-handlers.js
        1ms node_modules/next/dist/server/web/spec-extension/adapters/request-cookies.js
      2ms node_modules/next/dist/server/lib/match-next-data-pathname.js
      1ms node_modules/next/dist/lib/is-edge-runtime.js
      1ms node_modules/next/dist/shared/lib/runtime-config.external.js
      1ms node_modules/next/dist/server/lib/revalidate.js
      1ms node_modules/next/dist/shared/lib/router/utils/escape-path-delimiters.js
      1ms node_modules/next/dist/server/future/route-matcher-managers/default-route-matcher-manager.js
      1ms node_modules/next/dist/server/future/route-matcher-providers/pages-route-matcher-provider.js
      1ms node_modules/next/dist/shared/lib/router/utils/get-route-from-asset-path.js
      1ms node_modules/next/dist/server/app-render/strip-flight-headers.js
      1ms node_modules/next/dist/server/future/route-modules/checks.js
      1ms node_modules/next/dist/server/lib/server-action-request-meta.js
    91ms node_modules/next/dist/server/lib/router-utils/filesystem.js
      21ms node_modules/next/dist/lib/load-custom-routes.js
        16ms node_modules/next/dist/lib/try-to-parse-path.js
          13ms node_modules/next/dist/lib/is-error.js
            1ms node_modules/next/dist/shared/lib/is-plain-object.js
          2ms node_modules/next/dist/compiled/path-to-regexp/index.js
        3ms node_modules/next/dist/lib/redirect-status.js
          1ms node_modules/next/dist/client/components/redirect-status-code.js
      16ms node_modules/next/dist/server/future/normalizers/request/prefetch-rsc.js
      12ms node_modules/next/dist/lib/metadata/get-metadata-route.js
        10ms node_modules/next/dist/server/server-utils.js
        1ms node_modules/next/dist/shared/lib/isomorphic/path.js
      9ms node_modules/next/dist/shared/lib/router/utils/route-regex.js
        1ms node_modules/next/dist/shared/lib/router/utils/remove-trailing-slash.js
      6ms node_modules/next/dist/shared/lib/router/utils/index.js
        3ms node_modules/next/dist/shared/lib/router/utils/is-dynamic.js
          2ms node_modules/next/dist/server/future/helpers/interception-routes.js
            1ms node_modules/next/dist/shared/lib/router/utils/app-paths.js
              1ms node_modules/next/dist/shared/lib/page-path/ensure-leading-slash.js
        1ms node_modules/next/dist/shared/lib/router/utils/sorted-routes.js
      5ms node_modules/next/dist/shared/lib/router/utils/middleware-route-matcher.js
        5ms node_modules/next/dist/shared/lib/router/utils/prepare-destination.js
          1ms node_modules/next/dist/shared/lib/router/utils/parse-url.js
          1ms node_modules/next/dist/client/components/app-router-headers.js
          1ms node_modules/next/dist/server/api-utils/get-cookie-parser.js
      2ms node_modules/next/dist/compiled/lru-cache/index.js
      2ms node_modules/next/dist/server/future/normalizers/request/postponed.js
        1ms node_modules/next/dist/shared/lib/page-path/denormalize-page-path.js
      1ms node_modules/next/dist/lib/file-exists.js
      1ms node_modules/next/dist/lib/recursive-readdir.js
      1ms node_modules/next/dist/shared/lib/router/utils/path-match.js
      1ms node_modules/next/dist/server/future/normalizers/request/rsc.js
    24ms node_modules/next/dist/server/pipe-readable.js
      22ms node_modules/next/dist/server/web/spec-extension/adapters/next-request.js
        20ms node_modules/next/dist/server/web/spec-extension/request.js
          17ms node_modules/next/dist/server/web/next-url.js
            13ms node_modules/next/dist/shared/lib/i18n/detect-domain-locale.js
            2ms node_modules/next/dist/shared/lib/router/utils/format-next-pathname-info.js
              1ms node_modules/next/dist/shared/lib/router/utils/add-path-suffix.js
            1ms node_modules/next/dist/shared/lib/router/utils/get-next-pathname-info.js
          3ms node_modules/next/dist/server/web/spec-extension/cookies.js
            1ms node_modules/next/dist/compiled/@edge-runtime/cookies/index.js
        1ms node_modules/next/dist/server/web/utils.js
      1ms node_modules/next/dist/lib/detached-promise.js
    22ms node_modules/next/dist/server/serve-static.js
      21ms node_modules/next/dist/compiled/send/index.js
    18ms node_modules/next/dist/server/lib/router-utils/resolve-routes.js
      11ms node_modules/next/dist/server/body-streams.js
      1ms node_modules/next/dist/server/lib/server-ipc/utils.js
      1ms node_modules/next/dist/shared/lib/router/utils/relativize-url.js
      1ms node_modules/next/dist/server/future/normalizers/request/next-data.js
      1ms node_modules/next/dist/server/lib/mock-request.js
    18ms node_modules/next/dist/compiled/compression/index.js
      1ms node_modules/next/dist/compiled/bytes/index.js
    10ms node_modules/next/dist/server/lib/dev-bundler-service.js
    4ms node_modules/next/dist/trace/index.js
      2ms node_modules/next/dist/trace/trace.js
        2ms node_modules/next/dist/trace/report/index.js
          1ms node_modules/next/dist/trace/report/to-json.js
    3ms node_modules/next/dist/server/lib/router-utils/proxy-request.js
      2ms node_modules/next/dist/server/server-route-utils.js
        1ms node_modules/next/dist/server/request-meta.js
    2ms node_modules/next/dist/shared/lib/utils.js
    1ms node_modules/next/dist/server/node-environment.js
    1ms node_modules/next/dist/lib/find-pages-dir.js
    1ms node_modules/next/dist/server/lib/router-utils/is-postpone.js
  157ms node_modules/next/dist/server/next.js
    99ms node_modules/next/dist/server/config.js
      24ms node_modules/next/dist/shared/lib/match-remote-pattern.js
        5ms node_modules/next/dist/compiled/micromatch/index.js
      17ms node_modules/next/dist/compiled/zod/index.js
      15ms node_modules/next/dist/shared/lib/constants.js
        1ms node_modules/@swc/helpers/cjs/_interop_require_default.cjs
        1ms node_modules/next/dist/shared/lib/modern-browserslist-target.js
      4ms node_modules/next/dist/compiled/find-up/index.js
        1ms node_modules/next/dist/compiled/p-limit/index.js
      4ms node_modules/next/dist/telemetry/ci-info.js
        2ms node_modules/next/dist/compiled/ci-info/index.js
      3ms node_modules/next/dist/server/config-shared.js
        1ms node_modules/next/dist/shared/lib/image-config.js
      2ms node_modules/next/dist/telemetry/flush-and-exit.js
      2ms node_modules/next/dist/lib/find-root.js
      2ms node_modules/next/dist/server/setup-http-agent-env.js
      2ms node_modules/next/dist/shared/lib/router/utils/path-has-prefix.js
        1ms node_modules/next/dist/shared/lib/router/utils/parse-path.js
      1ms node_modules/@next/env/dist/index.js
    17ms node_modules/next/dist/server/lib/trace/tracer.js
      14ms node_modules/next/dist/compiled/@opentelemetry/api/index.js
      1ms node_modules/next/dist/server/lib/trace/constants.js
    13ms node_modules/next/dist/lib/constants.js
    5ms node_modules/next/dist/shared/lib/router/utils/format-url.js
      1ms node_modules/@swc/helpers/cjs/_interop_require_wildcard.cjs
      1ms node_modules/next/dist/shared/lib/router/utils/querystring.js
    4ms node_modules/next/dist/build/output/log.js
      1ms node_modules/next/dist/lib/picocolors.js
    3ms node_modules/next/dist/server/require-hook.js
    1ms node_modules/next/dist/server/lib/utils.js
  7ms node_modules/next/dist/compiled/watchpack/watchpack.js
  3ms node_modules/next/dist/compiled/debug/index.js
  2ms node_modules/next/dist/server/lib/format-hostname.js
    1ms node_modules/next/dist/server/lib/is-ipv6.js
  1ms node_modules/next/dist/server/lib/app-info-log.js
  1ms node_modules/next/dist/lib/turbopack-warning.js

I would not pay much attention to absolute numbers as there will be variance and those are single runs - but from first "require time dump" you can estimate importing Telemetry (that might be unused) is costing 149ms / 658ms ~= 22.5% of entire time spent on importing modules - that's pretty significant

How?

By moving static import/require from top level to conditional code path that actually uses it. This code path already have some modules lazy/conditionally loaded. packages/next/src/telemetry/storage.ts doesn't seem to have import side effects so at least on my first glance it doesn't seem like moving import should cause problems?

@ijjk
Copy link
Member

ijjk commented Mar 21, 2024

Failing test suites

Commit: 01ea276

pnpm test test/integration/amphtml-ssg/test/index.test.js

  • AMP SSG Support > export mode > production mode > should have copied SSG files correctly
  • AMP SSG Support > production mode > should load an amp first page correctly
  • AMP SSG Support > production mode > should load a hybrid amp page without query correctly
  • AMP SSG Support > production mode > should load dynamic hybrid SSG/AMP page
  • AMP SSG Support > production mode > should load dynamic hybrid SSG/AMP page with trailing slash
  • AMP SSG Support > production mode > should load dynamic hybrid SSG/AMP page with query
  • AMP SSG Support > production mode > should load a hybrid amp page with query correctly
  • AMP SSG Support > production mode > should output prerendered files correctly during build
Expand output

● AMP SSG Support › production mode › should load an amp first page correctly

command failed with code 1 signal null
   ▲ Next.js 14.2.0-canary.42

   Linting and checking validity of types ...

 ⚠ The Next.js plugin was not detected in your ESLint configuration. See https://nextjs.org/docs/basic-features/eslint#migrating-existing-config
   Creating an optimized production build ...
 ✓ Compiled successfully
   Collecting page data ...
   Generating static pages (0/7) ...
   Generating static pages (1/7) 
   Generating static pages (3/7) 

Error occurred prerendering page "/blog/post-1". Read more: https://nextjs.org/docs/messages/prerender-error

Error: Could not read from https://cdn.ampproject.org/v0/validator_wasm.js - aborted

  15 |  * See the License for the specific language governing permissions and
  16 |  * limitations under the license.
> 17 |  */const t=__nccwpck_require__(915);const r=__nccwpck_require__(147);const i=__nccwpck_require__(685);const s=__nccwpck_require__(687);const o=__nccwpck_require__(17);const a=__nccwpck_require__(642);const l=__nccwpck_require__(263);const u=__nccwpck_require__(477);const c=__nccwpck_require__(310);const h=__nccwpck_require__(837);const p=__nccwpck_require__(144);const f="amphtml-validator";function hasPrefix(e,t){return e.indexOf(t)==0}function isHttpOrHttpsUrl(e){return hasPrefix(e,"http://")||hasPrefix(e,"https://")}function readFromFile(e){return new l((function(t,n){r.readFile(e,"utf8",(function(e,r){if(e){n(e)}else{t(r.trim())}}))}))}function readFromReadable(e,t){return new l((function(n,r){const i=[];t.setEncoding("utf8");t.on("data",(function(e){i.push(e)}));t.on("end",(function(){n(i.join(""))}));t.on("error",(function(t){r(new Error("Could not read from "+e+" - "+t.message))}))}))}function readFromStdin(){return readFromReadable("stdin",process.stdin).then((function(e){process.stdin.resume();return e}))}function readFromUrl(e,t){return new l((function(n,r){const o=hasPrefix(e,"http://")?i:s;const a=o.request(e,(function(t){if(t.statusCode!==200){t.resume();r(new Error("Unable to fetch "+e+" - HTTP Status "+t.statusCode))}else{n(t)}}));a.setHeader("User-Agent",t);a.on("error",(function(t){r(new Error("Unable to fetch "+e+" - "+t.message))}));a.end()})).then(readFromReadable.bind(null,e))}function ValidationResult(){this.status="UNKNOWN";this.errors=[]}function ValidationError(){this.severity="UNKNOWN_SEVERITY";this.line=1;this.col=0;this.message="";this.specUrl=null;this.code="UNKNOWN_CODE";this.params=[]}function Validator(e){this.sandbox=p.createContext();try{new p.Script(e).runInContext(this.sandbox)}catch(e){throw new Error("Could not instantiate validator_wasm.js - "+e.message)}}Validator.prototype.init=function(){if(this.sandbox.amp.validator.init){return this.sandbox.amp.validator.init()}else{return l.resolve(undefined)}};Validator.prototype.validateString=function(e,t){const n=this.sandbox.amp.validator.validateString(e,t);const r=new ValidationResult;r.status=n.status;for(let e=0;e<n.errors.length;e++){const t=n.errors[e];const i=new ValidationError;i.severity=t.severity;i.line=t.line;i.col=t.col;i.message=this.sandbox.amp.validator.renderErrorMessage(t);i.specUrl=t.specUrl;i.code=t.code;i.params=t.params;r.errors.push(i)}return r};const m={};function getInstance(e,t){const n=e||"https://cdn.ampproject.org/v0/validator_wasm.js";const r=t||f;if(m.hasOwnProperty(n)){return l.resolve(m[n])}const i=isHttpOrHttpsUrl(n)?readFromUrl(n,r):readFromFile(n);return i.then((function(e){let t;try{t=new Validator(e)}catch(e){throw e}m[n]=t;return t})).then((function(e){return e.init().then((()=>e))}))}e.getInstance=getInstance;function newInstance(e){return new Validator(e)}e.newInstance=newInstance;function logValidationResult(e,n,r){if(n.status==="PASS"){process.stdout.write(e+": "+(r?t.green("PASS"):"PASS")+"\n")}for(let i=0;i<n.errors.length;i++){const s=n.errors[i];let o=e+":"+s.line+":"+s.col+" ";if(r){o+=(s.severity==="ERROR"?t.red:t.magenta)(s.message)}else{o+=s.message}if(s.specUrl){o+=" (see "+s.specUrl+")"}process.stderr.write(o+"\n")}}function main(){a.usage("[options] <fileOrUrlOrMinus...>\n\n"+'  Validates the files or urls provided as arguments. If "-" is\n'+"  specified, reads from stdin instead.").option("--validator_js <fileOrUrl>","The Validator Javascript.\n"+"  Latest published version by default, or\n"+"  dist/validator_minified.js (built with build.py)\n"+"  for development.","https://cdn.ampproject.org/v0/validator_wasm.js").option("--user-agent <userAgent>","User agent string to use in requests.",f).option("--html_format <AMP|AMP4ADS|AMP4EMAIL>","The input format to be validated.\n"+"  AMP by default.","AMP").option("--format <color|text|json>","How to format the output.\n"+'  "color" displays errors/warnings/success in\n'+"          red/orange/green.\n"+'  "text"  avoids color (e.g., useful in terminals not\n'+"          supporting color).\n"+'  "json"  emits json corresponding to the ValidationResult\n'+"          message in validator.proto.","color").parse(process.argv);const e=a.opts();if(e.length===0){a.outputHelp();process.exit(1)}if(e.html_format!=="AMP"&&e.html_format!=="AMP4ADS"&&e.html_format!=="AMP4EMAIL"){process.stderr.write('--html_format must be set to "AMP", "AMP4ADS", or "AMP4EMAIL".\n',(function(){process.exit(1)}))}if(e.format!=="color"&&e.format!=="text"&&e.format!=="json"){process.stderr.write('--format must be set to "color", "text", or "json".\n',(function(){process.exit(1)}))}const n=[];for(let t=0;t<a.args.length;t++){const r=a.args[t];if(r==="-"){n.push(readFromStdin())}else if(isHttpOrHttpsUrl(r)){n.push(readFromUrl(r,e.userAgent))}else{n.push(readFromFile(r))}}getInstance(e.validator_js,e.userAgent).then((function(r){l.all(n).then((function(t){const n={};let i=false;for(let s=0;s<t.length;s++){const o=r.validateString(t[s],e.html_format);if(e.format==="json"){n[a.args[s]]=o}else{logValidationResult(a.args[s],o,e.format==="color"?true:false)}if(o.status!=="PASS"){i=true}}if(e.format==="json"){process.stdout.write(JSON.stringify(n)+"\n",(function(){process.exit(i?1:0)}))}else if(i){process.stderr.write("",(function(){process.exit(1)}))}else{process.stdout.write("",(function(){process.exit(0)}))}})).catch((function(n){process.stderr.write((e.format=="color"?t.red(n.message):n.message)+"\n",(function(){process.exit(1)}))}))})).catch((function(n){process.stderr.write((e.format=="color"?t.red(n.message):n.message)+"\n",(function(){process.exit(1)}))}))}e.main=main})();module.exports=n})();
     |                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              ^

  at IncomingMessage.<anonymous> (../packages/next/dist/compiled/amphtml-validator/index.js:17:846)
     Generating static pages (5/7) 
   ✓ Generating static pages (7/7) 
  > Export encountered errors on following paths:
  	/blog/[slug]: /blog/post-1
  at ChildProcess.<anonymous> (lib/next-test-utils.ts:284:11)

● AMP SSG Support › production mode › should load a hybrid amp page without query correctly

command failed with code 1 signal null
   ▲ Next.js 14.2.0-canary.42

   Linting and checking validity of types ...

 ⚠ The Next.js plugin was not detected in your ESLint configuration. See https://nextjs.org/docs/basic-features/eslint#migrating-existing-config
   Creating an optimized production build ...
 ✓ Compiled successfully
   Collecting page data ...
   Generating static pages (0/7) ...
   Generating static pages (1/7) 
   Generating static pages (3/7) 

Error occurred prerendering page "/blog/post-1". Read more: https://nextjs.org/docs/messages/prerender-error

Error: Could not read from https://cdn.ampproject.org/v0/validator_wasm.js - aborted

  15 |  * See the License for the specific language governing permissions and
  16 |  * limitations under the license.
> 17 |  */const t=__nccwpck_require__(915);const r=__nccwpck_require__(147);const i=__nccwpck_require__(685);const s=__nccwpck_require__(687);const o=__nccwpck_require__(17);const a=__nccwpck_require__(642);const l=__nccwpck_require__(263);const u=__nccwpck_require__(477);const c=__nccwpck_require__(310);const h=__nccwpck_require__(837);const p=__nccwpck_require__(144);const f="amphtml-validator";function hasPrefix(e,t){return e.indexOf(t)==0}function isHttpOrHttpsUrl(e){return hasPrefix(e,"http://")||hasPrefix(e,"https://")}function readFromFile(e){return new l((function(t,n){r.readFile(e,"utf8",(function(e,r){if(e){n(e)}else{t(r.trim())}}))}))}function readFromReadable(e,t){return new l((function(n,r){const i=[];t.setEncoding("utf8");t.on("data",(function(e){i.push(e)}));t.on("end",(function(){n(i.join(""))}));t.on("error",(function(t){r(new Error("Could not read from "+e+" - "+t.message))}))}))}function readFromStdin(){return readFromReadable("stdin",process.stdin).then((function(e){process.stdin.resume();return e}))}function readFromUrl(e,t){return new l((function(n,r){const o=hasPrefix(e,"http://")?i:s;const a=o.request(e,(function(t){if(t.statusCode!==200){t.resume();r(new Error("Unable to fetch "+e+" - HTTP Status "+t.statusCode))}else{n(t)}}));a.setHeader("User-Agent",t);a.on("error",(function(t){r(new Error("Unable to fetch "+e+" - "+t.message))}));a.end()})).then(readFromReadable.bind(null,e))}function ValidationResult(){this.status="UNKNOWN";this.errors=[]}function ValidationError(){this.severity="UNKNOWN_SEVERITY";this.line=1;this.col=0;this.message="";this.specUrl=null;this.code="UNKNOWN_CODE";this.params=[]}function Validator(e){this.sandbox=p.createContext();try{new p.Script(e).runInContext(this.sandbox)}catch(e){throw new Error("Could not instantiate validator_wasm.js - "+e.message)}}Validator.prototype.init=function(){if(this.sandbox.amp.validator.init){return this.sandbox.amp.validator.init()}else{return l.resolve(undefined)}};Validator.prototype.validateString=function(e,t){const n=this.sandbox.amp.validator.validateString(e,t);const r=new ValidationResult;r.status=n.status;for(let e=0;e<n.errors.length;e++){const t=n.errors[e];const i=new ValidationError;i.severity=t.severity;i.line=t.line;i.col=t.col;i.message=this.sandbox.amp.validator.renderErrorMessage(t);i.specUrl=t.specUrl;i.code=t.code;i.params=t.params;r.errors.push(i)}return r};const m={};function getInstance(e,t){const n=e||"https://cdn.ampproject.org/v0/validator_wasm.js";const r=t||f;if(m.hasOwnProperty(n)){return l.resolve(m[n])}const i=isHttpOrHttpsUrl(n)?readFromUrl(n,r):readFromFile(n);return i.then((function(e){let t;try{t=new Validator(e)}catch(e){throw e}m[n]=t;return t})).then((function(e){return e.init().then((()=>e))}))}e.getInstance=getInstance;function newInstance(e){return new Validator(e)}e.newInstance=newInstance;function logValidationResult(e,n,r){if(n.status==="PASS"){process.stdout.write(e+": "+(r?t.green("PASS"):"PASS")+"\n")}for(let i=0;i<n.errors.length;i++){const s=n.errors[i];let o=e+":"+s.line+":"+s.col+" ";if(r){o+=(s.severity==="ERROR"?t.red:t.magenta)(s.message)}else{o+=s.message}if(s.specUrl){o+=" (see "+s.specUrl+")"}process.stderr.write(o+"\n")}}function main(){a.usage("[options] <fileOrUrlOrMinus...>\n\n"+'  Validates the files or urls provided as arguments. If "-" is\n'+"  specified, reads from stdin instead.").option("--validator_js <fileOrUrl>","The Validator Javascript.\n"+"  Latest published version by default, or\n"+"  dist/validator_minified.js (built with build.py)\n"+"  for development.","https://cdn.ampproject.org/v0/validator_wasm.js").option("--user-agent <userAgent>","User agent string to use in requests.",f).option("--html_format <AMP|AMP4ADS|AMP4EMAIL>","The input format to be validated.\n"+"  AMP by default.","AMP").option("--format <color|text|json>","How to format the output.\n"+'  "color" displays errors/warnings/success in\n'+"          red/orange/green.\n"+'  "text"  avoids color (e.g., useful in terminals not\n'+"          supporting color).\n"+'  "json"  emits json corresponding to the ValidationResult\n'+"          message in validator.proto.","color").parse(process.argv);const e=a.opts();if(e.length===0){a.outputHelp();process.exit(1)}if(e.html_format!=="AMP"&&e.html_format!=="AMP4ADS"&&e.html_format!=="AMP4EMAIL"){process.stderr.write('--html_format must be set to "AMP", "AMP4ADS", or "AMP4EMAIL".\n',(function(){process.exit(1)}))}if(e.format!=="color"&&e.format!=="text"&&e.format!=="json"){process.stderr.write('--format must be set to "color", "text", or "json".\n',(function(){process.exit(1)}))}const n=[];for(let t=0;t<a.args.length;t++){const r=a.args[t];if(r==="-"){n.push(readFromStdin())}else if(isHttpOrHttpsUrl(r)){n.push(readFromUrl(r,e.userAgent))}else{n.push(readFromFile(r))}}getInstance(e.validator_js,e.userAgent).then((function(r){l.all(n).then((function(t){const n={};let i=false;for(let s=0;s<t.length;s++){const o=r.validateString(t[s],e.html_format);if(e.format==="json"){n[a.args[s]]=o}else{logValidationResult(a.args[s],o,e.format==="color"?true:false)}if(o.status!=="PASS"){i=true}}if(e.format==="json"){process.stdout.write(JSON.stringify(n)+"\n",(function(){process.exit(i?1:0)}))}else if(i){process.stderr.write("",(function(){process.exit(1)}))}else{process.stdout.write("",(function(){process.exit(0)}))}})).catch((function(n){process.stderr.write((e.format=="color"?t.red(n.message):n.message)+"\n",(function(){process.exit(1)}))}))})).catch((function(n){process.stderr.write((e.format=="color"?t.red(n.message):n.message)+"\n",(function(){process.exit(1)}))}))}e.main=main})();module.exports=n})();
     |                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              ^

  at IncomingMessage.<anonymous> (../packages/next/dist/compiled/amphtml-validator/index.js:17:846)
     Generating static pages (5/7) 
   ✓ Generating static pages (7/7) 
  > Export encountered errors on following paths:
  	/blog/[slug]: /blog/post-1
  at ChildProcess.<anonymous> (lib/next-test-utils.ts:284:11)

● AMP SSG Support › production mode › should load dynamic hybrid SSG/AMP page

command failed with code 1 signal null
   ▲ Next.js 14.2.0-canary.42

   Linting and checking validity of types ...

 ⚠ The Next.js plugin was not detected in your ESLint configuration. See https://nextjs.org/docs/basic-features/eslint#migrating-existing-config
   Creating an optimized production build ...
 ✓ Compiled successfully
   Collecting page data ...
   Generating static pages (0/7) ...
   Generating static pages (1/7) 
   Generating static pages (3/7) 

Error occurred prerendering page "/blog/post-1". Read more: https://nextjs.org/docs/messages/prerender-error

Error: Could not read from https://cdn.ampproject.org/v0/validator_wasm.js - aborted

  15 |  * See the License for the specific language governing permissions and
  16 |  * limitations under the license.
> 17 |  */const t=__nccwpck_require__(915);const r=__nccwpck_require__(147);const i=__nccwpck_require__(685);const s=__nccwpck_require__(687);const o=__nccwpck_require__(17);const a=__nccwpck_require__(642);const l=__nccwpck_require__(263);const u=__nccwpck_require__(477);const c=__nccwpck_require__(310);const h=__nccwpck_require__(837);const p=__nccwpck_require__(144);const f="amphtml-validator";function hasPrefix(e,t){return e.indexOf(t)==0}function isHttpOrHttpsUrl(e){return hasPrefix(e,"http://")||hasPrefix(e,"https://")}function readFromFile(e){return new l((function(t,n){r.readFile(e,"utf8",(function(e,r){if(e){n(e)}else{t(r.trim())}}))}))}function readFromReadable(e,t){return new l((function(n,r){const i=[];t.setEncoding("utf8");t.on("data",(function(e){i.push(e)}));t.on("end",(function(){n(i.join(""))}));t.on("error",(function(t){r(new Error("Could not read from "+e+" - "+t.message))}))}))}function readFromStdin(){return readFromReadable("stdin",process.stdin).then((function(e){process.stdin.resume();return e}))}function readFromUrl(e,t){return new l((function(n,r){const o=hasPrefix(e,"http://")?i:s;const a=o.request(e,(function(t){if(t.statusCode!==200){t.resume();r(new Error("Unable to fetch "+e+" - HTTP Status "+t.statusCode))}else{n(t)}}));a.setHeader("User-Agent",t);a.on("error",(function(t){r(new Error("Unable to fetch "+e+" - "+t.message))}));a.end()})).then(readFromReadable.bind(null,e))}function ValidationResult(){this.status="UNKNOWN";this.errors=[]}function ValidationError(){this.severity="UNKNOWN_SEVERITY";this.line=1;this.col=0;this.message="";this.specUrl=null;this.code="UNKNOWN_CODE";this.params=[]}function Validator(e){this.sandbox=p.createContext();try{new p.Script(e).runInContext(this.sandbox)}catch(e){throw new Error("Could not instantiate validator_wasm.js - "+e.message)}}Validator.prototype.init=function(){if(this.sandbox.amp.validator.init){return this.sandbox.amp.validator.init()}else{return l.resolve(undefined)}};Validator.prototype.validateString=function(e,t){const n=this.sandbox.amp.validator.validateString(e,t);const r=new ValidationResult;r.status=n.status;for(let e=0;e<n.errors.length;e++){const t=n.errors[e];const i=new ValidationError;i.severity=t.severity;i.line=t.line;i.col=t.col;i.message=this.sandbox.amp.validator.renderErrorMessage(t);i.specUrl=t.specUrl;i.code=t.code;i.params=t.params;r.errors.push(i)}return r};const m={};function getInstance(e,t){const n=e||"https://cdn.ampproject.org/v0/validator_wasm.js";const r=t||f;if(m.hasOwnProperty(n)){return l.resolve(m[n])}const i=isHttpOrHttpsUrl(n)?readFromUrl(n,r):readFromFile(n);return i.then((function(e){let t;try{t=new Validator(e)}catch(e){throw e}m[n]=t;return t})).then((function(e){return e.init().then((()=>e))}))}e.getInstance=getInstance;function newInstance(e){return new Validator(e)}e.newInstance=newInstance;function logValidationResult(e,n,r){if(n.status==="PASS"){process.stdout.write(e+": "+(r?t.green("PASS"):"PASS")+"\n")}for(let i=0;i<n.errors.length;i++){const s=n.errors[i];let o=e+":"+s.line+":"+s.col+" ";if(r){o+=(s.severity==="ERROR"?t.red:t.magenta)(s.message)}else{o+=s.message}if(s.specUrl){o+=" (see "+s.specUrl+")"}process.stderr.write(o+"\n")}}function main(){a.usage("[options] <fileOrUrlOrMinus...>\n\n"+'  Validates the files or urls provided as arguments. If "-" is\n'+"  specified, reads from stdin instead.").option("--validator_js <fileOrUrl>","The Validator Javascript.\n"+"  Latest published version by default, or\n"+"  dist/validator_minified.js (built with build.py)\n"+"  for development.","https://cdn.ampproject.org/v0/validator_wasm.js").option("--user-agent <userAgent>","User agent string to use in requests.",f).option("--html_format <AMP|AMP4ADS|AMP4EMAIL>","The input format to be validated.\n"+"  AMP by default.","AMP").option("--format <color|text|json>","How to format the output.\n"+'  "color" displays errors/warnings/success in\n'+"          red/orange/green.\n"+'  "text"  avoids color (e.g., useful in terminals not\n'+"          supporting color).\n"+'  "json"  emits json corresponding to the ValidationResult\n'+"          message in validator.proto.","color").parse(process.argv);const e=a.opts();if(e.length===0){a.outputHelp();process.exit(1)}if(e.html_format!=="AMP"&&e.html_format!=="AMP4ADS"&&e.html_format!=="AMP4EMAIL"){process.stderr.write('--html_format must be set to "AMP", "AMP4ADS", or "AMP4EMAIL".\n',(function(){process.exit(1)}))}if(e.format!=="color"&&e.format!=="text"&&e.format!=="json"){process.stderr.write('--format must be set to "color", "text", or "json".\n',(function(){process.exit(1)}))}const n=[];for(let t=0;t<a.args.length;t++){const r=a.args[t];if(r==="-"){n.push(readFromStdin())}else if(isHttpOrHttpsUrl(r)){n.push(readFromUrl(r,e.userAgent))}else{n.push(readFromFile(r))}}getInstance(e.validator_js,e.userAgent).then((function(r){l.all(n).then((function(t){const n={};let i=false;for(let s=0;s<t.length;s++){const o=r.validateString(t[s],e.html_format);if(e.format==="json"){n[a.args[s]]=o}else{logValidationResult(a.args[s],o,e.format==="color"?true:false)}if(o.status!=="PASS"){i=true}}if(e.format==="json"){process.stdout.write(JSON.stringify(n)+"\n",(function(){process.exit(i?1:0)}))}else if(i){process.stderr.write("",(function(){process.exit(1)}))}else{process.stdout.write("",(function(){process.exit(0)}))}})).catch((function(n){process.stderr.write((e.format=="color"?t.red(n.message):n.message)+"\n",(function(){process.exit(1)}))}))})).catch((function(n){process.stderr.write((e.format=="color"?t.red(n.message):n.message)+"\n",(function(){process.exit(1)}))}))}e.main=main})();module.exports=n})();
     |                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              ^

  at IncomingMessage.<anonymous> (../packages/next/dist/compiled/amphtml-validator/index.js:17:846)
     Generating static pages (5/7) 
   ✓ Generating static pages (7/7) 
  > Export encountered errors on following paths:
  	/blog/[slug]: /blog/post-1
  at ChildProcess.<anonymous> (lib/next-test-utils.ts:284:11)

● AMP SSG Support › production mode › should load dynamic hybrid SSG/AMP page with trailing slash

command failed with code 1 signal null
   ▲ Next.js 14.2.0-canary.42

   Linting and checking validity of types ...

 ⚠ The Next.js plugin was not detected in your ESLint configuration. See https://nextjs.org/docs/basic-features/eslint#migrating-existing-config
   Creating an optimized production build ...
 ✓ Compiled successfully
   Collecting page data ...
   Generating static pages (0/7) ...
   Generating static pages (1/7) 
   Generating static pages (3/7) 

Error occurred prerendering page "/blog/post-1". Read more: https://nextjs.org/docs/messages/prerender-error

Error: Could not read from https://cdn.ampproject.org/v0/validator_wasm.js - aborted

  15 |  * See the License for the specific language governing permissions and
  16 |  * limitations under the license.
> 17 |  */const t=__nccwpck_require__(915);const r=__nccwpck_require__(147);const i=__nccwpck_require__(685);const s=__nccwpck_require__(687);const o=__nccwpck_require__(17);const a=__nccwpck_require__(642);const l=__nccwpck_require__(263);const u=__nccwpck_require__(477);const c=__nccwpck_require__(310);const h=__nccwpck_require__(837);const p=__nccwpck_require__(144);const f="amphtml-validator";function hasPrefix(e,t){return e.indexOf(t)==0}function isHttpOrHttpsUrl(e){return hasPrefix(e,"http://")||hasPrefix(e,"https://")}function readFromFile(e){return new l((function(t,n){r.readFile(e,"utf8",(function(e,r){if(e){n(e)}else{t(r.trim())}}))}))}function readFromReadable(e,t){return new l((function(n,r){const i=[];t.setEncoding("utf8");t.on("data",(function(e){i.push(e)}));t.on("end",(function(){n(i.join(""))}));t.on("error",(function(t){r(new Error("Could not read from "+e+" - "+t.message))}))}))}function readFromStdin(){return readFromReadable("stdin",process.stdin).then((function(e){process.stdin.resume();return e}))}function readFromUrl(e,t){return new l((function(n,r){const o=hasPrefix(e,"http://")?i:s;const a=o.request(e,(function(t){if(t.statusCode!==200){t.resume();r(new Error("Unable to fetch "+e+" - HTTP Status "+t.statusCode))}else{n(t)}}));a.setHeader("User-Agent",t);a.on("error",(function(t){r(new Error("Unable to fetch "+e+" - "+t.message))}));a.end()})).then(readFromReadable.bind(null,e))}function ValidationResult(){this.status="UNKNOWN";this.errors=[]}function ValidationError(){this.severity="UNKNOWN_SEVERITY";this.line=1;this.col=0;this.message="";this.specUrl=null;this.code="UNKNOWN_CODE";this.params=[]}function Validator(e){this.sandbox=p.createContext();try{new p.Script(e).runInContext(this.sandbox)}catch(e){throw new Error("Could not instantiate validator_wasm.js - "+e.message)}}Validator.prototype.init=function(){if(this.sandbox.amp.validator.init){return this.sandbox.amp.validator.init()}else{return l.resolve(undefined)}};Validator.prototype.validateString=function(e,t){const n=this.sandbox.amp.validator.validateString(e,t);const r=new ValidationResult;r.status=n.status;for(let e=0;e<n.errors.length;e++){const t=n.errors[e];const i=new ValidationError;i.severity=t.severity;i.line=t.line;i.col=t.col;i.message=this.sandbox.amp.validator.renderErrorMessage(t);i.specUrl=t.specUrl;i.code=t.code;i.params=t.params;r.errors.push(i)}return r};const m={};function getInstance(e,t){const n=e||"https://cdn.ampproject.org/v0/validator_wasm.js";const r=t||f;if(m.hasOwnProperty(n)){return l.resolve(m[n])}const i=isHttpOrHttpsUrl(n)?readFromUrl(n,r):readFromFile(n);return i.then((function(e){let t;try{t=new Validator(e)}catch(e){throw e}m[n]=t;return t})).then((function(e){return e.init().then((()=>e))}))}e.getInstance=getInstance;function newInstance(e){return new Validator(e)}e.newInstance=newInstance;function logValidationResult(e,n,r){if(n.status==="PASS"){process.stdout.write(e+": "+(r?t.green("PASS"):"PASS")+"\n")}for(let i=0;i<n.errors.length;i++){const s=n.errors[i];let o=e+":"+s.line+":"+s.col+" ";if(r){o+=(s.severity==="ERROR"?t.red:t.magenta)(s.message)}else{o+=s.message}if(s.specUrl){o+=" (see "+s.specUrl+")"}process.stderr.write(o+"\n")}}function main(){a.usage("[options] <fileOrUrlOrMinus...>\n\n"+'  Validates the files or urls provided as arguments. If "-" is\n'+"  specified, reads from stdin instead.").option("--validator_js <fileOrUrl>","The Validator Javascript.\n"+"  Latest published version by default, or\n"+"  dist/validator_minified.js (built with build.py)\n"+"  for development.","https://cdn.ampproject.org/v0/validator_wasm.js").option("--user-agent <userAgent>","User agent string to use in requests.",f).option("--html_format <AMP|AMP4ADS|AMP4EMAIL>","The input format to be validated.\n"+"  AMP by default.","AMP").option("--format <color|text|json>","How to format the output.\n"+'  "color" displays errors/warnings/success in\n'+"          red/orange/green.\n"+'  "text"  avoids color (e.g., useful in terminals not\n'+"          supporting color).\n"+'  "json"  emits json corresponding to the ValidationResult\n'+"          message in validator.proto.","color").parse(process.argv);const e=a.opts();if(e.length===0){a.outputHelp();process.exit(1)}if(e.html_format!=="AMP"&&e.html_format!=="AMP4ADS"&&e.html_format!=="AMP4EMAIL"){process.stderr.write('--html_format must be set to "AMP", "AMP4ADS", or "AMP4EMAIL".\n',(function(){process.exit(1)}))}if(e.format!=="color"&&e.format!=="text"&&e.format!=="json"){process.stderr.write('--format must be set to "color", "text", or "json".\n',(function(){process.exit(1)}))}const n=[];for(let t=0;t<a.args.length;t++){const r=a.args[t];if(r==="-"){n.push(readFromStdin())}else if(isHttpOrHttpsUrl(r)){n.push(readFromUrl(r,e.userAgent))}else{n.push(readFromFile(r))}}getInstance(e.validator_js,e.userAgent).then((function(r){l.all(n).then((function(t){const n={};let i=false;for(let s=0;s<t.length;s++){const o=r.validateString(t[s],e.html_format);if(e.format==="json"){n[a.args[s]]=o}else{logValidationResult(a.args[s],o,e.format==="color"?true:false)}if(o.status!=="PASS"){i=true}}if(e.format==="json"){process.stdout.write(JSON.stringify(n)+"\n",(function(){process.exit(i?1:0)}))}else if(i){process.stderr.write("",(function(){process.exit(1)}))}else{process.stdout.write("",(function(){process.exit(0)}))}})).catch((function(n){process.stderr.write((e.format=="color"?t.red(n.message):n.message)+"\n",(function(){process.exit(1)}))}))})).catch((function(n){process.stderr.write((e.format=="color"?t.red(n.message):n.message)+"\n",(function(){process.exit(1)}))}))}e.main=main})();module.exports=n})();
     |                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              ^

  at IncomingMessage.<anonymous> (../packages/next/dist/compiled/amphtml-validator/index.js:17:846)
     Generating static pages (5/7) 
   ✓ Generating static pages (7/7) 
  > Export encountered errors on following paths:
  	/blog/[slug]: /blog/post-1
  at ChildProcess.<anonymous> (lib/next-test-utils.ts:284:11)

● AMP SSG Support › production mode › should load dynamic hybrid SSG/AMP page with query

command failed with code 1 signal null
   ▲ Next.js 14.2.0-canary.42

   Linting and checking validity of types ...

 ⚠ The Next.js plugin was not detected in your ESLint configuration. See https://nextjs.org/docs/basic-features/eslint#migrating-existing-config
   Creating an optimized production build ...
 ✓ Compiled successfully
   Collecting page data ...
   Generating static pages (0/7) ...
   Generating static pages (1/7) 
   Generating static pages (3/7) 

Error occurred prerendering page "/blog/post-1". Read more: https://nextjs.org/docs/messages/prerender-error

Error: Could not read from https://cdn.ampproject.org/v0/validator_wasm.js - aborted

  15 |  * See the License for the specific language governing permissions and
  16 |  * limitations under the license.
> 17 |  */const t=__nccwpck_require__(915);const r=__nccwpck_require__(147);const i=__nccwpck_require__(685);const s=__nccwpck_require__(687);const o=__nccwpck_require__(17);const a=__nccwpck_require__(642);const l=__nccwpck_require__(263);const u=__nccwpck_require__(477);const c=__nccwpck_require__(310);const h=__nccwpck_require__(837);const p=__nccwpck_require__(144);const f="amphtml-validator";function hasPrefix(e,t){return e.indexOf(t)==0}function isHttpOrHttpsUrl(e){return hasPrefix(e,"http://")||hasPrefix(e,"https://")}function readFromFile(e){return new l((function(t,n){r.readFile(e,"utf8",(function(e,r){if(e){n(e)}else{t(r.trim())}}))}))}function readFromReadable(e,t){return new l((function(n,r){const i=[];t.setEncoding("utf8");t.on("data",(function(e){i.push(e)}));t.on("end",(function(){n(i.join(""))}));t.on("error",(function(t){r(new Error("Could not read from "+e+" - "+t.message))}))}))}function readFromStdin(){return readFromReadable("stdin",process.stdin).then((function(e){process.stdin.resume();return e}))}function readFromUrl(e,t){return new l((function(n,r){const o=hasPrefix(e,"http://")?i:s;const a=o.request(e,(function(t){if(t.statusCode!==200){t.resume();r(new Error("Unable to fetch "+e+" - HTTP Status "+t.statusCode))}else{n(t)}}));a.setHeader("User-Agent",t);a.on("error",(function(t){r(new Error("Unable to fetch "+e+" - "+t.message))}));a.end()})).then(readFromReadable.bind(null,e))}function ValidationResult(){this.status="UNKNOWN";this.errors=[]}function ValidationError(){this.severity="UNKNOWN_SEVERITY";this.line=1;this.col=0;this.message="";this.specUrl=null;this.code="UNKNOWN_CODE";this.params=[]}function Validator(e){this.sandbox=p.createContext();try{new p.Script(e).runInContext(this.sandbox)}catch(e){throw new Error("Could not instantiate validator_wasm.js - "+e.message)}}Validator.prototype.init=function(){if(this.sandbox.amp.validator.init){return this.sandbox.amp.validator.init()}else{return l.resolve(undefined)}};Validator.prototype.validateString=function(e,t){const n=this.sandbox.amp.validator.validateString(e,t);const r=new ValidationResult;r.status=n.status;for(let e=0;e<n.errors.length;e++){const t=n.errors[e];const i=new ValidationError;i.severity=t.severity;i.line=t.line;i.col=t.col;i.message=this.sandbox.amp.validator.renderErrorMessage(t);i.specUrl=t.specUrl;i.code=t.code;i.params=t.params;r.errors.push(i)}return r};const m={};function getInstance(e,t){const n=e||"https://cdn.ampproject.org/v0/validator_wasm.js";const r=t||f;if(m.hasOwnProperty(n)){return l.resolve(m[n])}const i=isHttpOrHttpsUrl(n)?readFromUrl(n,r):readFromFile(n);return i.then((function(e){let t;try{t=new Validator(e)}catch(e){throw e}m[n]=t;return t})).then((function(e){return e.init().then((()=>e))}))}e.getInstance=getInstance;function newInstance(e){return new Validator(e)}e.newInstance=newInstance;function logValidationResult(e,n,r){if(n.status==="PASS"){process.stdout.write(e+": "+(r?t.green("PASS"):"PASS")+"\n")}for(let i=0;i<n.errors.length;i++){const s=n.errors[i];let o=e+":"+s.line+":"+s.col+" ";if(r){o+=(s.severity==="ERROR"?t.red:t.magenta)(s.message)}else{o+=s.message}if(s.specUrl){o+=" (see "+s.specUrl+")"}process.stderr.write(o+"\n")}}function main(){a.usage("[options] <fileOrUrlOrMinus...>\n\n"+'  Validates the files or urls provided as arguments. If "-" is\n'+"  specified, reads from stdin instead.").option("--validator_js <fileOrUrl>","The Validator Javascript.\n"+"  Latest published version by default, or\n"+"  dist/validator_minified.js (built with build.py)\n"+"  for development.","https://cdn.ampproject.org/v0/validator_wasm.js").option("--user-agent <userAgent>","User agent string to use in requests.",f).option("--html_format <AMP|AMP4ADS|AMP4EMAIL>","The input format to be validated.\n"+"  AMP by default.","AMP").option("--format <color|text|json>","How to format the output.\n"+'  "color" displays errors/warnings/success in\n'+"          red/orange/green.\n"+'  "text"  avoids color (e.g., useful in terminals not\n'+"          supporting color).\n"+'  "json"  emits json corresponding to the ValidationResult\n'+"          message in validator.proto.","color").parse(process.argv);const e=a.opts();if(e.length===0){a.outputHelp();process.exit(1)}if(e.html_format!=="AMP"&&e.html_format!=="AMP4ADS"&&e.html_format!=="AMP4EMAIL"){process.stderr.write('--html_format must be set to "AMP", "AMP4ADS", or "AMP4EMAIL".\n',(function(){process.exit(1)}))}if(e.format!=="color"&&e.format!=="text"&&e.format!=="json"){process.stderr.write('--format must be set to "color", "text", or "json".\n',(function(){process.exit(1)}))}const n=[];for(let t=0;t<a.args.length;t++){const r=a.args[t];if(r==="-"){n.push(readFromStdin())}else if(isHttpOrHttpsUrl(r)){n.push(readFromUrl(r,e.userAgent))}else{n.push(readFromFile(r))}}getInstance(e.validator_js,e.userAgent).then((function(r){l.all(n).then((function(t){const n={};let i=false;for(let s=0;s<t.length;s++){const o=r.validateString(t[s],e.html_format);if(e.format==="json"){n[a.args[s]]=o}else{logValidationResult(a.args[s],o,e.format==="color"?true:false)}if(o.status!=="PASS"){i=true}}if(e.format==="json"){process.stdout.write(JSON.stringify(n)+"\n",(function(){process.exit(i?1:0)}))}else if(i){process.stderr.write("",(function(){process.exit(1)}))}else{process.stdout.write("",(function(){process.exit(0)}))}})).catch((function(n){process.stderr.write((e.format=="color"?t.red(n.message):n.message)+"\n",(function(){process.exit(1)}))}))})).catch((function(n){process.stderr.write((e.format=="color"?t.red(n.message):n.message)+"\n",(function(){process.exit(1)}))}))}e.main=main})();module.exports=n})();
     |                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              ^

  at IncomingMessage.<anonymous> (../packages/next/dist/compiled/amphtml-validator/index.js:17:846)
     Generating static pages (5/7) 
   ✓ Generating static pages (7/7) 
  > Export encountered errors on following paths:
  	/blog/[slug]: /blog/post-1
  at ChildProcess.<anonymous> (lib/next-test-utils.ts:284:11)

● AMP SSG Support › production mode › should load a hybrid amp page with query correctly

command failed with code 1 signal null
   ▲ Next.js 14.2.0-canary.42

   Linting and checking validity of types ...

 ⚠ The Next.js plugin was not detected in your ESLint configuration. See https://nextjs.org/docs/basic-features/eslint#migrating-existing-config
   Creating an optimized production build ...
 ✓ Compiled successfully
   Collecting page data ...
   Generating static pages (0/7) ...
   Generating static pages (1/7) 
   Generating static pages (3/7) 

Error occurred prerendering page "/blog/post-1". Read more: https://nextjs.org/docs/messages/prerender-error

Error: Could not read from https://cdn.ampproject.org/v0/validator_wasm.js - aborted

  15 |  * See the License for the specific language governing permissions and
  16 |  * limitations under the license.
> 17 |  */const t=__nccwpck_require__(915);const r=__nccwpck_require__(147);const i=__nccwpck_require__(685);const s=__nccwpck_require__(687);const o=__nccwpck_require__(17);const a=__nccwpck_require__(642);const l=__nccwpck_require__(263);const u=__nccwpck_require__(477);const c=__nccwpck_require__(310);const h=__nccwpck_require__(837);const p=__nccwpck_require__(144);const f="amphtml-validator";function hasPrefix(e,t){return e.indexOf(t)==0}function isHttpOrHttpsUrl(e){return hasPrefix(e,"http://")||hasPrefix(e,"https://")}function readFromFile(e){return new l((function(t,n){r.readFile(e,"utf8",(function(e,r){if(e){n(e)}else{t(r.trim())}}))}))}function readFromReadable(e,t){return new l((function(n,r){const i=[];t.setEncoding("utf8");t.on("data",(function(e){i.push(e)}));t.on("end",(function(){n(i.join(""))}));t.on("error",(function(t){r(new Error("Could not read from "+e+" - "+t.message))}))}))}function readFromStdin(){return readFromReadable("stdin",process.stdin).then((function(e){process.stdin.resume();return e}))}function readFromUrl(e,t){return new l((function(n,r){const o=hasPrefix(e,"http://")?i:s;const a=o.request(e,(function(t){if(t.statusCode!==200){t.resume();r(new Error("Unable to fetch "+e+" - HTTP Status "+t.statusCode))}else{n(t)}}));a.setHeader("User-Agent",t);a.on("error",(function(t){r(new Error("Unable to fetch "+e+" - "+t.message))}));a.end()})).then(readFromReadable.bind(null,e))}function ValidationResult(){this.status="UNKNOWN";this.errors=[]}function ValidationError(){this.severity="UNKNOWN_SEVERITY";this.line=1;this.col=0;this.message="";this.specUrl=null;this.code="UNKNOWN_CODE";this.params=[]}function Validator(e){this.sandbox=p.createContext();try{new p.Script(e).runInContext(this.sandbox)}catch(e){throw new Error("Could not instantiate validator_wasm.js - "+e.message)}}Validator.prototype.init=function(){if(this.sandbox.amp.validator.init){return this.sandbox.amp.validator.init()}else{return l.resolve(undefined)}};Validator.prototype.validateString=function(e,t){const n=this.sandbox.amp.validator.validateString(e,t);const r=new ValidationResult;r.status=n.status;for(let e=0;e<n.errors.length;e++){const t=n.errors[e];const i=new ValidationError;i.severity=t.severity;i.line=t.line;i.col=t.col;i.message=this.sandbox.amp.validator.renderErrorMessage(t);i.specUrl=t.specUrl;i.code=t.code;i.params=t.params;r.errors.push(i)}return r};const m={};function getInstance(e,t){const n=e||"https://cdn.ampproject.org/v0/validator_wasm.js";const r=t||f;if(m.hasOwnProperty(n)){return l.resolve(m[n])}const i=isHttpOrHttpsUrl(n)?readFromUrl(n,r):readFromFile(n);return i.then((function(e){let t;try{t=new Validator(e)}catch(e){throw e}m[n]=t;return t})).then((function(e){return e.init().then((()=>e))}))}e.getInstance=getInstance;function newInstance(e){return new Validator(e)}e.newInstance=newInstance;function logValidationResult(e,n,r){if(n.status==="PASS"){process.stdout.write(e+": "+(r?t.green("PASS"):"PASS")+"\n")}for(let i=0;i<n.errors.length;i++){const s=n.errors[i];let o=e+":"+s.line+":"+s.col+" ";if(r){o+=(s.severity==="ERROR"?t.red:t.magenta)(s.message)}else{o+=s.message}if(s.specUrl){o+=" (see "+s.specUrl+")"}process.stderr.write(o+"\n")}}function main(){a.usage("[options] <fileOrUrlOrMinus...>\n\n"+'  Validates the files or urls provided as arguments. If "-" is\n'+"  specified, reads from stdin instead.").option("--validator_js <fileOrUrl>","The Validator Javascript.\n"+"  Latest published version by default, or\n"+"  dist/validator_minified.js (built with build.py)\n"+"  for development.","https://cdn.ampproject.org/v0/validator_wasm.js").option("--user-agent <userAgent>","User agent string to use in requests.",f).option("--html_format <AMP|AMP4ADS|AMP4EMAIL>","The input format to be validated.\n"+"  AMP by default.","AMP").option("--format <color|text|json>","How to format the output.\n"+'  "color" displays errors/warnings/success in\n'+"          red/orange/green.\n"+'  "text"  avoids color (e.g., useful in terminals not\n'+"          supporting color).\n"+'  "json"  emits json corresponding to the ValidationResult\n'+"          message in validator.proto.","color").parse(process.argv);const e=a.opts();if(e.length===0){a.outputHelp();process.exit(1)}if(e.html_format!=="AMP"&&e.html_format!=="AMP4ADS"&&e.html_format!=="AMP4EMAIL"){process.stderr.write('--html_format must be set to "AMP", "AMP4ADS", or "AMP4EMAIL".\n',(function(){process.exit(1)}))}if(e.format!=="color"&&e.format!=="text"&&e.format!=="json"){process.stderr.write('--format must be set to "color", "text", or "json".\n',(function(){process.exit(1)}))}const n=[];for(let t=0;t<a.args.length;t++){const r=a.args[t];if(r==="-"){n.push(readFromStdin())}else if(isHttpOrHttpsUrl(r)){n.push(readFromUrl(r,e.userAgent))}else{n.push(readFromFile(r))}}getInstance(e.validator_js,e.userAgent).then((function(r){l.all(n).then((function(t){const n={};let i=false;for(let s=0;s<t.length;s++){const o=r.validateString(t[s],e.html_format);if(e.format==="json"){n[a.args[s]]=o}else{logValidationResult(a.args[s],o,e.format==="color"?true:false)}if(o.status!=="PASS"){i=true}}if(e.format==="json"){process.stdout.write(JSON.stringify(n)+"\n",(function(){process.exit(i?1:0)}))}else if(i){process.stderr.write("",(function(){process.exit(1)}))}else{process.stdout.write("",(function(){process.exit(0)}))}})).catch((function(n){process.stderr.write((e.format=="color"?t.red(n.message):n.message)+"\n",(function(){process.exit(1)}))}))})).catch((function(n){process.stderr.write((e.format=="color"?t.red(n.message):n.message)+"\n",(function(){process.exit(1)}))}))}e.main=main})();module.exports=n})();
     |                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              ^

  at IncomingMessage.<anonymous> (../packages/next/dist/compiled/amphtml-validator/index.js:17:846)
     Generating static pages (5/7) 
   ✓ Generating static pages (7/7) 
  > Export encountered errors on following paths:
  	/blog/[slug]: /blog/post-1
  at ChildProcess.<anonymous> (lib/next-test-utils.ts:284:11)

● AMP SSG Support › production mode › should output prerendered files correctly during build

command failed with code 1 signal null
   ▲ Next.js 14.2.0-canary.42

   Linting and checking validity of types ...

 ⚠ The Next.js plugin was not detected in your ESLint configuration. See https://nextjs.org/docs/basic-features/eslint#migrating-existing-config
   Creating an optimized production build ...
 ✓ Compiled successfully
   Collecting page data ...
   Generating static pages (0/7) ...
   Generating static pages (1/7) 
   Generating static pages (3/7) 

Error occurred prerendering page "/blog/post-1". Read more: https://nextjs.org/docs/messages/prerender-error

Error: Could not read from https://cdn.ampproject.org/v0/validator_wasm.js - aborted

  15 |  * See the License for the specific language governing permissions and
  16 |  * limitations under the license.
> 17 |  */const t=__nccwpck_require__(915);const r=__nccwpck_require__(147);const i=__nccwpck_require__(685);const s=__nccwpck_require__(687);const o=__nccwpck_require__(17);const a=__nccwpck_require__(642);const l=__nccwpck_require__(263);const u=__nccwpck_require__(477);const c=__nccwpck_require__(310);const h=__nccwpck_require__(837);const p=__nccwpck_require__(144);const f="amphtml-validator";function hasPrefix(e,t){return e.indexOf(t)==0}function isHttpOrHttpsUrl(e){return hasPrefix(e,"http://")||hasPrefix(e,"https://")}function readFromFile(e){return new l((function(t,n){r.readFile(e,"utf8",(function(e,r){if(e){n(e)}else{t(r.trim())}}))}))}function readFromReadable(e,t){return new l((function(n,r){const i=[];t.setEncoding("utf8");t.on("data",(function(e){i.push(e)}));t.on("end",(function(){n(i.join(""))}));t.on("error",(function(t){r(new Error("Could not read from "+e+" - "+t.message))}))}))}function readFromStdin(){return readFromReadable("stdin",process.stdin).then((function(e){process.stdin.resume();return e}))}function readFromUrl(e,t){return new l((function(n,r){const o=hasPrefix(e,"http://")?i:s;const a=o.request(e,(function(t){if(t.statusCode!==200){t.resume();r(new Error("Unable to fetch "+e+" - HTTP Status "+t.statusCode))}else{n(t)}}));a.setHeader("User-Agent",t);a.on("error",(function(t){r(new Error("Unable to fetch "+e+" - "+t.message))}));a.end()})).then(readFromReadable.bind(null,e))}function ValidationResult(){this.status="UNKNOWN";this.errors=[]}function ValidationError(){this.severity="UNKNOWN_SEVERITY";this.line=1;this.col=0;this.message="";this.specUrl=null;this.code="UNKNOWN_CODE";this.params=[]}function Validator(e){this.sandbox=p.createContext();try{new p.Script(e).runInContext(this.sandbox)}catch(e){throw new Error("Could not instantiate validator_wasm.js - "+e.message)}}Validator.prototype.init=function(){if(this.sandbox.amp.validator.init){return this.sandbox.amp.validator.init()}else{return l.resolve(undefined)}};Validator.prototype.validateString=function(e,t){const n=this.sandbox.amp.validator.validateString(e,t);const r=new ValidationResult;r.status=n.status;for(let e=0;e<n.errors.length;e++){const t=n.errors[e];const i=new ValidationError;i.severity=t.severity;i.line=t.line;i.col=t.col;i.message=this.sandbox.amp.validator.renderErrorMessage(t);i.specUrl=t.specUrl;i.code=t.code;i.params=t.params;r.errors.push(i)}return r};const m={};function getInstance(e,t){const n=e||"https://cdn.ampproject.org/v0/validator_wasm.js";const r=t||f;if(m.hasOwnProperty(n)){return l.resolve(m[n])}const i=isHttpOrHttpsUrl(n)?readFromUrl(n,r):readFromFile(n);return i.then((function(e){let t;try{t=new Validator(e)}catch(e){throw e}m[n]=t;return t})).then((function(e){return e.init().then((()=>e))}))}e.getInstance=getInstance;function newInstance(e){return new Validator(e)}e.newInstance=newInstance;function logValidationResult(e,n,r){if(n.status==="PASS"){process.stdout.write(e+": "+(r?t.green("PASS"):"PASS")+"\n")}for(let i=0;i<n.errors.length;i++){const s=n.errors[i];let o=e+":"+s.line+":"+s.col+" ";if(r){o+=(s.severity==="ERROR"?t.red:t.magenta)(s.message)}else{o+=s.message}if(s.specUrl){o+=" (see "+s.specUrl+")"}process.stderr.write(o+"\n")}}function main(){a.usage("[options] <fileOrUrlOrMinus...>\n\n"+'  Validates the files or urls provided as arguments. If "-" is\n'+"  specified, reads from stdin instead.").option("--validator_js <fileOrUrl>","The Validator Javascript.\n"+"  Latest published version by default, or\n"+"  dist/validator_minified.js (built with build.py)\n"+"  for development.","https://cdn.ampproject.org/v0/validator_wasm.js").option("--user-agent <userAgent>","User agent string to use in requests.",f).option("--html_format <AMP|AMP4ADS|AMP4EMAIL>","The input format to be validated.\n"+"  AMP by default.","AMP").option("--format <color|text|json>","How to format the output.\n"+'  "color" displays errors/warnings/success in\n'+"          red/orange/green.\n"+'  "text"  avoids color (e.g., useful in terminals not\n'+"          supporting color).\n"+'  "json"  emits json corresponding to the ValidationResult\n'+"          message in validator.proto.","color").parse(process.argv);const e=a.opts();if(e.length===0){a.outputHelp();process.exit(1)}if(e.html_format!=="AMP"&&e.html_format!=="AMP4ADS"&&e.html_format!=="AMP4EMAIL"){process.stderr.write('--html_format must be set to "AMP", "AMP4ADS", or "AMP4EMAIL".\n',(function(){process.exit(1)}))}if(e.format!=="color"&&e.format!=="text"&&e.format!=="json"){process.stderr.write('--format must be set to "color", "text", or "json".\n',(function(){process.exit(1)}))}const n=[];for(let t=0;t<a.args.length;t++){const r=a.args[t];if(r==="-"){n.push(readFromStdin())}else if(isHttpOrHttpsUrl(r)){n.push(readFromUrl(r,e.userAgent))}else{n.push(readFromFile(r))}}getInstance(e.validator_js,e.userAgent).then((function(r){l.all(n).then((function(t){const n={};let i=false;for(let s=0;s<t.length;s++){const o=r.validateString(t[s],e.html_format);if(e.format==="json"){n[a.args[s]]=o}else{logValidationResult(a.args[s],o,e.format==="color"?true:false)}if(o.status!=="PASS"){i=true}}if(e.format==="json"){process.stdout.write(JSON.stringify(n)+"\n",(function(){process.exit(i?1:0)}))}else if(i){process.stderr.write("",(function(){process.exit(1)}))}else{process.stdout.write("",(function(){process.exit(0)}))}})).catch((function(n){process.stderr.write((e.format=="color"?t.red(n.message):n.message)+"\n",(function(){process.exit(1)}))}))})).catch((function(n){process.stderr.write((e.format=="color"?t.red(n.message):n.message)+"\n",(function(){process.exit(1)}))}))}e.main=main})();module.exports=n})();
     |                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              ^

  at IncomingMessage.<anonymous> (../packages/next/dist/compiled/amphtml-validator/index.js:17:846)
     Generating static pages (5/7) 
   ✓ Generating static pages (7/7) 
  > Export encountered errors on following paths:
  	/blog/[slug]: /blog/post-1
  at ChildProcess.<anonymous> (lib/next-test-utils.ts:284:11)

● AMP SSG Support › export mode › production mode › should have copied SSG files correctly

command failed with code 1 signal null
   ▲ Next.js 14.2.0-canary.42

   Linting and checking validity of types ...

 ⚠ The Next.js plugin was not detected in your ESLint configuration. See https://nextjs.org/docs/basic-features/eslint#migrating-existing-config
   Creating an optimized production build ...
 ✓ Compiled successfully
   Collecting page data ...
   Generating static pages (0/7) ...
   Generating static pages (1/7) 
   Generating static pages (3/7) 

Error occurred prerendering page "/hybrid". Read more: https://nextjs.org/docs/messages/prerender-error

Error: Could not read from https://cdn.ampproject.org/v0/validator_wasm.js - aborted

  15 |  * See the License for the specific language governing permissions and
  16 |  * limitations under the license.
> 17 |  */const t=__nccwpck_require__(915);const r=__nccwpck_require__(147);const i=__nccwpck_require__(685);const s=__nccwpck_require__(687);const o=__nccwpck_require__(17);const a=__nccwpck_require__(642);const l=__nccwpck_require__(263);const u=__nccwpck_require__(477);const c=__nccwpck_require__(310);const h=__nccwpck_require__(837);const p=__nccwpck_require__(144);const f="amphtml-validator";function hasPrefix(e,t){return e.indexOf(t)==0}function isHttpOrHttpsUrl(e){return hasPrefix(e,"http://")||hasPrefix(e,"https://")}function readFromFile(e){return new l((function(t,n){r.readFile(e,"utf8",(function(e,r){if(e){n(e)}else{t(r.trim())}}))}))}function readFromReadable(e,t){return new l((function(n,r){const i=[];t.setEncoding("utf8");t.on("data",(function(e){i.push(e)}));t.on("end",(function(){n(i.join(""))}));t.on("error",(function(t){r(new Error("Could not read from "+e+" - "+t.message))}))}))}function readFromStdin(){return readFromReadable("stdin",process.stdin).then((function(e){process.stdin.resume();return e}))}function readFromUrl(e,t){return new l((function(n,r){const o=hasPrefix(e,"http://")?i:s;const a=o.request(e,(function(t){if(t.statusCode!==200){t.resume();r(new Error("Unable to fetch "+e+" - HTTP Status "+t.statusCode))}else{n(t)}}));a.setHeader("User-Agent",t);a.on("error",(function(t){r(new Error("Unable to fetch "+e+" - "+t.message))}));a.end()})).then(readFromReadable.bind(null,e))}function ValidationResult(){this.status="UNKNOWN";this.errors=[]}function ValidationError(){this.severity="UNKNOWN_SEVERITY";this.line=1;this.col=0;this.message="";this.specUrl=null;this.code="UNKNOWN_CODE";this.params=[]}function Validator(e){this.sandbox=p.createContext();try{new p.Script(e).runInContext(this.sandbox)}catch(e){throw new Error("Could not instantiate validator_wasm.js - "+e.message)}}Validator.prototype.init=function(){if(this.sandbox.amp.validator.init){return this.sandbox.amp.validator.init()}else{return l.resolve(undefined)}};Validator.prototype.validateString=function(e,t){const n=this.sandbox.amp.validator.validateString(e,t);const r=new ValidationResult;r.status=n.status;for(let e=0;e<n.errors.length;e++){const t=n.errors[e];const i=new ValidationError;i.severity=t.severity;i.line=t.line;i.col=t.col;i.message=this.sandbox.amp.validator.renderErrorMessage(t);i.specUrl=t.specUrl;i.code=t.code;i.params=t.params;r.errors.push(i)}return r};const m={};function getInstance(e,t){const n=e||"https://cdn.ampproject.org/v0/validator_wasm.js";const r=t||f;if(m.hasOwnProperty(n)){return l.resolve(m[n])}const i=isHttpOrHttpsUrl(n)?readFromUrl(n,r):readFromFile(n);return i.then((function(e){let t;try{t=new Validator(e)}catch(e){throw e}m[n]=t;return t})).then((function(e){return e.init().then((()=>e))}))}e.getInstance=getInstance;function newInstance(e){return new Validator(e)}e.newInstance=newInstance;function logValidationResult(e,n,r){if(n.status==="PASS"){process.stdout.write(e+": "+(r?t.green("PASS"):"PASS")+"\n")}for(let i=0;i<n.errors.length;i++){const s=n.errors[i];let o=e+":"+s.line+":"+s.col+" ";if(r){o+=(s.severity==="ERROR"?t.red:t.magenta)(s.message)}else{o+=s.message}if(s.specUrl){o+=" (see "+s.specUrl+")"}process.stderr.write(o+"\n")}}function main(){a.usage("[options] <fileOrUrlOrMinus...>\n\n"+'  Validates the files or urls provided as arguments. If "-" is\n'+"  specified, reads from stdin instead.").option("--validator_js <fileOrUrl>","The Validator Javascript.\n"+"  Latest published version by default, or\n"+"  dist/validator_minified.js (built with build.py)\n"+"  for development.","https://cdn.ampproject.org/v0/validator_wasm.js").option("--user-agent <userAgent>","User agent string to use in requests.",f).option("--html_format <AMP|AMP4ADS|AMP4EMAIL>","The input format to be validated.\n"+"  AMP by default.","AMP").option("--format <color|text|json>","How to format the output.\n"+'  "color" displays errors/warnings/success in\n'+"          red/orange/green.\n"+'  "text"  avoids color (e.g., useful in terminals not\n'+"          supporting color).\n"+'  "json"  emits json corresponding to the ValidationResult\n'+"          message in validator.proto.","color").parse(process.argv);const e=a.opts();if(e.length===0){a.outputHelp();process.exit(1)}if(e.html_format!=="AMP"&&e.html_format!=="AMP4ADS"&&e.html_format!=="AMP4EMAIL"){process.stderr.write('--html_format must be set to "AMP", "AMP4ADS", or "AMP4EMAIL".\n',(function(){process.exit(1)}))}if(e.format!=="color"&&e.format!=="text"&&e.format!=="json"){process.stderr.write('--format must be set to "color", "text", or "json".\n',(function(){process.exit(1)}))}const n=[];for(let t=0;t<a.args.length;t++){const r=a.args[t];if(r==="-"){n.push(readFromStdin())}else if(isHttpOrHttpsUrl(r)){n.push(readFromUrl(r,e.userAgent))}else{n.push(readFromFile(r))}}getInstance(e.validator_js,e.userAgent).then((function(r){l.all(n).then((function(t){const n={};let i=false;for(let s=0;s<t.length;s++){const o=r.validateString(t[s],e.html_format);if(e.format==="json"){n[a.args[s]]=o}else{logValidationResult(a.args[s],o,e.format==="color"?true:false)}if(o.status!=="PASS"){i=true}}if(e.format==="json"){process.stdout.write(JSON.stringify(n)+"\n",(function(){process.exit(i?1:0)}))}else if(i){process.stderr.write("",(function(){process.exit(1)}))}else{process.stdout.write("",(function(){process.exit(0)}))}})).catch((function(n){process.stderr.write((e.format=="color"?t.red(n.message):n.message)+"\n",(function(){process.exit(1)}))}))})).catch((function(n){process.stderr.write((e.format=="color"?t.red(n.message):n.message)+"\n",(function(){process.exit(1)}))}))}e.main=main})();module.exports=n})();
     |                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              ^

  at IncomingMessage.<anonymous> (../packages/next/dist/compiled/amphtml-validator/index.js:17:846)
     Generating static pages (5/7) 
   ✓ Generating static pages (7/7) 
  > Export encountered errors on following paths:
  	/hybrid
  at ChildProcess.<anonymous> (lib/next-test-utils.ts:284:11)

Read more about building and testing Next.js in contributing.md.

pnpm test-start test/e2e/prerender.test.ts

  • Prerender > should not error when rewriting to fallback dynamic SSG page
Expand output

● Prerender › should not error when rewriting to fallback dynamic SSG page

TIMED OUT: /Post: post-100/



undefined

  636 |
  637 |   if (hardError) {
> 638 |     throw new Error('TIMED OUT: ' + regex + '\n\n' + content + '\n\n' + lastErr)
      |           ^
  639 |   }
  640 |   return false
  641 | }

  at check (lib/next-test-utils.ts:638:11)
  at Object.<anonymous> (e2e/prerender.test.ts:944:7)

Read more about building and testing Next.js in contributing.md.

@ijjk
Copy link
Member

ijjk commented Mar 21, 2024

Stats from current PR

Default Build (Increase detected ⚠️)
General Overall increase ⚠️
vercel/next.js canary grajen3/next.js perf/lazy-import-telemetry-in-standalone Change
buildDuration 14.4s 14.5s ⚠️ +170ms
buildDurationCached 7.9s 6.7s N/A
nodeModulesSize 198 MB 198 MB ⚠️ +106 B
nextStartRea..uration (ms) 445ms 406ms N/A
Client Bundles (main, webpack)
vercel/next.js canary grajen3/next.js perf/lazy-import-telemetry-in-standalone Change
2453-HASH.js gzip 30.8 kB 30.8 kB N/A
3304.HASH.js gzip 181 B 181 B
3f784ff6-HASH.js gzip 53.7 kB 53.7 kB
8299-HASH.js gzip 5.04 kB 5.04 kB N/A
framework-HASH.js gzip 45.2 kB 45.2 kB
main-app-HASH.js gzip 242 B 242 B
main-HASH.js gzip 32.2 kB 32.2 kB N/A
webpack-HASH.js gzip 1.68 kB 1.68 kB N/A
Overall change 99.3 kB 99.3 kB
Legacy Client Bundles (polyfills)
vercel/next.js canary grajen3/next.js perf/lazy-import-telemetry-in-standalone Change
polyfills-HASH.js gzip 31 kB 31 kB
Overall change 31 kB 31 kB
Client Pages
vercel/next.js canary grajen3/next.js perf/lazy-import-telemetry-in-standalone Change
_app-HASH.js gzip 196 B 197 B N/A
_error-HASH.js gzip 184 B 184 B
amp-HASH.js gzip 505 B 505 B
css-HASH.js gzip 324 B 325 B N/A
dynamic-HASH.js gzip 2.5 kB 2.5 kB N/A
edge-ssr-HASH.js gzip 258 B 258 B
head-HASH.js gzip 352 B 352 B
hooks-HASH.js gzip 370 B 371 B N/A
image-HASH.js gzip 4.21 kB 4.21 kB
index-HASH.js gzip 259 B 259 B
link-HASH.js gzip 2.67 kB 2.67 kB N/A
routerDirect..HASH.js gzip 314 B 312 B N/A
script-HASH.js gzip 386 B 386 B
withRouter-HASH.js gzip 309 B 309 B
1afbb74e6ecf..834.css gzip 106 B 106 B
Overall change 6.57 kB 6.57 kB
Client Build Manifests
vercel/next.js canary grajen3/next.js perf/lazy-import-telemetry-in-standalone Change
_buildManifest.js gzip 481 B 484 B N/A
Overall change 0 B 0 B
Rendered Page Sizes
vercel/next.js canary grajen3/next.js perf/lazy-import-telemetry-in-standalone Change
index.html gzip 529 B 529 B
link.html gzip 541 B 541 B
withRouter.html gzip 523 B 523 B
Overall change 1.59 kB 1.59 kB
Edge SSR bundle Size
vercel/next.js canary grajen3/next.js perf/lazy-import-telemetry-in-standalone Change
edge-ssr.js gzip 95.3 kB 95.3 kB N/A
page.js gzip 3.04 kB 3.04 kB N/A
Overall change 0 B 0 B
Middleware size
vercel/next.js canary grajen3/next.js perf/lazy-import-telemetry-in-standalone Change
middleware-b..fest.js gzip 625 B 626 B N/A
middleware-r..fest.js gzip 151 B 151 B
middleware.js gzip 25.5 kB 25.5 kB N/A
edge-runtime..pack.js gzip 839 B 839 B
Overall change 990 B 990 B
Next Runtimes
vercel/next.js canary grajen3/next.js perf/lazy-import-telemetry-in-standalone Change
app-page-exp...dev.js gzip 170 kB 170 kB
app-page-exp..prod.js gzip 96.8 kB 96.8 kB
app-page-tur..prod.js gzip 98.5 kB 98.5 kB
app-page-tur..prod.js gzip 92.8 kB 92.8 kB
app-page.run...dev.js gzip 144 kB 144 kB
app-page.run..prod.js gzip 91.3 kB 91.3 kB
app-route-ex...dev.js gzip 21.4 kB 21.4 kB
app-route-ex..prod.js gzip 15.1 kB 15.1 kB
app-route-tu..prod.js gzip 15.1 kB 15.1 kB
app-route-tu..prod.js gzip 14.8 kB 14.8 kB
app-route.ru...dev.js gzip 21 kB 21 kB
app-route.ru..prod.js gzip 14.8 kB 14.8 kB
pages-api-tu..prod.js gzip 9.55 kB 9.55 kB
pages-api.ru...dev.js gzip 9.82 kB 9.82 kB
pages-api.ru..prod.js gzip 9.55 kB 9.55 kB
pages-turbo...prod.js gzip 22.5 kB 22.5 kB
pages.runtim...dev.js gzip 23.1 kB 23.1 kB
pages.runtim..prod.js gzip 22.4 kB 22.4 kB
server.runti..prod.js gzip 50.9 kB 50.9 kB
Overall change 943 kB 943 kB
build cache Overall increase ⚠️
vercel/next.js canary grajen3/next.js perf/lazy-import-telemetry-in-standalone Change
0.pack gzip 1.56 MB 1.57 MB ⚠️ +412 B
index.pack gzip 106 kB 105 kB N/A
Overall change 1.56 MB 1.57 MB ⚠️ +412 B
Diff details
Diff for middleware.js

Diff too large to display

Commit: 01ea276

@grajen3
Copy link
Contributor Author

grajen3 commented Mar 22, 2024

Those tests that are reported as failing are passing at least locally - are those perhaps flaky?

 PASS  test/integration/app-dir-export/test/dynamicpage-prod.test.ts (78.431 s)
  app dir - with output export - dynamic api route prod
    production mode
      ✓ should work in prod with dynamicPage undefined (22818 ms)
      ✓ should work in prod with dynamicPage 'error' (21973 ms)
      ✓ should work in prod with dynamicPage 'force-static' (21981 ms)
      ✓ should work in prod with dynamicPage 'force-dynamic' (11257 ms)

Test Suites: 1 passed, 1 total
Tests:       4 passed, 4 total
Snapshots:   0 total
Time:        78.462 s
Ran all test suites matching /test\/integration\/app-dir-export\/test\/dynamicpage-prod.test.ts/i.
misiek@dellek:~/dev/next.js$ git show HEAD
commit d1a572810e117ec43e41092c8a5c708aa481e518 (HEAD -> perf/lazy-import-telemetry-in-standalone, origin/perf/lazy-import-telemetry-in-standalone)
Merge: d1a510b996 7de7cbf283
Author: JJ Kasper <jj@jjsweb.site>
Date:   Thu Mar 21 12:32:25 2024 -0700

    Merge branch 'canary' into perf/lazy-import-telemetry-in-standalone

@ijjk ijjk enabled auto-merge (squash) March 25, 2024 17:05
@ijjk ijjk merged commit 043bbaa into vercel:canary Mar 25, 2024
71 checks passed
@remorses
Copy link
Contributor

Awesome! I wonder if there are more opportunities like this to improve cold start performance

@grajen3
Copy link
Contributor Author

grajen3 commented Mar 26, 2024

@remorses

Awesome! I wonder if there are more opportunities like this to improve cold start performance

From time spent on importing

  14ms node_modules/next/dist/compiled/watchpack/watchpack.js

also caught my attention as something that doesn't seem like it would be needed to run production server (this seems more like something for dev server to watch source files and recompile them when users make edits), but this one had much smaller cost so I didn't yet look into it as I do have other opportunities to look into first (more on my side of things than Next.js) - but maybe this is something someone else can look into as well?

This changed just seemed like real low hanging fruit

Of course there is also whole other part which is actual initialization of the server (after it is imported) that could be profiled? I did see open-telemetry instrumentation across Next.js codebase as well, so potentially that could yield some insights that would be easier to read than something like CPU profile

@grajen3 grajen3 deleted the perf/lazy-import-telemetry-in-standalone branch March 26, 2024 12:43
@github-actions github-actions bot locked as resolved and limited conversation to collaborators Apr 10, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants