Skip to content

Commit

Permalink
Add gSP and gSSP checks for both server and client layers in the SWC …
Browse files Browse the repository at this point in the history
…transform (vercel#43391)

We currently have these as a build runtime check. This PR ensures that
it happens during the SWC compilation time, and applies to both server
and client entries.

Also adds link to the docs:

<img width="768" alt="CleanShot 2022-11-25 at 18 14 54@2x"
src="https://user-images.githubusercontent.com/3676859/204031972-51447236-77f3-4c78-8e53-a7708aa3952a.png">

## Bug

- [ ] Related issues linked using `fixes #number`
- [x] Integration tests added
- [x] Errors have a helpful link attached, see
[`contributing.md`](https://github.com/vercel/next.js/blob/canary/contributing.md)

## Feature

- [ ] Implements an existing feature request or RFC. Make sure the
feature request has been accepted for implementation before opening a
PR.
- [ ] Related issues linked using `fixes #number`
- [ ]
[e2e](https://github.com/vercel/next.js/blob/canary/contributing/core/testing.md#writing-tests-for-nextjs)
tests added
- [ ] Documentation added
- [ ] Telemetry added. In case of a feature if it's used or not.
- [ ] Errors have a helpful link attached, see
[`contributing.md`](https://github.com/vercel/next.js/blob/canary/contributing.md)

## Documentation / Examples

- [ ] Make sure the linting passes by running `pnpm build && pnpm lint`
- [ ] The "examples guidelines" are followed from [our contributing
doc](https://github.com/vercel/next.js/blob/canary/contributing/examples/adding-examples.md)
  • Loading branch information
shuding authored and brvnonascimento committed Nov 28, 2022
1 parent 09add3b commit 84ff27b
Show file tree
Hide file tree
Showing 13 changed files with 54 additions and 22 deletions.
13 changes: 10 additions & 3 deletions packages/next-swc/crates/core/src/react_server_components.rs
Expand Up @@ -58,7 +58,7 @@ impl<C: Comments> VisitMut for ReactServerComponents<C> {

if self.is_server {
if !is_client_entry {
self.assert_server_graph(&imports);
self.assert_server_graph(&imports, module);
} else {
self.to_module_ref(module);
return;
Expand Down Expand Up @@ -246,7 +246,7 @@ impl<C: Comments> ReactServerComponents<C> {
);
}

fn assert_server_graph(&self, imports: &Vec<ModuleImports>) {
fn assert_server_graph(&self, imports: &Vec<ModuleImports>, module: &Module) {
for import in imports {
let source = import.source.0.clone();
if self.invalid_server_imports.contains(&source) {
Expand Down Expand Up @@ -288,6 +288,8 @@ impl<C: Comments> ReactServerComponents<C> {
}
}
}

self.assert_invalid_api(module);
}

fn assert_client_graph(&self, imports: &Vec<ModuleImports>, module: &Module) {
Expand All @@ -305,10 +307,15 @@ impl<C: Comments> ReactServerComponents<C> {
}
}

self.assert_invalid_api(module);
}

fn assert_invalid_api(&self, module: &Module) {
// Assert `getServerSideProps` and `getStaticProps` exports.
let is_layout_or_page = Regex::new(r"/(page|layout)\.(ts|js)x?$")
.unwrap()
.is_match(&self.filepath);

if is_layout_or_page {
let mut span = DUMMY_SP;
let mut has_get_server_side_props = false;
Expand Down Expand Up @@ -389,7 +396,7 @@ impl<C: Comments> ReactServerComponents<C> {
.struct_span_err(
span,
format!(
"`{}` is not allowed in Client Components.",
"NEXT_RSC_ERR_INVALID_API: {}",
if has_get_server_side_props {
"getServerSideProps"
} else {
Expand Down
2 changes: 1 addition & 1 deletion packages/next-swc/crates/core/tests/errors.rs
Expand Up @@ -82,7 +82,7 @@ fn react_server_components_server_graph_errors(input: PathBuf) {
syntax(),
&|tr| {
server_components(
FileName::Real(PathBuf::from("/some-project/src/some-file.js")),
FileName::Real(PathBuf::from("/some-project/src/layout.js")),
next_swc::react_server_components::Config::WithOptions(
next_swc::react_server_components::Options { is_server: true },
),
Expand Down
@@ -1,5 +1,5 @@

x `getServerSideProps` is not allowed in Client Components.
x NEXT_RSC_ERR_INVALID_API: getServerSideProps
,-[input.js:1:1]
1 | export function getServerSideProps (){
: ^^^^^^^^^^^^^^^^^^
Expand Down
@@ -1,5 +1,5 @@

x `getStaticProps` is not allowed in Client Components.
x NEXT_RSC_ERR_INVALID_API: getStaticProps
,-[input.js:1:1]
1 | export function getStaticProps (){
: ^^^^^^^^^^^^^^
Expand Down
@@ -0,0 +1,6 @@
export function getServerSideProps (){
}

export default function () {
return null;
}
@@ -0,0 +1,4 @@
export function getServerSideProps() {}
export default function() {
return null;
}
@@ -0,0 +1,6 @@

x NEXT_RSC_ERR_INVALID_API: getServerSideProps
,-[input.js:1:1]
1 | export function getServerSideProps (){
: ^^^^^^^^^^^^^^^^^^
`----
@@ -0,0 +1,6 @@
export function getStaticProps (){
}

export default function () {
return null;
}
@@ -0,0 +1,4 @@
export function getStaticProps() {}
export default function() {
return null;
}
@@ -0,0 +1,6 @@

x NEXT_RSC_ERR_INVALID_API: getStaticProps
,-[input.js:1:1]
1 | export function getStaticProps (){
: ^^^^^^^^^^^^^^
`----
Expand Up @@ -16,6 +16,7 @@ function formatRSCErrorMessage(message: string): null | [string, string] {
const NEXT_RSC_ERR_CLIENT_DIRECTIVE = /.+NEXT_RSC_ERR_CLIENT_DIRECTIVE\n/s
const NEXT_RSC_ERR_CLIENT_DIRECTIVE_PAREN =
/.+NEXT_RSC_ERR_CLIENT_DIRECTIVE_PAREN\n/s
const NEXT_RSC_ERR_INVALID_API = /.+NEXT_RSC_ERR_INVALID_API: (.*?)\n/s

if (NEXT_RSC_ERR_REACT_API.test(message)) {
formattedMessage = message.replace(
Expand Down Expand Up @@ -62,6 +63,12 @@ function formatRSCErrorMessage(message: string): null | [string, string] {
`\n\n"use client" must be a directive, and placed before other expressions. Remove the parentheses and move it to the top of the file to resolve this issue.\n\n`
)
formattedVerboseMessage = '\n\nImport path:\n'
} else if (NEXT_RSC_ERR_INVALID_API.test(message)) {
formattedMessage = message.replace(
NEXT_RSC_ERR_INVALID_API,
`\n\n"$1" is not supported in app/. Read more: https://beta.nextjs.org/docs/data-fetching/fundamentals\n\n`
)
formattedVerboseMessage = '\n\nFile path:\n'
}

return [formattedMessage, formattedVerboseMessage]
Expand Down
14 changes: 0 additions & 14 deletions packages/next/server/app-render.tsx
Expand Up @@ -1127,20 +1127,6 @@ export async function renderToHTMLOrFlight(
}
}

// TODO-APP: move these errors to the loader instead?
// we will also need a migration doc here to link to
if (typeof layoutOrPageMod?.getServerSideProps === 'function') {
throw new Error(
`getServerSideProps is not supported in app/, detected in ${segment}`
)
}

if (typeof layoutOrPageMod?.getStaticProps === 'function') {
throw new Error(
`getStaticProps is not supported in app/, detected in ${segment}`
)
}

/**
* The React Component to render.
*/
Expand Down
4 changes: 2 additions & 2 deletions test/e2e/app-dir/rsc-errors.test.ts
Expand Up @@ -52,7 +52,7 @@ describe('app dir - rsc errors', () => {

expect(res.status).toBe(500)
expect(await res.text()).toContain(
'`getServerSideProps` is not allowed in Client Components'
'"getServerSideProps\\" is not supported in app/'
)
})

Expand All @@ -79,7 +79,7 @@ describe('app dir - rsc errors', () => {

expect(res.status).toBe(500)
expect(await res.text()).toContain(
'`getStaticProps` is not allowed in Client Components'
'"getStaticProps\\" is not supported in app/'
)
})

Expand Down

0 comments on commit 84ff27b

Please sign in to comment.