NextJs 是一款优秀的 react 同构直出框架,写一次代码,能够同时在服务端和浏览器端。这是因为 NextJs 会在服务端和浏览器分别打包一份,然后通过数据进行互通。 可是若一些模块只能在浏览器端使用,或只能在服务端使用,该怎么办呢? 例如 例如: 会提示 window 变量不存在的错误: ReferenceError: window is not defined 这是因为,在 FingerprintJS 模块中,直接调用了 window 变量,而 window 变量只有在浏览器端才有。因此,引用模块后,啥也没干,就已经报错了。 解决方案,就是使用 import 异步引入: 这里也仅仅是用 FingerprintJS 模块来举个例子,不过该模块已经从 3.0.6 版本开始解决这个问题了。它会在调用 load 方法时,才会去引用 window 变量。 某组件 A 引用了 net 模块、stream 模块等只有在服务端才有的模块,这些模块就只能在服务端使用。 若直接 import 的话,NextJs 也会在浏览器端打包一份,但这个组件在浏览器端又无法使用。 我们公司一个很有名的名字服务-北极星模块,一个只在服务端使用的模块。开发的过程中,是没有感觉的,但打包时就会提示找不到模块: 有两种解决方案。 NextJs 可以自定义 sever 文件,自定义 server 的文档:https://nextjs.org/docs/advanced-features/custom-server。 如果可以的话,我们把代码逻辑引导 sever 文件中。 server.js 本身就是服务端的文件,它不会通过 NextJs 的打包系统引入到浏览器端。 若不方便将代码执行路径引导到服务端的文件。我们可以在服务侧按需引入,然后在 next.config.js 中配置不要打包到浏览器端。 接着在 next.config.js 中: 在浏览器端,忽略这些模块的打包。 NextJs 是一个在服务端和浏览器都可以运行的 react 框架,我们在使用的使用要特别注意有哪些是只能在客户端使用,哪些是只能在服务端使用。1. 只在浏览器端使用的模块 #
@fingerprintjs/fingerprintjs
组件,在 3.0.3 版本及之前,若在 NextJs 中引用时,会直接报错。这是我之前提的 issue:https://github.com/fingerprintjs/fingerprintjs/issues/602。import FingerprintJS from '@fingerprintjs/fingerprintjs';
useEffect(() => {
FingerprintJS.load();
}, []);
useEffect(() => {
// 这里是浏览器的环境
import('@fingerprintjs/fingerprintjs')
.then((FingerprintJS) => FingerprintJS.load())
.then((fp) => fp.get())
.then((result) => console.log(result.visitorId));
}, []);
2. 只在服务端使用的模块 #
2.1 只在 server 端引用 #
// 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');
});
});
2.2 在服务侧按需引入 #
export default function App {
};
export async function getStaticProps() {
const Polaris = require('@tencent/polaris');
console.log(Polaris);
return {};
}
getStaticProps()
方法在 NextJs 中,就是服务端运行的方法。我们在这里面使用require()
来按需引入。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;
},
});
3. 总结 #
版权属于:
加速器之家
作品采用:
《
署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0)
》许可协议授权
评论