/
index.ts
87 lines (75 loc) · 2.61 KB
/
index.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
import path from 'path'
import { RSC_MODULE_TYPES } from '../../../../shared/lib/constants'
import {
checkExports,
getRSCModuleType,
} from '../../../analysis/get-page-static-info'
import { parse } from '../../../swc'
function transformClient(resourcePath: string): string {
const output = `
const { createProxy } = require("next/dist/build/webpack/loaders/next-flight-loader/module-proxy")\n
module.exports = createProxy(${JSON.stringify(resourcePath)})
`
return output
}
function transformServer(source: string, isESModule: boolean) {
return (
source +
(isESModule ? `export const __next_rsc__` : `exports.__next_rsc__`) +
` = { __webpack_require__, server: true }\n`
)
}
function containsPath(parent: string, child: string) {
const relation = path.relative(parent, child)
return !!relation && !relation.startsWith('..') && !path.isAbsolute(relation)
}
const isPageOrLayoutFile = (filePath: string) => {
const filename = path.basename(filePath)
return /^(page|layout)\.[\w.]+$/.test(filename)
}
export default async function transformSource(
this: any,
source: string,
sourceMap: any
) {
if (typeof source !== 'string') {
throw new Error('Expected source to have been transformed to a string.')
}
const { resourcePath } = this
const callback = this.async()
const buildInfo = (this as any)._module.buildInfo
const swcAST = await parse(source, {
filename: resourcePath,
isModule: 'unknown',
})
const rscType = getRSCModuleType(swcAST)
// Assign the RSC meta information to buildInfo.
buildInfo.rsc = { type: rscType }
const isModule = swcAST.type === 'Module'
const createError = (name: string) =>
new Error(
`${name} is not supported in client components.\nFrom: ${this.resourcePath}`
)
const appDir = path.join(this.rootContext, 'app')
const isUnderAppDir = containsPath(appDir, this.resourcePath)
const isResourcePageOrLayoutFile = isPageOrLayoutFile(this.resourcePath)
// If client entry has any gSSP/gSP data fetching methods, error
function errorForInvalidDataFetching(onError: (error: any) => void) {
if (isUnderAppDir && isResourcePageOrLayoutFile) {
const { ssg, ssr } = checkExports(swcAST)
if (ssg) {
onError(createError('getStaticProps'))
}
if (ssr) {
onError(createError('getServerSideProps'))
}
}
}
if (buildInfo.rsc.type === RSC_MODULE_TYPES.client) {
errorForInvalidDataFetching(this.emitError)
const code = transformClient(this.resourcePath)
return callback(null, code, sourceMap)
}
const code = transformServer(source, isModule)
return callback(null, code, sourceMap)
}