Skip to content

Commit

Permalink
Show inlined error if the "use client" directive is not before other …
Browse files Browse the repository at this point in the history
…statements/expressions (#42507)

An example will be:


![image](https://user-images.githubusercontent.com/3676859/200087667-53548f58-4627-422f-a191-548aba194707.png)

## Bug

- [ ] Related issues linked using `fixes #number`
- [ ] Integration tests added
- [ ] Errors have a helpful link attached, see `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`
- [ ] Integration 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`

## 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 committed Nov 7, 2022
1 parent 984627a commit 3e2e39c
Showing 1 changed file with 34 additions and 7 deletions.
41 changes: 34 additions & 7 deletions packages/next/server/next-typescript.ts
Expand Up @@ -187,19 +187,34 @@ export function createTSPlugin(modules: {
)
}

function getIsClientEntry(fileName: string) {
function getIsClientEntry(
fileName: string,
throwOnInvalidDirective?: boolean
) {
const source = info.languageService.getProgram()?.getSourceFile(fileName)
if (source) {
let isClientEntry = false
let isDirective = true

ts.forEachChild(source!, (node) => {
if (isClientEntry || !isDirective) return

if (isDirective && ts.isExpressionStatement(node)) {
if (ts.isStringLiteral(node.expression)) {
if (node.expression.text === 'use client') {
if (
ts.isExpressionStatement(node) &&
ts.isStringLiteral(node.expression)
) {
if (node.expression.text === 'use client') {
if (isDirective) {
isClientEntry = true
} else {
if (throwOnInvalidDirective) {
const e = {
messageText:
'The `"use client"` directive must be put at the top of the file.',
start: node.expression.getStart(),
length:
node.expression.getEnd() - node.expression.getStart(),
}
throw e
}
}
}
} else {
Expand Down Expand Up @@ -473,7 +488,19 @@ export function createTSPlugin(modules: {

const source = info.languageService.getProgram()?.getSourceFile(fileName)
if (source) {
const isClientEntry = getIsClientEntry(fileName)
let isClientEntry = false

try {
isClientEntry = getIsClientEntry(fileName, true)
} catch (e: any) {
prior.push({
file: source,
category: ts.DiagnosticCategory.Error,
code: 71004,
...e,
})
isClientEntry = false
}

ts.forEachChild(source!, (node) => {
if (ts.isImportDeclaration(node)) {
Expand Down

0 comments on commit 3e2e39c

Please sign in to comment.