diff --git a/.github/workflows/validate_issue.yml b/.github/workflows/validate_issue.yml
index 3c6e3a4a2e43..abd6c0784d5f 100644
--- a/.github/workflows/validate_issue.yml
+++ b/.github/workflows/validate_issue.yml
@@ -15,4 +15,3 @@ jobs:
run: node ./.github/actions/issue-validator/index.mjs
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- DEBUG: 1
diff --git a/examples/with-context-api/components/Counter.js b/examples/with-context-api/components/Counter.js
deleted file mode 100644
index 19911d6eabc4..000000000000
--- a/examples/with-context-api/components/Counter.js
+++ /dev/null
@@ -1,31 +0,0 @@
-import { useReducer, useContext, createContext } from 'react'
-
-const CounterStateContext = createContext()
-const CounterDispatchContext = createContext()
-
-const reducer = (state, action) => {
- switch (action.type) {
- case 'INCREASE':
- return state + 1
- case 'DECREASE':
- return state - 1
- case 'INCREASE_BY':
- return state + action.payload
- default:
- throw new Error(`Unknown action: ${action.type}`)
- }
-}
-
-export const CounterProvider = ({ children }) => {
- const [state, dispatch] = useReducer(reducer, 0)
- return (
-
-
- {children}
-
-
- )
-}
-
-export const useCount = () => useContext(CounterStateContext)
-export const useDispatchCount = () => useContext(CounterDispatchContext)
diff --git a/examples/with-context-api/components/Counter.tsx b/examples/with-context-api/components/Counter.tsx
new file mode 100644
index 000000000000..0f8eae33512d
--- /dev/null
+++ b/examples/with-context-api/components/Counter.tsx
@@ -0,0 +1,57 @@
+import {
+ useReducer,
+ useContext,
+ createContext,
+ ReactNode,
+ Dispatch,
+} from 'react'
+
+type CounterState = number
+type CounterAction =
+ | {
+ type: 'INCREASE' | 'DECREASE'
+ }
+ | {
+ type: 'INCREASE_BY'
+ payload: number
+ }
+
+const CounterStateContext = createContext(0)
+const CounterDispatchContext = createContext>(
+ () => null
+)
+
+const reducer = (state: CounterState, action: CounterAction) => {
+ switch (action.type) {
+ case 'INCREASE':
+ return state + 1
+ case 'DECREASE':
+ return state - 1
+ case 'INCREASE_BY':
+ return state + action.payload
+ default:
+ throw new Error(`Unknown action: ${JSON.stringify(action)}`)
+ }
+}
+
+type CounterProviderProps = {
+ children: ReactNode
+ initialValue?: number
+}
+
+export const CounterProvider = ({
+ children,
+ initialValue = 0,
+}: CounterProviderProps) => {
+ const [state, dispatch] = useReducer(reducer, initialValue)
+ return (
+
+
+ {children}
+
+
+ )
+}
+
+export const useCount = () => useContext(CounterStateContext)
+export const useDispatchCount = () => useContext(CounterDispatchContext)
diff --git a/examples/with-context-api/package.json b/examples/with-context-api/package.json
index 349de02f4d84..46775cdf8044 100644
--- a/examples/with-context-api/package.json
+++ b/examples/with-context-api/package.json
@@ -7,7 +7,12 @@
},
"dependencies": {
"next": "latest",
- "react": "^17.0.2",
- "react-dom": "^17.0.2"
+ "react": "^18.2.0",
+ "react-dom": "^18.2.0"
+ },
+ "devDependencies": {
+ "@types/node": "18.7.15",
+ "@types/react": "16.9.17",
+ "typescript": "4.8.2"
}
}
diff --git a/examples/with-context-api/pages/_app.js b/examples/with-context-api/pages/_app.tsx
similarity index 58%
rename from examples/with-context-api/pages/_app.js
rename to examples/with-context-api/pages/_app.tsx
index 4fe390a79d9b..6f852027a9e9 100644
--- a/examples/with-context-api/pages/_app.js
+++ b/examples/with-context-api/pages/_app.tsx
@@ -1,11 +1,10 @@
+import type { AppProps } from 'next/app'
import { CounterProvider } from '../components/Counter'
-function MyApp({ Component, pageProps }) {
+export default function MyApp({ Component, pageProps }: AppProps) {
return (
)
}
-
-export default MyApp
diff --git a/examples/with-context-api/pages/about.js b/examples/with-context-api/pages/about.tsx
similarity index 77%
rename from examples/with-context-api/pages/about.js
rename to examples/with-context-api/pages/about.tsx
index 481c9c048159..f45d699aabf4 100644
--- a/examples/with-context-api/pages/about.js
+++ b/examples/with-context-api/pages/about.tsx
@@ -1,3 +1,4 @@
+import type { MouseEvent } from 'react'
import Link from 'next/link'
import { useCount, useDispatchCount } from '../components/Counter'
@@ -5,11 +6,11 @@ const AboutPage = () => {
const count = useCount()
const dispatch = useDispatchCount()
- const handleIncrease = (event) =>
+ const handleIncrease = (event: MouseEvent) =>
dispatch({
type: 'INCREASE',
})
- const handleIncrease15 = (event) =>
+ const handleIncrease15 = (event: MouseEvent) =>
dispatch({
type: 'INCREASE_BY',
payload: 15,
diff --git a/examples/with-context-api/pages/index.js b/examples/with-context-api/pages/index.tsx
similarity index 77%
rename from examples/with-context-api/pages/index.js
rename to examples/with-context-api/pages/index.tsx
index 7e26a78c30aa..585aacff1c45 100644
--- a/examples/with-context-api/pages/index.js
+++ b/examples/with-context-api/pages/index.tsx
@@ -1,3 +1,4 @@
+import type { MouseEvent } from 'react'
import Link from 'next/link'
import { useCount, useDispatchCount } from '../components/Counter'
@@ -5,11 +6,11 @@ const IndexPage = () => {
const count = useCount()
const dispatch = useDispatchCount()
- const handleIncrease = (event) =>
+ const handleIncrease = (event: MouseEvent) =>
dispatch({
type: 'INCREASE',
})
- const handleDecrease = (event) =>
+ const handleDecrease = (event: MouseEvent) =>
dispatch({
type: 'DECREASE',
})
diff --git a/examples/with-context-api/tsconfig.json b/examples/with-context-api/tsconfig.json
new file mode 100644
index 000000000000..ccaea0672d6e
--- /dev/null
+++ b/examples/with-context-api/tsconfig.json
@@ -0,0 +1,20 @@
+{
+ "compilerOptions": {
+ "target": "es5",
+ "lib": ["dom", "dom.iterable", "esnext"],
+ "allowJs": true,
+ "skipLibCheck": true,
+ "strict": true,
+ "forceConsistentCasingInFileNames": true,
+ "noEmit": true,
+ "incremental": true,
+ "esModuleInterop": true,
+ "moduleResolution": "node",
+ "module": "esnext",
+ "resolveJsonModule": true,
+ "isolatedModules": true,
+ "jsx": "preserve"
+ },
+ "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"],
+ "exclude": ["node_modules"]
+}
diff --git a/packages/next/build/analysis/get-page-static-info.ts b/packages/next/build/analysis/get-page-static-info.ts
index cc18cc8d743a..bcaaac6bd2cc 100644
--- a/packages/next/build/analysis/get-page-static-info.ts
+++ b/packages/next/build/analysis/get-page-static-info.ts
@@ -53,6 +53,19 @@ export function checkExports(swcAST: any): { ssr: boolean; ssg: boolean } {
}
}
+ if (
+ node.type === 'ExportDeclaration' &&
+ node.declaration?.type === 'VariableDeclaration'
+ ) {
+ const id = node.declaration?.declarations[0]?.id.value
+ if (['getStaticProps', 'getServerSideProps'].includes(id)) {
+ return {
+ ssg: id === 'getStaticProps',
+ ssr: id === 'getServerSideProps',
+ }
+ }
+ }
+
if (node.type === 'ExportNamedDeclaration') {
const values = node.specifiers.map(
(specifier: any) =>
diff --git a/test/unit/fixtures/page-runtime/ssr-variable-gssp.js b/test/unit/fixtures/page-runtime/ssr-variable-gssp.js
new file mode 100644
index 000000000000..e09007babef5
--- /dev/null
+++ b/test/unit/fixtures/page-runtime/ssr-variable-gssp.js
@@ -0,0 +1,12 @@
+export default function Nodejs() {
+ return 'nodejs'
+}
+
+// export an identifier instead of function
+export const getServerSideProps = async () => {
+ return { props: {} }
+}
+
+export const config = {
+ runtime: 'experimental-edge',
+}
diff --git a/test/unit/parse-page-runtime.test.ts b/test/unit/parse-page-static-info.test.ts
similarity index 69%
rename from test/unit/parse-page-runtime.test.ts
rename to test/unit/parse-page-static-info.test.ts
index a9c4a358faaf..772081e53fb0 100644
--- a/test/unit/parse-page-runtime.test.ts
+++ b/test/unit/parse-page-static-info.test.ts
@@ -9,21 +9,25 @@ function createNextConfig(runtime?: 'experimental-edge' | 'nodejs') {
}
}
-describe('parse page runtime config', () => {
+describe('parse page static info', () => {
it('should parse nodejs runtime correctly', async () => {
- const { runtime } = await getPageStaticInfo({
+ const { runtime, ssr, ssg } = await getPageStaticInfo({
pageFilePath: join(fixtureDir, 'page-runtime/nodejs-ssr.js'),
nextConfig: createNextConfig(),
})
expect(runtime).toBe('nodejs')
+ expect(ssr).toBe(true)
+ expect(ssg).toBe(false)
})
it('should parse static runtime correctly', async () => {
- const { runtime } = await getPageStaticInfo({
+ const { runtime, ssr, ssg } = await getPageStaticInfo({
pageFilePath: join(fixtureDir, 'page-runtime/nodejs.js'),
nextConfig: createNextConfig(),
})
expect(runtime).toBe(undefined)
+ expect(ssr).toBe(false)
+ expect(ssg).toBe(false)
})
it('should parse edge runtime correctly', async () => {
@@ -41,22 +45,35 @@ describe('parse page runtime config', () => {
})
expect(runtime).toBe(undefined)
})
+
+ it('should parse ssr info with variable exported gSSP correctly', async () => {
+ const { ssr, ssg } = await getPageStaticInfo({
+ pageFilePath: join(fixtureDir, 'page-runtime/ssr-variable-gssp.js'),
+ nextConfig: createNextConfig(),
+ })
+ expect(ssr).toBe(true)
+ expect(ssg).toBe(false)
+ })
})
describe('fallback to the global runtime configuration', () => {
it('should fallback when gSP is defined and exported', async () => {
- const { runtime } = await getPageStaticInfo({
+ const { runtime, ssr, ssg } = await getPageStaticInfo({
pageFilePath: join(fixtureDir, 'page-runtime/fallback-with-gsp.js'),
nextConfig: createNextConfig('experimental-edge'),
})
expect(runtime).toBe('experimental-edge')
+ expect(ssr).toBe(false)
+ expect(ssg).toBe(true)
})
it('should fallback when gSP is re-exported from other module', async () => {
- const { runtime } = await getPageStaticInfo({
+ const { runtime, ssr, ssg } = await getPageStaticInfo({
pageFilePath: join(fixtureDir, 'page-runtime/fallback-re-export-gsp.js'),
nextConfig: createNextConfig('experimental-edge'),
})
expect(runtime).toBe('experimental-edge')
+ expect(ssr).toBe(false)
+ expect(ssg).toBe(true)
})
})