diff --git a/docs/generated/packages/nuxt/generators/application.json b/docs/generated/packages/nuxt/generators/application.json
index 16e17b76a4f830..4877abbc541066 100644
--- a/docs/generated/packages/nuxt/generators/application.json
+++ b/docs/generated/packages/nuxt/generators/application.json
@@ -22,24 +22,27 @@
"pattern": "^[a-zA-Z][^:]*$",
"x-priority": "important"
},
- "linter": {
- "description": "The tool to use for running lint checks.",
- "type": "string",
- "enum": ["eslint"],
- "default": "eslint"
- },
"skipFormat": {
"description": "Skip formatting files.",
"type": "boolean",
"default": false,
"x-priority": "internal"
},
+ "linter": {
+ "description": "The tool to use for running lint checks.",
+ "type": "string",
+ "enum": ["eslint", "none"],
+ "default": "none",
+ "x-prompt": "Which linter would you like to use?",
+ "x-priority": "important"
+ },
"unitTestRunner": {
"type": "string",
"enum": ["vitest", "none"],
"description": "Test runner to use for unit tests.",
"x-prompt": "Which unit test runner would you like to use?",
- "default": "none"
+ "default": "none",
+ "x-priority": "important"
},
"e2eTestRunner": {
"type": "string",
diff --git a/docs/generated/packages/vue/generators/application.json b/docs/generated/packages/vue/generators/application.json
index 70212ea56f8e9c..d545250bec98a1 100644
--- a/docs/generated/packages/vue/generators/application.json
+++ b/docs/generated/packages/vue/generators/application.json
@@ -54,12 +54,6 @@
]
}
},
- "linter": {
- "description": "The tool to use for running lint checks.",
- "type": "string",
- "enum": ["eslint", "none"],
- "default": "eslint"
- },
"routing": {
"type": "boolean",
"description": "Generate application with routes.",
@@ -72,12 +66,21 @@
"default": false,
"x-priority": "internal"
},
+ "linter": {
+ "description": "The tool to use for running lint checks.",
+ "type": "string",
+ "enum": ["eslint", "none"],
+ "default": "none",
+ "x-prompt": "Which linter would you like to use?",
+ "x-priority": "important"
+ },
"unitTestRunner": {
"type": "string",
"enum": ["vitest", "none"],
"description": "Test runner to use for unit tests.",
"x-prompt": "Which unit test runner would you like to use?",
- "default": "vitest"
+ "default": "none",
+ "x-priority": "important"
},
"inSourceTests": {
"type": "boolean",
diff --git a/docs/generated/packages/vue/generators/library.json b/docs/generated/packages/vue/generators/library.json
index 664b2b97a13076..418e359c36a427 100644
--- a/docs/generated/packages/vue/generators/library.json
+++ b/docs/generated/packages/vue/generators/library.json
@@ -36,13 +36,17 @@
"description": "The tool to use for running lint checks.",
"type": "string",
"enum": ["eslint", "none"],
- "default": "eslint"
+ "default": "none",
+ "x-prompt": "Which linter would you like to use?",
+ "x-priority": "important"
},
"unitTestRunner": {
"type": "string",
"enum": ["vitest", "none"],
"description": "Test runner to use for unit tests.",
- "x-prompt": "What unit test runner should be used?"
+ "x-prompt": "What unit test runner should be used?",
+ "default": "none",
+ "x-priority": "important"
},
"inSourceTests": {
"type": "boolean",
diff --git a/packages/create-nx-workspace/bin/create-nx-workspace.ts b/packages/create-nx-workspace/bin/create-nx-workspace.ts
index 1fe2eace4247ea..86fb208d971eb8 100644
--- a/packages/create-nx-workspace/bin/create-nx-workspace.ts
+++ b/packages/create-nx-workspace/bin/create-nx-workspace.ts
@@ -32,6 +32,9 @@ import { printSocialInformation } from '../src/utils/social-information';
interface BaseArguments extends CreateWorkspaceOptions {
preset: Preset;
+ linter?: 'none' | 'eslint';
+ formatter?: 'none' | 'prettier';
+ workspaces?: boolean;
}
interface NoneArguments extends BaseArguments {
@@ -39,7 +42,6 @@ interface NoneArguments extends BaseArguments {
workspaceType?: 'package-based' | 'integrated' | 'standalone';
js?: boolean;
appName?: string | undefined;
- formatter?: 'none' | 'prettier';
}
interface ReactArguments extends BaseArguments {
@@ -52,9 +54,6 @@ interface ReactArguments extends BaseArguments {
nextAppDir: boolean;
nextSrcDir: boolean;
e2eTestRunner: 'none' | 'cypress' | 'playwright';
- linter?: 'none' | 'eslint';
- formatter?: 'none' | 'prettier';
- workspaces?: boolean;
}
interface AngularArguments extends BaseArguments {
@@ -730,6 +729,10 @@ async function determineVueOptions(
let style: undefined | string = undefined;
let appName: string;
let e2eTestRunner: undefined | 'none' | 'cypress' | 'playwright' = undefined;
+ let linter: undefined | 'none' | 'eslint';
+ let formatter: undefined | 'none' | 'prettier';
+
+ const workspaces = parsedArgs.workspaces ?? false;
if (parsedArgs.preset && parsedArgs.preset !== Preset.Vue) {
preset = parsedArgs.preset;
@@ -741,7 +744,9 @@ async function determineVueOptions(
} else {
const framework = await determineVueFramework(parsedArgs);
- const workspaceType = await determineStandaloneOrMonorepo();
+ const workspaceType = workspaces
+ ? 'monorepo'
+ : await determineStandaloneOrMonorepo();
if (workspaceType === 'standalone') {
appName = parsedArgs.appName ?? parsedArgs.name;
} else {
@@ -798,7 +803,23 @@ async function determineVueOptions(
style = reply.style;
}
- return { preset, style, appName, e2eTestRunner };
+ if (workspaces) {
+ linter = await determineLinterOptions(parsedArgs);
+ formatter = await determineFormatterOptions(parsedArgs);
+ } else {
+ linter = 'eslint';
+ formatter = 'prettier';
+ }
+
+ return {
+ preset,
+ style,
+ appName,
+ e2eTestRunner,
+ linter,
+ formatter,
+ workspaces,
+ };
}
async function determineAngularOptions(
diff --git a/packages/nuxt/src/generators/application/application.spec.ts b/packages/nuxt/src/generators/application/application.spec.ts
index f26160511b18b1..387ea579e63111 100644
--- a/packages/nuxt/src/generators/application/application.spec.ts
+++ b/packages/nuxt/src/generators/application/application.spec.ts
@@ -1,7 +1,13 @@
import 'nx/src/internal-testing-utils/mock-project-graph';
import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing';
-import { Tree, readJson, readProjectConfiguration } from '@nx/devkit';
+import {
+ Tree,
+ readJson,
+ readProjectConfiguration,
+ updateJson,
+ writeJson,
+} from '@nx/devkit';
import { applicationGenerator } from './application';
describe('app', () => {
@@ -194,4 +200,177 @@ describe('app', () => {
});
}
);
+
+ describe('TS solution setup', () => {
+ beforeEach(() => {
+ tree = createTreeWithEmptyWorkspace();
+ updateJson(tree, 'package.json', (json) => {
+ json.workspaces = ['packages/*', 'apps/*'];
+ return json;
+ });
+ writeJson(tree, 'tsconfig.base.json', {
+ compilerOptions: {
+ composite: true,
+ declaration: true,
+ },
+ });
+ writeJson(tree, 'tsconfig.json', {
+ extends: './tsconfig.base.json',
+ files: [],
+ references: [],
+ });
+ });
+
+ it('should add project references when using TS solution', async () => {
+ await applicationGenerator(tree, {
+ directory: 'myapp',
+ e2eTestRunner: 'playwright',
+ unitTestRunner: 'vitest',
+ linter: 'eslint',
+ });
+
+ expect(tree.read('myapp/vite.config.ts', 'utf-8')).toMatchInlineSnapshot(
+ `null`
+ );
+ expect(readJson(tree, 'tsconfig.json').references).toMatchInlineSnapshot(`
+ [
+ {
+ "path": "./myapp-e2e",
+ },
+ {
+ "path": "./myapp",
+ },
+ ]
+ `);
+ expect(readJson(tree, 'myapp/tsconfig.json')).toMatchInlineSnapshot(`
+ {
+ "compilerOptions": {},
+ "extends": "../tsconfig.base.json",
+ "files": [],
+ "include": [
+ ".nuxt/nuxt.d.ts",
+ ],
+ "references": [
+ {
+ "path": "./tsconfig.app.json",
+ },
+ {
+ "path": "./tsconfig.spec.json",
+ },
+ ],
+ }
+ `);
+ expect(readJson(tree, 'myapp/tsconfig.app.json')).toMatchInlineSnapshot(`
+ {
+ "compilerOptions": {
+ "composite": true,
+ "jsx": "preserve",
+ "jsxImportSource": "vue",
+ "module": "esnext",
+ "moduleResolution": "bundler",
+ "outDir": "out-tsc/myapp",
+ "resolveJsonModule": true,
+ "rootDir": "src",
+ },
+ "exclude": [
+ "dist",
+ "vite.config.ts",
+ "vite.config.mts",
+ "vitest.config.ts",
+ "vitest.config.mts",
+ "src/**/*.test.ts",
+ "src/**/*.spec.ts",
+ "src/**/*.test.tsx",
+ "src/**/*.spec.tsx",
+ "src/**/*.test.js",
+ "src/**/*.spec.js",
+ "src/**/*.test.jsx",
+ "src/**/*.spec.jsx",
+ "eslint.config.js",
+ "eslint.config.cjs",
+ "eslint.config.mjs",
+ ],
+ "extends": "../tsconfig.base.json",
+ "include": [
+ ".nuxt/nuxt.d.ts",
+ "src/**/*",
+ ],
+ }
+ `);
+ expect(readJson(tree, 'myapp/tsconfig.spec.json')).toMatchInlineSnapshot(`
+ {
+ "compilerOptions": {
+ "composite": true,
+ "jsx": "preserve",
+ "jsxImportSource": "vue",
+ "module": "esnext",
+ "moduleResolution": "bundler",
+ "outDir": "./out-tsc/vitest",
+ "resolveJsonModule": true,
+ "types": [
+ "vitest/globals",
+ "vitest/importMeta",
+ "vite/client",
+ "node",
+ "vitest",
+ ],
+ },
+ "extends": "../tsconfig.base.json",
+ "include": [
+ ".nuxt/nuxt.d.ts",
+ "vite.config.ts",
+ "vite.config.mts",
+ "vitest.config.ts",
+ "vitest.config.mts",
+ "src/**/*.test.ts",
+ "src/**/*.spec.ts",
+ "src/**/*.test.tsx",
+ "src/**/*.spec.tsx",
+ "src/**/*.test.js",
+ "src/**/*.spec.js",
+ "src/**/*.test.jsx",
+ "src/**/*.spec.jsx",
+ "src/**/*.d.ts",
+ ],
+ "references": [
+ {
+ "path": "./tsconfig.app.json",
+ },
+ ],
+ }
+ `);
+ expect(readJson(tree, 'myapp-e2e/tsconfig.json')).toMatchInlineSnapshot(`
+ {
+ "compilerOptions": {
+ "allowJs": true,
+ "outDir": "dist",
+ "sourceMap": false,
+ "tsBuildInfoFile": "dist/tsconfig.tsbuildinfo",
+ },
+ "exclude": [
+ "dist",
+ "eslint.config.js",
+ "eslint.config.mjs",
+ "eslint.config.cjs",
+ ],
+ "extends": "../tsconfig.base.json",
+ "include": [
+ "**/*.ts",
+ "**/*.js",
+ "playwright.config.ts",
+ "src/**/*.spec.ts",
+ "src/**/*.spec.js",
+ "src/**/*.test.ts",
+ "src/**/*.test.js",
+ "src/**/*.d.ts",
+ ],
+ "references": [
+ {
+ "path": "../myapp",
+ },
+ ],
+ }
+ `);
+ });
+ });
});
diff --git a/packages/nuxt/src/generators/application/application.ts b/packages/nuxt/src/generators/application/application.ts
index 0ce521f9139e92..cff6c382d0de53 100644
--- a/packages/nuxt/src/generators/application/application.ts
+++ b/packages/nuxt/src/generators/application/application.ts
@@ -9,6 +9,7 @@ import {
runTasksInSerial,
toJS,
Tree,
+ writeJson,
} from '@nx/devkit';
import { Schema } from './schema';
import nuxtInitGenerator from '../init/init';
@@ -18,7 +19,6 @@ import {
getRelativePathToRootTsConfig,
initGenerator as jsInitGenerator,
} from '@nx/js';
-import { assertNotUsingTsSolutionSetup } from '@nx/js/src/utils/typescript/ts-solution-setup';
import { updateGitIgnore } from '../../utils/update-gitignore';
import { Linter } from '@nx/eslint';
import { addE2e } from './lib/add-e2e';
@@ -32,12 +32,20 @@ import {
getNxCloudAppOnBoardingUrl,
createNxCloudOnboardingURLForWelcomeApp,
} from 'nx/src/nx-cloud/utilities/onboarding';
+import { getImportPath } from '@nx/js/src/utils/get-import-path';
+import { updateTsconfigFiles } from '@nx/js/src/utils/typescript/ts-solution-setup';
export async function applicationGenerator(tree: Tree, schema: Schema) {
- assertNotUsingTsSolutionSetup(tree, 'nuxt', 'application');
-
const tasks: GeneratorCallback[] = [];
+ const jsInitTask = await jsInitGenerator(tree, {
+ ...schema,
+ tsConfigName: schema.rootProject ? 'tsconfig.json' : 'tsconfig.base.json',
+ skipFormat: true,
+ addTsPlugin: schema.useTsSolution,
+ });
+ tasks.push(jsInitTask);
+
const options = await normalizeOptions(tree, schema);
const projectOffsetFromRoot = offsetFromRoot(options.appProjectRoot);
@@ -51,20 +59,29 @@ export async function applicationGenerator(tree: Tree, schema: Schema) {
onBoardingStatus === 'unclaimed' &&
(await getNxCloudAppOnBoardingUrl(options.nxCloudToken));
- const jsInitTask = await jsInitGenerator(tree, {
- ...schema,
- tsConfigName: schema.rootProject ? 'tsconfig.json' : 'tsconfig.base.json',
- skipFormat: true,
- });
- tasks.push(jsInitTask);
tasks.push(ensureDependencies(tree, options));
- addProjectConfiguration(tree, options.projectName, {
- root: options.appProjectRoot,
- projectType: 'application',
- sourceRoot: `${options.appProjectRoot}/src`,
- targets: {},
- });
+ if (options.isUsingTsSolutionConfig) {
+ writeJson(tree, joinPathFragments(options.appProjectRoot, 'package.json'), {
+ 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,
+ },
+ });
+ } else {
+ addProjectConfiguration(tree, options.projectName, {
+ root: options.appProjectRoot,
+ projectType: 'application',
+ sourceRoot: `${options.appProjectRoot}/src`,
+ tags: options.parsedTags?.length ? options.parsedTags : undefined,
+ targets: {},
+ });
+ }
generateFiles(
tree,
@@ -168,6 +185,24 @@ export async function applicationGenerator(tree: Tree, schema: Schema) {
}
});
+ if (options.isUsingTsSolutionConfig) {
+ updateTsconfigFiles(
+ tree,
+ options.appProjectRoot,
+ 'tsconfig.app.json',
+ {
+ jsx: 'preserve',
+ jsxImportSource: 'vue',
+ module: 'esnext',
+ moduleResolution: 'bundler',
+ resolveJsonModule: true,
+ },
+ options.linter === 'eslint'
+ ? ['eslint.config.js', 'eslint.config.cjs', 'eslint.config.mjs']
+ : undefined
+ );
+ }
+
tasks.push(() => {
logShowProjectCommand(options.projectName);
});
diff --git a/packages/nuxt/src/generators/application/lib/normalize-options.ts b/packages/nuxt/src/generators/application/lib/normalize-options.ts
index d35182f9416244..4fdee758de7a61 100644
--- a/packages/nuxt/src/generators/application/lib/normalize-options.ts
+++ b/packages/nuxt/src/generators/application/lib/normalize-options.ts
@@ -4,6 +4,7 @@ import {
ensureProjectName,
} 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';
export async function normalizeOptions(
host: Tree,
@@ -35,6 +36,7 @@ export async function normalizeOptions(
e2eProjectRoot,
parsedTags,
style: options.style ?? 'none',
+ isUsingTsSolutionConfig: isUsingTsSolutionSetup(host),
} as NormalizedSchema;
normalized.unitTestRunner ??= 'vitest';
diff --git a/packages/nuxt/src/generators/application/schema.d.ts b/packages/nuxt/src/generators/application/schema.d.ts
index a758930a817ad2..14095fb47e2d4f 100644
--- a/packages/nuxt/src/generators/application/schema.d.ts
+++ b/packages/nuxt/src/generators/application/schema.d.ts
@@ -14,6 +14,7 @@ export interface Schema {
setParserOptionsProject?: boolean;
style?: 'css' | 'scss' | 'less' | 'none';
nxCloudToken?: string;
+ useTsSolution?: boolean;
}
export interface NormalizedSchema extends Schema {
@@ -22,4 +23,5 @@ export interface NormalizedSchema extends Schema {
e2eProjectName: string;
e2eProjectRoot: string;
parsedTags: string[];
+ isUsingTsSolutionConfig: boolean;
}
diff --git a/packages/nuxt/src/generators/application/schema.json b/packages/nuxt/src/generators/application/schema.json
index effd221b7efeae..75f4fd461a4e8b 100644
--- a/packages/nuxt/src/generators/application/schema.json
+++ b/packages/nuxt/src/generators/application/schema.json
@@ -22,24 +22,27 @@
"pattern": "^[a-zA-Z][^:]*$",
"x-priority": "important"
},
- "linter": {
- "description": "The tool to use for running lint checks.",
- "type": "string",
- "enum": ["eslint"],
- "default": "eslint"
- },
"skipFormat": {
"description": "Skip formatting files.",
"type": "boolean",
"default": false,
"x-priority": "internal"
},
+ "linter": {
+ "description": "The tool to use for running lint checks.",
+ "type": "string",
+ "enum": ["eslint", "none"],
+ "default": "none",
+ "x-prompt": "Which linter would you like to use?",
+ "x-priority": "important"
+ },
"unitTestRunner": {
"type": "string",
"enum": ["vitest", "none"],
"description": "Test runner to use for unit tests.",
"x-prompt": "Which unit test runner would you like to use?",
- "default": "none"
+ "default": "none",
+ "x-priority": "important"
},
"e2eTestRunner": {
"type": "string",
diff --git a/packages/nuxt/src/generators/init/init.ts b/packages/nuxt/src/generators/init/init.ts
index 5eef7f78ea4771..1bc971e19b9049 100644
--- a/packages/nuxt/src/generators/init/init.ts
+++ b/packages/nuxt/src/generators/init/init.ts
@@ -1,14 +1,11 @@
import { createProjectGraphAsync, GeneratorCallback, Tree } from '@nx/devkit';
import { addPluginV1 } from '@nx/devkit/src/utils/add-plugin';
-import { assertNotUsingTsSolutionSetup } from '@nx/js/src/utils/typescript/ts-solution-setup';
import { createNodes } from '../../plugins/plugin';
import { InitSchema } from './schema';
import { updateDependencies } from './lib/utils';
export async function nuxtInitGenerator(host: Tree, schema: InitSchema) {
- assertNotUsingTsSolutionSetup(host, 'nuxt', 'init');
-
await addPluginV1(
host,
await createProjectGraphAsync(),
diff --git a/packages/playwright/src/generators/configuration/configuration.ts b/packages/playwright/src/generators/configuration/configuration.ts
index e245e8c4d22962..5e9d6030a5f209 100644
--- a/packages/playwright/src/generators/configuration/configuration.ts
+++ b/packages/playwright/src/generators/configuration/configuration.ts
@@ -97,7 +97,12 @@ export async function configurationGeneratorInternal(
if (isTsSolutionSetup) {
// skip eslint from typechecking since it extends from root file that is outside rootDir
if (options.linter === 'eslint') {
- tsconfig.exclude = ['dist', 'eslint.config.js'];
+ tsconfig.exclude = [
+ 'dist',
+ 'eslint.config.js',
+ 'eslint.config.mjs',
+ 'eslint.config.cjs',
+ ];
}
tsconfig.compilerOptions.outDir = 'dist';
diff --git a/packages/react/src/generators/application/application.spec.ts b/packages/react/src/generators/application/application.spec.ts
index 874abcde483763..1ea17f678b9c12 100644
--- a/packages/react/src/generators/application/application.spec.ts
+++ b/packages/react/src/generators/application/application.spec.ts
@@ -1398,6 +1398,8 @@ describe('app', () => {
"exclude": [
"dist",
"eslint.config.js",
+ "eslint.config.mjs",
+ "eslint.config.cjs",
],
"extends": "../tsconfig.base.json",
"include": [
diff --git a/packages/remix/src/generators/application/application.impl.spec.ts b/packages/remix/src/generators/application/application.impl.spec.ts
index cc510d65b853ae..9737ca910b0e40 100644
--- a/packages/remix/src/generators/application/application.impl.spec.ts
+++ b/packages/remix/src/generators/application/application.impl.spec.ts
@@ -507,6 +507,8 @@ describe('Remix Application', () => {
"exclude": [
"dist",
"eslint.config.js",
+ "eslint.config.mjs",
+ "eslint.config.cjs",
],
"extends": "../tsconfig.base.json",
"include": [
diff --git a/packages/vue/src/generators/application/__snapshots__/application.spec.ts.snap b/packages/vue/src/generators/application/__snapshots__/application.spec.ts.snap
index 84f0aba45dcf71..2944d649a680a3 100644
--- a/packages/vue/src/generators/application/__snapshots__/application.spec.ts.snap
+++ b/packages/vue/src/generators/application/__snapshots__/application.spec.ts.snap
@@ -361,6 +361,7 @@ exports[`application generator should set up project correctly with given option
"test/src/app/NxWelcome.vue",
"test/src/main.ts",
"test/src/styles.css",
+ "test/src/vue-shims.d.ts",
"test/tsconfig.app.json",
"test/tsconfig.json",
"test/tsconfig.spec.json",
diff --git a/packages/vue/src/generators/application/application.spec.ts b/packages/vue/src/generators/application/application.spec.ts
index 244728a729667b..fcddea4516e19a 100644
--- a/packages/vue/src/generators/application/application.spec.ts
+++ b/packages/vue/src/generators/application/application.spec.ts
@@ -6,6 +6,9 @@ import {
readProjectConfiguration,
readNxJson,
updateNxJson,
+ updateJson,
+ writeJson,
+ readJson,
} from '@nx/devkit';
import * as devkitExports from 'nx/src/devkit-exports';
@@ -96,6 +99,188 @@ describe('application generator', () => {
expect(tree.exists('test/src/style.none')).toBeFalsy();
expect(tree.read('test/src/main.ts', 'utf-8')).not.toContain('styles.none');
});
+
+ describe('TS solution setup', () => {
+ beforeEach(() => {
+ tree = createTreeWithEmptyWorkspace();
+ updateJson(tree, 'package.json', (json) => {
+ json.workspaces = ['packages/*', 'apps/*'];
+ return json;
+ });
+ writeJson(tree, 'tsconfig.base.json', {
+ compilerOptions: {
+ composite: true,
+ declaration: true,
+ },
+ });
+ writeJson(tree, 'tsconfig.json', {
+ extends: './tsconfig.base.json',
+ files: [],
+ references: [],
+ });
+ });
+
+ it('should add project references when using TS solution', async () => {
+ await applicationGenerator(tree, {
+ ...options,
+ style: 'none',
+ linter: 'eslint',
+ });
+
+ expect(tree.read('test/vite.config.ts', 'utf-8')).toMatchInlineSnapshot(`
+ "///
+ import { defineConfig } from 'vite';
+ import vue from '@vitejs/plugin-vue';
+
+ export default defineConfig({
+ root: __dirname,
+ cacheDir: '../node_modules/.vite/test',
+ server: {
+ port: 4200,
+ host: 'localhost',
+ },
+ preview: {
+ port: 4300,
+ host: 'localhost',
+ },
+ plugins: [vue()],
+ // Uncomment this if you are using workers.
+ // worker: {
+ // plugins: [ nxViteTsPaths() ],
+ // },
+ build: {
+ outDir: './dist',
+ emptyOutDir: true,
+ reportCompressedSize: true,
+ commonjsOptions: {
+ transformMixedEsModules: true,
+ },
+ },
+ test: {
+ watch: false,
+ globals: true,
+ environment: 'jsdom',
+ include: ['src/**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'],
+ reporters: ['default'],
+ coverage: {
+ reportsDirectory: '../coverage/test',
+ provider: 'v8',
+ },
+ },
+ });
+ "
+ `);
+
+ expect(readJson(tree, 'tsconfig.json').references).toMatchInlineSnapshot(`
+ [
+ {
+ "path": "./test-e2e",
+ },
+ {
+ "path": "./test",
+ },
+ ]
+ `);
+ expect(readJson(tree, 'test/tsconfig.json')).toMatchInlineSnapshot(`
+ {
+ "extends": "../tsconfig.base.json",
+ "files": [],
+ "include": [],
+ "references": [
+ {
+ "path": "./tsconfig.app.json",
+ },
+ {
+ "path": "./tsconfig.spec.json",
+ },
+ ],
+ }
+ `);
+ expect(readJson(tree, 'test/tsconfig.app.json')).toMatchInlineSnapshot(`
+ {
+ "compilerOptions": {
+ "jsx": "preserve",
+ "jsxImportSource": "vue",
+ "module": "esnext",
+ "moduleResolution": "bundler",
+ "outDir": "out-tsc/test",
+ "resolveJsonModule": true,
+ "rootDir": "src",
+ "types": [
+ "vite/client",
+ ],
+ },
+ "exclude": [
+ "dist",
+ "src/**/*.spec.ts",
+ "src/**/*.test.ts",
+ "src/**/*.spec.vue",
+ "src/**/*.test.vue",
+ "vite.config.ts",
+ "vite.config.mts",
+ "vitest.config.ts",
+ "vitest.config.mts",
+ "src/**/*.test.tsx",
+ "src/**/*.spec.tsx",
+ "src/**/*.test.js",
+ "src/**/*.spec.js",
+ "src/**/*.test.jsx",
+ "src/**/*.spec.jsx",
+ "eslint.config.js",
+ "eslint.config.cjs",
+ "eslint.config.mjs",
+ ],
+ "extends": "../tsconfig.base.json",
+ "include": [
+ "src/**/*.js",
+ "src/**/*.jsx",
+ "src/**/*.ts",
+ "src/**/*.vue",
+ ],
+ }
+ `);
+ expect(readJson(tree, 'test/tsconfig.spec.json')).toMatchInlineSnapshot(`
+ {
+ "compilerOptions": {
+ "jsx": "preserve",
+ "jsxImportSource": "vue",
+ "module": "esnext",
+ "moduleResolution": "bundler",
+ "outDir": "./out-tsc/vitest",
+ "resolveJsonModule": true,
+ "types": [
+ "vitest/globals",
+ "vitest/importMeta",
+ "vite/client",
+ "node",
+ "vitest",
+ ],
+ },
+ "extends": "../tsconfig.base.json",
+ "include": [
+ "vite.config.ts",
+ "vite.config.mts",
+ "vitest.config.ts",
+ "vitest.config.mts",
+ "src/**/*.test.ts",
+ "src/**/*.spec.ts",
+ "src/**/*.test.tsx",
+ "src/**/*.spec.tsx",
+ "src/**/*.test.js",
+ "src/**/*.spec.js",
+ "src/**/*.test.jsx",
+ "src/**/*.spec.jsx",
+ "src/**/*.d.ts",
+ ],
+ "references": [
+ {
+ "path": "./tsconfig.app.json",
+ },
+ ],
+ }
+ `);
+ });
+ });
});
function listFiles(tree: Tree): string[] {
diff --git a/packages/vue/src/generators/application/application.ts b/packages/vue/src/generators/application/application.ts
index 3b85e58abfd9cf..b76078b87115cd 100644
--- a/packages/vue/src/generators/application/application.ts
+++ b/packages/vue/src/generators/application/application.ts
@@ -2,14 +2,15 @@ import {
addProjectConfiguration,
formatFiles,
GeneratorCallback,
+ joinPathFragments,
readNxJson,
runTasksInSerial,
toJS,
Tree,
+ writeJson,
} from '@nx/devkit';
import { Linter } from '@nx/eslint';
import { initGenerator as jsInitGenerator } from '@nx/js';
-import { assertNotUsingTsSolutionSetup } from '@nx/js/src/utils/typescript/ts-solution-setup';
import { Schema } from './schema';
import { normalizeOptions } from './lib/normalize-options';
import { vueInitGenerator } from '../init/init';
@@ -20,6 +21,8 @@ import { addVite } from './lib/add-vite';
import { extractTsConfigBase } from '../../utils/create-ts-config';
import { ensureDependencies } from '../../utils/ensure-dependencies';
import { logShowProjectCommand } from '@nx/devkit/src/utils/log-show-project-command';
+import { getImportPath } from '@nx/js/src/utils/get-import-path';
+import { updateTsconfigFiles } from '@nx/js/src/utils/typescript/ts-solution-setup';
export function applicationGenerator(tree: Tree, options: Schema) {
return applicationGeneratorInternal(tree, { addPlugin: false, ...options });
@@ -29,7 +32,18 @@ export async function applicationGeneratorInternal(
tree: Tree,
_options: Schema
): Promise {
- assertNotUsingTsSolutionSetup(tree, 'vue', 'application');
+ const tasks: GeneratorCallback[] = [];
+ tasks.push(
+ await jsInitGenerator(tree, {
+ ..._options,
+ tsConfigName: _options.rootProject
+ ? 'tsconfig.json'
+ : 'tsconfig.base.json',
+ skipFormat: true,
+ addTsPlugin: _options.useTsSolution,
+ formatter: _options.formatter,
+ })
+ );
const options = await normalizeOptions(tree, _options);
const nxJson = readNxJson(tree);
@@ -38,24 +52,28 @@ export async function applicationGeneratorInternal(
process.env.NX_ADD_PLUGINS !== 'false' &&
nxJson.useInferencePlugins !== false;
- const tasks: GeneratorCallback[] = [];
-
- addProjectConfiguration(tree, options.projectName, {
- root: options.appProjectRoot,
- projectType: 'application',
- sourceRoot: `${options.appProjectRoot}/src`,
- targets: {},
- });
+ if (options.isUsingTsSolutionConfig) {
+ writeJson(tree, joinPathFragments(options.appProjectRoot, 'package.json'), {
+ 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,
+ },
+ });
+ } else {
+ addProjectConfiguration(tree, options.projectName, {
+ root: options.appProjectRoot,
+ projectType: 'application',
+ sourceRoot: `${options.appProjectRoot}/src`,
+ tags: options.parsedTags?.length ? options.parsedTags : undefined,
+ targets: {},
+ });
+ }
- tasks.push(
- await jsInitGenerator(tree, {
- ...options,
- tsConfigName: options.rootProject
- ? 'tsconfig.json'
- : 'tsconfig.base.json',
- skipFormat: true,
- })
- );
tasks.push(
await vueInitGenerator(tree, {
...options,
@@ -97,6 +115,24 @@ export async function applicationGeneratorInternal(
if (!options.skipFormat) await formatFiles(tree);
+ if (options.isUsingTsSolutionConfig) {
+ updateTsconfigFiles(
+ tree,
+ options.appProjectRoot,
+ 'tsconfig.app.json',
+ {
+ jsx: 'preserve',
+ jsxImportSource: 'vue',
+ module: 'esnext',
+ moduleResolution: 'bundler',
+ resolveJsonModule: true,
+ },
+ options.linter === 'eslint'
+ ? ['eslint.config.js', 'eslint.config.cjs', 'eslint.config.mjs']
+ : undefined
+ );
+ }
+
tasks.push(() => {
logShowProjectCommand(options.projectName);
});
diff --git a/packages/vue/src/generators/application/files/common/src/vue-shims.d.ts.template b/packages/vue/src/generators/application/files/common/src/vue-shims.d.ts.template
new file mode 100644
index 00000000000000..798e8fcfac4afa
--- /dev/null
+++ b/packages/vue/src/generators/application/files/common/src/vue-shims.d.ts.template
@@ -0,0 +1,5 @@
+declare module '*.vue' {
+ import { defineComponent } from 'vue';
+ const component: ReturnType;
+ export default component;
+}
diff --git a/packages/vue/src/generators/application/lib/normalize-options.ts b/packages/vue/src/generators/application/lib/normalize-options.ts
index bfefcd687d59f8..5a8e8752b519dc 100644
--- a/packages/vue/src/generators/application/lib/normalize-options.ts
+++ b/packages/vue/src/generators/application/lib/normalize-options.ts
@@ -4,6 +4,7 @@ import {
ensureProjectName,
} 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';
export async function normalizeOptions(
host: Tree,
@@ -39,6 +40,7 @@ export async function normalizeOptions(
normalized.routing = normalized.routing ?? false;
normalized.unitTestRunner ??= 'vitest';
normalized.e2eTestRunner = normalized.e2eTestRunner ?? 'playwright';
+ normalized.isUsingTsSolutionConfig = isUsingTsSolutionSetup(host);
return normalized;
}
diff --git a/packages/vue/src/generators/application/schema.d.ts b/packages/vue/src/generators/application/schema.d.ts
index 46d4eb6e28715b..b98873f749af33 100644
--- a/packages/vue/src/generators/application/schema.d.ts
+++ b/packages/vue/src/generators/application/schema.d.ts
@@ -10,6 +10,7 @@ export interface Schema {
inSourceTests?: boolean;
e2eTestRunner: 'cypress' | 'playwright' | 'none';
linter: Linter | LinterType;
+ formatter?: 'none' | 'prettier';
routing?: boolean;
js?: boolean;
strict?: boolean;
@@ -18,6 +19,7 @@ export interface Schema {
rootProject?: boolean;
addPlugin?: boolean;
nxCloudToken?: string;
+ useTsSolution?: boolean;
}
export interface NormalizedSchema extends Schema {
@@ -27,4 +29,5 @@ export interface NormalizedSchema extends Schema {
e2eProjectRoot: string;
parsedTags: string[];
devServerPort?: number;
+ isUsingTsSolutionConfig: boolean;
}
diff --git a/packages/vue/src/generators/application/schema.json b/packages/vue/src/generators/application/schema.json
index a063888fd10117..a18386d23db6bf 100644
--- a/packages/vue/src/generators/application/schema.json
+++ b/packages/vue/src/generators/application/schema.json
@@ -60,12 +60,6 @@
]
}
},
- "linter": {
- "description": "The tool to use for running lint checks.",
- "type": "string",
- "enum": ["eslint", "none"],
- "default": "eslint"
- },
"routing": {
"type": "boolean",
"description": "Generate application with routes.",
@@ -78,12 +72,21 @@
"default": false,
"x-priority": "internal"
},
+ "linter": {
+ "description": "The tool to use for running lint checks.",
+ "type": "string",
+ "enum": ["eslint", "none"],
+ "default": "none",
+ "x-prompt": "Which linter would you like to use?",
+ "x-priority": "important"
+ },
"unitTestRunner": {
"type": "string",
"enum": ["vitest", "none"],
"description": "Test runner to use for unit tests.",
"x-prompt": "Which unit test runner would you like to use?",
- "default": "vitest"
+ "default": "none",
+ "x-priority": "important"
},
"inSourceTests": {
"type": "boolean",
diff --git a/packages/vue/src/generators/init/init.ts b/packages/vue/src/generators/init/init.ts
index d3bcdb0ed90cd7..dc258ca2f940d3 100755
--- a/packages/vue/src/generators/init/init.ts
+++ b/packages/vue/src/generators/init/init.ts
@@ -6,7 +6,6 @@ import {
runTasksInSerial,
Tree,
} from '@nx/devkit';
-import { assertNotUsingTsSolutionSetup } from '@nx/js/src/utils/typescript/ts-solution-setup';
import { nxVersion, vueVersion } from '../../utils/versions';
import { InitSchema } from './schema';
@@ -28,8 +27,6 @@ function updateDependencies(host: Tree, schema: InitSchema) {
}
export async function vueInitGenerator(host: Tree, schema: InitSchema) {
- assertNotUsingTsSolutionSetup(host, 'vue', 'init');
-
let installTask: GeneratorCallback = () => {};
if (!schema.skipPackageJson) {
installTask = updateDependencies(host, schema);
diff --git a/packages/vue/src/generators/library/files/package.json__tmpl__ b/packages/vue/src/generators/library/files/package.json__tmpl__
deleted file mode 100644
index 507420ee308347..00000000000000
--- a/packages/vue/src/generators/library/files/package.json__tmpl__
+++ /dev/null
@@ -1,12 +0,0 @@
-{
- "name": "<%= name %>",
- "version": "0.0.1",
- "main": "./index.js",
- "types": "./index.d.ts",
- "exports": {
- ".": {
- "import": "./index.mjs",
- "require": "./index.js"
- }
- }
-}
diff --git a/packages/vue/src/generators/library/lib/create-library-files.ts b/packages/vue/src/generators/library/lib/create-library-files.ts
index 9e2c6ccb3b2608..ae1d352b756ba8 100644
--- a/packages/vue/src/generators/library/lib/create-library-files.ts
+++ b/packages/vue/src/generators/library/lib/create-library-files.ts
@@ -31,8 +31,22 @@ export function createLibraryFiles(host: Tree, options: NormalizedSchema) {
substitutions
);
- if (!options.publishable && options.bundler === 'none') {
- host.delete(`${options.projectRoot}/package.json`);
+ if (
+ !options.isUsingTsSolutionConfig &&
+ (options.publishable || options.bundler !== 'none')
+ ) {
+ writeJson(host, joinPathFragments(options.projectRoot, 'package.json'), {
+ name: options.name,
+ version: '0.0.1',
+ main: './index.js',
+ types: './index.d.ts',
+ exports: {
+ '.': {
+ import: './index.mjs',
+ require: './index.js',
+ },
+ },
+ });
}
if (options.unitTestRunner !== 'vitest') {
diff --git a/packages/vue/src/generators/library/lib/normalize-options.ts b/packages/vue/src/generators/library/lib/normalize-options.ts
index 2a91e17a1c7342..eabe320f65238f 100644
--- a/packages/vue/src/generators/library/lib/normalize-options.ts
+++ b/packages/vue/src/generators/library/lib/normalize-options.ts
@@ -10,6 +10,7 @@ import {
ensureProjectName,
} 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';
export async function normalizeOptions(
host: Tree,
@@ -60,6 +61,7 @@ export async function normalizeOptions(
projectRoot,
parsedTags,
importPath,
+ isUsingTsSolutionConfig: isUsingTsSolutionSetup(host),
} as NormalizedSchema;
// Libraries with a bundler or is publishable must also be buildable.
diff --git a/packages/vue/src/generators/library/library.spec.ts b/packages/vue/src/generators/library/library.spec.ts
index 94092f41301e2b..620a57f34dc238 100644
--- a/packages/vue/src/generators/library/library.spec.ts
+++ b/packages/vue/src/generators/library/library.spec.ts
@@ -5,6 +5,7 @@ import {
readProjectConfiguration,
Tree,
updateJson,
+ writeJson,
} from '@nx/devkit';
import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing';
import { Linter } from '@nx/eslint';
@@ -438,4 +439,209 @@ module.exports = [
expect(eslintConfig.overrides[0].files).toContain('*.vue');
});
});
+ describe('TS solution setup', () => {
+ beforeEach(() => {
+ tree = createTreeWithEmptyWorkspace();
+ updateJson(tree, 'package.json', (json) => {
+ json.workspaces = ['packages/*', 'apps/*'];
+ return json;
+ });
+ writeJson(tree, 'tsconfig.base.json', {
+ compilerOptions: {
+ composite: true,
+ declaration: true,
+ },
+ });
+ writeJson(tree, 'tsconfig.json', {
+ extends: './tsconfig.base.json',
+ files: [],
+ references: [],
+ });
+ });
+
+ it('should add project references when using TS solution', async () => {
+ await libraryGenerator(tree, {
+ ...defaultSchema,
+ setParserOptionsProject: true,
+ linter: 'eslint',
+ });
+
+ expect(tree.read('my-lib/vite.config.ts', 'utf-8'))
+ .toMatchInlineSnapshot(`
+ "import vue from '@vitejs/plugin-vue';
+ import { defineConfig } from 'vite';
+
+ export default defineConfig({
+ root: __dirname,
+ cacheDir: '../node_modules/.vite/my-lib',
+ plugins: [vue()],
+ // Uncomment this if you are using workers.
+ // worker: {
+ // plugins: [ nxViteTsPaths() ],
+ // },
+ test: {
+ watch: false,
+ globals: true,
+ environment: 'jsdom',
+ include: ['src/**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'],
+ reporters: ['default'],
+ coverage: { reportsDirectory: '../coverage/my-lib', provider: 'v8' },
+ },
+ });
+ "
+ `);
+
+ expect(readJson(tree, 'tsconfig.json').references).toMatchInlineSnapshot(`
+ [
+ {
+ "path": "./my-lib",
+ },
+ ]
+ `);
+ expect(readJson(tree, 'my-lib/tsconfig.json')).toMatchInlineSnapshot(`
+ {
+ "extends": "../tsconfig.base.json",
+ "files": [],
+ "include": [],
+ "references": [
+ {
+ "path": "./tsconfig.lib.json",
+ },
+ {
+ "path": "./tsconfig.spec.json",
+ },
+ ],
+ }
+ `);
+ expect(readJson(tree, 'my-lib/tsconfig.lib.json')).toMatchInlineSnapshot(`
+ {
+ "compilerOptions": {
+ "jsx": "preserve",
+ "jsxImportSource": "vue",
+ "module": "esnext",
+ "moduleResolution": "bundler",
+ "outDir": "out-tsc/my-lib",
+ "resolveJsonModule": true,
+ "rootDir": "src",
+ "types": [
+ "vite/client",
+ ],
+ },
+ "exclude": [
+ "dist",
+ "src/**/__tests__/*",
+ "src/**/*.spec.vue",
+ "src/**/*.test.vue",
+ "vite.config.ts",
+ "vite.config.mts",
+ "vitest.config.ts",
+ "vitest.config.mts",
+ "src/**/*.test.ts",
+ "src/**/*.spec.ts",
+ "src/**/*.test.tsx",
+ "src/**/*.spec.tsx",
+ "src/**/*.test.js",
+ "src/**/*.spec.js",
+ "src/**/*.test.jsx",
+ "src/**/*.spec.jsx",
+ "eslint.config.js",
+ "eslint.config.cjs",
+ "eslint.config.mjs",
+ ],
+ "extends": "../tsconfig.base.json",
+ "include": [
+ "src/**/*.js",
+ "src/**/*.jsx",
+ "src/**/*.ts",
+ "src/**/*.tsx",
+ "src/**/*.vue",
+ ],
+ }
+ `);
+ expect(readJson(tree, 'my-lib/tsconfig.spec.json'))
+ .toMatchInlineSnapshot(`
+ {
+ "compilerOptions": {
+ "jsx": "preserve",
+ "jsxImportSource": "vue",
+ "module": "esnext",
+ "moduleResolution": "bundler",
+ "outDir": "./out-tsc/vitest",
+ "resolveJsonModule": true,
+ "types": [
+ "vitest/globals",
+ "vitest/importMeta",
+ "vite/client",
+ "node",
+ "vitest",
+ ],
+ },
+ "extends": "../tsconfig.base.json",
+ "include": [
+ "vite.config.ts",
+ "vite.config.mts",
+ "vitest.config.ts",
+ "vitest.config.mts",
+ "src/**/*.test.ts",
+ "src/**/*.spec.ts",
+ "src/**/*.test.tsx",
+ "src/**/*.spec.tsx",
+ "src/**/*.test.js",
+ "src/**/*.spec.js",
+ "src/**/*.test.jsx",
+ "src/**/*.spec.jsx",
+ "src/**/*.d.ts",
+ ],
+ "references": [
+ {
+ "path": "./tsconfig.lib.json",
+ },
+ ],
+ }
+ `);
+ });
+
+ it('should exclude non-buildable libraries from TS plugin registration', async () => {
+ updateJson(tree, 'nx.json', (json) => {
+ json.plugins = ['@nx/js/typescript'];
+ return json;
+ });
+ await libraryGenerator(tree, {
+ ...defaultSchema,
+ addPlugin: true,
+ setParserOptionsProject: true,
+ linter: 'eslint',
+ bundler: 'none',
+ });
+
+ const nxJson = readJson(tree, 'nx.json');
+ expect(nxJson.plugins).toMatchInlineSnapshot(`
+ [
+ {
+ "exclude": [
+ "my-lib/*",
+ ],
+ "plugin": "@nx/js/typescript",
+ },
+ {
+ "options": {
+ "targetName": "lint",
+ },
+ "plugin": "@nx/eslint/plugin",
+ },
+ {
+ "options": {
+ "buildTargetName": "build",
+ "previewTargetName": "preview",
+ "serveStaticTargetName": "serve-static",
+ "serveTargetName": "serve",
+ "testTargetName": "test",
+ "typecheckTargetName": "typecheck",
+ },
+ "plugin": "@nx/vite/plugin",
+ },
+ ]
+ `);
+ });
+ });
});
diff --git a/packages/vue/src/generators/library/library.ts b/packages/vue/src/generators/library/library.ts
index 25a721b9da1e8f..4e6e943d1eb2df 100644
--- a/packages/vue/src/generators/library/library.ts
+++ b/packages/vue/src/generators/library/library.ts
@@ -2,14 +2,17 @@ import {
addProjectConfiguration,
formatFiles,
GeneratorCallback,
+ installPackagesTask,
joinPathFragments,
+ readNxJson,
runTasksInSerial,
toJS,
Tree,
updateJson,
+ updateNxJson,
+ writeJson,
} from '@nx/devkit';
import { addTsConfigPath, initGenerator as jsInitGenerator } from '@nx/js';
-import { assertNotUsingTsSolutionSetup } from '@nx/js/src/utils/typescript/ts-solution-setup';
import { vueInitGenerator } from '../init/init';
import { Schema } from './schema';
import { normalizeOptions } from './lib/normalize-options';
@@ -22,16 +25,19 @@ import { ensureDependencies } from '../../utils/ensure-dependencies';
import { logShowProjectCommand } from '@nx/devkit/src/utils/log-show-project-command';
import { getRelativeCwd } from '@nx/devkit/src/generators/artifact-name-and-directory-utils';
import { relative } from 'path';
+import { getImportPath } from '@nx/js/src/utils/get-import-path';
+import { updateTsconfigFiles } from '@nx/js/src/utils/typescript/ts-solution-setup';
+import { ensureProjectIsExcludedFromPluginRegistrations } from '@nx/js/src/utils/typescript/plugin';
export function libraryGenerator(tree: Tree, schema: Schema) {
return libraryGeneratorInternal(tree, { addPlugin: false, ...schema });
}
export async function libraryGeneratorInternal(tree: Tree, schema: Schema) {
- assertNotUsingTsSolutionSetup(tree, 'vue', 'library');
-
const tasks: GeneratorCallback[] = [];
+ tasks.push(await jsInitGenerator(tree, { ...schema, skipFormat: true }));
+
const options = await normalizeOptions(tree, schema);
if (options.publishable === true && !schema.importPath) {
throw new Error(
@@ -39,15 +45,37 @@ export async function libraryGeneratorInternal(tree: Tree, schema: Schema) {
);
}
- addProjectConfiguration(tree, options.name, {
- root: options.projectRoot,
- sourceRoot: joinPathFragments(options.projectRoot, 'src'),
- projectType: 'library',
- tags: options.parsedTags,
- targets: {},
- });
+ if (options.isUsingTsSolutionConfig) {
+ const sourceEntry =
+ options.bundler === 'none'
+ ? options.js
+ ? './src/index.js'
+ : './src/index.ts'
+ : undefined;
+ writeJson(tree, joinPathFragments(options.projectRoot, 'package.json'), {
+ name: getImportPath(tree, options.name),
+ version: '0.0.1',
+ private: true,
+ main: sourceEntry,
+ types: sourceEntry,
+ files: options.publishable ? ['dist', '!**/*.tsbuildinfo'] : undefined,
+ nx: {
+ name: options.name,
+ projectType: 'application',
+ sourceRoot: `${options.projectRoot}/src`,
+ tags: options.parsedTags?.length ? options.parsedTags : undefined,
+ },
+ });
+ } else {
+ addProjectConfiguration(tree, options.name, {
+ root: options.projectRoot,
+ sourceRoot: joinPathFragments(options.projectRoot, 'src'),
+ projectType: 'library',
+ tags: options.parsedTags,
+ targets: {},
+ });
+ }
- tasks.push(await jsInitGenerator(tree, { ...schema, skipFormat: true }));
tasks.push(
await vueInitGenerator(tree, {
...options,
@@ -86,14 +114,23 @@ export async function libraryGeneratorInternal(tree: Tree, schema: Schema) {
});
}
- if (options.publishable || options.bundler !== 'none') {
+ if (
+ !options.isUsingTsSolutionConfig &&
+ (options.publishable || options.bundler !== 'none')
+ ) {
updateJson(tree, `${options.projectRoot}/package.json`, (json) => {
json.name = options.importPath;
return json;
});
}
- if (!options.skipTsConfig) {
+ if (options.bundler === 'none' && options.addPlugin) {
+ const nxJson = readNxJson(tree);
+ ensureProjectIsExcludedFromPluginRegistrations(nxJson, options.projectRoot);
+ updateNxJson(tree, nxJson);
+ }
+
+ if (!options.skipTsConfig && !options.isUsingTsSolutionConfig) {
addTsConfigPath(tree, options.importPath, [
joinPathFragments(
options.projectRoot,
@@ -107,6 +144,29 @@ export async function libraryGeneratorInternal(tree: Tree, schema: Schema) {
if (!options.skipFormat) await formatFiles(tree);
+ if (options.isUsingTsSolutionConfig) {
+ updateTsconfigFiles(
+ tree,
+ options.projectRoot,
+ 'tsconfig.lib.json',
+ {
+ jsx: 'preserve',
+ jsxImportSource: 'vue',
+ module: 'esnext',
+ moduleResolution: 'bundler',
+ resolveJsonModule: true,
+ },
+ options.linter === 'eslint'
+ ? ['eslint.config.js', 'eslint.config.cjs', 'eslint.config.mjs']
+ : undefined
+ );
+ }
+
+ // Always run install to link packages.
+ if (options.isUsingTsSolutionConfig) {
+ tasks.push(() => installPackagesTask(tree));
+ }
+
tasks.push(() => {
logShowProjectCommand(options.name);
});
diff --git a/packages/vue/src/generators/library/schema.d.ts b/packages/vue/src/generators/library/schema.d.ts
index 198e8cd5840ba7..ed8dc8249f096a 100644
--- a/packages/vue/src/generators/library/schema.d.ts
+++ b/packages/vue/src/generators/library/schema.d.ts
@@ -35,4 +35,5 @@ export interface NormalizedSchema extends Schema {
appMain?: string;
appSourceRoot?: string;
unitTestRunner?: 'vitest' | 'none';
+ isUsingTsSolutionConfig: boolean;
}
diff --git a/packages/vue/src/generators/library/schema.json b/packages/vue/src/generators/library/schema.json
index 7ca310f6b938dd..dda7e5bbb558cb 100644
--- a/packages/vue/src/generators/library/schema.json
+++ b/packages/vue/src/generators/library/schema.json
@@ -36,13 +36,17 @@
"description": "The tool to use for running lint checks.",
"type": "string",
"enum": ["eslint", "none"],
- "default": "eslint"
+ "default": "none",
+ "x-prompt": "Which linter would you like to use?",
+ "x-priority": "important"
},
"unitTestRunner": {
"type": "string",
"enum": ["vitest", "none"],
"description": "Test runner to use for unit tests.",
- "x-prompt": "What unit test runner should be used?"
+ "x-prompt": "What unit test runner should be used?",
+ "default": "none",
+ "x-priority": "important"
},
"inSourceTests": {
"type": "boolean",
diff --git a/packages/vue/src/utils/create-ts-config.ts b/packages/vue/src/utils/create-ts-config.ts
index 421303d8991b29..9179cac644843e 100644
--- a/packages/vue/src/utils/create-ts-config.ts
+++ b/packages/vue/src/utils/create-ts-config.ts
@@ -1,7 +1,92 @@
import { Tree, updateJson, writeJson } from '@nx/devkit';
import * as shared from '@nx/js/src/utils/typescript/create-ts-config';
+import { isUsingTsSolutionSetup } from '@nx/js/src/utils/typescript/ts-solution-setup';
export function createTsConfig(
+ host: Tree,
+ projectRoot: string,
+ type: 'app' | 'lib',
+ options: {
+ strict?: boolean;
+ style?: string;
+ bundler?: string;
+ rootProject?: boolean;
+ unitTestRunner?: string;
+ },
+ relativePathToRootTsConfig: string
+) {
+ if (isUsingTsSolutionSetup(host)) {
+ createTsConfigForTsSolution(
+ host,
+ projectRoot,
+ type,
+ options,
+ relativePathToRootTsConfig
+ );
+ } else {
+ createTsConfigForNonTsSolution(
+ host,
+ projectRoot,
+ type,
+ options,
+ relativePathToRootTsConfig
+ );
+ }
+}
+
+export function createTsConfigForTsSolution(
+ host: Tree,
+ projectRoot: string,
+ type: 'app' | 'lib',
+ options: {
+ strict?: boolean;
+ style?: string;
+ rootProject?: boolean;
+ unitTestRunner?: string;
+ },
+ relativePathToRootTsConfig: string
+) {
+ const json = {
+ files: [],
+ include: [],
+ references: [
+ {
+ path: type === 'app' ? './tsconfig.app.json' : './tsconfig.lib.json',
+ },
+ ],
+ } as any;
+
+ // inline tsconfig.base.json into the project
+ if (options.rootProject) {
+ json.compileOnSave = false;
+ json.compilerOptions = {
+ ...shared.tsConfigBaseOptions,
+ ...json.compilerOptions,
+ };
+ json.exclude = ['node_modules', 'tmp'];
+ } else {
+ json.extends = relativePathToRootTsConfig;
+ }
+
+ writeJson(host, `${projectRoot}/tsconfig.json`, json);
+
+ const tsconfigProjectPath = `${projectRoot}/tsconfig.${type}.json`;
+ if (host.exists(tsconfigProjectPath)) {
+ updateJson(host, tsconfigProjectPath, (json) => {
+ json.compilerOptions ??= {};
+
+ const types = new Set(json.compilerOptions.types ?? []);
+ types.add('vite/client');
+
+ json.compilerOptions.types = Array.from(types);
+
+ return json;
+ });
+ } else {
+ }
+}
+
+export function createTsConfigForNonTsSolution(
host: Tree,
projectRoot: string,
type: 'app' | 'lib',
diff --git a/packages/workspace/src/generators/new/generate-workspace-files.ts b/packages/workspace/src/generators/new/generate-workspace-files.ts
index da8bb757206806..9698efba5da38b 100644
--- a/packages/workspace/src/generators/new/generate-workspace-files.ts
+++ b/packages/workspace/src/generators/new/generate-workspace-files.ts
@@ -421,7 +421,9 @@ function setUpWorkspacesInPackageJson(tree: Tree, options: NormalizedSchema) {
options.preset === Preset.NextJs ||
options.preset === Preset.ReactMonorepo ||
options.preset === Preset.ReactNative ||
- options.preset === Preset.RemixMonorepo) &&
+ options.preset === Preset.RemixMonorepo ||
+ options.preset === Preset.VueMonorepo ||
+ options.preset === Preset.Nuxt) &&
options.workspaces)
) {
const workspaces = options.workspaceGlobs ?? ['packages/**'];
diff --git a/packages/workspace/src/generators/preset/preset.ts b/packages/workspace/src/generators/preset/preset.ts
index d5f633d91444e5..d9d8a278f7490f 100644
--- a/packages/workspace/src/generators/preset/preset.ts
+++ b/packages/workspace/src/generators/preset/preset.ts
@@ -135,6 +135,7 @@ async function createPreset(tree: Tree, options: Schema) {
e2eTestRunner: options.e2eTestRunner ?? 'playwright',
addPlugin,
nxCloudToken: options.nxCloudToken,
+ useTsSolution: options.workspaces,
});
} else if (options.preset === Preset.VueStandalone) {
const { applicationGenerator: vueApplicationGenerator } = require('@nx' +
@@ -163,6 +164,7 @@ async function createPreset(tree: Tree, options: Schema) {
e2eTestRunner: options.e2eTestRunner ?? 'playwright',
addPlugin,
nxCloudToken: options.nxCloudToken,
+ useTsSolution: options.workspaces,
});
} else if (options.preset === Preset.NuxtStandalone) {
const { applicationGenerator: nuxtApplicationGenerator } = require('@nx' +