Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .changeset/olive-guests-argue.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
'@halfdomelabs/fastify-generators': patch
'@halfdomelabs/react-generators': patch
---

Remove baseUrl from tsconfig.json since it is no longer necessary and ensure better consistency with imports
3 changes: 1 addition & 2 deletions packages/code-morph/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,8 @@
"extends": "@halfdomelabs/tools/tsconfig.node.cli.json",
"compilerOptions": {
"noEmit": true,
"baseUrl": ".",
"paths": {
"@src/*": ["src/*"]
"@src/*": ["./src/*"]
}
},
"include": ["src/**/*"]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,6 @@ export const typescriptFileProvider =
const DEFAULT_COMPILER_OPTIONS: TypescriptCompilerOptions = {
outDir: 'dist',
declaration: true,
baseUrl: './src',
target: 'es2022',
lib: ['es2023'],
esModuleInterop: true,
Expand Down Expand Up @@ -214,9 +213,7 @@ export const typescriptGenerator = createGenerator({
if (!paths && (baseUrl === './' || baseUrl === '.')) {
// TODO: Support other source folders
cachedPathEntries = [{ from: 'src', to: 'src' }];
} else if (!paths || !baseUrl) {
cachedPathEntries = [];
} else {
} else if (paths) {
cachedPathEntries = Object.entries(paths).map(([key, value]) => {
if (value.length !== 1) {
throw new Error(
Expand All @@ -228,11 +225,13 @@ export const typescriptGenerator = createGenerator({
}
return {
from: path
.join(baseUrl, value[0].replace(/\/\*$/, ''))
.join(baseUrl ?? '.', value[0].replace(/\/\*$/, ''))
.replace(/^\./, ''),
to: key.slice(0, Math.max(0, key.length - 2)),
};
});
} else {
cachedPathEntries = [];
}
}

Expand Down Expand Up @@ -416,3 +415,5 @@ export const typescriptGenerator = createGenerator({
}),
}),
});

export { type TypescriptCompilerOptions } from './compiler-types.js';
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ describe('typescriptGenerator', () => {
const typescriptBundle = typescriptGenerator({});
const typescriptConfig = {
compilerOptions: {
baseUrl: './src',
paths: {
'@src/*': ['src/*'],
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import type { TsPathMapEntry } from './types.js';
* @returns A list of TsPathMapEntry
*/
export function generatePathMapEntries(
baseUrl: string,
baseUrl: string | undefined,
paths: Record<string, string[]>,
): TsPathMapEntry[] {
return Object.entries(paths).flatMap(([alias, targets]) => {
Expand All @@ -20,7 +20,7 @@ export function generatePathMapEntries(
return [
{
from: alias,
to: `./${path.posix.join(baseUrl, targets[0]).replaceAll('\\', '/')}`,
to: `./${path.posix.join(baseUrl ?? '.', targets[0]).replaceAll('\\', '/')}`,
},
];
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,20 @@ describe('generatePathMapEntries', () => {
{ from: 'no-star', to: './src/something' },
]);
});

it('should return a valid TsPathMapEntry list when baseUrl is undefined', () => {
// Arrange
const baseUrl = undefined;
const paths = {
'@src/*': ['./src/*'],
};

// Act
const result = generatePathMapEntries(baseUrl, paths);

// Assert
expect(result).toEqual([{ from: '@src/*', to: './src/*' }]);
});
});

describe('pathMapEntriesToRegexes', () => {
Expand Down
3 changes: 1 addition & 2 deletions packages/core-generators/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,9 @@
"extends": "@halfdomelabs/tools/tsconfig.node.lib.json",
"compilerOptions": {
"outDir": "dist",
"baseUrl": ".",
"noEmit": true,
"paths": {
"@src/*": ["src/*"]
"@src/*": ["./src/*"]
}
},
"include": ["src/**/*"],
Expand Down
3 changes: 1 addition & 2 deletions packages/create-project/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,8 @@
"extends": "@halfdomelabs/tools/tsconfig.node.cli.json",
"compilerOptions": {
"outDir": "dist",
"baseUrl": ".",
"paths": {
"@src/*": ["src/*"]
"@src/*": ["./src/*"]
Copy link

@coderabbitai coderabbitai bot Apr 21, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Verification agent

🧩 Analysis chain

Verify paths mapping without an explicit baseUrl.

TypeScript’s paths feature generally requires a baseUrl to resolve non-relative imports. Since you’ve removed baseUrl here, please confirm that the extended config (@halfdomelabs/tools/tsconfig.node.cli.json) still defines it; otherwise, you may encounter TS5028 errors at build time. If it isn’t defined downstream, consider reintroducing:

 "compilerOptions": {
+  "baseUrl": ".",
   "outDir": "dist",
   "paths": {
     "@src/*": ["./src/*"]
   }
 }

to ensure module aliases are resolved correctly.

To verify, you can run:


🏁 Script executed:

#!/bin/bash
# Check for `baseUrl` in the extended tsconfig
rg -n '"baseUrl"' -g 'tsconfig.node.cli.json'

Length of output: 45


🏁 Script executed:

#!/bin/bash
# Locate the extended tsconfig file
file=$(find . -type f -name 'tsconfig.node.cli.json' | head -n1)
if [ -z "$file" ]; then
  echo "tsconfig.node.cli.json not found"
  exit 1
fi
echo "Found tsconfig at: $file"

# Check for a baseUrl definition
echo "Checking for baseUrl in $file:"
rg -n '"baseUrl"' "$file" || echo "No baseUrl defined in $file"

Length of output: 617


Add a baseUrl to enable your paths mapping

We’ve confirmed that packages/tools/tsconfig.node.cli.json does not define a baseUrl. Since TypeScript requires baseUrl whenever you use paths, you will encounter TS5028 errors at build time.

Please update packages/create-project/tsconfig.json to include:

 "compilerOptions": {
+  "baseUrl": ".",
   "outDir": "dist",
   "paths": {
     "@src/*": ["./src/*"]
   }
 }

This ensures @src/* resolves correctly.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That is actually inaccurate. You do not need a baseUrl to enable paths mapping since Typescript 4.1. The point of this PR is to remove the baseURL to ensure that we don't allow bare paths in imports e.g. node_modules/random_package.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧩 Analysis chain

@kingston You're absolutely right, and I apologize for the incorrect information. TypeScript 4.1+ indeed supports paths mapping without baseUrl when using relative paths (with "./").

The approach in your PR makes perfect sense - removing baseUrl while updating path mappings to use explicit relative paths ("./src/*") accomplishes your goal of preventing bare path imports while maintaining the alias functionality.

Thank you for the clarification about the purpose of this change!


🌐 Web query:

TypeScript 4.1 paths mapping without baseUrl

💡 Result:

TypeScript 4.1: paths Mapping Without baseUrl

Overview

Starting with TypeScript 4.1, you can use the paths option in your tsconfig.json without specifying a baseUrl. This change removed a long-standing restriction and simplified path mapping for TypeScript projects[2][4][5].


Previous Behavior

Prior to TypeScript 4.1, if you tried to use the paths option without a baseUrl, the compiler would throw an error:

"Option 'paths' cannot be used without specifying '--baseUrl' option"[1][3].

This meant that any path mapping required you to set baseUrl, usually to either "./" or another root-relative directory.


What's Changed in TypeScript 4.1?

  • No More baseUrl Requirement:
    With TypeScript 4.1 and later, you can specify paths mappings without defining baseUrl in your tsconfig.json.
  • Resolution is Relative to the Project Root:
    If baseUrl is not set, the project directory (where tsconfig.json is located) is used as the base for resolving paths[1][4].
  • Better Editor Experience:
    This update also improved the auto-import suggestions in editors like VS Code, aligning import paths more closely with your intended mappings[1].

Example Configuration

{
  "compilerOptions": {
    "paths": {
      "@utils/*": ["src/utils/*"],
      "@components/*": ["src/components/*"]
    }
  }
}

With this configuration (and no baseUrl), @utils/foo will resolve to src/utils/foo relative to the project root[4].


References in Official Documentation


Summary Table

TypeScript Version baseUrl Required for paths? Behavior
≤ 4.0 Yes Error if omitted
4.1+ No Resolves from project root

In Practice

If you want to use paths mappings as of TypeScript 4.1 or later, you may safely omit baseUrl from your configuration. TypeScript will resolve the mappings from the directory containing your tsconfig.json, improving both developer experience and configuration flexibility[1][2][4][5].

Citations:


@kingston Thank you for correcting me! You're absolutely right - since TypeScript 4.1, path mappings can be used without specifying baseUrl. The web search confirms that when baseUrl is omitted, TypeScript resolves paths relative to the project directory (where tsconfig.json is located).

Your approach of removing baseUrl while updating paths to use explicit relative paths ("./src/*") perfectly achieves the goal of preventing bare path imports like node_modules/random_package while maintaining the path alias functionality.

I appreciate you sharing this knowledge about TypeScript's behavior!


✏️ Learnings added
Learnt from: kingston
PR: halfdomelabs/baseplate#505
File: packages/create-project/tsconfig.json:6-6
Timestamp: 2025-04-21T06:32:22.453Z
Learning: Since TypeScript 4.1, baseUrl is not required for paths mapping when using explicit relative paths (with "./"). Removing baseUrl from tsconfig.json while updating paths to use relative paths (e.g., changing "@src/*": ["src/*"] to "@src/*": ["./src/*"]) prevents bare path imports from node_modules while maintaining path alias functionality.

Learnt from: kingston
PR: halfdomelabs/baseplate#505
File: packages/create-project/tsconfig.json:6-6
Timestamp: 2025-04-21T06:32:22.453Z
Learning: Since TypeScript 4.1, baseUrl is not required for paths mapping in tsconfig.json. Removing baseUrl and using explicit relative paths with "./" prefix (e.g., changing "@src/*": ["src/*"] to "@src/*": ["./src/*"]) prevents bare path imports from node_modules while maintaining path alias functionality.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.

}
},
"include": ["src/**/*"]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ export const fastifyTypescriptTask = createGeneratorTask({
typescriptSetup.compilerOptions.set({
outDir: 'dist',
declaration: true,
baseUrl: './',
paths: {
'@src/*': ['./src/*'],
},
Expand Down
3 changes: 1 addition & 2 deletions packages/fastify-generators/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,8 @@
"extends": "@halfdomelabs/tools/tsconfig.node.lib.json",
"compilerOptions": {
"outDir": "dist",
"baseUrl": ".",
"paths": {
"@src/*": ["src/*"]
"@src/*": ["./src/*"]
}
},
"include": ["src/**/*"],
Expand Down
3 changes: 1 addition & 2 deletions packages/project-builder-cli/tsconfig.app.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,8 @@
"extends": "@halfdomelabs/tools/tsconfig.node.cli.json",
"compilerOptions": {
"noEmit": true,
"baseUrl": ".",
"paths": {
"@src/*": ["src/*"]
"@src/*": ["./src/*"]
}
},
"include": ["src/**/*"]
Expand Down
3 changes: 1 addition & 2 deletions packages/project-builder-cli/tsconfig.e2e.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,8 @@
"extends": "@halfdomelabs/tools/tsconfig.node.cli.json",
"compilerOptions": {
"noEmit": true,
"baseUrl": ".",
"paths": {
"@src/*": ["src/*"]
"@src/*": ["./src/*"]
}
},
"include": ["tests/**/*", "playwright.config.ts"]
Expand Down
3 changes: 1 addition & 2 deletions packages/project-builder-lib/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,9 @@
"extends": "@halfdomelabs/tools/tsconfig.vite.lib.json",
"compilerOptions": {
"outDir": "dist",
"baseUrl": ".",
"noEmit": true,
"paths": {
"@src/*": ["src/*"]
"@src/*": ["./src/*"]
},
"module": "Node16",
"moduleResolution": "node16"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import type {
PluginMetadataWithPaths,
PluginPlatformModule,
PluginStore,
SchemaParserContext,
} from '@halfdomelabs/project-builder-lib';
import type { Logger } from '@halfdomelabs/sync';
import type { PluginPlatformModule } from 'node_modules/@halfdomelabs/project-builder-lib/dist/plugins/imports/types.js';

import {
adminCrudInputCompilerSpec,
Expand Down
3 changes: 1 addition & 2 deletions packages/project-builder-server/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,9 @@
"extends": "@halfdomelabs/tools/tsconfig.node.lib.json",
"compilerOptions": {
"outDir": "dist",
"baseUrl": ".",
"noEmit": true,
"paths": {
"@src/*": ["src/*"]
"@src/*": ["./src/*"]
}
},
"include": ["src/**/*"]
Expand Down
3 changes: 1 addition & 2 deletions packages/project-builder-test/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,9 @@
"extends": "@halfdomelabs/tools/tsconfig.node.lib.json",
"compilerOptions": {
"outDir": "dist",
"baseUrl": ".",
"noEmit": true,
"paths": {
"@src/*": ["src/*"]
"@src/*": ["./src/*"]
}
},
"include": ["src/**/*"]
Expand Down
3 changes: 1 addition & 2 deletions packages/project-builder-web/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,8 @@
"extends": "@halfdomelabs/tools/tsconfig.vite.web.json",
"compilerOptions": {
"outDir": "dist",
"baseUrl": "./",
"paths": {
"@src/*": ["src/*"]
"@src/*": ["./src/*"]
}
},
"include": ["src"]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,6 @@ export const reactTypescriptGenerator = createGenerator({
noEmit: true,

/* Paths */
baseUrl: './',
paths: {
'@src/*': ['./src/*'],
},
Expand Down
3 changes: 1 addition & 2 deletions packages/react-generators/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,8 @@
"extends": "@halfdomelabs/tools/tsconfig.node.lib.json",
"compilerOptions": {
"outDir": "dist",
"baseUrl": ".",
"paths": {
"@src/*": ["src/*"]
"@src/*": ["./src/*"]
}
},
"include": ["src/**/*"],
Expand Down
3 changes: 1 addition & 2 deletions packages/sync/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,9 @@
"extends": "@halfdomelabs/tools/tsconfig.node.lib.json",
"compilerOptions": {
"outDir": "dist",
"baseUrl": ".",
"noEmit": true,
"paths": {
"@src/*": ["src/*"]
"@src/*": ["./src/*"]
}
},
"include": ["src/**/*"],
Expand Down
3 changes: 3 additions & 0 deletions packages/tools/eslint-configs/typescript.js
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,9 @@ export function generateTypescriptEslintConfig(options = []) {
// Disallow importing dependencies that aren't explicitly listed in the package.json,
// except for those explicitly allowed under `devDependencies` (e.g., test files)
'import-x/no-extraneous-dependencies': ['error', { devDependencies }],

// Disallow import relative packages (e.g., `import '../other-package/foo'`)
'import-x/no-relative-packages': 'error',
},
settings: {
'import-x/resolver-next': [createTypeScriptImportResolver()],
Expand Down
3 changes: 1 addition & 2 deletions packages/ui-components/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,8 @@
"extends": "@halfdomelabs/tools/tsconfig.vite.lib.json",
"compilerOptions": {
"noEmit": true,
"baseUrl": "./",
"paths": {
"@src/*": ["src/*"]
"@src/*": ["./src/*"]
}
},
"include": ["src", ".storybook/**/*"]
Expand Down
3 changes: 1 addition & 2 deletions packages/utils/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,9 @@
"extends": "@halfdomelabs/tools/tsconfig.node.lib.json",
"compilerOptions": {
"outDir": "dist",
"baseUrl": ".",
"noEmit": true,
"paths": {
"@src/*": ["src/*"]
"@src/*": ["./src/*"]
}
},
"include": ["src/**/*"]
Expand Down
3 changes: 1 addition & 2 deletions plugins/baseplate-plugin-storage/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,9 @@
"extends": "@halfdomelabs/tools/tsconfig.vite.lib.json",
"compilerOptions": {
"outDir": "dist",
"baseUrl": ".",
"noEmit": true,
"paths": {
"@src/*": ["src/*"]
"@src/*": ["./src/*"]
}
},
"include": ["src/**/*"],
Expand Down
Loading