最小的可重现示例
一个简洁的最小示例将有利于 Webpack 初学者,因为基于使用的自动拆分是如此令人兴奋的魔法。
工作你好世界基线:
pages/index.js
// Client + server code.
export default function IndexPage(props) {
return <div>{props.msg}</div>
}
// Server-only code.
export function getStaticProps() {
return { props: { msg: 'hello world' } }
}
package.json
{
"name": "test",
"version": "1.0.0",
"scripts": {
"dev": "next",
"build": "next build",
"start": "next start"
},
"dependencies": {
"next": "12.0.7",
"react": "17.0.2",
"react-dom": "17.0.2"
}
}
运行:
npm install
npm run dev
现在让我们添加一个虚拟require('fs') 来炸毁它:
// Client + server code.
export default function IndexPage(props) {
return <div>{props.msg}</div>
}
// Server-only code.
const fs = require('fs')
export function getStaticProps() {
return { props: { msg: 'hello world' } }
}
失败:
Module not found: Can't resolve 'fs'
这并不奇怪,因为 Next.js 无法知道 fs 只是服务器,我们不希望它只是忽略随机的 require 错误,对吧? Next.js 只知道getStaticProps,因为那是一个硬编码的 Next.js 函数名称。
好的,让我们通过在getStaticProps 中使用fs 来通知Next.js,以下再次起作用:
// Client + server code.
export default function IndexPage(props) {
return <div>{props.msg}</div>
}
// Server-only code.
const fs = require('fs')
export function getStaticProps() {
fs
return { props: { msg: 'hello world' } }
}
头脑等于炸毁。所以我们知道,在 getStaticProps 的正文中提到 fs,即使是像上面这样无用的,也会让 Next.js/Webpack 明白它将是仅限服务器的。
getServerSideProps 和 getStaticPaths 的情况相同。
高阶组件 (HOC) 必须位于它们自己的文件中
现在,我们在不同但相似的页面中分解IndexPage 和getStaticProps 的方法是使用HOC,它们只是返回其他函数的函数。
HOC 通常会放在pages/ 之外,然后在多个位置都需要,但是当您要考虑因素以进行概括时,您可能会想暂时将它们直接放在pages/ 文件中,例如:
// Client + server code.
import Link from 'next/link'
export function makeIndexPage(isIndex) {
return (props) => {
return <>
<Link href={isIndex ? '/index' : '/notindex'}>
<a>{isIndex ? 'index' : 'notindex'}</a>
</Link>
<div>{props.fs}</div>
<div>{props.isBlue}</div>
</>
}
}
export default makeIndexPage(true)
// Server-only code.
const fs = require('fs')
export function makeGetStaticProps(isBlue) {
return () => {
return { props: {
fs: Object.keys(fs).join(' '),
isBlue,
} }
}
}
export const getStaticProps = makeGetStaticProps(true)
但如果你这样做,你会很难过:
Module not found: Can't resolve 'fs'
所以我们明白了另一件事:fs 的用法必须直接在 getStaticProps 函数体内,Webpack 无法在子函数中捕获它。
解决此问题的唯一方法是为仅后端的内容创建一个单独的文件,如下所示:
pages/index.js
// Client + server code.
import { makeIndexPage } from "../front"
export default makeIndexPage(true)
// Server-only code.
import { makeGetStaticProps } from "../back"
export const getStaticProps = makeGetStaticProps(true)
pages/notindex.js
// Client + server code.
import { makeIndexPage } from "../front"
export default makeIndexPage(false)
// Server-only code.
import { makeGetStaticProps } from "../back"
export const getStaticProps = makeGetStaticProps(false)
front.js
// Client + server code.
import Link from 'next/link'
export function makeIndexPage(isIndex) {
return (props) => {
console.error('page');
return <>
<Link href={isIndex ? '/notindex' : '/'}>
<a>{isIndex ? 'notindex' : 'index'}</a>
</Link>
<div>{props.fs}</div>
<div>{props.isBlue}</div>
</>
}
}
back.js
// Server-only code.
const fs = require('fs')
export function makeGetStaticProps(isBlue) {
return () => {
return { props: {
fs: Object.keys(fs).join(' '),
isBlue,
} }
}
}
Webpack 必须看到名称 makeGetStaticProps 被分配给 getStaticProps,因此它决定整个 back 文件是服务器专用的。
请注意,如果您尝试将 back.js 和 front.js 合并到一个文件中,则它不起作用,可能是因为当您这样做时,export default makeIndexPage(true) webpack 必然会尝试将整个 front.js 文件拉入前端,这包括 fs,所以它失败了。
这导致库文件在以下之间自然拆分:
-
front.js 和 front/*:前端 + 后端文件。这些对前端来说是安全的。后端可以做前端可以做的任何事情(我们正在做 SSR 对吗?)所以这些也可以从后端使用
-
back.js 和 back/*(或者front/* 之外的任何内容):仅后端文件。这些只能后端使用,在前端导入会报错