next.js icon indicating copy to clipboard operation
next.js copied to clipboard

Object.defineProperty called on non-object when importing an ESM module built with Webpack

Open ljwagerfield opened this issue 1 year ago • 1 comments

Verify canary release

  • [X] I verified that the issue exists in the latest Next.js canary release

Provide environment information

Operating System:
      Platform: darwin
      Arch: x64
      Version: Darwin Kernel Version 22.4.0: Mon Mar  6 21:00:17 PST 2023; root:xnu-8796.101.5~3/RELEASE_X86_64
    Binaries:
      Node: 16.19.0
      npm: 8.19.3
      Yarn: 1.22.4
      pnpm: N/A
    Relevant Packages:
      next: 13.4.10-canary.3
      eslint-config-next: 13.4.9
      react: 18.2.0
      react-dom: 18.2.0
      typescript: 5.1.6
    Next.js Config:
      output: N/A

Which area(s) of Next.js are affected? (leave empty if unsure)

Package manager (npm, pnpm, Yarn), SWC transpilation

Link to the code that reproduces this issue or a replay of the bug

https://github.com/ljwagerfield/next-webpack-incompatibility-bug

To Reproduce

test.ts

const __webpack_exports__ = {}; // This appears in libraries built with Webpack.
const __webpack_exports__example = "hello world";
export { __webpack_exports__example as ExampleExport };

page.tsx

import { ExampleExport } from "./test";

console.log(ExampleExport)

result

- error Error [ReferenceError]: Cannot access '__webpack_exports__' before initialization

Describe the Bug

If your code declares the following:

const __webpack_exports__ = {};

Then Next will behave erroneously -- reporting one of the following errors -- depending on the surrounding code:

- error Error [ReferenceError]: Cannot access '__webpack_exports__' before initialization
- error Error [TypeError]: Object.defineProperty called on non-object
    at Function.defineProperty (<anonymous>)
    at Function.__webpack_require__.r (/Users/lawrence/Downloads/next-sandbox/my-app/.next/server/webpack-runtime.js:141:21)

In some situations, the error is swallowed:

- error src/app/page.tsx (5:22) @ eval
- error Error [ReferenceError]: FooBar is not defined
    at eval (webpack-internal:///(sc_server)/./src/app/page.tsx:11:23)
    at Object.(sc_server)/./src/app/page.tsx (/Users/lawrence/Downloads/next-sandbox/my-app/.next/server/app/page.js:2339:1)
    at Function.__webpack_require__ (/Users/lawrence/Downloads/next-sandbox/my-app/.next/server/webpack-runtime.js:33:42)

(I get the above error when importing an ESM module that internally declares __webpack_exports__, as it's built with Webpack. The ESM module silently fails to initialize, so you only receive the above error when trying to import it.)

Expected Behavior

External modules built with Webpack (that contain __webpack_exports__ and any other Webpack artifacts) should work when imported into a Next.js project.

Which browser are you using? (if relevant)

No response

How are you deploying your application? (if relevant)

No response

NEXT-1430

ljwagerfield avatar Jul 11 '23 10:07 ljwagerfield

A very brittle workaround to getting Webpack-built libraries working in a Next.js app - assuming you're the author of the library - is to find/replace the bundled library code as so:

Find Replace
__webpack_ __foobar_
module foobar

I've found this works, although it's obviously very brittle: the find/replace on module is the most terrifying part, as it's quite possible the term module might appear in your code's public interface, and doing this would break it 😬

Ultimately it seems Next.js should be escaping these terms, or otherwise scoping/isolating modules, such that it doesn't matter which variable names library authors use in their code.

ljwagerfield avatar Jul 11 '23 13:07 ljwagerfield