From 490c00a34d6741db6fa01c8ef6bde082b11ed161 Mon Sep 17 00:00:00 2001 From: Ian Serpa Date: Mon, 3 Apr 2023 21:12:18 +0200 Subject: [PATCH] Fix relative import path for type plugin in NX workspaces Refs: #44363, nrwl/nx#14558 --- .../webpack/plugins/next-types-plugin.test.ts | 69 +++++++++++++++++++ .../webpack/plugins/next-types-plugin.ts | 38 +++++++--- 2 files changed, 96 insertions(+), 11 deletions(-) create mode 100644 packages/next/src/build/webpack/plugins/next-types-plugin.test.ts diff --git a/packages/next/src/build/webpack/plugins/next-types-plugin.test.ts b/packages/next/src/build/webpack/plugins/next-types-plugin.test.ts new file mode 100644 index 0000000000000..9d1db1731e08a --- /dev/null +++ b/packages/next/src/build/webpack/plugins/next-types-plugin.test.ts @@ -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' + ) + }) +}) diff --git a/packages/next/src/build/webpack/plugins/next-types-plugin.ts b/packages/next/src/build/webpack/plugins/next-types-plugin.ts index 0d5bd01f8f729..8b9b408a48dbe 100644 --- a/packages/next/src/build/webpack/plugins/next-types-plugin.ts +++ b/packages/next/src/build/webpack/plugins/next-types-plugin.ts @@ -435,6 +435,8 @@ declare module 'next/link' { }` } +const appTypesBasePath = path.join('types', 'app') + export class NextTypesPlugin { dir: string distDir: string @@ -463,6 +465,28 @@ export class NextTypesPlugin { } } + get distDirAbsolutePath() { + return path.join(this.dir, this.distDir) + } + + 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 @@ -503,9 +527,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 ? '..' @@ -533,7 +554,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) { @@ -542,16 +562,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)