feat(js): remove nx property from generated package.json files (#29705)
This PR updates our generators to no longer generate with `nx` in `package.json` by default. The only times it is needed is if you pass add `tags` or `implicitDependencies` to the project config. This PR replaces our `projectType` checks to use the `getProjectType` util from `@nx/js` to prefer the project config, but otherwise will check for our conventions (e.g. using `exports` for libs, `tsconfig.lib.json` vs `tsconfig.app.json`). ## Impact - There shouldn't be any behavioral changes to existing projects that have explicit `projectType`, `name`, etc. in with `project.json` or `package.json` (via `nx` property). - For new projects created under the new TS setup, the `nx` property will no longer be there. Generators with logic that depend on `projectType` will now check for `tsconfig.lib.json` and `tsconfig.app.json` (so all of our generators are covered). If none of those tsconfig files are found, then we check `package.json`, since libraries are required to have `exports` to be consumed.
This commit is contained in:
parent
ae9aa5ac76
commit
45847a6754
@ -114,70 +114,70 @@ ${content}`
|
||||
|
||||
// check build
|
||||
expect(runCLI(`build ${esbuildParentLib}`)).toContain(
|
||||
`Successfully ran target build for project ${esbuildParentLib} and 5 tasks it depends on`
|
||||
`Successfully ran target build for project @proj/${esbuildParentLib} and 5 tasks it depends on`
|
||||
);
|
||||
expect(runCLI(`build ${rollupParentLib}`)).toContain(
|
||||
`Successfully ran target build for project ${rollupParentLib} and 5 tasks it depends on`
|
||||
`Successfully ran target build for project @proj/${rollupParentLib} and 5 tasks it depends on`
|
||||
);
|
||||
expect(runCLI(`build ${swcParentLib}`)).toContain(
|
||||
`Successfully ran target build for project ${swcParentLib} and 5 tasks it depends on`
|
||||
`Successfully ran target build for project @proj/${swcParentLib} and 5 tasks it depends on`
|
||||
);
|
||||
expect(runCLI(`build ${tscParentLib}`)).toContain(
|
||||
`Successfully ran target build for project ${tscParentLib} and 5 tasks it depends on`
|
||||
`Successfully ran target build for project @proj/${tscParentLib} and 5 tasks it depends on`
|
||||
);
|
||||
expect(runCLI(`build ${viteParentLib}`)).toContain(
|
||||
`Successfully ran target build for project ${viteParentLib} and 5 tasks it depends on`
|
||||
`Successfully ran target build for project @proj/${viteParentLib} and 5 tasks it depends on`
|
||||
);
|
||||
|
||||
// check typecheck
|
||||
expect(runCLI(`typecheck ${esbuildParentLib}`)).toContain(
|
||||
`Successfully ran target typecheck for project ${esbuildParentLib} and 5 tasks it depends on`
|
||||
`Successfully ran target typecheck for project @proj/${esbuildParentLib} and 5 tasks it depends on`
|
||||
);
|
||||
expect(runCLI(`typecheck ${rollupParentLib}`)).toContain(
|
||||
`Successfully ran target typecheck for project ${rollupParentLib} and 5 tasks it depends on`
|
||||
`Successfully ran target typecheck for project @proj/${rollupParentLib} and 5 tasks it depends on`
|
||||
);
|
||||
expect(runCLI(`typecheck ${swcParentLib}`)).toContain(
|
||||
`Successfully ran target typecheck for project ${swcParentLib} and 5 tasks it depends on`
|
||||
`Successfully ran target typecheck for project @proj/${swcParentLib} and 5 tasks it depends on`
|
||||
);
|
||||
expect(runCLI(`typecheck ${tscParentLib}`)).toContain(
|
||||
`Successfully ran target typecheck for project ${tscParentLib} and 5 tasks it depends on`
|
||||
`Successfully ran target typecheck for project @proj/${tscParentLib} and 5 tasks it depends on`
|
||||
);
|
||||
expect(runCLI(`typecheck ${viteParentLib}`)).toContain(
|
||||
`Successfully ran target typecheck for project ${viteParentLib} and 5 tasks it depends on`
|
||||
`Successfully ran target typecheck for project @proj/${viteParentLib} and 5 tasks it depends on`
|
||||
);
|
||||
|
||||
// check lint
|
||||
expect(runCLI(`lint ${esbuildParentLib}`)).toContain(
|
||||
`Successfully ran target lint for project ${esbuildParentLib}`
|
||||
`Successfully ran target lint for project @proj/${esbuildParentLib}`
|
||||
);
|
||||
expect(runCLI(`lint ${rollupParentLib}`)).toContain(
|
||||
`Successfully ran target lint for project ${rollupParentLib}`
|
||||
`Successfully ran target lint for project @proj/${rollupParentLib}`
|
||||
);
|
||||
expect(runCLI(`lint ${swcParentLib}`)).toContain(
|
||||
`Successfully ran target lint for project ${swcParentLib}`
|
||||
`Successfully ran target lint for project @proj/${swcParentLib}`
|
||||
);
|
||||
expect(runCLI(`lint ${tscParentLib}`)).toContain(
|
||||
`Successfully ran target lint for project ${tscParentLib}`
|
||||
`Successfully ran target lint for project @proj/${tscParentLib}`
|
||||
);
|
||||
expect(runCLI(`lint ${viteParentLib}`)).toContain(
|
||||
`Successfully ran target lint for project ${viteParentLib}`
|
||||
`Successfully ran target lint for project @proj/${viteParentLib}`
|
||||
);
|
||||
|
||||
// check test
|
||||
expect(runCLI(`test ${esbuildParentLib}`)).toContain(
|
||||
`Successfully ran target test for project ${esbuildParentLib}`
|
||||
`Successfully ran target test for project @proj/${esbuildParentLib}`
|
||||
);
|
||||
expect(runCLI(`test ${rollupParentLib}`)).toContain(
|
||||
`Successfully ran target test for project ${rollupParentLib}`
|
||||
`Successfully ran target test for project @proj/${rollupParentLib}`
|
||||
);
|
||||
expect(runCLI(`test ${swcParentLib}`)).toContain(
|
||||
`Successfully ran target test for project ${swcParentLib}`
|
||||
`Successfully ran target test for project @proj/${swcParentLib}`
|
||||
);
|
||||
expect(runCLI(`test ${tscParentLib}`)).toContain(
|
||||
`Successfully ran target test for project ${tscParentLib}`
|
||||
`Successfully ran target test for project @proj/${tscParentLib}`
|
||||
);
|
||||
expect(runCLI(`test ${viteParentLib}`)).toContain(
|
||||
`Successfully ran target test for project ${viteParentLib}`
|
||||
`Successfully ran target test for project @proj/${viteParentLib}`
|
||||
);
|
||||
}, 300_000);
|
||||
});
|
||||
|
||||
@ -42,14 +42,14 @@ describe('Nx Plugin (TS solution)', () => {
|
||||
`generate @nx/plugin:migration packages/${plugin}/src/migrations/update-${migrationVersion}/update-${migrationVersion} --packageVersion=${migrationVersion} --packageJsonUpdates=false`
|
||||
);
|
||||
|
||||
expect(runCLI(`lint ${plugin}`)).toContain(
|
||||
`Successfully ran target lint for project ${plugin}`
|
||||
expect(runCLI(`lint @proj/${plugin}`)).toContain(
|
||||
`Successfully ran target lint for project @proj/${plugin}`
|
||||
);
|
||||
expect(runCLI(`typecheck ${plugin}`)).toContain(
|
||||
`Successfully ran target typecheck for project ${plugin}`
|
||||
expect(runCLI(`typecheck @proj/${plugin}`)).toContain(
|
||||
`Successfully ran target typecheck for project @proj/${plugin}`
|
||||
);
|
||||
expect(runCLI(`build ${plugin}`)).toContain(
|
||||
`Successfully ran target build for project ${plugin}`
|
||||
expect(runCLI(`build @proj/${plugin}`)).toContain(
|
||||
`Successfully ran target build for project @proj/${plugin}`
|
||||
);
|
||||
checkFilesExist(
|
||||
// entry point
|
||||
@ -71,11 +71,11 @@ describe('Nx Plugin (TS solution)', () => {
|
||||
`packages/${plugin}/dist/migrations/update-${migrationVersion}/update-${migrationVersion}.js`,
|
||||
`packages/${plugin}/dist/migrations/update-${migrationVersion}/update-${migrationVersion}.d.ts`
|
||||
);
|
||||
expect(runCLI(`test ${plugin}`)).toContain(
|
||||
`Successfully ran target test for project ${plugin}`
|
||||
expect(runCLI(`test @proj/${plugin}`)).toContain(
|
||||
`Successfully ran target test for project @proj/${plugin}`
|
||||
);
|
||||
expect(runCLI(`e2e ${plugin}-e2e`)).toContain(
|
||||
`Successfully ran target e2e for project ${plugin}-e2e`
|
||||
expect(runCLI(`e2e @proj/${plugin}-e2e`)).toContain(
|
||||
`Successfully ran target e2e for project @proj/${plugin}-e2e`
|
||||
);
|
||||
}, 90000);
|
||||
|
||||
|
||||
@ -32,13 +32,27 @@ describe('Vite - TS solution setup', () => {
|
||||
const viteLib = uniq('vite-lib');
|
||||
const noBundlerLib = uniq('no-bundler-lib');
|
||||
|
||||
runCLI(`generate @nx/react:app apps/${reactApp} --bundler=vite`);
|
||||
runCLI(`generate @nx/js:lib packages/${esbuildLib} --bundler=esbuild`);
|
||||
runCLI(`generate @nx/js:lib packages/${rollupLib} --bundler=rollup`);
|
||||
runCLI(`generate @nx/js:lib packages/${swcLib} --bundler=swc`);
|
||||
runCLI(`generate @nx/js:lib packages/${tscLib} --bundler=tsc`);
|
||||
runCLI(`generate @nx/js:lib packages/${viteLib} --bundler=vite`);
|
||||
runCLI(`generate @nx/js:lib packages/${noBundlerLib} --bundler=none`);
|
||||
runCLI(
|
||||
`generate @nx/react:app apps/${reactApp} --bundler=vite --e2eTestRunner=none`
|
||||
);
|
||||
runCLI(
|
||||
`generate @nx/js:lib packages/${esbuildLib} --bundler=esbuild --e2eTestRunner=none`
|
||||
);
|
||||
runCLI(
|
||||
`generate @nx/js:lib packages/${rollupLib} --bundler=rollup --e2eTestRunner=none`
|
||||
);
|
||||
runCLI(
|
||||
`generate @nx/js:lib packages/${swcLib} --bundler=swc --e2eTestRunner=none`
|
||||
);
|
||||
runCLI(
|
||||
`generate @nx/js:lib packages/${tscLib} --bundler=tsc --e2eTestRunner=none`
|
||||
);
|
||||
runCLI(
|
||||
`generate @nx/js:lib packages/${viteLib} --bundler=vite --e2eTestRunner=none`
|
||||
);
|
||||
runCLI(
|
||||
`generate @nx/js:lib packages/${noBundlerLib} --bundler=none --e2eTestRunner=none`
|
||||
);
|
||||
|
||||
// import all libs from the app
|
||||
updateFile(
|
||||
@ -87,12 +101,12 @@ ${content}`
|
||||
|
||||
// check build
|
||||
expect(runCLI(`build ${reactApp}`)).toContain(
|
||||
`Successfully ran target build for project ${reactApp} and 5 tasks it depends on`
|
||||
`Successfully ran target build for project @proj/${reactApp} and 5 tasks it depends on`
|
||||
);
|
||||
|
||||
// check typecheck
|
||||
expect(runCLI(`typecheck ${reactApp}`)).toContain(
|
||||
`Successfully ran target typecheck for project ${reactApp} and 6 tasks it depends on`
|
||||
`Successfully ran target typecheck for project @proj/${reactApp} and 6 tasks it depends on`
|
||||
);
|
||||
}, 300_000);
|
||||
});
|
||||
|
||||
@ -50,11 +50,11 @@ describe('Vue Plugin', () => {
|
||||
`
|
||||
);
|
||||
|
||||
expect(() => runCLI(`lint ${app}`)).not.toThrow();
|
||||
expect(() => runCLI(`test ${app}`)).not.toThrow();
|
||||
expect(() => runCLI(`build ${app}`)).not.toThrow();
|
||||
expect(() => runCLI(`lint ${lib}`)).not.toThrow();
|
||||
expect(() => runCLI(`test ${lib}`)).not.toThrow();
|
||||
expect(() => runCLI(`build ${lib}`)).not.toThrow();
|
||||
expect(() => runCLI(`lint @proj/${app}`)).not.toThrow();
|
||||
expect(() => runCLI(`test @proj/${app}`)).not.toThrow();
|
||||
expect(() => runCLI(`build @proj/${app}`)).not.toThrow();
|
||||
expect(() => runCLI(`lint @proj/${lib}`)).not.toThrow();
|
||||
expect(() => runCLI(`test @proj/${lib}`)).not.toThrow();
|
||||
expect(() => runCLI(`build @proj/${lib}`)).not.toThrow();
|
||||
}, 300_000);
|
||||
});
|
||||
|
||||
@ -202,14 +202,13 @@ export function updateTsConfigForComponentTesting(
|
||||
tree: Tree,
|
||||
projectConfig: ProjectConfiguration
|
||||
) {
|
||||
const tsConfigPath = joinPathFragments(
|
||||
projectConfig.root,
|
||||
projectConfig.projectType === 'library'
|
||||
? 'tsconfig.lib.json'
|
||||
: 'tsconfig.app.json'
|
||||
);
|
||||
let tsConfigPath: string | null = null;
|
||||
for (const candidate of ['tsconfig.lib.json', 'tsconfig.app.json']) {
|
||||
const p = joinPathFragments(projectConfig.root, candidate);
|
||||
if (tree.exists(p)) tsConfigPath = p;
|
||||
}
|
||||
|
||||
if (tree.exists(tsConfigPath)) {
|
||||
if (tsConfigPath !== null) {
|
||||
updateJson(tree, tsConfigPath, (json) => {
|
||||
const excluded = new Set([
|
||||
...(json.exclude || []),
|
||||
|
||||
@ -4,7 +4,7 @@ export function updateTsConfigsToJs(
|
||||
tree: Tree,
|
||||
options: { projectRoot: string }
|
||||
): void {
|
||||
let updateConfigPath: string;
|
||||
let updateConfigPath: string | null = null;
|
||||
|
||||
const paths = {
|
||||
tsConfig: `${options.projectRoot}/tsconfig.json`,
|
||||
@ -12,19 +12,6 @@ export function updateTsConfigsToJs(
|
||||
tsConfigApp: `${options.projectRoot}/tsconfig.app.json`,
|
||||
};
|
||||
|
||||
const getProjectType = (tree: Tree) => {
|
||||
if (tree.exists(paths.tsConfigApp)) {
|
||||
return 'application';
|
||||
}
|
||||
if (tree.exists(paths.tsConfigLib)) {
|
||||
return 'library';
|
||||
}
|
||||
|
||||
throw new Error(
|
||||
`project is missing tsconfig.lib.json or tsconfig.app.json`
|
||||
);
|
||||
};
|
||||
|
||||
updateJson(tree, paths.tsConfig, (json) => {
|
||||
if (json.compilerOptions) {
|
||||
json.compilerOptions.allowJs = true;
|
||||
@ -34,25 +21,30 @@ export function updateTsConfigsToJs(
|
||||
return json;
|
||||
});
|
||||
|
||||
const projectType = getProjectType(tree);
|
||||
|
||||
if (projectType === 'library') {
|
||||
if (tree.exists(paths.tsConfigLib)) {
|
||||
updateConfigPath = paths.tsConfigLib;
|
||||
}
|
||||
if (projectType === 'application') {
|
||||
|
||||
if (tree.exists(paths.tsConfigApp)) {
|
||||
updateConfigPath = paths.tsConfigApp;
|
||||
}
|
||||
|
||||
updateJson(tree, updateConfigPath, (json) => {
|
||||
json.include = uniq([...json.include, 'src/**/*.js']);
|
||||
json.exclude = uniq([
|
||||
...json.exclude,
|
||||
'src/**/*.spec.js',
|
||||
'src/**/*.test.js',
|
||||
]);
|
||||
if (updateConfigPath) {
|
||||
updateJson(tree, updateConfigPath, (json) => {
|
||||
json.include = uniq([...json.include, 'src/**/*.js']);
|
||||
json.exclude = uniq([
|
||||
...json.exclude,
|
||||
'src/**/*.spec.js',
|
||||
'src/**/*.test.js',
|
||||
]);
|
||||
|
||||
return json;
|
||||
});
|
||||
return json;
|
||||
});
|
||||
} else {
|
||||
throw new Error(
|
||||
`project is missing tsconfig.lib.json or tsconfig.app.json`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const uniq = <T extends string[]>(value: T) => [...new Set(value)] as T;
|
||||
|
||||
@ -39,6 +39,7 @@ import {
|
||||
} from '../../utils/config-file';
|
||||
import { hasEslintPlugin } from '../utils/plugin';
|
||||
import { setupRootEsLint } from './setup-root-eslint';
|
||||
import { getProjectType } from '@nx/js/src/utils/typescript/ts-solution-setup';
|
||||
|
||||
interface LintProjectOptions {
|
||||
project: string;
|
||||
@ -99,7 +100,7 @@ export async function lintProjectGeneratorInternal(
|
||||
lintFilePatterns &&
|
||||
lintFilePatterns.length &&
|
||||
!lintFilePatterns.includes('{projectRoot}') &&
|
||||
isBuildableLibraryProject(projectConfig)
|
||||
isBuildableLibraryProject(tree, projectConfig)
|
||||
) {
|
||||
lintFilePatterns.push(`{projectRoot}/package.json`);
|
||||
}
|
||||
@ -175,7 +176,7 @@ export async function lintProjectGeneratorInternal(
|
||||
|
||||
// Buildable libs need source analysis enabled for linting `package.json`.
|
||||
if (
|
||||
isBuildableLibraryProject(projectConfig) &&
|
||||
isBuildableLibraryProject(tree, projectConfig) &&
|
||||
!isJsAnalyzeSourceFilesEnabled(tree)
|
||||
) {
|
||||
updateJson(tree, 'nx.json', (json) => {
|
||||
@ -225,7 +226,7 @@ function createEsLintConfiguration(
|
||||
|
||||
const addDependencyChecks =
|
||||
options.addPackageJsonDependencyChecks ||
|
||||
isBuildableLibraryProject(projectConfig);
|
||||
isBuildableLibraryProject(tree, projectConfig);
|
||||
|
||||
const overrides: Linter.ConfigOverride<Linter.RulesRecord>[] = useFlatConfig(
|
||||
tree
|
||||
@ -328,10 +329,12 @@ function isJsAnalyzeSourceFilesEnabled(tree: Tree): boolean {
|
||||
}
|
||||
|
||||
function isBuildableLibraryProject(
|
||||
tree: Tree,
|
||||
projectConfig: ProjectConfiguration
|
||||
): boolean {
|
||||
return (
|
||||
projectConfig.projectType === 'library' &&
|
||||
getProjectType(tree, projectConfig.root, projectConfig.projectType) ===
|
||||
'library' &&
|
||||
projectConfig.targets?.build &&
|
||||
!!projectConfig.targets.build
|
||||
);
|
||||
|
||||
@ -11,6 +11,7 @@ import {
|
||||
import { NormalizedSchema, normalizeOptions } from './lib/normalize-options';
|
||||
import { addImport } from './lib/add-import';
|
||||
import { dirname, join, parse, relative } from 'path';
|
||||
import { getProjectType } from '@nx/js/src/utils/typescript/ts-solution-setup';
|
||||
|
||||
export async function expoComponentGenerator(host: Tree, schema: Schema) {
|
||||
const options = await normalizeOptions(host, schema);
|
||||
@ -46,8 +47,9 @@ function createComponentFiles(host: Tree, options: NormalizedSchema) {
|
||||
|
||||
function addExportsToBarrel(host: Tree, options: NormalizedSchema) {
|
||||
const workspace = getProjects(host);
|
||||
const proj = workspace.get(options.projectName);
|
||||
const isApp =
|
||||
workspace.get(options.projectName).projectType === 'application';
|
||||
getProjectType(host, proj.root, proj.projectType) === 'application';
|
||||
|
||||
if (options.export && !isApp) {
|
||||
const indexFilePath = joinPathFragments(
|
||||
|
||||
@ -4,6 +4,7 @@ import {
|
||||
type FileExtensionType,
|
||||
} from '@nx/devkit/src/generators/artifact-name-and-directory-utils';
|
||||
import { Schema } from '../schema';
|
||||
import { getProjectType } from '@nx/js/src/utils/typescript/ts-solution-setup';
|
||||
|
||||
export interface NormalizedSchema extends Omit<Schema, 'js'> {
|
||||
directory: string;
|
||||
@ -38,9 +39,12 @@ export async function normalizeOptions(
|
||||
|
||||
const { className } = names(name);
|
||||
const project = getProjects(host).get(projectName);
|
||||
const { sourceRoot: projectSourceRoot, projectType } = project;
|
||||
const { root, sourceRoot: projectSourceRoot, projectType } = project;
|
||||
|
||||
if (options.export && projectType === 'application') {
|
||||
if (
|
||||
options.export &&
|
||||
getProjectType(host, root, projectType) === 'application'
|
||||
) {
|
||||
logger.warn(
|
||||
`The "--export" option should not be used with applications and will do nothing.`
|
||||
);
|
||||
|
||||
@ -13,6 +13,7 @@ import {
|
||||
type JestPresetExtension,
|
||||
} from '../../../utils/config/config-file';
|
||||
import type { NormalizedJestProjectSchema } from '../schema';
|
||||
import { getProjectType } from '@nx/js/src/utils/typescript/ts-solution-setup';
|
||||
|
||||
export async function createJestConfig(
|
||||
tree: Tree,
|
||||
@ -91,7 +92,13 @@ module.exports = { ...nxPreset };`
|
||||
}
|
||||
|
||||
const jestProjectConfig = `jest.config.${
|
||||
rootProjectConfig.projectType === 'application' ? 'app' : 'lib'
|
||||
getProjectType(
|
||||
tree,
|
||||
rootProjectConfig.root,
|
||||
rootProjectConfig.projectType
|
||||
) === 'application'
|
||||
? 'app'
|
||||
: 'lib'
|
||||
}.${options.js ? 'js' : 'ts'}`;
|
||||
|
||||
tree.rename(rootJestPath, jestProjectConfig);
|
||||
|
||||
@ -6,12 +6,16 @@ import {
|
||||
type Tree,
|
||||
} from '@nx/devkit';
|
||||
import type { NormalizedJestProjectSchema } from '../schema';
|
||||
import { getProjectType } from '@nx/js/src/utils/typescript/ts-solution-setup';
|
||||
|
||||
export function updateTsConfig(
|
||||
host: Tree,
|
||||
options: NormalizedJestProjectSchema
|
||||
) {
|
||||
const { root, projectType } = readProjectConfiguration(host, options.project);
|
||||
const { root, projectType: _projectType } = readProjectConfiguration(
|
||||
host,
|
||||
options.project
|
||||
);
|
||||
if (!host.exists(joinPathFragments(root, 'tsconfig.json'))) {
|
||||
throw new Error(
|
||||
`Expected ${joinPathFragments(
|
||||
@ -31,6 +35,7 @@ export function updateTsConfig(
|
||||
}
|
||||
return json;
|
||||
});
|
||||
const projectType = getProjectType(host, root, _projectType);
|
||||
|
||||
// fall-back runtime tsconfig file path in case the user didn't provide one
|
||||
let runtimeTsconfigPath = joinPathFragments(
|
||||
|
||||
@ -2146,7 +2146,7 @@ describe('lib', () => {
|
||||
swcJestConfig.swcrc = false;
|
||||
|
||||
export default {
|
||||
displayName: 'my-lib',
|
||||
displayName: '@proj/my-lib',
|
||||
preset: '../jest.preset.js',
|
||||
transform: {
|
||||
'^.+\\\\.[tj]s$': ['@swc/jest', swcJestConfig],
|
||||
|
||||
@ -68,6 +68,7 @@ import type {
|
||||
NormalizedLibraryGeneratorOptions,
|
||||
} from './schema';
|
||||
import { sortPackageJsonFields } from '../../utils/package-json/sort-fields';
|
||||
import { getImportPath } from '../../utils/get-import-path';
|
||||
|
||||
const defaultOutputDirectory = 'dist';
|
||||
|
||||
@ -100,6 +101,12 @@ export async function libraryGeneratorInternal(
|
||||
);
|
||||
const options = await normalizeOptions(tree, schema);
|
||||
|
||||
// If we are using the new TS solution
|
||||
// We need to update the workspace file (package.json or pnpm-workspaces.yaml) to include the new project
|
||||
if (options.isUsingTsSolutionConfig) {
|
||||
addProjectToTsSolutionWorkspace(tree, options.projectRoot);
|
||||
}
|
||||
|
||||
createFiles(tree, options);
|
||||
|
||||
await configureProject(tree, options);
|
||||
@ -234,12 +241,6 @@ export async function libraryGeneratorInternal(
|
||||
);
|
||||
}
|
||||
|
||||
// If we are using the new TS solution
|
||||
// We need to update the workspace file (package.json or pnpm-workspaces.yaml) to include the new project
|
||||
if (options.isUsingTsSolutionConfig) {
|
||||
addProjectToTsSolutionWorkspace(tree, options.projectRoot);
|
||||
}
|
||||
|
||||
sortPackageJsonFields(tree, options.projectRoot);
|
||||
|
||||
if (!options.skipFormat) {
|
||||
@ -369,8 +370,24 @@ async function configureProject(
|
||||
delete projectConfiguration.tags;
|
||||
}
|
||||
|
||||
// We want a minimal setup, so unless targets and tags are set, just skip the `nx` property in `package.json`.
|
||||
if (options.isUsingTsSolutionConfig) {
|
||||
delete projectConfiguration.projectType;
|
||||
// SWC executor has logic around sourceRoot and `--strip-leading-paths`. If it is not set then dist will contain the `src` folder rather than being flat.
|
||||
// TODO(leo): Look at how we can remove the dependency on sourceRoot for SWC.
|
||||
if (options.bundler !== 'swc') {
|
||||
delete projectConfiguration.sourceRoot;
|
||||
}
|
||||
}
|
||||
|
||||
// empty targets are cleaned up automatically by `updateProjectConfiguration`
|
||||
updateProjectConfiguration(tree, options.name, projectConfiguration);
|
||||
updateProjectConfiguration(
|
||||
tree,
|
||||
options.isUsingTsSolutionConfig
|
||||
? options.importPath ?? options.name
|
||||
: options.name,
|
||||
projectConfiguration
|
||||
);
|
||||
} else if (options.config === 'workspace' || options.config === 'project') {
|
||||
addProjectConfiguration(tree, options.name, projectConfiguration);
|
||||
} else {
|
||||
@ -897,7 +914,9 @@ async function normalizeOptions(
|
||||
return {
|
||||
...options,
|
||||
fileName,
|
||||
name: projectName,
|
||||
name: isUsingTsSolutionConfig
|
||||
? getImportPath(tree, projectName)
|
||||
: projectName,
|
||||
projectNames,
|
||||
projectRoot,
|
||||
parsedTags,
|
||||
|
||||
@ -244,3 +244,22 @@ export function addProjectToTsSolutionWorkspace(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function getProjectType(
|
||||
tree: Tree,
|
||||
projectRoot: string,
|
||||
projectType?: 'library' | 'application'
|
||||
): 'library' | 'application' {
|
||||
if (projectType) return projectType;
|
||||
if (tree.exists(joinPathFragments(projectRoot, 'tsconfig.lib.json')))
|
||||
return 'library';
|
||||
if (tree.exists(joinPathFragments(projectRoot, 'tsconfig.app.json')))
|
||||
return 'application';
|
||||
// If there are no exports, assume it is an application since both buildable and non-buildable libraries have exports.
|
||||
const packageJsonPath = joinPathFragments(projectRoot, 'package.json');
|
||||
const packageJson = tree.exists(packageJsonPath)
|
||||
? readJson(tree, joinPathFragments(projectRoot, 'package.json'))
|
||||
: null;
|
||||
if (!packageJson?.exports) return 'application';
|
||||
return 'library';
|
||||
}
|
||||
|
||||
@ -7,6 +7,8 @@ import { getNpmScope } from '@nx/js/src/utils/package-json/get-npm-scope';
|
||||
import type { LibraryGeneratorSchema as JsLibraryGeneratorSchema } from '@nx/js/src/generators/library/schema';
|
||||
import { Linter } from '@nx/eslint';
|
||||
import type { LibraryGeneratorOptions, NormalizedOptions } from '../schema';
|
||||
import { isUsingTsSolutionSetup } from '@nx/js/src/utils/typescript/ts-solution-setup';
|
||||
import { getImportPath } from '@nx/js/src/utils/get-import-path';
|
||||
|
||||
export async function normalizeOptions(
|
||||
tree: Tree,
|
||||
@ -47,7 +49,9 @@ export async function normalizeOptions(
|
||||
linter: options.linter ?? Linter.EsLint,
|
||||
parsedTags,
|
||||
prefix: getNpmScope(tree), // we could also allow customizing this
|
||||
projectName,
|
||||
projectName: isUsingTsSolutionSetup(tree)
|
||||
? getImportPath(tree, projectName)
|
||||
: projectName,
|
||||
projectRoot,
|
||||
importPath,
|
||||
service: options.service ?? false,
|
||||
|
||||
@ -563,7 +563,6 @@ describe('lib', () => {
|
||||
"main",
|
||||
"types",
|
||||
"exports",
|
||||
"nx",
|
||||
"dependencies",
|
||||
]
|
||||
`);
|
||||
@ -580,11 +579,6 @@ describe('lib', () => {
|
||||
},
|
||||
"main": "./src/index.ts",
|
||||
"name": "@proj/mylib",
|
||||
"nx": {
|
||||
"name": "mylib",
|
||||
"projectType": "library",
|
||||
"sourceRoot": "mylib/src",
|
||||
},
|
||||
"private": true,
|
||||
"types": "./src/index.ts",
|
||||
"version": "0.0.1",
|
||||
@ -684,9 +678,6 @@ describe('lib', () => {
|
||||
"module": "./dist/index.js",
|
||||
"name": "@proj/mylib",
|
||||
"nx": {
|
||||
"name": "mylib",
|
||||
"projectType": "library",
|
||||
"sourceRoot": "mylib/src",
|
||||
"targets": {
|
||||
"build": {
|
||||
"executor": "@nx/js:swc",
|
||||
|
||||
@ -54,6 +54,13 @@ export async function libraryGenerator(tree: Tree, schema: Schema) {
|
||||
|
||||
export async function libraryGeneratorInternal(tree: Tree, schema: Schema) {
|
||||
const options = await normalizeOptions(tree, schema);
|
||||
|
||||
// If we are using the new TS solution
|
||||
// We need to update the workspace file (package.json or pnpm-workspaces.yaml) to include the new project
|
||||
if (options.isUsingTsSolutionConfig) {
|
||||
addProjectToTsSolutionWorkspace(tree, options.projectRoot);
|
||||
}
|
||||
|
||||
const tasks: GeneratorCallback[] = [];
|
||||
|
||||
if (options.publishable === true && !schema.importPath) {
|
||||
@ -112,12 +119,6 @@ export async function libraryGeneratorInternal(tree: Tree, schema: Schema) {
|
||||
tasks.push(() => installPackagesTask(tree, true));
|
||||
}
|
||||
|
||||
// If we are using the new TS solution
|
||||
// We need to update the workspace file (package.json or pnpm-workspaces.yaml) to include the new project
|
||||
if (options.isUsingTsSolutionConfig) {
|
||||
addProjectToTsSolutionWorkspace(tree, options.projectRoot);
|
||||
}
|
||||
|
||||
sortPackageJsonFields(tree, options.projectRoot);
|
||||
|
||||
if (!schema.skipFormat) {
|
||||
@ -163,14 +164,17 @@ async function normalizeOptions(
|
||||
? options.tags.split(',').map((s) => s.trim())
|
||||
: [];
|
||||
|
||||
const isUsingTsSolutionConfig = isUsingTsSolutionSetup(tree);
|
||||
return {
|
||||
...options,
|
||||
fileName,
|
||||
projectName,
|
||||
projectName: isUsingTsSolutionConfig
|
||||
? getImportPath(tree, projectName)
|
||||
: projectName,
|
||||
projectRoot,
|
||||
parsedTags,
|
||||
importPath,
|
||||
isUsingTsSolutionConfig: isUsingTsSolutionSetup(tree),
|
||||
isUsingTsSolutionConfig,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@ -190,7 +190,7 @@ async function normalizeOptions(
|
||||
propertyName,
|
||||
description,
|
||||
projectRoot,
|
||||
projectSourceRoot,
|
||||
projectSourceRoot: projectSourceRoot ?? join(projectRoot, 'src'),
|
||||
isTsSolutionSetup: isUsingTsSolutionSetup(tree),
|
||||
};
|
||||
}
|
||||
|
||||
@ -69,7 +69,7 @@ async function normalizeOptions(
|
||||
propertyName,
|
||||
description,
|
||||
projectRoot,
|
||||
projectSourceRoot,
|
||||
projectSourceRoot: projectSourceRoot ?? join(projectRoot, 'src'),
|
||||
isTsSolutionSetup: isUsingTsSolutionSetup(tree),
|
||||
};
|
||||
}
|
||||
|
||||
@ -57,7 +57,7 @@ async function normalizeOptions(
|
||||
name,
|
||||
description,
|
||||
projectRoot,
|
||||
projectSourceRoot,
|
||||
projectSourceRoot: projectSourceRoot ?? join(projectRoot, 'src'),
|
||||
isTsSolutionSetup: isUsingTsSolutionSetup(tree),
|
||||
};
|
||||
|
||||
|
||||
@ -330,6 +330,7 @@ describe('NxPlugin Plugin Generator', () => {
|
||||
describe('TS solution setup', () => {
|
||||
beforeEach(() => {
|
||||
tree = createTreeWithEmptyWorkspace();
|
||||
tree.write('.gitignore', '');
|
||||
updateJson(tree, 'package.json', (json) => {
|
||||
json.workspaces = ['packages/*'];
|
||||
return json;
|
||||
@ -371,7 +372,7 @@ describe('NxPlugin Plugin Generator', () => {
|
||||
swcJestConfig.swcrc = false;
|
||||
|
||||
export default {
|
||||
displayName: 'my-plugin',
|
||||
displayName: '@proj/my-plugin',
|
||||
preset: '../jest.preset.js',
|
||||
testEnvironment: 'node',
|
||||
transform: {
|
||||
@ -412,11 +413,119 @@ describe('NxPlugin Plugin Generator', () => {
|
||||
|
||||
const projectTargets = readProjectConfiguration(
|
||||
tree,
|
||||
'my-plugin'
|
||||
'@proj/my-plugin'
|
||||
).targets;
|
||||
|
||||
expect(projectTargets.test).toBeDefined();
|
||||
expect(projectTargets.test?.executor).toEqual('@nx/jest:jest');
|
||||
});
|
||||
|
||||
it('should add project references when using TS solution', async () => {
|
||||
await pluginGenerator(
|
||||
tree,
|
||||
getSchema({
|
||||
e2eTestRunner: 'jest',
|
||||
})
|
||||
);
|
||||
|
||||
expect(readJson(tree, 'tsconfig.json').references).toMatchInlineSnapshot(`
|
||||
[
|
||||
{
|
||||
"path": "./my-plugin",
|
||||
},
|
||||
{
|
||||
"path": "./my-plugin-e2e",
|
||||
},
|
||||
]
|
||||
`);
|
||||
expect(readJson(tree, 'my-plugin/package.json')).toMatchInlineSnapshot(`
|
||||
{
|
||||
"dependencies": {
|
||||
"tslib": "^2.3.0",
|
||||
},
|
||||
"exports": {
|
||||
".": {
|
||||
"default": "./dist/index.js",
|
||||
"import": "./dist/index.js",
|
||||
"types": "./dist/index.d.ts",
|
||||
},
|
||||
"./package.json": "./package.json",
|
||||
},
|
||||
"main": "./dist/index.js",
|
||||
"module": "./dist/index.js",
|
||||
"name": "@proj/my-plugin",
|
||||
"types": "./dist/index.d.ts",
|
||||
"version": "0.0.1",
|
||||
}
|
||||
`);
|
||||
expect(readJson(tree, 'my-plugin/tsconfig.json')).toMatchInlineSnapshot(`
|
||||
{
|
||||
"extends": "../tsconfig.base.json",
|
||||
"files": [],
|
||||
"include": [],
|
||||
"references": [
|
||||
{
|
||||
"path": "./tsconfig.lib.json",
|
||||
},
|
||||
{
|
||||
"path": "./tsconfig.spec.json",
|
||||
},
|
||||
],
|
||||
}
|
||||
`);
|
||||
expect(readJson(tree, 'my-plugin/tsconfig.lib.json'))
|
||||
.toMatchInlineSnapshot(`
|
||||
{
|
||||
"compilerOptions": {
|
||||
"baseUrl": ".",
|
||||
"emitDeclarationOnly": false,
|
||||
"module": "nodenext",
|
||||
"moduleResolution": "nodenext",
|
||||
"outDir": "dist",
|
||||
"rootDir": "src",
|
||||
"tsBuildInfoFile": "dist/tsconfig.lib.tsbuildinfo",
|
||||
"types": [
|
||||
"node",
|
||||
],
|
||||
},
|
||||
"exclude": [
|
||||
"jest.config.ts",
|
||||
"src/**/*.spec.ts",
|
||||
"src/**/*.test.ts",
|
||||
],
|
||||
"extends": "../tsconfig.base.json",
|
||||
"include": [
|
||||
"src/**/*.ts",
|
||||
],
|
||||
"references": [],
|
||||
}
|
||||
`);
|
||||
expect(readJson(tree, 'my-plugin/tsconfig.spec.json'))
|
||||
.toMatchInlineSnapshot(`
|
||||
{
|
||||
"compilerOptions": {
|
||||
"module": "nodenext",
|
||||
"moduleResolution": "nodenext",
|
||||
"outDir": "./out-tsc/jest",
|
||||
"types": [
|
||||
"jest",
|
||||
"node",
|
||||
],
|
||||
},
|
||||
"extends": "../tsconfig.base.json",
|
||||
"include": [
|
||||
"jest.config.ts",
|
||||
"src/**/*.test.ts",
|
||||
"src/**/*.spec.ts",
|
||||
"src/**/*.d.ts",
|
||||
],
|
||||
"references": [
|
||||
{
|
||||
"path": "./tsconfig.lib.json",
|
||||
},
|
||||
],
|
||||
}
|
||||
`);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@ -41,11 +41,12 @@ async function addFiles(host: Tree, options: NormalizedSchema) {
|
||||
}
|
||||
|
||||
function updatePluginConfig(host: Tree, options: NormalizedSchema) {
|
||||
const project = readProjectConfiguration(host, options.name);
|
||||
const project = readProjectConfiguration(host, options.projectName);
|
||||
|
||||
if (project.targets.build) {
|
||||
if (options.isTsSolutionSetup && options.bundler === 'tsc') {
|
||||
project.targets.build.options.rootDir = project.sourceRoot;
|
||||
project.targets.build.options.rootDir =
|
||||
project.sourceRoot ?? joinPathFragments(project.root, 'src');
|
||||
project.targets.build.options.generatePackageJson = false;
|
||||
}
|
||||
|
||||
@ -69,7 +70,7 @@ function updatePluginConfig(host: Tree, options: NormalizedSchema) {
|
||||
);
|
||||
}
|
||||
|
||||
updateProjectConfiguration(host, options.name, project);
|
||||
updateProjectConfiguration(host, options.projectName, project);
|
||||
}
|
||||
}
|
||||
|
||||
@ -144,7 +145,7 @@ export async function pluginGeneratorInternal(host: Tree, schema: Schema) {
|
||||
if (options.e2eTestRunner !== 'none') {
|
||||
tasks.push(
|
||||
await e2eProjectGenerator(host, {
|
||||
pluginName: options.name,
|
||||
pluginName: options.projectName,
|
||||
projectDirectory: options.projectDirectory,
|
||||
pluginOutputPath: joinPathFragments(
|
||||
'dist',
|
||||
@ -161,7 +162,7 @@ export async function pluginGeneratorInternal(host: Tree, schema: Schema) {
|
||||
}
|
||||
|
||||
if (options.linter === Linter.EsLint && !options.skipLintChecks) {
|
||||
await pluginLintCheckGenerator(host, { projectName: options.name });
|
||||
await pluginLintCheckGenerator(host, { projectName: options.projectName });
|
||||
}
|
||||
|
||||
if (!options.skipFormat) {
|
||||
|
||||
@ -10,9 +10,11 @@ import {
|
||||
} from '@nx/js/src/utils/generator-prompts';
|
||||
import { isUsingTsSolutionSetup } from '@nx/js/src/utils/typescript/ts-solution-setup';
|
||||
import type { Schema } from '../schema';
|
||||
import { getImportPath } from '@nx/js/src/utils/get-import-path';
|
||||
|
||||
export interface NormalizedSchema extends Schema {
|
||||
name: string;
|
||||
projectName: string;
|
||||
fileName: string;
|
||||
projectRoot: string;
|
||||
projectDirectory: string;
|
||||
@ -71,6 +73,9 @@ export async function normalizeOptions(
|
||||
bundler: options.compiler ?? 'tsc',
|
||||
fileName: projectName,
|
||||
name: projectName,
|
||||
projectName: isTsSolutionSetup
|
||||
? getImportPath(host, projectName)
|
||||
: projectName,
|
||||
projectRoot,
|
||||
projectDirectory,
|
||||
parsedTags,
|
||||
|
||||
@ -82,13 +82,14 @@ export async function reactNativeApplicationGeneratorInternal(
|
||||
options.appProjectRoot,
|
||||
options.js,
|
||||
options.skipPackageJson,
|
||||
options.addPlugin
|
||||
options.addPlugin,
|
||||
'tsconfig.app.json'
|
||||
);
|
||||
tasks.push(jestTask);
|
||||
|
||||
const webTask = await webConfigurationGenerator(host, {
|
||||
...options,
|
||||
project: options.name,
|
||||
project: options.projectName,
|
||||
skipFormat: true,
|
||||
});
|
||||
tasks.push(webTask);
|
||||
|
||||
@ -29,13 +29,10 @@ export function addProject(host: Tree, options: NormalizedSchema) {
|
||||
|
||||
if (isUsingTsSolutionSetup(host)) {
|
||||
writeJson(host, joinPathFragments(options.appProjectRoot, 'package.json'), {
|
||||
name: getImportPath(host, options.name),
|
||||
name: options.projectName,
|
||||
version: '0.0.1',
|
||||
private: true,
|
||||
nx: {
|
||||
name: options.name,
|
||||
projectType: 'application',
|
||||
sourceRoot: `${options.appProjectRoot}/src`,
|
||||
targets: hasPlugin ? {} : getTargets(options),
|
||||
tags: options.parsedTags?.length ? options.parsedTags : undefined,
|
||||
},
|
||||
|
||||
@ -5,6 +5,7 @@ import {
|
||||
} from '@nx/devkit/src/generators/project-name-and-root-utils';
|
||||
import { Schema } from '../schema';
|
||||
import { isUsingTsSolutionSetup } from '@nx/js/src/utils/typescript/ts-solution-setup';
|
||||
import { getImportPath } from '@nx/js/src/utils/get-import-path';
|
||||
|
||||
export interface NormalizedSchema extends Schema {
|
||||
className: string; // app name in class case
|
||||
@ -56,6 +57,8 @@ export async function normalizeOptions(
|
||||
|
||||
const entryFile = options.js ? 'src/main.js' : 'src/main.tsx';
|
||||
|
||||
const isTsSolutionSetup = isUsingTsSolutionSetup(host);
|
||||
|
||||
return {
|
||||
...options,
|
||||
name: projectNames.projectSimpleName,
|
||||
@ -63,7 +66,9 @@ export async function normalizeOptions(
|
||||
fileName,
|
||||
lowerCaseName: className.toLowerCase(),
|
||||
displayName: options.displayName || className,
|
||||
projectName: appProjectName,
|
||||
projectName: isTsSolutionSetup
|
||||
? getImportPath(host, appProjectName)
|
||||
: appProjectName,
|
||||
appProjectRoot,
|
||||
iosProjectRoot,
|
||||
androidProjectRoot,
|
||||
@ -72,6 +77,6 @@ export async function normalizeOptions(
|
||||
rootProject,
|
||||
e2eProjectName,
|
||||
e2eProjectRoot,
|
||||
isTsSolutionSetup: isUsingTsSolutionSetup(host),
|
||||
isTsSolutionSetup,
|
||||
};
|
||||
}
|
||||
|
||||
@ -11,6 +11,7 @@ import { NormalizedSchema, normalizeOptions } from './lib/normalize-options';
|
||||
import { addImport } from './lib/add-import';
|
||||
import { ensureTypescript } from '@nx/js/src/utils/typescript/ensure-typescript';
|
||||
import { dirname, join, parse, relative } from 'path';
|
||||
import { getProjectType } from '@nx/js/src/utils/typescript/ts-solution-setup';
|
||||
|
||||
export async function reactNativeComponentGenerator(
|
||||
host: Tree,
|
||||
@ -52,8 +53,9 @@ function addExportsToBarrel(host: Tree, options: NormalizedSchema) {
|
||||
tsModule = ensureTypescript();
|
||||
}
|
||||
const workspace = getProjects(host);
|
||||
const proj = workspace.get(options.projectName);
|
||||
const isApp =
|
||||
workspace.get(options.projectName).projectType === 'application';
|
||||
getProjectType(host, proj.root, proj.projectType) === 'application';
|
||||
|
||||
if (options.export && !isApp) {
|
||||
const indexFilePath = joinPathFragments(
|
||||
|
||||
@ -4,6 +4,7 @@ import {
|
||||
type FileExtensionType,
|
||||
} from '@nx/devkit/src/generators/artifact-name-and-directory-utils';
|
||||
import { Schema } from '../schema';
|
||||
import { getProjectType } from '@nx/js/src/utils/typescript/ts-solution-setup';
|
||||
|
||||
export interface NormalizedSchema extends Omit<Schema, 'js'> {
|
||||
directory: string;
|
||||
@ -40,9 +41,12 @@ export async function normalizeOptions(
|
||||
|
||||
const { className } = names(name);
|
||||
|
||||
const { sourceRoot: projectSourceRoot, projectType } = project;
|
||||
const { root, sourceRoot: projectSourceRoot, projectType } = project;
|
||||
|
||||
if (options.export && projectType === 'application') {
|
||||
if (
|
||||
options.export &&
|
||||
getProjectType(host, root, projectType) === 'application'
|
||||
) {
|
||||
logger.warn(
|
||||
`The "--export" option should not be used with applications and will do nothing.`
|
||||
);
|
||||
|
||||
@ -5,6 +5,7 @@ import {
|
||||
} from '@nx/devkit/src/generators/project-name-and-root-utils';
|
||||
import { Schema } from '../schema';
|
||||
import { isUsingTsSolutionSetup } from '@nx/js/src/utils/typescript/ts-solution-setup';
|
||||
import { getImportPath } from '@nx/js/src/utils/get-import-path';
|
||||
|
||||
export interface NormalizedSchema extends Schema {
|
||||
name: string;
|
||||
@ -44,15 +45,18 @@ export async function normalizeOptions(
|
||||
? options.tags.split(',').map((s) => s.trim())
|
||||
: [];
|
||||
|
||||
const isUsingTsSolutionConfig = isUsingTsSolutionSetup(host);
|
||||
const normalized: NormalizedSchema = {
|
||||
...options,
|
||||
fileName: projectName,
|
||||
routePath: `/${projectNames.projectSimpleName}`,
|
||||
name: projectName,
|
||||
name: isUsingTsSolutionConfig
|
||||
? getImportPath(host, projectName)
|
||||
: projectName,
|
||||
projectRoot,
|
||||
parsedTags,
|
||||
importPath,
|
||||
isUsingTsSolutionConfig: isUsingTsSolutionSetup(host),
|
||||
isUsingTsSolutionConfig,
|
||||
};
|
||||
|
||||
return normalized;
|
||||
|
||||
@ -101,7 +101,8 @@ export async function reactNativeLibraryGeneratorInternal(
|
||||
options.projectRoot,
|
||||
options.js,
|
||||
options.skipPackageJson,
|
||||
options.addPlugin
|
||||
options.addPlugin,
|
||||
'tsconfig.lib.json'
|
||||
);
|
||||
tasks.push(jestTask);
|
||||
|
||||
@ -171,14 +172,11 @@ async function addProject(
|
||||
'package.json'
|
||||
);
|
||||
if (options.isUsingTsSolutionConfig) {
|
||||
writeJson(host, packageJsonPath, {
|
||||
name: getImportPath(host, options.name),
|
||||
writeJson(host, joinPathFragments(options.projectRoot, 'package.json'), {
|
||||
name: options.name,
|
||||
version: '0.0.1',
|
||||
...determineEntryFields(options),
|
||||
nx: {
|
||||
name: options.name,
|
||||
sourceRoot: joinPathFragments(options.projectRoot, 'src'),
|
||||
projectType: 'library',
|
||||
tags: options.parsedTags?.length ? options.parsedTags : undefined,
|
||||
},
|
||||
});
|
||||
|
||||
@ -8,7 +8,8 @@ export async function addJest(
|
||||
appProjectRoot: string,
|
||||
js: boolean,
|
||||
skipPackageJson: boolean,
|
||||
addPlugin: boolean
|
||||
addPlugin: boolean,
|
||||
runtimeTsconfigFileName: string
|
||||
) {
|
||||
if (unitTestRunner !== 'jest') {
|
||||
return () => {};
|
||||
@ -24,6 +25,7 @@ export async function addJest(
|
||||
skipPackageJson,
|
||||
skipFormat: true,
|
||||
addPlugin,
|
||||
runtimeTsconfigFileName,
|
||||
});
|
||||
|
||||
// overwrite the jest.config.ts file because react native needs to have special transform property
|
||||
|
||||
@ -1331,7 +1331,6 @@ describe('app', () => {
|
||||
"name",
|
||||
"version",
|
||||
"private",
|
||||
"nx",
|
||||
]
|
||||
`);
|
||||
expect(readJson(appTree, 'myapp/tsconfig.json')).toMatchInlineSnapshot(`
|
||||
|
||||
@ -72,6 +72,13 @@ export async function applicationGeneratorInternal(
|
||||
tasks.push(jsInitTask);
|
||||
|
||||
const options = await normalizeOptions(tree, schema);
|
||||
|
||||
// If we are using the new TS solution
|
||||
// We need to update the workspace file (package.json or pnpm-workspaces.yaml) to include the new project
|
||||
if (options.isUsingTsSolutionConfig) {
|
||||
addProjectToTsSolutionWorkspace(tree, options.appProjectRoot);
|
||||
}
|
||||
|
||||
showPossibleWarnings(tree, options);
|
||||
|
||||
const initTask = await reactInitGenerator(tree, {
|
||||
@ -179,12 +186,6 @@ export async function applicationGeneratorInternal(
|
||||
: undefined
|
||||
);
|
||||
|
||||
// If we are using the new TS solution
|
||||
// We need to update the workspace file (package.json or pnpm-workspaces.yaml) to include the new project
|
||||
if (options.isUsingTsSolutionConfig) {
|
||||
addProjectToTsSolutionWorkspace(tree, options.appProjectRoot);
|
||||
}
|
||||
|
||||
sortPackageJsonFields(tree, options.appProjectRoot);
|
||||
|
||||
if (!options.skipFormat) {
|
||||
|
||||
@ -40,15 +40,14 @@ export function addProject(host: Tree, options: NormalizedSchema) {
|
||||
|
||||
if (options.isUsingTsSolutionConfig) {
|
||||
writeJson(host, joinPathFragments(options.appProjectRoot, 'package.json'), {
|
||||
name: getImportPath(host, options.name),
|
||||
name: options.projectName,
|
||||
version: '0.0.1',
|
||||
private: true,
|
||||
nx: {
|
||||
name: options.name,
|
||||
projectType: 'application',
|
||||
sourceRoot: `${options.appProjectRoot}/src`,
|
||||
tags: options.parsedTags?.length ? options.parsedTags : undefined,
|
||||
},
|
||||
nx: options.parsedTags?.length
|
||||
? {
|
||||
tags: options.parsedTags,
|
||||
}
|
||||
: undefined,
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@ -7,6 +7,7 @@ import { assertValidStyle } from '../../../utils/assertion';
|
||||
import { NormalizedSchema, Schema } from '../schema';
|
||||
import { findFreePort } from './find-free-port';
|
||||
import { isUsingTsSolutionSetup } from '@nx/js/src/utils/typescript/ts-solution-setup';
|
||||
import { getImportPath } from '@nx/js/src/utils/get-import-path';
|
||||
|
||||
export function normalizeDirectory(options: Schema) {
|
||||
options.directory = options.directory?.replace(/\\{1,2}/g, '/');
|
||||
@ -57,10 +58,13 @@ export async function normalizeOptions<T extends Schema = Schema>(
|
||||
|
||||
assertValidStyle(options.style);
|
||||
|
||||
const isUsingTsSolutionConfig = isUsingTsSolutionSetup(host);
|
||||
const normalized = {
|
||||
...options,
|
||||
name: names(options.name).fileName,
|
||||
projectName: appProjectName,
|
||||
name: appProjectName,
|
||||
projectName: isUsingTsSolutionConfig
|
||||
? getImportPath(host, appProjectName)
|
||||
: appProjectName,
|
||||
appProjectRoot,
|
||||
e2eProjectName,
|
||||
e2eProjectRoot,
|
||||
@ -68,7 +72,7 @@ export async function normalizeOptions<T extends Schema = Schema>(
|
||||
fileName,
|
||||
styledModule,
|
||||
hasStyles: options.style !== 'none',
|
||||
isUsingTsSolutionConfig: isUsingTsSolutionSetup(host),
|
||||
isUsingTsSolutionConfig,
|
||||
} as NormalizedSchema;
|
||||
|
||||
normalized.routing = normalized.routing ?? false;
|
||||
|
||||
@ -4,6 +4,7 @@ import { determineArtifactNameAndDirectoryOptions } from '@nx/devkit/src/generat
|
||||
|
||||
import { assertValidStyle } from '../../../utils/assertion';
|
||||
import { NormalizedSchema, Schema } from '../schema';
|
||||
import { getProjectType } from '@nx/js/src/utils/typescript/ts-solution-setup';
|
||||
|
||||
export async function normalizeOptions(
|
||||
tree: Tree,
|
||||
@ -41,7 +42,10 @@ export async function normalizeOptions(
|
||||
? null
|
||||
: options.style;
|
||||
|
||||
if (options.export && projectType === 'application') {
|
||||
if (
|
||||
options.export &&
|
||||
getProjectType(tree, projectRoot, projectType) === 'application'
|
||||
) {
|
||||
logger.warn(
|
||||
`The "--export" option should not be used with applications and will do nothing.`
|
||||
);
|
||||
|
||||
@ -17,6 +17,7 @@ import { ensureTypescript } from '@nx/js/src/utils/typescript/ensure-typescript'
|
||||
import { join } from 'path';
|
||||
import { addImport } from '../../utils/ast-utils';
|
||||
import { Schema } from './schema';
|
||||
import { getProjectType } from '@nx/js/src/utils/typescript/ts-solution-setup';
|
||||
|
||||
interface NormalizedSchema extends Omit<Schema, 'js'> {
|
||||
projectSourceRoot: string;
|
||||
@ -127,9 +128,12 @@ async function normalizeOptions(
|
||||
const hookTypeName = names(hookName).className;
|
||||
const project = getProjects(host).get(projectName);
|
||||
|
||||
const { sourceRoot: projectSourceRoot, projectType } = project;
|
||||
const { root, sourceRoot: projectSourceRoot, projectType } = project;
|
||||
|
||||
if (options.export && projectType === 'application') {
|
||||
if (
|
||||
options.export &&
|
||||
getProjectType(host, root, projectType) === 'application'
|
||||
) {
|
||||
logger.warn(
|
||||
`The "--export" option should not be used with applications and will do nothing.`
|
||||
);
|
||||
|
||||
@ -1,4 +1,3 @@
|
||||
import * as devkit from '@nx/devkit';
|
||||
import { Tree, updateJson, writeJson } from '@nx/devkit';
|
||||
import { ProjectGraph, readJson } from '@nx/devkit';
|
||||
import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing';
|
||||
|
||||
@ -64,7 +64,7 @@ export async function hostGenerator(
|
||||
const initTask = await applicationGenerator(host, {
|
||||
...options,
|
||||
directory: options.appProjectRoot,
|
||||
name: options.projectName,
|
||||
name: options.name,
|
||||
// The target use-case is loading remotes as child routes, thus always enable routing.
|
||||
routing: true,
|
||||
skipFormat: true,
|
||||
|
||||
@ -70,7 +70,7 @@ export async function normalizeOptions(
|
||||
bundler,
|
||||
fileName,
|
||||
routePath: `/${projectNames.projectSimpleName}`,
|
||||
name: projectName,
|
||||
name: isUsingTsSolutionConfig ? importPath : projectName,
|
||||
projectRoot,
|
||||
parsedTags,
|
||||
importPath,
|
||||
|
||||
@ -932,7 +932,7 @@ module.exports = withNx(
|
||||
beforeEach(() => {
|
||||
tree = createTreeWithEmptyWorkspace();
|
||||
updateJson(tree, 'package.json', (json) => {
|
||||
json.workspaces = ['packages/*', 'apps/*'];
|
||||
json.workspaces = ['packages/*', 'apps/*', 'libs/*'];
|
||||
return json;
|
||||
});
|
||||
writeJson(tree, 'tsconfig.base.json', {
|
||||
@ -953,11 +953,11 @@ module.exports = withNx(
|
||||
...defaultSchema,
|
||||
bundler: 'vite',
|
||||
unitTestRunner: 'vitest',
|
||||
directory: 'mylib',
|
||||
name: 'mylib',
|
||||
directory: 'libs/mylib',
|
||||
});
|
||||
|
||||
expect(tree.read('mylib/vite.config.ts', 'utf-8')).toMatchInlineSnapshot(`
|
||||
expect(tree.read('libs/mylib/vite.config.ts', 'utf-8'))
|
||||
.toMatchInlineSnapshot(`
|
||||
"/// <reference types='vitest' />
|
||||
import { defineConfig } from 'vite';
|
||||
import react from '@vitejs/plugin-react';
|
||||
@ -966,7 +966,7 @@ module.exports = withNx(
|
||||
|
||||
export default defineConfig({
|
||||
root: __dirname,
|
||||
cacheDir: '../node_modules/.vite/mylib',
|
||||
cacheDir: '../../node_modules/.vite/libs/mylib',
|
||||
plugins: [react(), dts({ entryRoot: 'src', tsconfigPath: path.join(__dirname, 'tsconfig.lib.json') })],
|
||||
// Uncomment this if you are using workers.
|
||||
// worker: {
|
||||
@ -984,7 +984,7 @@ module.exports = withNx(
|
||||
lib: {
|
||||
// Could also be a dictionary or array of multiple entry points.
|
||||
entry: 'src/index.ts',
|
||||
name: 'mylib',
|
||||
name: '@proj/mylib',
|
||||
fileName: 'index',
|
||||
// Change this to the formats you want to support.
|
||||
// Don't forget to update your package.json as well.
|
||||
@ -1013,12 +1013,12 @@ module.exports = withNx(
|
||||
expect(readJson(tree, 'tsconfig.json').references).toMatchInlineSnapshot(`
|
||||
[
|
||||
{
|
||||
"path": "./mylib",
|
||||
"path": "./libs/mylib",
|
||||
},
|
||||
]
|
||||
`);
|
||||
// Make sure keys are in idiomatic order
|
||||
expect(Object.keys(readJson(tree, 'mylib/package.json')))
|
||||
expect(Object.keys(readJson(tree, 'libs/mylib/package.json')))
|
||||
.toMatchInlineSnapshot(`
|
||||
[
|
||||
"name",
|
||||
@ -1028,12 +1028,11 @@ module.exports = withNx(
|
||||
"module",
|
||||
"types",
|
||||
"exports",
|
||||
"nx",
|
||||
]
|
||||
`);
|
||||
expect(readJson(tree, 'mylib/tsconfig.json')).toMatchInlineSnapshot(`
|
||||
expect(readJson(tree, 'libs/mylib/tsconfig.json')).toMatchInlineSnapshot(`
|
||||
{
|
||||
"extends": "../tsconfig.base.json",
|
||||
"extends": "../../tsconfig.base.json",
|
||||
"files": [],
|
||||
"include": [],
|
||||
"references": [
|
||||
@ -1046,7 +1045,8 @@ module.exports = withNx(
|
||||
],
|
||||
}
|
||||
`);
|
||||
expect(readJson(tree, 'mylib/tsconfig.lib.json')).toMatchInlineSnapshot(`
|
||||
expect(readJson(tree, 'libs/mylib/tsconfig.lib.json'))
|
||||
.toMatchInlineSnapshot(`
|
||||
{
|
||||
"compilerOptions": {
|
||||
"jsx": "react-jsx",
|
||||
@ -1089,7 +1089,7 @@ module.exports = withNx(
|
||||
"eslint.config.cjs",
|
||||
"eslint.config.mjs",
|
||||
],
|
||||
"extends": "../tsconfig.base.json",
|
||||
"extends": "../../tsconfig.base.json",
|
||||
"include": [
|
||||
"src/**/*.js",
|
||||
"src/**/*.jsx",
|
||||
@ -1098,7 +1098,8 @@ module.exports = withNx(
|
||||
],
|
||||
}
|
||||
`);
|
||||
expect(readJson(tree, 'mylib/tsconfig.spec.json')).toMatchInlineSnapshot(`
|
||||
expect(readJson(tree, 'libs/mylib/tsconfig.spec.json'))
|
||||
.toMatchInlineSnapshot(`
|
||||
{
|
||||
"compilerOptions": {
|
||||
"jsx": "react-jsx",
|
||||
@ -1113,7 +1114,7 @@ module.exports = withNx(
|
||||
"vitest",
|
||||
],
|
||||
},
|
||||
"extends": "../tsconfig.base.json",
|
||||
"extends": "../../tsconfig.base.json",
|
||||
"include": [
|
||||
"vite.config.ts",
|
||||
"vite.config.mts",
|
||||
@ -1143,20 +1144,18 @@ module.exports = withNx(
|
||||
...defaultSchema,
|
||||
bundler: 'none',
|
||||
unitTestRunner: 'none',
|
||||
directory: 'mylib',
|
||||
name: 'mylib',
|
||||
directory: 'libs/mylib',
|
||||
});
|
||||
|
||||
await libraryGenerator(tree, {
|
||||
...defaultSchema,
|
||||
bundler: 'none',
|
||||
unitTestRunner: 'none',
|
||||
directory: 'myjslib',
|
||||
name: 'myjslib',
|
||||
directory: 'libs/myjslib',
|
||||
js: true,
|
||||
});
|
||||
|
||||
expect(readJson(tree, 'mylib/package.json')).toMatchInlineSnapshot(`
|
||||
expect(readJson(tree, 'libs/mylib/package.json')).toMatchInlineSnapshot(`
|
||||
{
|
||||
"exports": {
|
||||
".": {
|
||||
@ -1168,16 +1167,12 @@ module.exports = withNx(
|
||||
},
|
||||
"main": "./src/index.ts",
|
||||
"name": "@proj/mylib",
|
||||
"nx": {
|
||||
"name": "mylib",
|
||||
"projectType": "library",
|
||||
"sourceRoot": "mylib/src",
|
||||
},
|
||||
"types": "./src/index.ts",
|
||||
"version": "0.0.1",
|
||||
}
|
||||
`);
|
||||
expect(readJson(tree, 'myjslib/package.json')).toMatchInlineSnapshot(`
|
||||
expect(readJson(tree, 'libs/myjslib/package.json'))
|
||||
.toMatchInlineSnapshot(`
|
||||
{
|
||||
"exports": {
|
||||
".": "./src/index.js",
|
||||
@ -1185,11 +1180,6 @@ module.exports = withNx(
|
||||
},
|
||||
"main": "./src/index.js",
|
||||
"name": "@proj/myjslib",
|
||||
"nx": {
|
||||
"name": "myjslib",
|
||||
"projectType": "library",
|
||||
"sourceRoot": "myjslib/src",
|
||||
},
|
||||
"types": "./src/index.js",
|
||||
"version": "0.0.1",
|
||||
}
|
||||
@ -1201,11 +1191,10 @@ module.exports = withNx(
|
||||
...defaultSchema,
|
||||
bundler: 'rollup',
|
||||
unitTestRunner: 'none',
|
||||
directory: 'mylib',
|
||||
name: 'mylib',
|
||||
directory: 'libs/mylib',
|
||||
});
|
||||
|
||||
expect(tree.read('mylib/rollup.config.cjs', 'utf-8'))
|
||||
expect(tree.read('libs/mylib/rollup.config.cjs', 'utf-8'))
|
||||
.toMatchInlineSnapshot(`
|
||||
"const { withNx } = require('@nx/rollup/with-nx');
|
||||
const url = require('@rollup/plugin-url');
|
||||
@ -1242,13 +1231,12 @@ module.exports = withNx(
|
||||
await libraryGenerator(tree, {
|
||||
...defaultSchema,
|
||||
bundler: 'rollup',
|
||||
directory: 'mylib',
|
||||
name: 'mylib',
|
||||
directory: 'libs/mylib',
|
||||
publishable: true,
|
||||
importPath: '@acme/mylib',
|
||||
});
|
||||
|
||||
expect(readJson(tree, 'mylib/package.json')).toMatchInlineSnapshot(`
|
||||
expect(readJson(tree, 'libs/mylib/package.json')).toMatchInlineSnapshot(`
|
||||
{
|
||||
"exports": {
|
||||
".": {
|
||||
@ -1265,11 +1253,6 @@ module.exports = withNx(
|
||||
"main": "./dist/index.esm.js",
|
||||
"module": "./dist/index.esm.js",
|
||||
"name": "@acme/mylib",
|
||||
"nx": {
|
||||
"name": "mylib",
|
||||
"projectType": "library",
|
||||
"sourceRoot": "mylib/src",
|
||||
},
|
||||
"type": "module",
|
||||
"types": "./dist/index.esm.d.ts",
|
||||
"version": "0.0.1",
|
||||
|
||||
@ -55,6 +55,11 @@ export async function libraryGeneratorInternal(host: Tree, schema: Schema) {
|
||||
tasks.push(jsInitTask);
|
||||
|
||||
const options = await normalizeOptions(host, schema);
|
||||
|
||||
if (options.isUsingTsSolutionConfig) {
|
||||
addProjectToTsSolutionWorkspace(host, options.projectRoot);
|
||||
}
|
||||
|
||||
if (options.publishable === true && !schema.importPath) {
|
||||
throw new Error(
|
||||
`For publishable libs you have to provide a proper "--importPath" which needs to be a valid npm package name (e.g. my-awesome-lib or @myorg/my-lib)`
|
||||
@ -75,12 +80,11 @@ export async function libraryGeneratorInternal(host: Tree, schema: Schema) {
|
||||
name: options.importPath,
|
||||
version: '0.0.1',
|
||||
...determineEntryFields(options),
|
||||
nx: {
|
||||
name: options.importPath === options.name ? undefined : options.name,
|
||||
projectType: 'library',
|
||||
sourceRoot: `${options.projectRoot}/src`,
|
||||
tags: options.parsedTags?.length ? options.parsedTags : undefined,
|
||||
},
|
||||
nx: options.parsedTags?.length
|
||||
? {
|
||||
tags: options.parsedTags,
|
||||
}
|
||||
: undefined,
|
||||
files: options.publishable ? ['dist', '!**/*.tsbuildinfo'] : undefined,
|
||||
});
|
||||
} else {
|
||||
@ -273,10 +277,6 @@ export async function libraryGeneratorInternal(host: Tree, schema: Schema) {
|
||||
: undefined
|
||||
);
|
||||
|
||||
if (options.isUsingTsSolutionConfig) {
|
||||
addProjectToTsSolutionWorkspace(host, options.projectRoot);
|
||||
}
|
||||
|
||||
sortPackageJsonFields(host, options.projectRoot);
|
||||
|
||||
if (!options.skipFormat) {
|
||||
|
||||
@ -20,6 +20,7 @@ import {
|
||||
import { getRootTsConfigPathInTree } from '@nx/js';
|
||||
import { ensureTypescript } from '@nx/js/src/utils/typescript/ensure-typescript';
|
||||
import { determineArtifactNameAndDirectoryOptions } from '@nx/devkit/src/generators/artifact-name-and-directory-utils';
|
||||
import { getProjectType } from '@nx/js/src/utils/typescript/ts-solution-setup';
|
||||
|
||||
let tsModule: typeof import('typescript');
|
||||
|
||||
@ -165,14 +166,14 @@ async function normalizeOptions(
|
||||
|
||||
const projects = getProjects(host);
|
||||
const project = projects.get(projectName);
|
||||
const { sourceRoot, projectType } = project;
|
||||
const { root, sourceRoot, projectType } = project;
|
||||
|
||||
const tsConfigJson = readJson(host, getRootTsConfigPathInTree(host));
|
||||
const tsPaths: { [module: string]: string[] } = tsConfigJson.compilerOptions
|
||||
? tsConfigJson.compilerOptions.paths || {}
|
||||
: {};
|
||||
const modulePath =
|
||||
projectType === 'application'
|
||||
getProjectType(host, root, projectType) === 'application'
|
||||
? options.path
|
||||
? `./app/${options.path}/${extraNames.fileName}.slice`
|
||||
: `./app/${extraNames.fileName}.slice`
|
||||
|
||||
@ -111,10 +111,10 @@ export async function remoteGenerator(host: Tree, schema: Schema) {
|
||||
if (options.dynamic) {
|
||||
// Dynamic remotes generate with library { type: 'var' } by default.
|
||||
// We need to ensure that the remote name is a valid variable name.
|
||||
const isValidRemote = isValidVariable(options.projectName);
|
||||
const isValidRemote = isValidVariable(options.name);
|
||||
if (!isValidRemote.isValid) {
|
||||
throw new Error(
|
||||
`Invalid remote name provided: ${options.projectName}. ${isValidRemote.message}`
|
||||
`Invalid remote name provided: ${options.name}. ${isValidRemote.message}`
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -122,9 +122,9 @@ export async function remoteGenerator(host: Tree, schema: Schema) {
|
||||
await ensureProjectName(host, options, 'application');
|
||||
const REMOTE_NAME_REGEX = '^[a-zA-Z_$][a-zA-Z_$0-9]*$';
|
||||
const remoteNameRegex = new RegExp(REMOTE_NAME_REGEX);
|
||||
if (!remoteNameRegex.test(options.projectName)) {
|
||||
if (!remoteNameRegex.test(options.name)) {
|
||||
throw new Error(
|
||||
stripIndents`Invalid remote name: ${options.projectName}. Remote project names must:
|
||||
stripIndents`Invalid remote name: ${options.name}. Remote project names must:
|
||||
- Start with a letter, dollar sign ($) or underscore (_)
|
||||
- Followed by any valid character (letters, digits, underscores, or dollar signs)
|
||||
The regular expression used is ${REMOTE_NAME_REGEX}.`
|
||||
@ -132,14 +132,14 @@ export async function remoteGenerator(host: Tree, schema: Schema) {
|
||||
}
|
||||
const initAppTask = await applicationGenerator(host, {
|
||||
...options,
|
||||
name: options.projectName,
|
||||
name: options.name,
|
||||
skipFormat: true,
|
||||
alwaysGenerateProjectJson: true,
|
||||
});
|
||||
tasks.push(initAppTask);
|
||||
|
||||
if (schema.host) {
|
||||
updateHostWithRemote(host, schema.host, options.projectName);
|
||||
if (options.host) {
|
||||
updateHostWithRemote(host, options.host, options.name);
|
||||
}
|
||||
|
||||
// Module federation requires bootstrap code to be dynamically imported.
|
||||
|
||||
@ -19,6 +19,7 @@ import { basename, join } from 'path';
|
||||
import { minimatch } from 'minimatch';
|
||||
import { ensureTypescript } from '@nx/js/src/utils/typescript/ensure-typescript';
|
||||
import { nxVersion } from '../../utils/versions';
|
||||
import { getProjectType } from '@nx/js/src/utils/typescript/ts-solution-setup';
|
||||
|
||||
let tsModule: typeof import('typescript');
|
||||
|
||||
@ -35,7 +36,7 @@ export async function projectRootPath(
|
||||
config: ProjectConfiguration
|
||||
): Promise<string> {
|
||||
let projectDir: string;
|
||||
if (config.projectType === 'application') {
|
||||
if (getProjectType(tree, config.root, config.projectType) === 'application') {
|
||||
const isNextJs = await isNextJsProject(tree, config);
|
||||
if (isNextJs) {
|
||||
// Next.js apps
|
||||
|
||||
@ -379,10 +379,8 @@ describe('Remix Application', () => {
|
||||
"engines": {
|
||||
"node": ">=20",
|
||||
},
|
||||
"name": "myapp",
|
||||
"name": "@proj/myapp",
|
||||
"nx": {
|
||||
"projectType": "application",
|
||||
"sourceRoot": "myapp",
|
||||
"tags": [
|
||||
"foo",
|
||||
],
|
||||
@ -541,6 +539,41 @@ describe('Remix Application', () => {
|
||||
`);
|
||||
});
|
||||
|
||||
it('should skip nx property in package.json when no tags are provided', async () => {
|
||||
await applicationGenerator(tree, {
|
||||
directory: 'apps/myapp',
|
||||
e2eTestRunner: 'playwright',
|
||||
unitTestRunner: 'jest',
|
||||
addPlugin: true,
|
||||
});
|
||||
|
||||
expect(readJson(tree, 'apps/myapp/package.json')).toMatchInlineSnapshot(`
|
||||
{
|
||||
"dependencies": {
|
||||
"@remix-run/node": "^2.14.0",
|
||||
"@remix-run/react": "^2.14.0",
|
||||
"@remix-run/serve": "^2.14.0",
|
||||
"isbot": "^4.4.0",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
},
|
||||
"devDependencies": {
|
||||
"@remix-run/dev": "^2.14.0",
|
||||
"@types/react": "^18.2.0",
|
||||
"@types/react-dom": "^18.2.0",
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=20",
|
||||
},
|
||||
"name": "@proj/myapp",
|
||||
"private": true,
|
||||
"scripts": {},
|
||||
"sideEffects": false,
|
||||
"type": "module",
|
||||
}
|
||||
`);
|
||||
});
|
||||
|
||||
it('should generate valid package.json without formatting', async () => {
|
||||
await applicationGenerator(tree, {
|
||||
directory: 'myapp',
|
||||
|
||||
@ -12,12 +12,10 @@ import {
|
||||
Tree,
|
||||
updateJson,
|
||||
updateProjectConfiguration,
|
||||
visitNotIgnoredFiles,
|
||||
} from '@nx/devkit';
|
||||
import { logShowProjectCommand } from '@nx/devkit/src/utils/log-show-project-command';
|
||||
import { initGenerator as jsInitGenerator } from '@nx/js';
|
||||
import { extractTsConfigBase } from '@nx/js/src/utils/typescript/create-ts-config';
|
||||
import { dirname } from 'node:path';
|
||||
import {
|
||||
createNxCloudOnboardingURLForWelcomeApp,
|
||||
getNxCloudAppOnBoardingUrl,
|
||||
@ -39,14 +37,13 @@ import initGenerator from '../init/init';
|
||||
import { updateDependencies } from '../utils/update-dependencies';
|
||||
import {
|
||||
addE2E,
|
||||
addViteTempFilesToGitIgnore,
|
||||
normalizeOptions,
|
||||
updateUnitTestConfig,
|
||||
addViteTempFilesToGitIgnore,
|
||||
} from './lib';
|
||||
import { NxRemixGeneratorSchema } from './schema';
|
||||
import {
|
||||
addProjectToTsSolutionWorkspace,
|
||||
isUsingTsSolutionSetup,
|
||||
updateTsconfigFiles,
|
||||
} from '@nx/js/src/utils/typescript/ts-solution-setup';
|
||||
import { sortPackageJsonFields } from '@nx/js/src/utils/package-json/sort-fields';
|
||||
@ -85,9 +82,13 @@ export async function remixApplicationGeneratorInternal(
|
||||
);
|
||||
}
|
||||
|
||||
const isUsingTsSolution = isUsingTsSolutionSetup(tree);
|
||||
// If we are using the new TS solution
|
||||
// We need to update the workspace file (package.json or pnpm-workspaces.yaml) to include the new project
|
||||
if (options.isUsingTsSolutionConfig) {
|
||||
addProjectToTsSolutionWorkspace(tree, options.projectRoot);
|
||||
}
|
||||
|
||||
if (!isUsingTsSolution) {
|
||||
if (!options.isUsingTsSolutionConfig) {
|
||||
addProjectConfiguration(tree, options.projectName, {
|
||||
root: options.projectRoot,
|
||||
sourceRoot: `${options.projectRoot}`,
|
||||
@ -122,7 +123,6 @@ export async function remixApplicationGeneratorInternal(
|
||||
eslintVersion,
|
||||
typescriptVersion,
|
||||
viteVersion,
|
||||
isUsingTsSolution,
|
||||
};
|
||||
|
||||
generateFiles(
|
||||
@ -154,7 +154,7 @@ export async function remixApplicationGeneratorInternal(
|
||||
);
|
||||
}
|
||||
|
||||
if (isUsingTsSolution) {
|
||||
if (options.isUsingTsSolutionConfig) {
|
||||
generateFiles(
|
||||
tree,
|
||||
joinPathFragments(__dirname, 'files/ts-solution'),
|
||||
@ -328,12 +328,6 @@ export default {...nxPreset};
|
||||
'.'
|
||||
);
|
||||
|
||||
// If we are using the new TS solution
|
||||
// We need to update the workspace file (package.json or pnpm-workspaces.yaml) to include the new project
|
||||
if (options.useTsSolution) {
|
||||
addProjectToTsSolutionWorkspace(tree, options.projectRoot);
|
||||
}
|
||||
|
||||
sortPackageJsonFields(tree, options.projectRoot);
|
||||
|
||||
if (!options.skipFormat) {
|
||||
|
||||
@ -19,13 +19,8 @@
|
||||
"engines": {
|
||||
"node": ">=20"
|
||||
},
|
||||
"sideEffects": false<% if (isUsingTsSolution) { %>,
|
||||
"sideEffects": false<% if (isUsingTsSolutionConfig && parsedTags?.length) { %>,
|
||||
"nx": {
|
||||
<%_ if (name !== projectName) { _%>
|
||||
"name": "<%= name %>",<%_ } _%>
|
||||
"projectType": "application",
|
||||
"sourceRoot": "<%- projectRoot %>"<%_ if (parsedTags?.length) { _%>,
|
||||
"tags": <%- JSON.stringify(parsedTags) %>
|
||||
<%_ } _%>
|
||||
}<% } %>
|
||||
}
|
||||
|
||||
@ -6,6 +6,7 @@ import {
|
||||
import { Linter } from '@nx/eslint';
|
||||
import { isUsingTsSolutionSetup } from '@nx/js/src/utils/typescript/ts-solution-setup';
|
||||
import { type NxRemixGeneratorSchema } from '../schema';
|
||||
import { getImportPath } from '@nx/js/src/utils/get-import-path';
|
||||
|
||||
export interface NormalizedSchema extends NxRemixGeneratorSchema {
|
||||
projectName: string;
|
||||
@ -13,6 +14,7 @@ export interface NormalizedSchema extends NxRemixGeneratorSchema {
|
||||
e2eProjectName: string;
|
||||
e2eProjectRoot: string;
|
||||
parsedTags: string[];
|
||||
isUsingTsSolutionConfig: boolean;
|
||||
}
|
||||
|
||||
export async function normalizeOptions(
|
||||
@ -43,14 +45,18 @@ export async function normalizeOptions(
|
||||
? options.tags.split(',').map((s) => s.trim())
|
||||
: [];
|
||||
|
||||
const isUsingTsSolutionConfig = isUsingTsSolutionSetup(tree);
|
||||
return {
|
||||
...options,
|
||||
linter: options.linter ?? Linter.EsLint,
|
||||
projectName,
|
||||
projectName: isUsingTsSolutionConfig
|
||||
? getImportPath(tree, projectName)
|
||||
: projectName,
|
||||
projectRoot,
|
||||
e2eProjectName,
|
||||
e2eProjectRoot,
|
||||
parsedTags,
|
||||
useTsSolution: options.useTsSolution ?? isUsingTsSolutionSetup(tree),
|
||||
useTsSolution: options.useTsSolution ?? isUsingTsSolutionConfig,
|
||||
isUsingTsSolutionConfig,
|
||||
};
|
||||
}
|
||||
|
||||
@ -16,7 +16,7 @@ export function addTsconfigEntryPoints(
|
||||
tree,
|
||||
options.projectName
|
||||
);
|
||||
const serverFilePath = joinPathFragments(sourceRoot, 'server.ts');
|
||||
const serverFilePath = joinPathFragments(sourceRoot ?? 'src', 'server.ts');
|
||||
|
||||
tree.write(
|
||||
serverFilePath,
|
||||
|
||||
@ -5,6 +5,7 @@ import {
|
||||
} from '@nx/devkit/src/generators/project-name-and-root-utils';
|
||||
import type { NxRemixGeneratorSchema } from '../schema';
|
||||
import { isUsingTsSolutionSetup } from '@nx/js/src/utils/typescript/ts-solution-setup';
|
||||
import { getImportPath } from '@nx/js/src/utils/get-import-path';
|
||||
|
||||
export interface RemixLibraryOptions extends NxRemixGeneratorSchema {
|
||||
projectName: string;
|
||||
@ -32,11 +33,14 @@ export async function normalizeOptions(
|
||||
nxJson.useInferencePlugins !== false;
|
||||
options.addPlugin ??= addPluginDefault;
|
||||
|
||||
const isUsingTsSolutionConfig = isUsingTsSolutionSetup(tree);
|
||||
return {
|
||||
...options,
|
||||
unitTestRunner: options.unitTestRunner ?? 'vitest',
|
||||
projectName,
|
||||
projectName: isUsingTsSolutionConfig
|
||||
? getImportPath(tree, projectName)
|
||||
: projectName,
|
||||
projectRoot,
|
||||
isUsingTsSolutionConfig: isUsingTsSolutionSetup(tree),
|
||||
isUsingTsSolutionConfig,
|
||||
};
|
||||
}
|
||||
|
||||
@ -173,7 +173,6 @@ describe('Remix Library Generator', () => {
|
||||
"main",
|
||||
"types",
|
||||
"exports",
|
||||
"nx",
|
||||
]
|
||||
`);
|
||||
expect(readJson(tree, 'packages/foo/package.json'))
|
||||
@ -189,15 +188,27 @@ describe('Remix Library Generator', () => {
|
||||
},
|
||||
"main": "./src/index.ts",
|
||||
"name": "@proj/foo",
|
||||
"nx": {
|
||||
"name": "foo",
|
||||
"projectType": "library",
|
||||
"sourceRoot": "packages/foo/src",
|
||||
},
|
||||
"types": "./src/index.ts",
|
||||
"version": "0.0.1",
|
||||
}
|
||||
`);
|
||||
});
|
||||
|
||||
it('should generate server entrypoint', async () => {
|
||||
await libraryGenerator(tree, {
|
||||
directory: 'test',
|
||||
style: 'css',
|
||||
addPlugin: true,
|
||||
});
|
||||
|
||||
expect(tree.exists(`test/src/server.ts`));
|
||||
expect(tree.children(`test/src/lib`).sort()).toMatchInlineSnapshot(`
|
||||
[
|
||||
"test.module.css",
|
||||
"test.spec.tsx",
|
||||
"test.tsx",
|
||||
]
|
||||
`);
|
||||
}, 25_000);
|
||||
});
|
||||
});
|
||||
|
||||
@ -29,6 +29,10 @@ export async function remixLibraryGeneratorInternal(
|
||||
const tasks: GeneratorCallback[] = [];
|
||||
const options = await normalizeOptions(tree, schema);
|
||||
|
||||
if (options.isUsingTsSolutionConfig) {
|
||||
addProjectToTsSolutionWorkspace(tree, options.projectRoot);
|
||||
}
|
||||
|
||||
const jsInitTask = await jsInitGenerator(tree, {
|
||||
js: options.js,
|
||||
skipFormat: true,
|
||||
@ -77,10 +81,6 @@ export async function remixLibraryGeneratorInternal(
|
||||
: undefined
|
||||
);
|
||||
|
||||
if (options.isUsingTsSolutionConfig) {
|
||||
addProjectToTsSolutionWorkspace(tree, options.projectRoot);
|
||||
}
|
||||
|
||||
sortPackageJsonFields(tree, options.projectRoot);
|
||||
|
||||
if (!options.skipFormat) {
|
||||
|
||||
@ -20,6 +20,7 @@ import {
|
||||
import { editTsConfig } from '../application/lib/create-ts-config';
|
||||
import rspackInitGenerator from '../init/init';
|
||||
import { ConfigurationSchema } from './schema';
|
||||
import { getProjectType } from '@nx/js/src/utils/typescript/ts-solution-setup';
|
||||
|
||||
export async function configurationGenerator(
|
||||
tree: Tree,
|
||||
@ -73,7 +74,7 @@ export async function configurationGenerator(
|
||||
if (
|
||||
alreadyHasNxRspackTargets.build &&
|
||||
(alreadyHasNxRspackTargets.serve ||
|
||||
projectType === 'library' ||
|
||||
getProjectType(tree, options.project, projectType) === 'library' ||
|
||||
options.framework === 'nest')
|
||||
) {
|
||||
throw new Error(
|
||||
|
||||
@ -825,7 +825,7 @@ describe('@nx/storybook:configuration for Storybook v7', () => {
|
||||
});
|
||||
|
||||
await configurationGenerator(tree, {
|
||||
project: 'mylib',
|
||||
project: '@proj/mylib',
|
||||
standaloneConfig: false,
|
||||
uiFramework: '@storybook/react-vite',
|
||||
addPlugin: true,
|
||||
|
||||
@ -47,6 +47,7 @@ import {
|
||||
import { interactionTestsDependencies } from './lib/interaction-testing.utils';
|
||||
import { ensureDependencies } from './lib/ensure-dependencies';
|
||||
import { editRootTsConfig } from './lib/edit-root-tsconfig';
|
||||
import { getProjectType } from '@nx/js/src/utils/typescript/ts-solution-setup';
|
||||
|
||||
export function configurationGenerator(
|
||||
tree: Tree,
|
||||
@ -126,7 +127,8 @@ export async function configurationGeneratorInternal(
|
||||
);
|
||||
|
||||
const mainDir =
|
||||
!!nextConfigFilePath && projectType === 'application'
|
||||
!!nextConfigFilePath &&
|
||||
getProjectType(tree, root, projectType) === 'application'
|
||||
? 'components'
|
||||
: 'src';
|
||||
|
||||
|
||||
@ -30,6 +30,7 @@ import { findEslintFile } from '@nx/eslint/src/generators/utils/eslint-file';
|
||||
import { useFlatConfig } from '@nx/eslint/src/utils/flat-config';
|
||||
import {
|
||||
findRuntimeTsConfigName,
|
||||
getProjectType,
|
||||
isUsingTsSolutionSetup,
|
||||
} from '@nx/js/src/utils/typescript/ts-solution-setup';
|
||||
|
||||
@ -581,7 +582,8 @@ export function createProjectStorybookDir(
|
||||
usesReactNative?: boolean
|
||||
) {
|
||||
let projectDirectory =
|
||||
projectType === 'application'
|
||||
getProjectType(tree, root, projectType as 'application' | 'library') ===
|
||||
'application'
|
||||
? isNextJs
|
||||
? 'components'
|
||||
: 'src/app'
|
||||
@ -616,7 +618,10 @@ export function createProjectStorybookDir(
|
||||
projectType,
|
||||
interactionTests,
|
||||
mainDir,
|
||||
isNextJs: isNextJs && projectType === 'application',
|
||||
isNextJs:
|
||||
isNextJs &&
|
||||
getProjectType(tree, root, projectType as 'application' | 'library') ===
|
||||
'application',
|
||||
usesSwc,
|
||||
usesVite,
|
||||
isRootProject: projectIsRootProjectInStandaloneWorkspace,
|
||||
@ -651,7 +656,7 @@ export function getTsConfigPath(
|
||||
root,
|
||||
path?.length > 0
|
||||
? path
|
||||
: projectType === 'application'
|
||||
: getProjectType(tree, root, projectType) === 'application'
|
||||
? 'tsconfig.app.json'
|
||||
: 'tsconfig.lib.json'
|
||||
);
|
||||
|
||||
@ -15,7 +15,10 @@ import {
|
||||
initGenerator as jsInitGenerator,
|
||||
} from '@nx/js';
|
||||
import { getImportPath } from '@nx/js/src/utils/get-import-path';
|
||||
import { isUsingTsSolutionSetup } from '@nx/js/src/utils/typescript/ts-solution-setup';
|
||||
import {
|
||||
getProjectType,
|
||||
isUsingTsSolutionSetup,
|
||||
} from '@nx/js/src/utils/typescript/ts-solution-setup';
|
||||
import { join } from 'node:path/posix';
|
||||
import type { PackageJson } from 'nx/src/utils/package-json';
|
||||
import { ensureDependencies } from '../../utils/ensure-dependencies';
|
||||
@ -50,8 +53,11 @@ export async function viteConfigurationGeneratorInternal(
|
||||
const projectConfig = readProjectConfiguration(tree, schema.project);
|
||||
const { targets, root: projectRoot } = projectConfig;
|
||||
|
||||
const projectType =
|
||||
schema.projectType ?? projectConfig.projectType ?? 'library';
|
||||
const projectType = getProjectType(
|
||||
tree,
|
||||
projectConfig.root,
|
||||
schema.projectType ?? projectConfig.projectType
|
||||
);
|
||||
|
||||
schema.includeLib ??= projectType === 'library';
|
||||
|
||||
@ -196,7 +202,7 @@ function updatePackageJson(
|
||||
name: getImportPath(tree, options.project),
|
||||
version: '0.0.1',
|
||||
};
|
||||
if (projectType === 'application') {
|
||||
if (getProjectType(tree, project.root, projectType) === 'application') {
|
||||
packageJson.private = true;
|
||||
}
|
||||
}
|
||||
|
||||
@ -16,12 +16,13 @@ import {
|
||||
handleUnknownConfiguration,
|
||||
moveAndEditIndexHtml,
|
||||
} from '../../../utils/generator-utils';
|
||||
import { getProjectType } from '@nx/js/src/utils/typescript/ts-solution-setup';
|
||||
|
||||
export async function convertNonVite(
|
||||
tree: Tree,
|
||||
schema: ViteConfigurationGeneratorSchema,
|
||||
projectRoot: string,
|
||||
projectType: string,
|
||||
_projectType: string,
|
||||
targets: {
|
||||
[targetName: string]: TargetConfiguration<any>;
|
||||
}
|
||||
@ -34,6 +35,11 @@ export async function convertNonVite(
|
||||
|
||||
// Check if it has webpack
|
||||
const hasWebpackConfig = findWebpackConfig(tree, projectRoot);
|
||||
const projectType = getProjectType(
|
||||
tree,
|
||||
projectRoot,
|
||||
_projectType as 'application' | 'library'
|
||||
);
|
||||
if (hasWebpackConfig) {
|
||||
if (projectType === 'application') {
|
||||
moveAndEditIndexHtml(tree, schema);
|
||||
|
||||
@ -15,7 +15,10 @@ import {
|
||||
updateNxJson,
|
||||
} from '@nx/devkit';
|
||||
import { initGenerator as jsInitGenerator } from '@nx/js';
|
||||
import { isUsingTsSolutionSetup } from '@nx/js/src/utils/typescript/ts-solution-setup';
|
||||
import {
|
||||
getProjectType,
|
||||
isUsingTsSolutionSetup,
|
||||
} from '@nx/js/src/utils/typescript/ts-solution-setup';
|
||||
import { join } from 'path';
|
||||
import { ensureDependencies } from '../../utils/ensure-dependencies';
|
||||
import {
|
||||
@ -118,7 +121,7 @@ getTestBed().initTestEnvironment(
|
||||
tree,
|
||||
{
|
||||
project: schema.project,
|
||||
includeLib: projectType === 'library',
|
||||
includeLib: getProjectType(tree, root, projectType) === 'library',
|
||||
includeVitest: true,
|
||||
inSourceTests: schema.inSourceTests,
|
||||
rollupOptionsExternal: [
|
||||
@ -142,7 +145,7 @@ getTestBed().initTestEnvironment(
|
||||
{
|
||||
...schema,
|
||||
includeVitest: true,
|
||||
includeLib: projectType === 'library',
|
||||
includeLib: getProjectType(tree, root, projectType) === 'library',
|
||||
},
|
||||
true
|
||||
);
|
||||
@ -265,7 +268,9 @@ function updateTsConfig(
|
||||
|
||||
let runtimeTsconfigPath = joinPathFragments(
|
||||
projectRoot,
|
||||
projectType === 'application' ? 'tsconfig.app.json' : 'tsconfig.lib.json'
|
||||
getProjectType(tree, projectRoot, projectType) === 'application'
|
||||
? 'tsconfig.app.json'
|
||||
: 'tsconfig.lib.json'
|
||||
);
|
||||
if (options.runtimeTsconfigFileName) {
|
||||
runtimeTsconfigPath = joinPathFragments(
|
||||
|
||||
@ -52,6 +52,13 @@ export async function applicationGeneratorInternal(
|
||||
);
|
||||
|
||||
const options = await normalizeOptions(tree, _options);
|
||||
|
||||
// If we are using the new TS solution
|
||||
// We need to update the workspace file (package.json or pnpm-workspaces.yaml) to include the new project
|
||||
if (options.isUsingTsSolutionConfig) {
|
||||
addProjectToTsSolutionWorkspace(tree, options.appProjectRoot);
|
||||
}
|
||||
|
||||
const nxJson = readNxJson(tree);
|
||||
|
||||
options.addPlugin ??=
|
||||
@ -60,15 +67,14 @@ export async function applicationGeneratorInternal(
|
||||
|
||||
if (options.isUsingTsSolutionConfig) {
|
||||
writeJson(tree, joinPathFragments(options.appProjectRoot, 'package.json'), {
|
||||
name: getImportPath(tree, options.name),
|
||||
name: options.projectName,
|
||||
version: '0.0.1',
|
||||
private: true,
|
||||
nx: {
|
||||
name: options.name,
|
||||
projectType: 'application',
|
||||
sourceRoot: `${options.appProjectRoot}/src`,
|
||||
tags: options.parsedTags?.length ? options.parsedTags : undefined,
|
||||
},
|
||||
nx: options.parsedTags?.length
|
||||
? {
|
||||
tags: options.parsedTags,
|
||||
}
|
||||
: undefined,
|
||||
});
|
||||
} else {
|
||||
addProjectConfiguration(tree, options.projectName, {
|
||||
@ -108,6 +114,7 @@ export async function applicationGeneratorInternal(
|
||||
setParserOptionsProject: options.setParserOptionsProject,
|
||||
rootProject: options.rootProject,
|
||||
addPlugin: options.addPlugin,
|
||||
projectName: options.projectName,
|
||||
},
|
||||
'app'
|
||||
)
|
||||
@ -146,12 +153,6 @@ export async function applicationGeneratorInternal(
|
||||
);
|
||||
}
|
||||
|
||||
// If we are using the new TS solution
|
||||
// We need to update the workspace file (package.json or pnpm-workspaces.yaml) to include the new project
|
||||
if (options.isUsingTsSolutionConfig) {
|
||||
addProjectToTsSolutionWorkspace(tree, options.appProjectRoot);
|
||||
}
|
||||
|
||||
sortPackageJsonFields(tree, options.appProjectRoot);
|
||||
|
||||
if (!options.skipFormat) await formatFiles(tree);
|
||||
|
||||
@ -5,6 +5,7 @@ import {
|
||||
} from '@nx/devkit/src/generators/project-name-and-root-utils';
|
||||
import { NormalizedSchema, Schema } from '../schema';
|
||||
import { isUsingTsSolutionSetup } from '@nx/js/src/utils/typescript/ts-solution-setup';
|
||||
import { getImportPath } from '@nx/js/src/utils/get-import-path';
|
||||
|
||||
export async function normalizeOptions(
|
||||
host: Tree,
|
||||
@ -27,20 +28,24 @@ export async function normalizeOptions(
|
||||
? options.tags.split(',').map((s) => s.trim())
|
||||
: [];
|
||||
|
||||
const isUsingTsSolutionConfig = isUsingTsSolutionSetup(host);
|
||||
|
||||
const normalized = {
|
||||
...options,
|
||||
projectName: appProjectName,
|
||||
projectName: isUsingTsSolutionConfig
|
||||
? getImportPath(host, appProjectName)
|
||||
: appProjectName,
|
||||
appProjectRoot,
|
||||
e2eProjectName,
|
||||
e2eProjectRoot,
|
||||
parsedTags,
|
||||
isUsingTsSolutionConfig,
|
||||
} as NormalizedSchema;
|
||||
|
||||
normalized.style = options.style ?? 'css';
|
||||
normalized.routing = normalized.routing ?? false;
|
||||
normalized.unitTestRunner ??= 'vitest';
|
||||
normalized.e2eTestRunner = normalized.e2eTestRunner ?? 'playwright';
|
||||
normalized.isUsingTsSolutionConfig = isUsingTsSolutionSetup(host);
|
||||
normalized.bundler = normalized.bundler ?? 'vite';
|
||||
|
||||
return normalized;
|
||||
|
||||
@ -12,6 +12,7 @@ import { determineArtifactNameAndDirectoryOptions } from '@nx/devkit/src/generat
|
||||
|
||||
import { NormalizedSchema, ComponentGeneratorSchema } from '../schema';
|
||||
import { addImport } from '../../../utils/ast-utils';
|
||||
import { getProjectType } from '@nx/js/src/utils/typescript/ts-solution-setup';
|
||||
|
||||
let tsModule: typeof import('typescript');
|
||||
|
||||
@ -33,9 +34,12 @@ export async function normalizeOptions(
|
||||
let { className } = names(fileName);
|
||||
const componentFileName = fileName;
|
||||
const project = getProjects(host).get(projectName);
|
||||
const { sourceRoot: projectSourceRoot, projectType } = project;
|
||||
const { root, sourceRoot: projectSourceRoot, projectType } = project;
|
||||
|
||||
if (options.export && projectType === 'application') {
|
||||
if (
|
||||
options.export &&
|
||||
getProjectType(host, root, projectType) === 'application'
|
||||
) {
|
||||
logger.warn(
|
||||
`The "--export" option should not be used with applications and will do nothing.`
|
||||
);
|
||||
@ -60,12 +64,13 @@ export function addExportsToBarrel(host: Tree, options: NormalizedSchema) {
|
||||
tsModule = ensureTypescript();
|
||||
}
|
||||
const workspace = getProjects(host);
|
||||
const proj = workspace.get(options.projectName);
|
||||
const isApp =
|
||||
workspace.get(options.projectName).projectType === 'application';
|
||||
getProjectType(host, proj.root, proj.projectType) === 'application';
|
||||
|
||||
if (options.export && !isApp) {
|
||||
const indexFilePath = joinPathFragments(
|
||||
options.projectSourceRoot,
|
||||
options.projectSourceRoot ?? 'src',
|
||||
options.js ? 'index.js' : 'index.ts'
|
||||
);
|
||||
const indexSource = host.read(indexFilePath, 'utf-8');
|
||||
|
||||
@ -18,7 +18,7 @@ export async function addVite(
|
||||
ensurePackage<typeof import('@nx/vite')>('@nx/vite', nxVersion);
|
||||
const viteTask = await viteConfigurationGenerator(tree, {
|
||||
uiFramework: 'none',
|
||||
project: options.name,
|
||||
project: options.projectName,
|
||||
newProject: true,
|
||||
includeLib: true,
|
||||
inSourceTests: options.inSourceTests,
|
||||
@ -32,7 +32,7 @@ export async function addVite(
|
||||
createOrEditViteConfig(
|
||||
tree,
|
||||
{
|
||||
project: options.name,
|
||||
project: options.projectName,
|
||||
includeLib: true,
|
||||
includeVitest: options.unitTestRunner === 'vitest',
|
||||
inSourceTests: options.inSourceTests,
|
||||
@ -53,7 +53,7 @@ export async function addVite(
|
||||
>('@nx/vite', nxVersion);
|
||||
const vitestTask = await vitestGenerator(tree, {
|
||||
uiFramework: 'none',
|
||||
project: options.name,
|
||||
project: options.projectName,
|
||||
coverageProvider: 'v8',
|
||||
inSourceTests: options.inSourceTests,
|
||||
skipFormat: true,
|
||||
@ -66,7 +66,7 @@ export async function addVite(
|
||||
createOrEditViteConfig(
|
||||
tree,
|
||||
{
|
||||
project: options.name,
|
||||
project: options.projectName,
|
||||
includeLib: true,
|
||||
includeVitest: true,
|
||||
inSourceTests: options.inSourceTests,
|
||||
|
||||
@ -11,6 +11,7 @@ import {
|
||||
} from '@nx/devkit/src/generators/project-name-and-root-utils';
|
||||
import { NormalizedSchema, Schema } from '../schema';
|
||||
import { isUsingTsSolutionSetup } from '@nx/js/src/utils/typescript/ts-solution-setup';
|
||||
import { getImportPath } from '@nx/js/src/utils/get-import-path';
|
||||
|
||||
export async function normalizeOptions(
|
||||
host: Tree,
|
||||
@ -51,9 +52,14 @@ export async function normalizeOptions(
|
||||
process.env.NX_ADD_PLUGINS !== 'false' &&
|
||||
nxJson.useInferencePlugins !== false;
|
||||
|
||||
const isUsingTsSolutionConfig = isUsingTsSolutionSetup(host);
|
||||
|
||||
const normalized = {
|
||||
addPlugin,
|
||||
...options,
|
||||
projectName: isUsingTsSolutionConfig
|
||||
? getImportPath(host, projectName)
|
||||
: projectName,
|
||||
bundler,
|
||||
fileName,
|
||||
routePath: `/${projectNames.projectFileName}`,
|
||||
@ -61,7 +67,7 @@ export async function normalizeOptions(
|
||||
projectRoot,
|
||||
parsedTags,
|
||||
importPath,
|
||||
isUsingTsSolutionConfig: isUsingTsSolutionSetup(host),
|
||||
isUsingTsSolutionConfig,
|
||||
} as NormalizedSchema;
|
||||
|
||||
// Libraries with a bundler or is publishable must also be buildable.
|
||||
|
||||
@ -47,6 +47,12 @@ export async function libraryGeneratorInternal(tree: Tree, schema: Schema) {
|
||||
);
|
||||
}
|
||||
|
||||
// If we are using the new TS solution
|
||||
// We need to update the workspace file (package.json or pnpm-workspaces.yaml) to include the new project
|
||||
if (options.isUsingTsSolutionConfig) {
|
||||
addProjectToTsSolutionWorkspace(tree, options.projectRoot);
|
||||
}
|
||||
|
||||
if (options.isUsingTsSolutionConfig) {
|
||||
writeJson(tree, joinPathFragments(options.projectRoot, 'package.json'), {
|
||||
name: getImportPath(tree, options.name),
|
||||
@ -54,12 +60,11 @@ export async function libraryGeneratorInternal(tree: Tree, schema: Schema) {
|
||||
private: true,
|
||||
...determineEntryFields(options),
|
||||
files: options.publishable ? ['dist', '!**/*.tsbuildinfo'] : undefined,
|
||||
nx: {
|
||||
name: options.name,
|
||||
projectType: 'library',
|
||||
sourceRoot: `${options.projectRoot}/src`,
|
||||
tags: options.parsedTags?.length ? options.parsedTags : undefined,
|
||||
},
|
||||
nx: options.parsedTags?.length
|
||||
? {
|
||||
tags: options.parsedTags,
|
||||
}
|
||||
: undefined,
|
||||
});
|
||||
} else {
|
||||
addProjectConfiguration(tree, options.name, {
|
||||
@ -149,12 +154,6 @@ export async function libraryGeneratorInternal(tree: Tree, schema: Schema) {
|
||||
);
|
||||
}
|
||||
|
||||
// If we are using the new TS solution
|
||||
// We need to update the workspace file (package.json or pnpm-workspaces.yaml) to include the new project
|
||||
if (options.isUsingTsSolutionConfig) {
|
||||
addProjectToTsSolutionWorkspace(tree, options.projectRoot);
|
||||
}
|
||||
|
||||
sortPackageJsonFields(tree, options.projectRoot);
|
||||
|
||||
if (!options.skipFormat) await formatFiles(tree);
|
||||
|
||||
@ -27,6 +27,7 @@ export interface Schema {
|
||||
export interface NormalizedSchema extends Schema {
|
||||
js: boolean;
|
||||
name: string;
|
||||
projectName: string;
|
||||
linter: Linter | LinterType;
|
||||
fileName: string;
|
||||
projectRoot: string;
|
||||
|
||||
@ -30,6 +30,7 @@ export async function addLinting(
|
||||
skipPackageJson?: boolean;
|
||||
rootProject?: boolean;
|
||||
addPlugin?: boolean;
|
||||
projectName: string;
|
||||
},
|
||||
projectType: 'lib' | 'app'
|
||||
) {
|
||||
@ -37,7 +38,7 @@ export async function addLinting(
|
||||
const tasks: GeneratorCallback[] = [];
|
||||
const lintTask = await lintProjectGenerator(host, {
|
||||
linter: options.linter,
|
||||
project: options.name,
|
||||
project: options.projectName,
|
||||
tsConfigPaths: [
|
||||
joinPathFragments(options.projectRoot, `tsconfig.${projectType}.json`),
|
||||
],
|
||||
|
||||
@ -247,12 +247,11 @@ async function addProject(tree: Tree, options: NormalizedSchema) {
|
||||
name: getImportPath(tree, options.name),
|
||||
version: '0.0.1',
|
||||
private: true,
|
||||
nx: {
|
||||
name: options.name,
|
||||
projectType: 'application',
|
||||
sourceRoot: `${options.appProjectRoot}/src`,
|
||||
tags: options.parsedTags?.length ? options.parsedTags : undefined,
|
||||
},
|
||||
nx: options.parsedTags?.length
|
||||
? {
|
||||
tags: options.parsedTags,
|
||||
}
|
||||
: undefined,
|
||||
});
|
||||
} else {
|
||||
addProjectConfiguration(tree, options.projectName, {
|
||||
@ -288,6 +287,10 @@ export async function applicationGenerator(host: Tree, schema: Schema) {
|
||||
export async function applicationGeneratorInternal(host: Tree, schema: Schema) {
|
||||
const options = await normalizeOptions(host, schema);
|
||||
|
||||
if (options.isUsingTsSolutionConfig) {
|
||||
addProjectToTsSolutionWorkspace(host, options.appProjectRoot);
|
||||
}
|
||||
|
||||
const tasks: GeneratorCallback[] = [];
|
||||
|
||||
const jsInitTask = await jsInitGenerator(host, {
|
||||
@ -666,10 +669,6 @@ export async function applicationGeneratorInternal(host: Tree, schema: Schema) {
|
||||
: undefined
|
||||
);
|
||||
|
||||
if (options.isUsingTsSolutionConfig) {
|
||||
addProjectToTsSolutionWorkspace(host, options.appProjectRoot);
|
||||
}
|
||||
|
||||
if (!options.skipFormat) {
|
||||
await formatFiles(host);
|
||||
}
|
||||
@ -719,7 +718,9 @@ async function normalizeOptions(
|
||||
name: names(options.name).fileName,
|
||||
compiler: options.compiler ?? 'babel',
|
||||
bundler: options.bundler ?? 'webpack',
|
||||
projectName: appProjectName,
|
||||
projectName: isUsingTsSolutionConfig
|
||||
? getImportPath(host, appProjectName)
|
||||
: appProjectName,
|
||||
strict: options.strict ?? true,
|
||||
appProjectRoot,
|
||||
e2eProjectRoot,
|
||||
|
||||
@ -9,6 +9,7 @@ import {
|
||||
writeJson,
|
||||
} from '@nx/devkit';
|
||||
import { moveGenerator } from '../move/move';
|
||||
import { getProjectType } from '../../utils/ts-solution-setup';
|
||||
|
||||
export async function monorepoGenerator(tree: Tree, options: {}) {
|
||||
const projects = getProjects(tree);
|
||||
@ -32,7 +33,9 @@ export async function monorepoGenerator(tree: Tree, options: {}) {
|
||||
// Currently, Nx only handles apps+libs or packages. You cannot mix and match them.
|
||||
// If the standalone project is an app (React, Angular, etc), then use apps+libs.
|
||||
// Otherwise, for TS standalone (lib), use packages.
|
||||
const isRootProjectApp = rootProject.projectType === 'application';
|
||||
const isRootProjectApp =
|
||||
getProjectType(tree, rootProject.root, rootProject.projectType) ===
|
||||
'application';
|
||||
const appsDir = isRootProjectApp ? 'apps' : 'packages';
|
||||
const libsDir = isRootProjectApp ? 'libs' : 'packages';
|
||||
|
||||
@ -50,11 +53,12 @@ export async function monorepoGenerator(tree: Tree, options: {}) {
|
||||
}
|
||||
|
||||
for (const project of projectsToMove) {
|
||||
const projectType = getProjectType(tree, project.root, project.projectType);
|
||||
await moveGenerator(tree, {
|
||||
projectName: project.name,
|
||||
newProjectName: project.name,
|
||||
destination:
|
||||
project.projectType === 'application'
|
||||
projectType === 'application'
|
||||
? joinPathFragments(
|
||||
appsDir,
|
||||
project.root === '.' ? project.name : project.root
|
||||
@ -63,7 +67,7 @@ export async function monorepoGenerator(tree: Tree, options: {}) {
|
||||
libsDir,
|
||||
project.root === '.' ? project.name : project.root
|
||||
),
|
||||
updateImportPath: project.projectType === 'library',
|
||||
updateImportPath: projectType === 'library',
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,7 +1,12 @@
|
||||
import { type ProjectConfiguration, type Tree } from '@nx/devkit';
|
||||
import {
|
||||
joinPathFragments,
|
||||
type ProjectConfiguration,
|
||||
type Tree,
|
||||
} from '@nx/devkit';
|
||||
import { getNpmScope } from '../../../utilities/get-import-path';
|
||||
import type { NormalizedSchema, Schema } from '../schema';
|
||||
import { normalizePathSlashes } from './utils';
|
||||
import { getProjectType } from '../../../utils/ts-solution-setup';
|
||||
|
||||
export async function normalizeSchema(
|
||||
tree: Tree,
|
||||
@ -35,7 +40,7 @@ async function determineProjectNameAndRootOptions(
|
||||
options: Schema,
|
||||
projectConfiguration: ProjectConfiguration
|
||||
): Promise<ProjectNameAndRootOptions> {
|
||||
validateName(options.newProjectName, projectConfiguration);
|
||||
validateName(tree, options.newProjectName, projectConfiguration);
|
||||
const projectNameAndRootOptions = getProjectNameAndRootOptions(
|
||||
tree,
|
||||
options,
|
||||
@ -46,6 +51,7 @@ async function determineProjectNameAndRootOptions(
|
||||
}
|
||||
|
||||
function validateName(
|
||||
tree: Tree,
|
||||
name: string | undefined,
|
||||
projectConfiguration: ProjectConfiguration
|
||||
): void {
|
||||
@ -66,15 +72,26 @@ function validateName(
|
||||
const libraryPattern =
|
||||
'(?:^@[a-zA-Z0-9-*~][a-zA-Z0-9-*._~]*\\/[a-zA-Z0-9-~][a-zA-Z0-9-._~]*|^[a-zA-Z][^:]*)$';
|
||||
const appPattern = '^[a-zA-Z][^:]*$';
|
||||
const projectType = getProjectType(
|
||||
tree,
|
||||
projectConfiguration.root,
|
||||
projectConfiguration.projectType
|
||||
);
|
||||
|
||||
if (projectConfiguration.projectType === 'application') {
|
||||
if (projectType === 'application') {
|
||||
const validationRegex = new RegExp(appPattern);
|
||||
if (!validationRegex.test(name)) {
|
||||
throw new Error(
|
||||
`The new project name should match the pattern "${appPattern}". The provided value "${name}" does not match.`
|
||||
);
|
||||
}
|
||||
} else if (projectConfiguration.projectType === 'library') {
|
||||
} else if (
|
||||
getProjectType(
|
||||
tree,
|
||||
projectConfiguration.root,
|
||||
projectConfiguration.projectType
|
||||
) === 'library'
|
||||
) {
|
||||
const validationRegex = new RegExp(libraryPattern);
|
||||
if (!validationRegex.test(name)) {
|
||||
throw new Error(
|
||||
|
||||
@ -1,48 +1,4 @@
|
||||
import {
|
||||
getWorkspaceLayout,
|
||||
joinPathFragments,
|
||||
normalizePath,
|
||||
ProjectConfiguration,
|
||||
Tree,
|
||||
} from '@nx/devkit';
|
||||
import { Schema } from '../schema';
|
||||
|
||||
/**
|
||||
* This helper function ensures that we don't move libs or apps
|
||||
* outside of the folders they should be in.
|
||||
*
|
||||
* This will break if someone isn't using the default libs/apps
|
||||
* folders. In that case, they're on their own :/
|
||||
*/
|
||||
export function getDestination(
|
||||
host: Tree,
|
||||
schema: Schema,
|
||||
project: ProjectConfiguration
|
||||
): string {
|
||||
const projectType = project.projectType;
|
||||
|
||||
const workspaceLayout = getWorkspaceLayout(host);
|
||||
|
||||
let rootFolder = workspaceLayout.libsDir;
|
||||
if (projectType === 'application') {
|
||||
rootFolder = workspaceLayout.appsDir;
|
||||
}
|
||||
return joinPathFragments(rootFolder, schema.destination);
|
||||
}
|
||||
|
||||
/**
|
||||
* Joins path segments replacing slashes with dashes
|
||||
*
|
||||
* @param path
|
||||
*/
|
||||
export function getNewProjectName(path: string): string {
|
||||
// strip leading '/' or './' or '../' and trailing '/' and replaces '/' with '-'
|
||||
return normalizePath(path)
|
||||
.replace(/(^\.{0,2}\/|\.{1,2}\/|\/$)/g, '')
|
||||
.split('/')
|
||||
.filter((x) => !!x)
|
||||
.join('-');
|
||||
}
|
||||
import { normalizePath } from '@nx/devkit';
|
||||
|
||||
/**
|
||||
* Normalizes slashes (removes duplicates)
|
||||
|
||||
19
packages/workspace/src/utils/ts-solution-setup.ts
Normal file
19
packages/workspace/src/utils/ts-solution-setup.ts
Normal file
@ -0,0 +1,19 @@
|
||||
import { joinPathFragments, readJson, type Tree } from '@nx/devkit';
|
||||
|
||||
// This is copied from `@nx/js` to avoid circular dependencies.
|
||||
export function getProjectType(
|
||||
tree: Tree,
|
||||
projectRoot: string,
|
||||
projectType?: 'library' | 'application'
|
||||
): 'library' | 'application' {
|
||||
if (projectType) return projectType;
|
||||
if (joinPathFragments(projectRoot, 'tsconfig.lib.json')) return 'library';
|
||||
if (joinPathFragments(projectRoot, 'tsconfig.app.json')) return 'application';
|
||||
// If there are no exports, assume it is an application since both buildable and non-buildable libraries have exports.
|
||||
const packageJsonPath = joinPathFragments(projectRoot, 'package.json');
|
||||
const packageJson = tree.exists(packageJsonPath)
|
||||
? readJson(tree, joinPathFragments(projectRoot, 'package.json'))
|
||||
: null;
|
||||
if (!packageJson?.exports) return 'application';
|
||||
return 'library';
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user