antvis / LarkMap

A React toolkit for geospatial visualization based on L7.
https://larkmap.antv.antgroup.com
MIT License
73 stars 29 forks source link

🐛 [BUG] Error when used with Next.js #233

Open Chen-Zhihui opened 3 months ago

Chen-Zhihui commented 3 months ago

🐛 Bug description [Please make everyone to understand it]

Please provide a link by forking these links LarkMap or GitHub repo, a minimal reproduction.


"use client"
import type { LarkMapProps } from '@antv/larkmap';
import { LarkMap } from '@antv/larkmap';
import React from 'react';

const config: LarkMapProps = { mapType: 'Gaode', mapOptions: { style: 'light', center: [120.210792, 30.246026], zoom: 9, // token: '你申请的 Key', }, };

export default function L7Map() { return ( <LarkMap {...config} style={{ height: '300px' }}> <h2 style={{ position: 'absolute', left: '10px' }}>LarkMap ) }

### 📷 Step to reproduce
next.config.js
```js
const webpack = require('webpack');
const withLess = require('next-with-less');

const nextConfig = {
    reactStrictMode: true,
    webpack: config => {
      config.plugins.push(
        new webpack.DefinePlugin({
          CESIUM_BASE_URL: JSON.stringify('cesium'),
        }),
      );
      return config;
    },
    // experimental: true
    experimental : {
      esmExternals: 'loose',
    }
}

module.exports = withLess(nextConfig)

Error message reported by Next.js

- error ./node_modules/@antv/larkmap/es/components/ContextMenu/index.less
Global CSS cannot be imported from within node_modules.
Read more: https://nextjs.org/docs/messages/css-npm
Location: node_modules\@antv\larkmap\es\components\ContextMenu\index.js

🏞 Expected result

🚑 Any additional [like screenshots]

asgomda commented 3 months ago

Currently facing a similar problem with NextJS even when I update the config file to use less-loader.

/** @type {import('next').NextConfig} */
import { createRequire } from "module";
const require = createRequire(import.meta.url);

const nextConfig = {
    webpack(config, { isServer }) {
        config.module.rules.push(
            {
                test: /\.css$/,
                use: ["style-loader", "css-loader"],
            },
            {
                test: /\.less$/,
                use: [
                    "style-loader",
                    "css-loader",
                    {
                        loader: "less-loader",
                        options: {
                            lessOptions: {
                                javascriptEnabled: true,
                            },
                        },
                    },
                ],
            }
        );

        return config;
    },
};

export default nextConfig;
andybuibui commented 3 months ago

https://github.com/vercel/next.js/issues/19936

asgomda commented 3 months ago

For anyone having this issue here are the steps I used to resolve it for NextJS 14.2.3

  1. Add less-loader support since the Larkmap package requires it
    • Install the required packages npm install next-compose-plugins next-with-less
    • Modify the nextjs.config.mjs or nextjs.config.js file
      
      import withPlugins from "next-compose-plugins";;
      import withLess from "next-with-less";
      /** @type {import('next').NextConfig} */

const plugins = [ [ withLess, { lessLoaderOptions: {}, }, ], ];

export default withPlugins(plugins, { reactStrictMode: true, swcMinify: true, });

Note: Use _require_ and _module.exports_ instead of _import_ and _export default_ if your _next.config_ file has the extension _.js_ (ie not an ES module)

2. After the first step, you will get an error which says:
``` ./node_modules/@antv/larkmap/es/components/ContextMenu/index.less
Global CSS cannot be imported from within node_modules.
Read more: https://nextjs.org/docs/messages/css-npm
Location: node_modules/@antv/larkmap/es/components/ContextMenu/index.js

import withPlugins from "next-compose-plugins";
import removeImports from "next-remove-imports";
import withLess from "next-with-less";

/** @type {import('next').NextConfig} */

const removeImportsF = removeImports({
    test: /node_modules([\s\S]*?)\.(tsx|ts|js|mjs|jsx)$/,
    matchImports: "\\.(less|css|scss|sass|styl)$",
});

const nextConfig = {};
const plugins = [
    [
        withLess,
        {
            lessLoaderOptions: {},
        },
    ],
];

export default withPlugins(plugins, removeImportsF(nextConfig), {
    reactStrictMode: true,
    swcMinify: true,
});

Note: use require and module.exports if your config file is next.config.js

  1. After the second step, you might get an error that says:
    ReferenceError: document is not defined
    at __webpack_require__ (/Users/gomda/Desktop/web_graph/city-map/.next/server/webpack-runtime.js:33:43)

    This issue arises because LarkMap is a client component and cannot be server-side rendered. To solve this issue, you have to dynamically import the LarkMap component at runtime.

const config: LarkMapProps = { mapType: "Mapbox", // using mapbox here mapOptions: { style: "light", center: [120.210792, 30.246026], zoom: 9, token: "Your Map token", // token from the map library }, }; const LarkmapGlobe = () => { return ( <LarkMap {...config} className="h-9/10" style={{ width: "100vw", height: "100vh" }}

<h2 style={{ position: "absolute", left: "10px" }}>LarkMap ); };

export default LarkmapGlobe;


- Dynamically import the component into your page.tsx in your app

"use client"; import type { LarkMapProps } from "@antv/larkmap"; import { LarkMap } from "@antv/larkmap"; import dynamic from "next/dynamic"; import * as React from "react";

const Map = dynamic(() => import("@/components/trajectory/larkmap"), { ssr: false, loading: () =>

Loading ...
, });

const Larkmap = () => { return (

);

};

export default Larkmap;



Thats it! The map should now show with no errors.