Skip to content

Commit

Permalink
Fix type plugin for NX workspaces (#47534)
Browse files Browse the repository at this point in the history
The plugin was failing in NX monorepos due to a wrong import path.

#44363, nrwl/nx#14558

```
nx build my-next

> nx run my-next:build:production

warn  - You have enabled experimental feature (appDir) in next.config.js.
warn  - Experimental features are not covered by semver, and may cause unexpected or broken application behavior. Use at your own risk.
info  - Thank you for testing `appDir` please leave your feedback at https://nextjs.link/app-feedback

info  - Creating an optimized production build  
info  - Compiled successfully
info  - Skipping linting
info  - Checking validity of types ..Failed to compile.

Type error: Cannot find module '../../../../app/layout' or its corresponding type declarations.


 ——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————

 >  NX   Ran target build for project my-next (2s)
 
    ✖    1/1 failed
```

---------

Co-authored-by: Ian Serpa <[email protected]>
Co-authored-by: Shu Ding <[email protected]>
  • Loading branch information
3 people authored Apr 3, 2023
1 parent 9de5b7b commit 3e25b06
Show file tree
Hide file tree
Showing 2 changed files with 94 additions and 11 deletions.
69 changes: 69 additions & 0 deletions packages/next/src/build/webpack/plugins/next-types-plugin.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import { NextTypesPlugin } from './next-types-plugin'

describe('next-types-plugin', () => {
it('should generate correct base import path', () => {
const plugin = new NextTypesPlugin({
dir: '/Users/myself/myproject',
distDir: '.next',
appDir: '/Users/myself/myproject/app',
dev: false,
isEdgeServer: false,
pageExtensions: ['tsx', 'ts', 'jsx', 'js'],
typedRoutes: false,
originalRewrites: undefined,
originalRedirects: undefined,
})
expect(plugin.getRelativePathFromAppTypesDir('page.tsx')).toEqual(
'../../../app/page.tsx'
)
expect(plugin.getRelativePathFromAppTypesDir('layout.tsx')).toEqual(
'../../../app/layout.tsx'
)
expect(plugin.getRelativePathFromAppTypesDir('test/page.tsx')).toEqual(
'../../../../app/test/page.tsx'
)
expect(
plugin.getRelativePathFromAppTypesDir('deeply/nested/page.tsx')
).toEqual('../../../../../app/deeply/nested/page.tsx')
})

it('should generate correct base import path for nx monorepos', () => {
const plugin = new NextTypesPlugin({
dir: '/Users/myself/code/nx-monorepo/apps/myproject',
distDir: '../../dist/apps/myproject/.next',
appDir: '/Users/myself/code/nx-monorepo/apps/myproject/app',
dev: false,
isEdgeServer: false,
pageExtensions: ['tsx', 'ts', 'jsx', 'js'],
typedRoutes: false,
originalRewrites: undefined,
originalRedirects: undefined,
})
expect(plugin.getRelativePathFromAppTypesDir('layout.tsx')).toEqual(
'../../../../../../apps/myproject/app/layout.tsx'
)
expect(plugin.getRelativePathFromAppTypesDir('test/page.tsx')).toEqual(
'../../../../../../../apps/myproject/app/test/page.tsx'
)
})

it('should generate correct base import path for custom projects', () => {
const plugin = new NextTypesPlugin({
dir: '/Users/myself/code/custom-project/frontend/ui',
distDir: '../dist/ui/.next',
appDir: '/Users/myself/code/custom-project/frontend/ui/app',
dev: false,
isEdgeServer: false,
pageExtensions: ['tsx', 'ts', 'jsx', 'js'],
typedRoutes: false,
originalRewrites: undefined,
originalRedirects: undefined,
})
expect(plugin.getRelativePathFromAppTypesDir('layout.tsx')).toEqual(
'../../../../../ui/app/layout.tsx'
)
expect(plugin.getRelativePathFromAppTypesDir('test/page.tsx')).toEqual(
'../../../../../../ui/app/test/page.tsx'
)
})
})
36 changes: 25 additions & 11 deletions packages/next/src/build/webpack/plugins/next-types-plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -435,6 +435,8 @@ declare module 'next/link' {
}`
}

const appTypesBasePath = path.join('types', 'app')

export class NextTypesPlugin {
dir: string
distDir: string
Expand All @@ -444,6 +446,7 @@ export class NextTypesPlugin {
pageExtensions: string[]
pagesDir: string
typedRoutes: boolean
distDirAbsolutePath: string

constructor(options: Options) {
this.dir = options.dir
Expand All @@ -454,6 +457,7 @@ export class NextTypesPlugin {
this.pageExtensions = options.pageExtensions
this.pagesDir = path.join(this.appDir, '..', 'pages')
this.typedRoutes = options.typedRoutes
this.distDirAbsolutePath = path.join(this.dir, this.distDir)
if (this.typedRoutes && !redirectsRewritesTypesProcessed) {
redirectsRewritesTypesProcessed = true
addRedirectsRewritesRouteTypes(
Expand All @@ -463,6 +467,24 @@ export class NextTypesPlugin {
}
}

getRelativePathFromAppTypesDir(moduleRelativePathToAppDir: string) {
const moduleAbsolutePath = path.join(
this.appDir,
moduleRelativePathToAppDir
)

const moduleInAppTypesAbsolutePath = path.join(
this.distDirAbsolutePath,
appTypesBasePath,
moduleRelativePathToAppDir
)

return path.relative(
moduleInAppTypesAbsolutePath + '/..',
moduleAbsolutePath
)
}

collectPage(filePath: string) {
if (!this.typedRoutes) return

Expand Down Expand Up @@ -503,9 +525,6 @@ export class NextTypesPlugin {
}

apply(compiler: webpack.Compiler) {
// From dist root to project root
const distDirRelative = path.relative(this.distDir + '/..', '.')

// From asset root to dist root
const assetDirRelative = this.dev
? '..'
Expand Down Expand Up @@ -533,7 +552,6 @@ export class NextTypesPlugin {
const IS_PAGE = !IS_LAYOUT && /[/\\]page\.[^.]+$/.test(mod.resource)
const IS_ROUTE = !IS_PAGE && /[/\\]route\.[^.]+$/.test(mod.resource)
const relativePathToApp = path.relative(this.appDir, mod.resource)
const relativePathToRoot = path.relative(this.dir, mod.resource)

if (!this.dev) {
if (IS_PAGE || IS_ROUTE) {
Expand All @@ -542,16 +560,12 @@ export class NextTypesPlugin {
}

const typePath = path.join(
'types',
'app',
appTypesBasePath,
relativePathToApp.replace(/\.(js|jsx|ts|tsx|mjs)$/, '.ts')
)
const relativeImportPath = path
.join(
distDirRelative,
path.relative(typePath, ''),
relativePathToRoot.replace(/\.(js|jsx|ts|tsx|mjs)$/, '')
)
.join(this.getRelativePathFromAppTypesDir(relativePathToApp))
.replace(/\.(js|jsx|ts|tsx|mjs)$/, '')
.replace(/\\/g, '/')
const assetPath = assetDirRelative + '/' + normalizePathSep(typePath)

Expand Down

0 comments on commit 3e25b06

Please sign in to comment.