vercel / next.js

The React Framework
https://nextjs.org
MIT License
124.73k stars 26.62k forks source link

PGLite: 'import', and 'export' cannot be used outside of module code #65361

Open Neo-Ciber94 opened 4 months ago

Neo-Ciber94 commented 4 months ago

Link to the code that reproduces this issue

https://github.com/Neo-Ciber94/pglite-next-bug

To Reproduce

You can just clone the repo for reproduction, install dependencies and try build.

  1. Create a nextjs project 14
  2. Install @electric-sql/pglite
  3. Replace your page.tsx with this query, that just query the time:
    
    "use client";

import { PGlite } from "@electric-sql/pglite"; import { useEffect, useRef, useState } from "react";

export default function HomePage() { const db = useRef(); const [data, setData] = useState("PENDING");

useEffect(() => { if (db.current) { return; }

(async () => {
  db.current = new PGlite();
  const result = await db.current.query("SELECT NOW()");
  setData(result);
})();

}, []);

return (

PGlite

{JSON.stringify(data, null, 2)}

); }


4. Update your `next.config`, the package uses `fs` and `module` import for `nodejs` but those are not used on the client.

```js
/** @type {import('next').NextConfig} */
const nextConfig = {
  webpack: (config, options) => {
    if (!options.isServer) {
      config.resolve.fallback = { fs: false, module: false, path: false };
    }

    return config;
  },
  transpilePackages: ["@electric-sql/pglite"],
};

export default nextConfig;
  1. Try to build the project, npm run build, you will recieve this error:
static/media/index.a7d43220.js from Terser
  x 'import', and 'export' cannot be used outside of module code
   ,-[1:1]
 1 | import { a, b, c, d, e, f } from "./chunk-OVRU7FYL.js";
   : ^^^^^^
 2 | import "./chunk-EKNQE2HU.js";
 3 | export { a as Mutex, d as PGlite, e as messages, c as parse, f as protocol, b as types }; //# sourceMappingURL=index.js.map
   `----

Caused by:
    0: failed to parse input file
    1: Syntax Error
Error:
  x 'import', and 'export' cannot be used outside of module code
   ,-[1:1]
 1 | import { a, b, c, d, e, f } from "./chunk-OVRU7FYL.js";
   : ^^^^^^
 2 | import "./chunk-EKNQE2HU.js";
 3 | export { a as Mutex, d as PGlite, e as messages, c as parse, f as protocol, b as types }; //# sourceMappingURL=index.js.map
   `----

Caused by:
    0: failed to parse input file
    1: Syntax Error

> Build failed because of webpack errors

Current vs. Expected behavior

It should just bundle the @electric-sql/pglite without problems

Provide environment information

Operating System:
  Platform: win32
  Arch: x64
  Version: Windows 11 Home
  Available memory (MB): 16259
  Available CPU cores: 8
Binaries:
  Node: 20.11.1
  npm: N/A
  Yarn: N/A
  pnpm: N/A
Relevant Packages:
  next: 14.2.3 // Latest available version is detected (14.2.3).
  eslint-config-next: N/A
  react: 18.3.1
  react-dom: 18.3.1
  typescript: 5.4.5
Next.js Config:
  output: N/A

Which area(s) are affected? (Select all that apply)

Module Resolution, Webpack

Which stage(s) are affected? (Select all that apply)

next build (local)

Additional context

I used next 14.2.3, the lib @electric-sql/pglite only exports esm and is already minified.

Neo-Ciber94 commented 3 months ago

I found out nextjs is unable to resolve the location of @electric-sql/pglite maybe because is a monorepo.

Adding a loader that transpile the package its working for me

/** @type {import('next').NextConfig} */
let nextConfig = {
  images: {},
  webpack: (config, options) => {
    config.module.rules.push({
      test: /\.+(js|jsx|mjs|ts|tsx)$/,
      use: options.defaultLoaders.babel,
      include: fileURLToPath(import.meta.resolve("@electric-sql/pglite")),
      type: "javascript/auto",
    });

    if (!options.isServer) {
      config.resolve.fallback = { fs: false, module: false, path: false };
    }

    return config;
  },
  transpilePackages: [],
};
prananta commented 1 month ago

I found out nextjs is unable to resolve the location of @electric-sql/pglite maybe because is a monorepo.

Adding a loader that transpile the package its working for me

/** @type {import('next').NextConfig} */
let nextConfig = {
  images: {},
  webpack: (config, options) => {
    config.module.rules.push({
      test: /\.+(js|jsx|mjs|ts|tsx)$/,
      use: options.defaultLoaders.babel,
      include: fileURLToPath(import.meta.resolve("@electric-sql/pglite")),
      type: "javascript/auto",
    });

    if (!options.isServer) {
      config.resolve.fallback = { fs: false, module: false, path: false };
    }

    return config;
  },
  transpilePackages: [],
};

I tried this and worked in dev but not building. same error. any ideas?

zelief commented 2 weeks ago

@prananta I use pglite-react and pglite-repl. The solution above didn't work.

I am able to fix the build error by adding these options to next-config.js

const nextConfig = {
  swcMinify: false,
  transpilePackages: [
    '@electric-sql/pglite-react',
    '@electric-sql/pglite-repl',
    '@electric-sql/pglite',
  ],
}

Notes: I must delete .next folder before build or it will error again rm -rf .next

If a similar error occurs, try removing the packages and add again

wzulfikar commented 1 week ago

Thanks @zelief! I noticed I only needed the swcMinify: false (i.e. it can work without transpilePackages). FWIW, I use bun v1.1.21 with next v14.2.6.

It shows warning that this approach won't work in the next major version, but at least it works for now.

image
thebergamo commented 1 week ago

For me what helped was adding it as part of the experimental serverComponentsExternalPackages

...
experimental: {
    serverComponentsExternalPackages: ['@electric-sql/pglite'],
},
...