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

蚊子前端博客
发布于 2021-08-12 17:33
若一些模块只能在浏览器端使用,或只能在服务端使用,在NextJs中该怎么引用呢?

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

吃瓜中-蚊子的前端博客

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

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

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

例如:

COPYJAVASCRIPT

import FingerprintJS from '@fingerprintjs/fingerprintjs'; useEffect(() => { FingerprintJS.load(); }, []);

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

ReferenceError: window is not defined

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

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

COPYJAVASCRIPT

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 文件中。

COPYJAVASCRIPT

// 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 中配置不要打包到浏览器端。

COPYJAVASCRIPT

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

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

接着在 next.config.js 中:

COPYJAVASCRIPT

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 框架,我们在使用的使用要特别注意有哪些是只能在客户端使用,哪些是只能在服务端使用。

标签:
阅读(1472)

公众号:

qrcode

微信公众号:前端小茶馆