NextJs 如何按服务端或浏览器端的类型分别打包
侧边栏壁纸
  • 累计撰写 1,061 篇文章
  • 累计收到 0 条评论

NextJs 如何按服务端或浏览器端的类型分别打包

加速器之家
2024-10-20 / 0 评论 / 5 阅读 / 正在检测是否收录...

NextJs 是一款优秀的 react 同构直出框架,写一次代码,能够同时在服务端和浏览器端。这是因为 NextJs 会在服务端和浏览器分别打包一份,然后通过数据进行互通。

吃瓜中

可是若一些模块只能在浏览器端使用,或只能在服务端使用,该怎么办呢?

1. 只在浏览器端使用的模块 #

例如@fingerprintjs/fingerprintjs组件,在 3.0.3 版本及之前,若在 NextJs 中引用时,会直接报错。这是我之前提的 issue:https://github.com/fingerprintjs/fingerprintjs/issues/602

例如:

import FingerprintJS from '@fingerprintjs/fingerprintjs';

useEffect(() => {
  FingerprintJS.load();
}, []);

会提示 window 变量不存在的错误:

ReferenceError: window is not defined

这是因为,在 FingerprintJS 模块中,直接调用了 window 变量,而 window 变量只有在浏览器端才有。因此,引用模块后,啥也没干,就已经报错了。

解决方案,就是使用 import 异步引入:

useEffect(() => {
  // 这里是浏览器的环境
  import('@fingerprintjs/fingerprintjs')
    .then((FingerprintJS) => FingerprintJS.load())
    .then((fp) => fp.get())
    .then((result) => console.log(result.visitorId));
}, []);

这里也仅仅是用 FingerprintJS 模块来举个例子,不过该模块已经从 3.0.6 版本开始解决这个问题了。它会在调用 load 方法时,才会去引用 window 变量。

小细节 大成功

2. 只在服务端使用的模块 #

某组件 A 引用了 net 模块、stream 模块等只有在服务端才有的模块,这些模块就只能在服务端使用。

若直接 import 的话,NextJs 也会在浏览器端打包一份,但这个组件在浏览器端又无法使用。

我们公司一个很有名的名字服务-北极星模块,一个只在服务端使用的模块。开发的过程中,是没有感觉的,但打包时就会提示找不到模块:

找不到net模块

有两种解决方案。

2.1 只在 server 端引用 #

NextJs 可以自定义 sever 文件,自定义 server 的文档:https://nextjs.org/docs/advanced-features/custom-server

如果可以的话,我们把代码逻辑引导 sever 文件中。

// server.js
const { createServer } = require('http');
const { parse } = require('url');
const next = require('next');
const Polaris = require('@tencent/polaris'); // 服务模块在这里引用,就可以了

const dev = process.env.NODE_ENV !== 'production';
const app = next({ dev });
const handle = app.getRequestHandler();

app.prepare().then(() => {
  createServer((req, res) => {
    // Be sure to pass `true` as the second argument to `url.parse`.
    // This tells it to parse the query portion of the URL.
    const parsedUrl = parse(req.url, true);
    const { pathname, query } = parsedUrl;

    if (pathname === '/a') {
      console.log(Polaris);
      app.render(req, res, '/a', query);
    } else if (pathname === '/b') {
      app.render(req, res, '/b', query);
    } else {
      handle(req, res, parsedUrl);
    }
  }).listen(3000, (err) => {
    if (err) throw err;
    console.log('> Ready on http://localhost:3000');
  });
});

server.js 本身就是服务端的文件,它不会通过 NextJs 的打包系统引入到浏览器端。

2.2 在服务侧按需引入 #

若不方便将代码执行路径引导到服务端的文件。我们可以在服务侧按需引入,然后在 next.config.js 中配置不要打包到浏览器端。

export default function App {

};

export async function getStaticProps() {
  const Polaris = require('@tencent/polaris');
  console.log(Polaris);
  return {};
}

getStaticProps()方法在 NextJs 中,就是服务端运行的方法。我们在这里面使用require()来按需引入。

接着在 next.config.js 中:

const withAntdLess = require('next-plugin-antd-less');

module.exports = (phase) =>
  withAntdLess({
    webpack: (cfg, { isServer, webpack }) => {
      const config = cfg;

      if (!isServer) {
        // 在浏览器端,忽略这些模块的打包
        const ignoreList = ['@tencent\\/polaris', 'dns', 'dotenv'];
        ignoreList.forEach((n) => {
          config.plugins.push(new webpack.IgnorePlugin({ resourceRegExp: new RegExp(n) }));
        });
      }

      return config;
    },
  });

在浏览器端,忽略这些模块的打包。

nice

3. 总结 #

NextJs 是一个在服务端和浏览器都可以运行的 react 框架,我们在使用的使用要特别注意有哪些是只能在客户端使用,哪些是只能在服务端使用。

0

评论

博主关闭了当前页面的评论