3

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

 3 years ago
source link: https://www.xiabingbao.com/post/react/nextjs-server-client-build-qxpzwi.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client
若一些模块只能在浏览器端使用,或只能在服务端使用,在NextJs中该怎么引用呢?

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-蚊子的前端博客

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


Recommend

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK