nextjs + react + antd 冲突错误解决方案

1、使用了 antd-mobile 并且需要对它进行按需加载,下面是官方的文档,推荐我们使用 babel-plugin-import。


2、按照 nextjs 官方文档我们在 .babelrc 中添加插件

{
    "presets": ["next/babel"],
    "plugins": [
        ["import", { "libraryName": "antd-mobile", "style": true }]
    ]
}

可当我运行的时候报错了,报错如下。最开始感到奇怪,我并没有引入这个包,后来发现其实是 antd-mobile 中有引入它。但是为什么会报错呢, 便想到应该是 webpack loader 的问题,我认为是 loader 排除了node_modules。(这里解释一下,node_modules 中的包本应该都是打包好的,但是一些情况下,我们是直接引入源代码中的模块的,那这样的话我们就需要让我们的 loader 解析 node_modules 中的代码,然而有些默认配置就是排除了 node_modules 的,这样就会导致无法解析)。


3、后来我终于想清楚了,首先 next-transpile-modules 的目的就是让 node_modules 中的包可以使用 next-babel-loader ,它的文档第一句就是这个意思,我当时理解错误了。

其次我们再来说说 webpack.externals 这个配置,比如 nextjs 默认就是如下这样配置的,它把 node_modules 下的 js 作为一个公共的js来处理,当这样配置以后,webpack 就不会去分析 node_modules 下的 js 的依赖了。


比如我自己在 node_modules 里写一个文件夹 @test,里面是一个 index.js,index.js require了同级的 b.js,然后我们在 nextjs 的项目代码里引入 @test/index.js ,编译时就会报错,报错的行就在 require('b.js') 这里。

再来说说 next-transpile-modules, 它做了两个事情,第一是从 nextjs 默认的 externals 中,排除掉我们定义的 transpileModules: ["antd-mobile"],这样 antd-mobile 中的 js 就会被 webpack 正常解析依赖了。而后新建了一个 next-babel-loader ,include 的值是 transpileModules 配置的 ["antd-mobile"]。 由于我们的 antd-mobile 中的代码不需要被 next-babel-loader 解析,甚至如果使用 next-babel-loader 解析就会报错,因此我前面的配置把它添加的 loader 的 include 给清空了,这样所有的配置就 ok 了。因此我们只需要它其中的 externals 功能,ok, next.config.js 最终代码如下( .babelrc 参照上面不变)

const withLess = require("@zeit/next-less");
const withCss = require("@zeit/next-css");
const withPlugins = require("next-compose-plugins");
const cssLoaderGetLocalIdent = require("css-loader/lib/getLocalIdent.js");
const path = require('path');

module.exports = withPlugins([withLess, withCss], {
    cssModules: true,
    cssLoaderOptions: {
        camelCase: true,
        localIdentName: "[local]___[hash:base64:5]",
        getLocalIdent: (context, localIdentName, localName, options) => {
            let hz = context.resourcePath.replace(context.rootContext, "");
            if (/node_modules/.test(hz)) {
                return localName;
            } else {
                return cssLoaderGetLocalIdent(
                    context,
                    localIdentName,
                    localName,
                    options
                );
            }
        }
    },
    webpack(config) {
        if (config.externals) {
            const includes = [/antd-mobile/];
            config.externals = config.externals.map(external => {
                if (typeof external !== 'function') return external;
                return (ctx, req, cb) => {
                    return includes.find(include =>
                        req.startsWith('.')
                            ? include.test(path.resolve(ctx, req))
                            : include.test(req)
                    )
                        ? cb()
                        : external(ctx, req, cb);
                };
            });
        }
        return config;
    }
});

注意:参考子慕大诗人博——完美融合nextjs和antd

你可能感兴趣的:(nextjs + react + antd 冲突错误解决方案)