next.js/packages/next/src/server/require-hook.ts
require-hook.ts87 lines2.7 KB
// Synchronously inject a require hook for webpack and webpack/. It's required to use the internal ncc webpack version.
// This is needed for userland plugins to attach to the same webpack instance as Next.js'.
// Individually compiled modules are as defined for the compilation in bundles/webpack/packages/*.

// This module will only be loaded once per process.
const path = require('path') as typeof import('path')
const mod = require('module') as typeof import('module')
const originalRequire = mod.prototype.require
const resolveFilename =
  // @ts-expect-error
  mod._resolveFilename

let resolve: typeof require.resolve = process.env.NEXT_MINIMAL
  ? // @ts-ignore
    __non_webpack_require__.resolve
  : require.resolve

export const hookPropertyMap = new Map()

export const defaultOverrides: Record<string, string> = {}

try {
  Object.assign(defaultOverrides, {
    'styled-jsx': path.dirname(resolve('styled-jsx/package.json')),
    'styled-jsx/style': resolve('styled-jsx/style'),
    'styled-jsx/style.js': resolve('styled-jsx/style'),
  })
} catch (_) {}

const toResolveMap = (map: Record<string, string>): [string, string][] => {
  const resolveMap: [string, string][] = []
  for (const [key, value] of Object.entries(map)) {
    try {
      resolveMap.push([key, resolve(value)])
    } catch {}
  }
  return resolveMap
}

export function addHookAliases(aliases: [string, string][] = []) {
  for (const [key, value] of aliases) {
    hookPropertyMap.set(key, value)
  }
}

addHookAliases(toResolveMap(defaultOverrides))

// @ts-expect-error
mod._resolveFilename = function (
  originalResolveFilename: (
    request: string,
    parent: string,
    isMain: boolean,
    opts: any
  ) => string,
  requestMap: Map<string, string>,
  request: string,
  parent: string,
  isMain: boolean,
  options: any
) {
  const hookResolved = requestMap.get(request)
  if (hookResolved) request = hookResolved

  return originalResolveFilename.call(mod, request, parent, isMain, options)

  // We use `bind` here to avoid referencing outside variables to create potential memory leaks.
}.bind(null, resolveFilename, hookPropertyMap)

// @ts-expect-error
// This is a hack to make sure that if a user requires a Next.js module that wasn't bundled
// that needs to point to the rendering runtime version, it will point to the correct one.
// This can happen on `pages` when a user requires a dependency that uses next/image for example.
mod.prototype.require = function (request: string) {
  if (request.endsWith('.shared-runtime')) {
    return originalRequire.call(
      this,
      `next/dist/server/route-modules/pages/vendored/contexts/${path.basename(
        request,
        '.shared-runtime'
      )}`
    )
  }

  return originalRequire.call(this, request)
}
Quest for Codev2.0.0
/
SIGN IN