fix(bundling): fix esbuild to work with ts project references (#30230)
<!-- Please make sure you have read the submission guidelines before posting an PR --> <!-- https://github.com/nrwl/nx/blob/master/CONTRIBUTING.md#-submitting-a-pr --> <!-- Please make sure that your commit message follows our format --> <!-- Example: `fix(nx): must begin with lowercase` --> <!-- If this is a particularly complex change or feature addition, you can request a dedicated Nx release for this pull request branch. Mention someone from the Nx team or the `@nrwl/nx-pipelines-reviewers` and they will confirm if the PR warrants its own release for testing purposes, and generate it for you if appropriate. --> ## Current Behavior <!-- This is the behavior we have today --> If we are using `esbuild` as our bundler and ts project references (`--workspaces`) local libraries are not building are not resolved in the build artifacts. ## Expected Behavior <!-- This is the behavior we should expect with the changes in this PR --> When using ts project references with esbuild all types libraries (buildable / non-buildable) should work out of the box. ## Related Issue(s) <!-- Please link the issue being fixed so it gets closed when this is merged. --> Fixes #
This commit is contained in:
parent
1c323131f8
commit
7da48d6471
90
e2e/node/src/node-ts-solution-esbuild.test.ts
Normal file
90
e2e/node/src/node-ts-solution-esbuild.test.ts
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
import { names } from '@nx/devkit';
|
||||||
|
import {
|
||||||
|
cleanupProject,
|
||||||
|
getPackageManagerCommand,
|
||||||
|
getSelectedPackageManager,
|
||||||
|
newProject,
|
||||||
|
readFile,
|
||||||
|
runCLI,
|
||||||
|
runCommand,
|
||||||
|
uniq,
|
||||||
|
updateFile,
|
||||||
|
updateJson,
|
||||||
|
} from '@nx/e2e/utils';
|
||||||
|
|
||||||
|
let originalEnvPort;
|
||||||
|
|
||||||
|
describe('Node Esbuild Applications', () => {
|
||||||
|
beforeAll(() => {
|
||||||
|
originalEnvPort = process.env.PORT;
|
||||||
|
newProject({
|
||||||
|
preset: 'ts',
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
afterAll(() => {
|
||||||
|
process.env.PORT = originalEnvPort;
|
||||||
|
cleanupProject();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('it should generate an app that cosumes a non-buildable ts library', () => {
|
||||||
|
const nodeapp = uniq('nodeapp');
|
||||||
|
const lib = uniq('lib');
|
||||||
|
const port = getRandomPort();
|
||||||
|
process.env.PORT = `${port}`;
|
||||||
|
|
||||||
|
runCLI(
|
||||||
|
`generate @nx/node:app apps/${nodeapp} --port=${port} --bundler=esbuild --framework=fastify --no-interactive`
|
||||||
|
);
|
||||||
|
|
||||||
|
runCLI(
|
||||||
|
`generate @nx/js:lib packages/${lib} --bundler=none --e2eTestRunner=none --unitTestRunner=none`
|
||||||
|
);
|
||||||
|
|
||||||
|
updateFile(
|
||||||
|
`apps/${nodeapp}/src/main.ts`,
|
||||||
|
(content) => `import { ${names(lib).propertyName} } from '@proj/${lib}';
|
||||||
|
|
||||||
|
console.log(${names(lib).propertyName}());
|
||||||
|
|
||||||
|
${content}
|
||||||
|
`
|
||||||
|
);
|
||||||
|
|
||||||
|
// App is CJS by default so lets update the lib to follow the same pattern
|
||||||
|
updateJson(`packages/${lib}/tsconfig.lib.json`, (json) => {
|
||||||
|
json.compilerOptions.module = 'commonjs';
|
||||||
|
json.compilerOptions.moduleResolution = 'node';
|
||||||
|
return json;
|
||||||
|
});
|
||||||
|
|
||||||
|
updateJson('tsconfig.base.json', (json) => {
|
||||||
|
json.compilerOptions.moduleResolution = 'node';
|
||||||
|
json.compilerOptions.module = 'esnext';
|
||||||
|
return json;
|
||||||
|
});
|
||||||
|
|
||||||
|
const pm = getSelectedPackageManager();
|
||||||
|
if (pm === 'pnpm') {
|
||||||
|
updateJson(`apps/${nodeapp}/package.json`, (json) => {
|
||||||
|
json.dependencies ??= {};
|
||||||
|
json.dependencies[`@proj/${lib}`] = 'workspace:*';
|
||||||
|
return json;
|
||||||
|
});
|
||||||
|
|
||||||
|
const pmc = getPackageManagerCommand({ packageManager: pm });
|
||||||
|
runCommand(pmc.install);
|
||||||
|
}
|
||||||
|
|
||||||
|
runCLI('sync');
|
||||||
|
|
||||||
|
// check build
|
||||||
|
expect(runCLI(`build ${nodeapp}`)).toContain(
|
||||||
|
`Successfully ran target build for project ${nodeapp}`
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
function getRandomPort() {
|
||||||
|
return Math.floor(1000 + Math.random() * 7000);
|
||||||
|
}
|
||||||
@ -1,11 +1,12 @@
|
|||||||
import * as esbuild from 'esbuild';
|
import * as esbuild from 'esbuild';
|
||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
import { existsSync, mkdirSync, writeFileSync } from 'fs';
|
import { existsSync, mkdirSync, writeFileSync, lstatSync } from 'fs';
|
||||||
import {
|
import {
|
||||||
ExecutorContext,
|
ExecutorContext,
|
||||||
joinPathFragments,
|
joinPathFragments,
|
||||||
normalizePath,
|
normalizePath,
|
||||||
ProjectGraphProjectNode,
|
ProjectGraphProjectNode,
|
||||||
|
readJsonFile,
|
||||||
workspaceRoot,
|
workspaceRoot,
|
||||||
} from '@nx/devkit';
|
} from '@nx/devkit';
|
||||||
|
|
||||||
@ -74,7 +75,10 @@ export function buildEsbuildOptions(
|
|||||||
} else if (options.platform === 'node' && format === 'cjs') {
|
} else if (options.platform === 'node' && format === 'cjs') {
|
||||||
// When target platform Node and target format is CJS, then also transpile workspace libs used by the app.
|
// When target platform Node and target format is CJS, then also transpile workspace libs used by the app.
|
||||||
// Provide a `require` override in the main entry file so workspace libs can be loaded when running the app.
|
// Provide a `require` override in the main entry file so workspace libs can be loaded when running the app.
|
||||||
const paths = getTsConfigCompilerPaths(context);
|
const paths = options.isTsSolutionSetup
|
||||||
|
? createPathsFromTsConfigReferences(context)
|
||||||
|
: getTsConfigCompilerPaths(context);
|
||||||
|
|
||||||
const entryPointsFromProjects = getEntryPoints(
|
const entryPointsFromProjects = getEntryPoints(
|
||||||
context.projectName,
|
context.projectName,
|
||||||
context,
|
context,
|
||||||
@ -123,6 +127,132 @@ export function buildEsbuildOptions(
|
|||||||
return esbuildOptions;
|
return esbuildOptions;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When using TS project references we need to map the paths to the referenced projects.
|
||||||
|
* This is necessary because esbuild does not support project references out of the box.
|
||||||
|
* @param context ExecutorContext
|
||||||
|
*/
|
||||||
|
export function createPathsFromTsConfigReferences(
|
||||||
|
context: ExecutorContext
|
||||||
|
): Record<string, string[]> {
|
||||||
|
const {
|
||||||
|
findAllProjectNodeDependencies,
|
||||||
|
} = require('nx/src/utils/project-graph-utils');
|
||||||
|
const {
|
||||||
|
isValidPackageJsonBuildConfig,
|
||||||
|
} = require('@nx/js/src/plugins/typescript/util');
|
||||||
|
const { readTsConfig } = require('@nx/js');
|
||||||
|
const {
|
||||||
|
findRuntimeTsConfigName,
|
||||||
|
} = require('@nx/js/src/utils/typescript/ts-solution-setup');
|
||||||
|
|
||||||
|
const deps = findAllProjectNodeDependencies(
|
||||||
|
context.projectName,
|
||||||
|
context.projectGraph
|
||||||
|
);
|
||||||
|
const tsConfig = readJsonFile(
|
||||||
|
joinPathFragments(context.root, 'tsconfig.json')
|
||||||
|
);
|
||||||
|
const referencesAsPaths = new Set(
|
||||||
|
tsConfig.references.reduce((acc, ref) => {
|
||||||
|
if (!ref.path) return acc;
|
||||||
|
|
||||||
|
const fullPath = joinPathFragments(workspaceRoot, ref.path);
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (lstatSync(fullPath).isDirectory()) {
|
||||||
|
acc.push(fullPath);
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
// Ignore errors (e.g., path doesn't exist)
|
||||||
|
}
|
||||||
|
|
||||||
|
return acc;
|
||||||
|
}, [])
|
||||||
|
);
|
||||||
|
|
||||||
|
// for each dep we check if it contains a build target
|
||||||
|
// we only want to add the paths for projects that do not have a build target
|
||||||
|
return deps.reduce((acc, dep) => {
|
||||||
|
const projectNode = context.projectGraph.nodes[dep];
|
||||||
|
const projectPath = joinPathFragments(workspaceRoot, projectNode.data.root);
|
||||||
|
const resolvedTsConfigPath =
|
||||||
|
findRuntimeTsConfigName(projectPath) ?? 'tsconfig.json';
|
||||||
|
const projTsConfig = readTsConfig(resolvedTsConfigPath) as any;
|
||||||
|
|
||||||
|
const projectPkgJson = readJsonFile(
|
||||||
|
joinPathFragments(projectPath, 'package.json')
|
||||||
|
);
|
||||||
|
|
||||||
|
if (
|
||||||
|
projTsConfig &&
|
||||||
|
!isValidPackageJsonBuildConfig(
|
||||||
|
projTsConfig,
|
||||||
|
workspaceRoot,
|
||||||
|
projectPath
|
||||||
|
) &&
|
||||||
|
projectPkgJson?.name
|
||||||
|
) {
|
||||||
|
const entryPoint = getProjectEntryPoint(projectPkgJson, projectPath);
|
||||||
|
if (referencesAsPaths.has(projectPath)) {
|
||||||
|
acc[projectPkgJson.name] = [path.relative(workspaceRoot, entryPoint)];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return acc;
|
||||||
|
}, {});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the entry point for the project
|
||||||
|
function getProjectEntryPoint(projectPkgJson: any, projectPath: string) {
|
||||||
|
let entryPoint = null;
|
||||||
|
if (typeof projectPkgJson.exports === 'string') {
|
||||||
|
// If exports is a string, use it as the entry point
|
||||||
|
entryPoint = path.relative(
|
||||||
|
workspaceRoot,
|
||||||
|
joinPathFragments(projectPath, projectPkgJson.exports)
|
||||||
|
);
|
||||||
|
} else if (
|
||||||
|
typeof projectPkgJson.exports === 'object' &&
|
||||||
|
projectPkgJson.exports['.']
|
||||||
|
) {
|
||||||
|
// If exports is an object and has a '.' key, process it
|
||||||
|
const exportEntry = projectPkgJson.exports['.'];
|
||||||
|
if (typeof exportEntry === 'object') {
|
||||||
|
entryPoint =
|
||||||
|
exportEntry.import ||
|
||||||
|
exportEntry.require ||
|
||||||
|
exportEntry.default ||
|
||||||
|
null;
|
||||||
|
} else if (typeof exportEntry === 'string') {
|
||||||
|
entryPoint = exportEntry;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (entryPoint) {
|
||||||
|
entryPoint = path.relative(
|
||||||
|
workspaceRoot,
|
||||||
|
joinPathFragments(projectPath, entryPoint)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If no exports were found, fall back to main and module
|
||||||
|
if (!entryPoint) {
|
||||||
|
if (projectPkgJson.main) {
|
||||||
|
entryPoint = path.relative(
|
||||||
|
workspaceRoot,
|
||||||
|
joinPathFragments(projectPath, projectPkgJson.main)
|
||||||
|
);
|
||||||
|
} else if (projectPkgJson.module) {
|
||||||
|
entryPoint = path.relative(
|
||||||
|
workspaceRoot,
|
||||||
|
joinPathFragments(projectPath, projectPkgJson.module)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return entryPoint;
|
||||||
|
}
|
||||||
|
|
||||||
export function getOutExtension(
|
export function getOutExtension(
|
||||||
format: 'cjs' | 'esm',
|
format: 'cjs' | 'esm',
|
||||||
options: Pick<NormalizedEsBuildExecutorOptions, 'userDefinedBuildOptions'>
|
options: Pick<NormalizedEsBuildExecutorOptions, 'userDefinedBuildOptions'>
|
||||||
|
|||||||
@ -35,7 +35,11 @@ import { hashArray, hashFile, hashObject } from 'nx/src/hasher/file-hasher';
|
|||||||
import { getLockFileName } from 'nx/src/plugins/js/lock-file/lock-file';
|
import { getLockFileName } from 'nx/src/plugins/js/lock-file/lock-file';
|
||||||
import { workspaceDataDirectory } from 'nx/src/utils/cache-directory';
|
import { workspaceDataDirectory } from 'nx/src/utils/cache-directory';
|
||||||
import type { ParsedCommandLine, System } from 'typescript';
|
import type { ParsedCommandLine, System } from 'typescript';
|
||||||
import { addBuildAndWatchDepsTargets } from './util';
|
import {
|
||||||
|
addBuildAndWatchDepsTargets,
|
||||||
|
isValidPackageJsonBuildConfig,
|
||||||
|
ParsedTsconfigData,
|
||||||
|
} from './util';
|
||||||
|
|
||||||
export interface TscPluginOptions {
|
export interface TscPluginOptions {
|
||||||
typecheck?:
|
typecheck?:
|
||||||
@ -72,12 +76,7 @@ interface NormalizedPluginOptions {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type TscProjectResult = Pick<ProjectConfiguration, 'targets'>;
|
type TscProjectResult = Pick<ProjectConfiguration, 'targets'>;
|
||||||
type ParsedTsconfigData = Pick<
|
|
||||||
ParsedCommandLine,
|
|
||||||
'options' | 'projectReferences' | 'raw'
|
|
||||||
> & {
|
|
||||||
extendedConfigFile: { filePath: string; externalPackage?: string } | null;
|
|
||||||
};
|
|
||||||
type TsconfigCacheData = {
|
type TsconfigCacheData = {
|
||||||
data: ParsedTsconfigData;
|
data: ParsedTsconfigData;
|
||||||
hash: string;
|
hash: string;
|
||||||
@ -756,103 +755,6 @@ function getOutputs(
|
|||||||
return Array.from(outputs);
|
return Array.from(outputs);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Validates the build configuration of a `package.json` file by ensuring that paths in the `exports`, `module`,
|
|
||||||
* and `main` fields reference valid output paths within the `outDir` defined in the TypeScript configuration.
|
|
||||||
* Priority is given to the `exports` field, specifically the `.` export if defined. If `exports` is not defined,
|
|
||||||
* the function falls back to validating `main` and `module` fields. If `outFile` is specified, it validates that the file
|
|
||||||
* is located within the output directory.
|
|
||||||
* If no `package.json` file exists, it assumes the configuration is valid.
|
|
||||||
*
|
|
||||||
* @param tsConfig The TypeScript configuration object.
|
|
||||||
* @param workspaceRoot The workspace root path.
|
|
||||||
* @param projectRoot The project root path.
|
|
||||||
* @returns `true` if the package has a valid build configuration; otherwise, `false`.
|
|
||||||
*/
|
|
||||||
function isValidPackageJsonBuildConfig(
|
|
||||||
tsConfig: ParsedTsconfigData,
|
|
||||||
workspaceRoot: string,
|
|
||||||
projectRoot: string
|
|
||||||
): boolean {
|
|
||||||
const packageJsonPath = join(workspaceRoot, projectRoot, 'package.json');
|
|
||||||
if (!existsSync(packageJsonPath)) {
|
|
||||||
// If the package.json file does not exist.
|
|
||||||
// Assume it's valid because it would be using `project.json` instead.
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
const packageJson = readJsonFile(packageJsonPath);
|
|
||||||
|
|
||||||
const outDir = tsConfig.options.outFile
|
|
||||||
? dirname(tsConfig.options.outFile)
|
|
||||||
: tsConfig.options.outDir;
|
|
||||||
const resolvedOutDir = outDir
|
|
||||||
? resolve(workspaceRoot, projectRoot, outDir)
|
|
||||||
: undefined;
|
|
||||||
|
|
||||||
const isPathSourceFile = (path: string): boolean => {
|
|
||||||
if (resolvedOutDir) {
|
|
||||||
const pathToCheck = resolve(workspaceRoot, projectRoot, path);
|
|
||||||
return !pathToCheck.startsWith(resolvedOutDir);
|
|
||||||
}
|
|
||||||
|
|
||||||
const ext = extname(path);
|
|
||||||
// Check that the file extension is a TS file extension. As the source files are in the same directory as the output files.
|
|
||||||
return ['.ts', '.tsx', '.cts', '.mts'].includes(ext);
|
|
||||||
};
|
|
||||||
|
|
||||||
// Checks if the value is a path within the `src` directory.
|
|
||||||
const containsInvalidPath = (
|
|
||||||
value: string | Record<string, string>
|
|
||||||
): boolean => {
|
|
||||||
if (typeof value === 'string') {
|
|
||||||
return isPathSourceFile(value);
|
|
||||||
} else if (typeof value === 'object') {
|
|
||||||
return Object.entries(value).some(([currentKey, subValue]) => {
|
|
||||||
// Skip types field
|
|
||||||
if (currentKey === 'types') {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (typeof subValue === 'string') {
|
|
||||||
return isPathSourceFile(subValue);
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
};
|
|
||||||
|
|
||||||
const exports = packageJson?.exports;
|
|
||||||
|
|
||||||
// Check the `.` export if `exports` is defined.
|
|
||||||
if (exports) {
|
|
||||||
if (typeof exports === 'string') {
|
|
||||||
return !isPathSourceFile(exports);
|
|
||||||
}
|
|
||||||
if (typeof exports === 'object' && '.' in exports) {
|
|
||||||
return !containsInvalidPath(exports['.']);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check other exports if `.` is not defined or valid.
|
|
||||||
for (const key in exports) {
|
|
||||||
if (key !== '.' && containsInvalidPath(exports[key])) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If `exports` is not defined, fallback to `main` and `module` fields.
|
|
||||||
const buildPaths = ['main', 'module'];
|
|
||||||
for (const field of buildPaths) {
|
|
||||||
if (packageJson[field] && isPathSourceFile(packageJson[field])) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
function pathToInputOrOutput(
|
function pathToInputOrOutput(
|
||||||
path: string,
|
path: string,
|
||||||
workspaceRoot: string,
|
workspaceRoot: string,
|
||||||
|
|||||||
@ -1,7 +1,16 @@
|
|||||||
import { readJsonFile, type TargetConfiguration } from '@nx/devkit';
|
import { readJsonFile, type TargetConfiguration } from '@nx/devkit';
|
||||||
import { existsSync } from 'node:fs';
|
import { existsSync } from 'node:fs';
|
||||||
|
import { dirname, extname, isAbsolute, relative, resolve } from 'node:path';
|
||||||
import { type PackageManagerCommands } from 'nx/src/utils/package-manager';
|
import { type PackageManagerCommands } from 'nx/src/utils/package-manager';
|
||||||
import { join } from 'path';
|
import { join } from 'path';
|
||||||
|
import { type ParsedCommandLine } from 'typescript';
|
||||||
|
|
||||||
|
export type ParsedTsconfigData = Pick<
|
||||||
|
ParsedCommandLine,
|
||||||
|
'options' | 'projectReferences' | 'raw'
|
||||||
|
> & {
|
||||||
|
extendedConfigFile: { filePath: string; externalPackage?: string } | null;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Allow uses that use incremental builds to run `nx watch-deps` to continuously build all dependencies.
|
* Allow uses that use incremental builds to run `nx watch-deps` to continuously build all dependencies.
|
||||||
@ -39,3 +48,94 @@ export function addBuildAndWatchDepsTargets(
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function isValidPackageJsonBuildConfig(
|
||||||
|
tsConfig: ParsedTsconfigData,
|
||||||
|
workspaceRoot: string,
|
||||||
|
projectRoot: string
|
||||||
|
): boolean {
|
||||||
|
const resolvedProjectPath = isAbsolute(projectRoot)
|
||||||
|
? relative(workspaceRoot, projectRoot)
|
||||||
|
: projectRoot;
|
||||||
|
const packageJsonPath = join(
|
||||||
|
workspaceRoot,
|
||||||
|
resolvedProjectPath,
|
||||||
|
'package.json'
|
||||||
|
);
|
||||||
|
if (!existsSync(packageJsonPath)) {
|
||||||
|
// If the package.json file does not exist.
|
||||||
|
// Assume it's valid because it would be using `project.json` instead.
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
const packageJson = readJsonFile(packageJsonPath);
|
||||||
|
|
||||||
|
const outDir = tsConfig.options.outFile
|
||||||
|
? dirname(tsConfig.options.outFile)
|
||||||
|
: tsConfig.options.outDir;
|
||||||
|
const resolvedOutDir = outDir
|
||||||
|
? resolve(workspaceRoot, resolvedProjectPath, outDir)
|
||||||
|
: undefined;
|
||||||
|
|
||||||
|
const isPathSourceFile = (path: string): boolean => {
|
||||||
|
if (resolvedOutDir) {
|
||||||
|
const pathToCheck = resolve(workspaceRoot, resolvedProjectPath, path);
|
||||||
|
return !pathToCheck.startsWith(resolvedOutDir);
|
||||||
|
}
|
||||||
|
|
||||||
|
const ext = extname(path);
|
||||||
|
// Check that the file extension is a TS file extension. As the source files are in the same directory as the output files.
|
||||||
|
return ['.ts', '.tsx', '.cts', '.mts'].includes(ext);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Checks if the value is a path within the `src` directory.
|
||||||
|
const containsInvalidPath = (
|
||||||
|
value: string | Record<string, string>
|
||||||
|
): boolean => {
|
||||||
|
if (typeof value === 'string') {
|
||||||
|
return isPathSourceFile(value);
|
||||||
|
} else if (typeof value === 'object') {
|
||||||
|
return Object.entries(value).some(([currentKey, subValue]) => {
|
||||||
|
// Skip types field
|
||||||
|
if (currentKey === 'types') {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (typeof subValue === 'string') {
|
||||||
|
return isPathSourceFile(subValue);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
const exports = packageJson?.exports;
|
||||||
|
|
||||||
|
// Check the `.` export if `exports` is defined.
|
||||||
|
if (exports) {
|
||||||
|
if (typeof exports === 'string') {
|
||||||
|
return !isPathSourceFile(exports);
|
||||||
|
}
|
||||||
|
if (typeof exports === 'object' && '.' in exports) {
|
||||||
|
return !containsInvalidPath(exports['.']);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check other exports if `.` is not defined or valid.
|
||||||
|
for (const key in exports) {
|
||||||
|
if (key !== '.' && containsInvalidPath(exports[key])) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If `exports` is not defined, fallback to `main` and `module` fields.
|
||||||
|
const buildPaths = ['main', 'module'];
|
||||||
|
for (const field of buildPaths) {
|
||||||
|
if (packageJson[field] && isPathSourceFile(packageJson[field])) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|||||||
@ -108,9 +108,10 @@ export function assertNotUsingTsSolutionSetup(
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function findRuntimeTsConfigName(
|
export function findRuntimeTsConfigName(
|
||||||
tree: Tree,
|
projectRoot: string,
|
||||||
projectRoot: string
|
tree?: Tree
|
||||||
): string | null {
|
): string | null {
|
||||||
|
tree ??= new FsTree(workspaceRoot, false);
|
||||||
if (tree.exists(joinPathFragments(projectRoot, 'tsconfig.app.json')))
|
if (tree.exists(joinPathFragments(projectRoot, 'tsconfig.app.json')))
|
||||||
return 'tsconfig.app.json';
|
return 'tsconfig.app.json';
|
||||||
if (tree.exists(joinPathFragments(projectRoot, 'tsconfig.lib.json')))
|
if (tree.exists(joinPathFragments(projectRoot, 'tsconfig.lib.json')))
|
||||||
|
|||||||
@ -235,7 +235,7 @@ export function createStorybookTsconfigFile(
|
|||||||
};
|
};
|
||||||
|
|
||||||
if (useTsSolution) {
|
if (useTsSolution) {
|
||||||
const runtimeConfig = findRuntimeTsConfigName(tree, projectRoot);
|
const runtimeConfig = findRuntimeTsConfigName(projectRoot, tree);
|
||||||
if (runtimeConfig) {
|
if (runtimeConfig) {
|
||||||
storybookTsConfig.references ??= [];
|
storybookTsConfig.references ??= [];
|
||||||
storybookTsConfig.references.push({
|
storybookTsConfig.references.push({
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user