fix(vite): improve vite configuration (#13978)

This commit is contained in:
Katerina Skroumpelou 2022-12-22 16:56:39 +02:00 committed by GitHub
parent c51c178923
commit 6c6fd7ce1d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 819 additions and 366 deletions

View File

@ -941,7 +941,10 @@ describe('app', () => {
it('should create correct tsconfig compilerOptions', () => {
const tsconfigJson = readJson(viteAppTree, '/apps/my-app/tsconfig.json');
expect(tsconfigJson.compilerOptions.types).toMatchObject(['vite/client']);
expect(tsconfigJson.compilerOptions.types).toMatchObject([
'vite/client',
'vitest',
]);
});
it('should create index.html and vite.config file at the root of the app', () => {

View File

@ -11,6 +11,7 @@ export function createTsConfig(
style?: string;
bundler?: string;
rootProject?: boolean;
unitTestRunner?: string;
},
relativePathToRootTsConfig: string
) {
@ -36,7 +37,10 @@ export function createTsConfig(
}
if (options.bundler === 'vite') {
json.compilerOptions.types = ['vite/client'];
json.compilerOptions.types =
options.unitTestRunner === 'vitest'
? ['vite/client', 'vitest']
: ['vite/client'];
}
// inline tsconfig.base.json into the project

View File

@ -36,7 +36,7 @@ describe('@nrwl/storybook:configuration for workspaces with Root project', () =>
skipLibCheck: true,
strict: true,
target: 'ESNext',
types: ['vite/client'],
types: ['vite/client', 'vitest'],
useDefineForClassFields: true,
noImplicitOverride: true,
noPropertyAccessFromIndexSignature: true,

View File

@ -2,7 +2,6 @@
exports[`@nrwl/vite:configuration library mode should add config for building library 1`] = `
"
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import viteTsConfigPaths from 'vite-tsconfig-paths';
@ -49,7 +48,6 @@ import { join } from 'path';
exports[`@nrwl/vite:configuration library mode should set up non buildable library correctly 1`] = `
"
/// <reference types=\\"vitest\\" />
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import viteTsConfigPaths from 'vite-tsconfig-paths';
@ -295,7 +293,8 @@ exports[`@nrwl/vite:configuration transform React app to use Vite by providing c
\\"builder\\": \\"@nrwl/vite:dev-server\\",
\\"defaultConfiguration\\": \\"development\\",
\\"options\\": {
\\"buildTarget\\": \\"my-test-mixed-react-app:build\\"
\\"buildTarget\\": \\"my-test-mixed-react-app:build\\",
\\"hmr\\": true
},
\\"configurations\\": {
\\"development\\": {
@ -339,7 +338,6 @@ exports[`@nrwl/vite:configuration transform React app to use Vite by providing c
exports[`@nrwl/vite:configuration transform React app to use Vite should create vite.config file at the root of the app 1`] = `
"
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import viteTsConfigPaths from 'vite-tsconfig-paths';
@ -429,7 +427,8 @@ exports[`@nrwl/vite:configuration transform React app to use Vite should transfo
\\"builder\\": \\"@nrwl/vite:dev-server\\",
\\"defaultConfiguration\\": \\"development\\",
\\"options\\": {
\\"buildTarget\\": \\"my-test-react-app:build\\"
\\"buildTarget\\": \\"my-test-react-app:build\\",
\\"hmr\\": true
},
\\"configurations\\": {
\\"development\\": {
@ -473,7 +472,6 @@ exports[`@nrwl/vite:configuration transform React app to use Vite should transfo
exports[`@nrwl/vite:configuration transform Web app to use Vite should create vite.config file at the root of the app 1`] = `
"
import { defineConfig } from 'vite';
import viteTsConfigPaths from 'vite-tsconfig-paths';
@ -597,7 +595,6 @@ exports[`@nrwl/vite:configuration transform Web app to use Vite should transform
exports[`@nrwl/vite:configuration vitest should create a vitest configuration if "includeVitest" is true 1`] = `
"
/// <reference types=\\"vitest\\" />
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import viteTsConfigPaths from 'vite-tsconfig-paths';

View File

@ -16,6 +16,7 @@ import {
handleUnsupportedUserProvidedTargets,
handleUnknownExecutors,
UserProvidedTargetName,
TargetFlags,
} from '../../utils/generator-utils';
import initGenerator from '../init/init';
@ -39,6 +40,7 @@ export async function viteConfigurationGenerator(tree: Tree, schema: Schema) {
* This is for when we are convering an existing project
* to use the vite executors.
* */
let projectAlreadyHasViteTargets: TargetFlags;
if (!schema.newProject) {
const userProvidedTargetName: UserProvidedTargetName = {
build: schema.buildTarget,
@ -50,8 +52,9 @@ export async function viteConfigurationGenerator(tree: Tree, schema: Schema) {
validFoundTargetName,
projectContainsUnsupportedExecutor,
userProvidedTargetIsUnsupported,
alreadyHasNxViteTargets,
} = findExistingTargetsInProject(targets, userProvidedTargetName);
projectAlreadyHasViteTargets = alreadyHasNxViteTargets;
/**
* This means that we only found unsupported build targets in that project.
* The only way that buildTarget is defined, means that it is supported.
@ -68,6 +71,20 @@ export async function viteConfigurationGenerator(tree: Tree, schema: Schema) {
);
}
if (
alreadyHasNxViteTargets.build &&
(alreadyHasNxViteTargets.serve ||
(!alreadyHasNxViteTargets.serve && projectType === 'library')) &&
alreadyHasNxViteTargets.test
) {
throw new Error(
`The project ${schema.project} is aready configured to use the @nrwl/vite executors.
Please try a different project, or remove the existing targets
and re-run this generator to reset the existing Vite Configuration.
`
);
}
/**
* This means that we did not find any supported executors
* so we don't have any valid target names.
@ -84,7 +101,7 @@ export async function viteConfigurationGenerator(tree: Tree, schema: Schema) {
!validFoundTargetName.serve &&
!validFoundTargetName.test
) {
await handleUnknownExecutors();
await handleUnknownExecutors(schema.project);
}
/**
@ -127,13 +144,15 @@ export async function viteConfigurationGenerator(tree: Tree, schema: Schema) {
});
tasks.push(initTask);
addOrChangeBuildTarget(tree, schema, buildTargetName);
if (!projectAlreadyHasViteTargets?.build) {
addOrChangeBuildTarget(tree, schema, buildTargetName);
}
if (!schema.includeLib) {
if (!schema.includeLib && !projectAlreadyHasViteTargets?.serve) {
addOrChangeServeTarget(tree, schema, serveTargetName);
}
createOrEditViteConfig(tree, schema);
createOrEditViteConfig(tree, schema, false, projectAlreadyHasViteTargets);
if (schema.includeVitest) {
const vitestTask = await vitestGenerator(tree, {

View File

@ -2,7 +2,6 @@
exports[`vitest generator insourceTests should add the insourceSource option in the vite config 1`] = `
"
/// <reference types=\\"vitest\\" />
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import viteTsConfigPaths from 'vite-tsconfig-paths';
@ -37,7 +36,6 @@ exports[`vitest generator insourceTests should add the insourceSource option in
exports[`vitest generator vite.config should create correct vite.config.ts file for apps 1`] = `
"
/// <reference types=\\"vitest\\" />
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import viteTsConfigPaths from 'vite-tsconfig-paths';
@ -70,7 +68,6 @@ exports[`vitest generator vite.config should create correct vite.config.ts file
exports[`vitest generator vite.config should create correct vite.config.ts file for non buildable libs 1`] = `
"
/// <reference types=\\"vitest\\" />
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import viteTsConfigPaths from 'vite-tsconfig-paths';

View File

@ -96,6 +96,17 @@ function updateTsConfig(
path: './tsconfig.spec.json',
});
}
if (!json.compilerOptions?.types?.includes('vitest')) {
if (json.compilerOptions?.types) {
json.compilerOptions.types.push('vitest');
} else {
if (!json.compilerOptions) {
json.compilerOptions = {};
}
json.compilerOptions.types = ['vitest'];
}
}
return json;
});

View File

@ -1,6 +1,54 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`generator utils ensureBuildOptionsInViteConfig should add build options if build options don't exist 1`] = `
exports[`ensureBuildOptionsInViteConfig should add build and test options if defineConfig is empty 1`] = `
"import dts from 'vite-plugin-dts';
import { join } from 'path';
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import viteTsConfigPaths from 'vite-tsconfig-paths';
export default defineConfig({
// Configuration for building your library.
// See: https://vitejs.dev/guide/build.html#library-mode
build: {
lib: {
// Could also be a dictionary or array of multiple entry points.
entry: 'src/index.ts',
name: 'my-app',
fileName: 'index',
// Change this to the formats you want to support.
// Don't forgot to update your package.json as well.
formats: ['es', 'cjs']
},
rollupOptions: {
// External packages that should not be bundled into your library.
external: [\\"'react', 'react-dom', 'react/jsx-runtime'\\"]
}
},plugins: [
dts({
tsConfigFilePath: join(__dirname, 'tsconfig.lib.json'),
// Faster builds by skipping tests. Set this to false to enable type checking.
skipDiagnostics: true,
}),
react(),
viteTsConfigPaths({
root: '../../',
}),
],
test: {
globals: true,
cache: {
dir: '../node_modules/.vitest'
},
environment: 'jsdom',
include: ['src/**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'],
},});
"
`;
exports[`ensureBuildOptionsInViteConfig should add build option but not update test option if test already setup 1`] = `
"import dts from 'vite-plugin-dts';
import { join } from 'path';
import { defineConfig } from 'vite';
@ -52,16 +100,15 @@ import { defineConfig } from 'vite';
"
`;
exports[`generator utils ensureBuildOptionsInViteConfig should add build options if defineConfig is empty 1`] = `
exports[`ensureBuildOptionsInViteConfig should add build options if build options don't exist 1`] = `
"import dts from 'vite-plugin-dts';
import { join } from 'path';
import { defineConfig } from 'vite';
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import viteTsConfigPaths from 'vite-tsconfig-paths';
export default defineConfig({
// Configuration for building your library.
// See: https://vitejs.dev/guide/build.html#library-mode
build: {
@ -79,21 +126,33 @@ import { join } from 'path';
external: [\\"'react', 'react-dom', 'react/jsx-runtime'\\"]
}
},plugins: [
dts({
...[
react(),
viteTsConfigPaths({
root: '../../',
}),
],
dts({
tsConfigFilePath: join(__dirname, 'tsconfig.lib.json'),
// Faster builds by skipping tests. Set this to false to enable type checking.
skipDiagnostics: true,
}),
react(),
viteTsConfigPaths({
root: '../../',
}),
],
],
test: {
globals: true,
cache: {
dir: '../../node_modules/.vitest',
},
environment: 'jsdom',
include: ['src/**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'],
},
});
"
`;
exports[`generator utils ensureBuildOptionsInViteConfig should add build options if defineConfig is not used 1`] = `
exports[`ensureBuildOptionsInViteConfig should add build options if defineConfig is not used 1`] = `
"import dts from 'vite-plugin-dts';
import { join } from 'path';
import { defineConfig } from 'vite';
@ -117,6 +176,13 @@ import { defineConfig } from 'vite';
// External packages that should not be bundled into your library.
external: [\\"'react', 'react-dom', 'react/jsx-runtime'\\"]
}
},test: {
globals: true,
cache: {
dir: '../node_modules/.vitest'
},
environment: 'jsdom',
include: ['src/**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'],
},
plugins: [
...[
@ -135,7 +201,7 @@ import { defineConfig } from 'vite';
"
`;
exports[`generator utils ensureBuildOptionsInViteConfig should add build options if it is using conditional config 1`] = `
exports[`ensureBuildOptionsInViteConfig should add build options if it is using conditional config - do nothing for test 1`] = `
"
import { defineConfig } from 'vite';
export default defineConfig(({ command, mode, ssrBuild }) => {
@ -157,7 +223,7 @@ exports[`generator utils ensureBuildOptionsInViteConfig should add build options
"
`;
exports[`generator utils ensureBuildOptionsInViteConfig should add new build options if some build options already exist 1`] = `
exports[`ensureBuildOptionsInViteConfig should add new build options if some build options already exist 1`] = `
"import dts from 'vite-plugin-dts';
import { join } from 'path';
import { defineConfig } from 'vite';
@ -199,4 +265,93 @@ import { defineConfig } from 'vite';
"
`;
exports[`generator utils ensureBuildOptionsInViteConfig should not do anything if cannot understand syntax of vite config 1`] = `"console.log('Unknown syntax')"`;
exports[`ensureBuildOptionsInViteConfig should not do anything if cannot understand syntax of vite config 1`] = `"console.log('Unknown syntax')"`;
exports[`ensureBuildOptionsInViteConfig should not do anything if project has everything setup already 1`] = `
"
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import viteTsConfigPaths from 'vite-tsconfig-paths';
export default defineConfig({
plugins: [
dts({
tsConfigFilePath: join(__dirname, 'tsconfig.lib.json'),
// Faster builds by skipping tests. Set this to false to enable type checking.
skipDiagnostics: true,
}),
react(),
viteTsConfigPaths({
root: '../../../',
}),
],
// Configuration for building your library.
// See: https://vitejs.dev/guide/build.html#library-mode
build: {
lib: {
// Could also be a dictionary or array of multiple entry points.
entry: 'src/index.ts',
name: 'pure-libs-react-vite',
fileName: 'index',
// Change this to the formats you want to support.
// Don't forgot to update your package.json as well.
formats: ['es', 'cjs'],
},
rollupOptions: {
// External packages that should not be bundled into your library.
external: ['react', 'react-dom', 'react/jsx-runtime'],
},
},
test: {
globals: true,
cache: {
dir: '../../../node_modules/.vitest',
},
environment: 'jsdom',
include: ['src/**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'],
},
});
"
`;
exports[`ensureBuildOptionsInViteConfig should update both test and build options - keep existing settings 1`] = `
"import dts from 'vite-plugin-dts';
import { join } from 'path';
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import viteTsConfigPaths from 'vite-tsconfig-paths';
export default defineConfig({
plugins: [
...[
react(),
viteTsConfigPaths({
root: '../../',
}),
],
dts({
tsConfigFilePath: join(__dirname, 'tsconfig.lib.json'),
// Faster builds by skipping tests. Set this to false to enable type checking.
skipDiagnostics: true,
}),
],
test: {
...{
my: 'option',
},
...{\\"globals\\":true,\\"cache\\":{\\"dir\\":\\"../node_modules/.vitest\\"},\\"environment\\":\\"jsdom\\",\\"include\\":[\\"src/**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}\\"]}
},
build: {
...{
my: 'option',
},
...{\\"lib\\":{\\"entry\\":\\"src/index.ts\\",\\"name\\":\\"my-app\\",\\"fileName\\":\\"index\\",\\"formats\\":[\\"es\\",\\"cjs\\"]},\\"rollupOptions\\":{\\"external\\":[\\"'react', 'react-dom', 'react/jsx-runtime'\\"]}}
}
});
"
`;

View File

@ -15,7 +15,7 @@ import { VitestExecutorOptions } from '../executors/test/schema';
import { Schema } from '../generators/configuration/schema';
import { ensureBuildOptionsInViteConfig } from './vite-config-edit-utils';
export interface UserProvidedTargetIsUnsupported {
export interface TargetFlags {
build?: boolean;
serve?: boolean;
test?: boolean;
@ -41,7 +41,8 @@ export function findExistingTargetsInProject(
): {
validFoundTargetName: ValidFoundTargetName;
projectContainsUnsupportedExecutor?: boolean;
userProvidedTargetIsUnsupported?: UserProvidedTargetIsUnsupported;
userProvidedTargetIsUnsupported?: TargetFlags;
alreadyHasNxViteTargets?: TargetFlags;
} {
let validFoundBuildTarget: string | undefined,
validFoundServeTarget: string | undefined,
@ -49,7 +50,10 @@ export function findExistingTargetsInProject(
projectContainsUnsupportedExecutor: boolean | undefined,
unsupportedUserProvidedTargetBuild: boolean | undefined,
unsupportedUserProvidedTargetServe: boolean | undefined,
unsupportedUserProvidedTargetTest: boolean | undefined;
unsupportedUserProvidedTargetTest: boolean | undefined,
alreadyHasNxViteTargetBuild: boolean | undefined,
alreadyHasNxViteTargetServe: boolean | undefined,
alreadyHasNxViteTargetTest: boolean | undefined;
const arrayOfSupportedBuilders = [
'@nxext/vite:build',
@ -82,6 +86,12 @@ export function findExistingTargetsInProject(
'@nrwl/js:tsc',
];
const arrayOfNxViteExecutors = [
'@nrwl/vite:build',
'@nrwl/vite:dev-server',
'@nrwl/vite:test',
];
// First, we check if the user has provided a target
// If they have, we check if the executor the target is using is supported
// If it's not supported, then we set the unsupported flag to true for that target
@ -134,6 +144,17 @@ export function findExistingTargetsInProject(
) {
break;
}
if (targets[target].executor === '@nrwl/vite:build') {
alreadyHasNxViteTargetBuild = true;
}
if (targets[target].executor === '@nrwl/vite:dev-server') {
alreadyHasNxViteTargetServe = true;
}
if (targets[target].executor === '@nrwl/vite:test') {
alreadyHasNxViteTargetTest = true;
}
if (
!validFoundBuildTarget &&
arrayOfSupportedBuilders.includes(targets[target].executor)
@ -152,7 +173,10 @@ export function findExistingTargetsInProject(
) {
validFoundTestTarget = target;
}
if (arrayofUnsupportedExecutors.includes(targets[target].executor)) {
if (
!arrayOfNxViteExecutors.includes(targets[target].executor) &&
arrayofUnsupportedExecutors.includes(targets[target].executor)
) {
projectContainsUnsupportedExecutor = true;
}
}
@ -169,6 +193,11 @@ export function findExistingTargetsInProject(
serve: unsupportedUserProvidedTargetServe,
test: unsupportedUserProvidedTargetTest,
},
alreadyHasNxViteTargets: {
build: alreadyHasNxViteTargetBuild,
serve: alreadyHasNxViteTargetServe,
test: alreadyHasNxViteTargetTest,
},
};
}
@ -270,6 +299,9 @@ export function addOrChangeServeTarget(
}
project.targets[target].options = {
...serveOptions,
https: project.targets[target].options?.https,
hmr: project.targets[target].options?.hmr,
open: project.targets[target].options?.open,
};
project.targets[target].executor = '@nrwl/vite:dev-server';
} else {
@ -308,6 +340,7 @@ export function editTsConfig(tree: Tree, options: Schema) {
config.compilerOptions = {
target: 'ESNext',
useDefineForClassFields: true,
module: 'ESNext',
lib: ['DOM', 'DOM.Iterable', 'ESNext'],
allowJs: false,
skipLibCheck: true,
@ -315,13 +348,14 @@ export function editTsConfig(tree: Tree, options: Schema) {
allowSyntheticDefaultImports: true,
strict: true,
forceConsistentCasingInFileNames: true,
module: 'ESNext',
moduleResolution: 'Node',
resolveJsonModule: true,
isolatedModules: true,
noEmit: true,
jsx: 'react-jsx',
types: ['vite/client'],
types: options.includeVitest
? ['vite/client', 'vitest']
: ['vite/client'],
};
config.include = [...config.include, 'src'];
break;
@ -331,17 +365,19 @@ export function editTsConfig(tree: Tree, options: Schema) {
useDefineForClassFields: true,
module: 'ESNext',
lib: ['ESNext', 'DOM'],
moduleResolution: 'Node',
skipLibCheck: true,
esModuleInterop: true,
strict: true,
moduleResolution: 'Node',
resolveJsonModule: true,
isolatedModules: true,
esModuleInterop: true,
noEmit: true,
noUnusedLocals: true,
noUnusedParameters: true,
noImplicitReturns: true,
skipLibCheck: true,
types: ['vite/client'],
types: options.includeVitest
? ['vite/client', 'vitest']
: ['vite/client'],
};
config.include = [...config.include, 'src'];
break;
@ -418,7 +454,8 @@ export function moveAndEditIndexHtml(
export function createOrEditViteConfig(
tree: Tree,
options: Schema,
onlyVitest?: boolean
onlyVitest?: boolean,
projectAlreadyHasViteTargets?: TargetFlags
) {
const projectConfig = readProjectConfiguration(tree, options.project);
@ -484,9 +521,6 @@ export function createOrEditViteConfig(
}
},`
: '';
const vitestTypes = options.includeVitest
? `/// <reference types="vitest" />`
: '';
const defineOption = options.inSourceTests
? `define: {
@ -529,13 +563,15 @@ export function createOrEditViteConfig(
buildOption,
dtsPlugin,
dtsImportLine,
pluginOption
pluginOption,
testOption,
offsetFromRoot(projectConfig.root),
projectAlreadyHasViteTargets
);
return;
}
viteConfigContent = `
${vitestTypes}
import { defineConfig } from 'vite';
${reactPluginImportLine}
import viteTsConfigPaths from 'vite-tsconfig-paths';
@ -588,7 +624,7 @@ export function getViteConfigPathForProject(
}
export async function handleUnsupportedUserProvidedTargets(
userProvidedTargetIsUnsupported: UserProvidedTargetIsUnsupported,
userProvidedTargetIsUnsupported: TargetFlags,
userProvidedTargetName: UserProvidedTargetName,
validFoundTargetName: ValidFoundTargetName
) {
@ -654,10 +690,10 @@ async function handleUnsupportedUserProvidedTargetsErrors(
}
}
export async function handleUnknownExecutors() {
export async function handleUnknownExecutors(projectName: string) {
logger.warn(
`
We could not find any targets in your project that use executors which
We could not find any targets in project ${projectName} that use executors which
can be converted to the @nrwl/vite executors.
This either means that your project may not have a target
@ -691,8 +727,15 @@ function handleViteConfigFileExists(
buildOption: string,
dtsPlugin: string,
dtsImportLine: string,
pluginOption: string
pluginOption: string,
testOption: string,
offsetFromRoot: string,
projectAlreadyHasViteTargets?: TargetFlags
) {
if (projectAlreadyHasViteTargets.build && projectAlreadyHasViteTargets.test) {
return;
}
logger.info(`vite.config.ts already exists for project ${options.project}.`);
const buildOptionObject = {
lib: {
@ -709,6 +752,16 @@ function handleViteConfigFileExists(
],
},
};
const testOptionObject = {
globals: true,
cache: {
dir: `${offsetFromRoot}node_modules/.vitest`,
},
environment: 'jsdom',
include: ['src/**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'],
};
const changed = ensureBuildOptionsInViteConfig(
tree,
viteConfigPath,
@ -716,7 +769,10 @@ function handleViteConfigFileExists(
buildOptionObject,
dtsPlugin,
dtsImportLine,
pluginOption
pluginOption,
testOption,
testOptionObject,
projectAlreadyHasViteTargets
);
if (!changed) {
@ -729,7 +785,7 @@ function handleViteConfigFileExists(
);
} else {
logger.info(`
Vite configuration file (${viteConfigPath}) has been updated with the required settings for build.
Vite configuration file (${viteConfigPath}) has been updated with the required settings for the new target(s).
`);
}
}

View File

@ -0,0 +1,254 @@
export const noBuildOptions = `
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import viteTsConfigPaths from 'vite-tsconfig-paths';
export default defineConfig({
plugins: [
react(),
viteTsConfigPaths({
root: '../../',
}),
],
test: {
globals: true,
cache: {
dir: '../../node_modules/.vitest',
},
environment: 'jsdom',
include: ['src/**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'],
},
});
`;
export const someBuildOptions = `
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import viteTsConfigPaths from 'vite-tsconfig-paths';
export default defineConfig({
plugins: [
react(),
viteTsConfigPaths({
root: '../../',
}),
],
test: {
globals: true,
cache: {
dir: '../../node_modules/.vitest',
},
environment: 'jsdom',
include: ['src/**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'],
},
build: {
my: 'option',
}
});
`;
export const noContentDefineConfig = `
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import viteTsConfigPaths from 'vite-tsconfig-paths';
export default defineConfig({});
`;
export const conditionalConfig = `
import { defineConfig } from 'vite';
export default defineConfig(({ command, mode, ssrBuild }) => {
if (command === 'serve') {
return {
port: 4200,
host: 'localhost',
}
} else {
// command === 'build'
return {
my: 'option',
}
}
})
`;
export const configNoDefineConfig = `
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import viteTsConfigPaths from 'vite-tsconfig-paths';
export default {
plugins: [
react(),
viteTsConfigPaths({
root: '../../',
}),
],
};
`;
export const noBuildOptionsHasTestOption = `
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import viteTsConfigPaths from 'vite-tsconfig-paths';
export default defineConfig({
plugins: [
react(),
viteTsConfigPaths({
root: '../../',
}),
],
test: {
globals: true,
cache: {
dir: '../../node_modules/.vitest',
},
environment: 'jsdom',
include: ['src/**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'],
},
});
`;
export const someBuildOptionsSomeTestOption = `
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import viteTsConfigPaths from 'vite-tsconfig-paths';
export default defineConfig({
plugins: [
react(),
viteTsConfigPaths({
root: '../../',
}),
],
test: {
my: 'option',
},
build: {
my: 'option',
}
});
`;
export const hasEverything = `
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import viteTsConfigPaths from 'vite-tsconfig-paths';
export default defineConfig({
plugins: [
dts({
tsConfigFilePath: join(__dirname, 'tsconfig.lib.json'),
// Faster builds by skipping tests. Set this to false to enable type checking.
skipDiagnostics: true,
}),
react(),
viteTsConfigPaths({
root: '../../../',
}),
],
// Configuration for building your library.
// See: https://vitejs.dev/guide/build.html#library-mode
build: {
lib: {
// Could also be a dictionary or array of multiple entry points.
entry: 'src/index.ts',
name: 'pure-libs-react-vite',
fileName: 'index',
// Change this to the formats you want to support.
// Don't forgot to update your package.json as well.
formats: ['es', 'cjs'],
},
rollupOptions: {
// External packages that should not be bundled into your library.
external: ['react', 'react-dom', 'react/jsx-runtime'],
},
},
test: {
globals: true,
cache: {
dir: '../../../node_modules/.vitest',
},
environment: 'jsdom',
include: ['src/**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'],
},
});
`;
export const buildOption = `
// Configuration for building your library.
// See: https://vitejs.dev/guide/build.html#library-mode
build: {
lib: {
// Could also be a dictionary or array of multiple entry points.
entry: 'src/index.ts',
name: 'my-app',
fileName: 'index',
// Change this to the formats you want to support.
// Don't forgot to update your package.json as well.
formats: ['es', 'cjs']
},
rollupOptions: {
// External packages that should not be bundled into your library.
external: ["'react', 'react-dom', 'react/jsx-runtime'"]
}
},`;
export const buildOptionObject = {
lib: {
entry: 'src/index.ts',
name: 'my-app',
fileName: 'index',
formats: ['es', 'cjs'],
},
rollupOptions: {
external: ["'react', 'react-dom', 'react/jsx-runtime'"],
},
};
export const testOption = `test: {
globals: true,
cache: {
dir: '../node_modules/.vitest'
},
environment: 'jsdom',
include: ['src/**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'],
},`;
export const testOptionObject = {
globals: true,
cache: {
dir: `../node_modules/.vitest`,
},
environment: 'jsdom',
include: ['src/**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'],
};
export const dtsPlugin = `dts({
tsConfigFilePath: join(__dirname, 'tsconfig.lib.json'),
// Faster builds by skipping tests. Set this to false to enable type checking.
skipDiagnostics: true,
}),`;
export const dtsImportLine = `import dts from 'vite-plugin-dts';\nimport { join } from 'path';`;
export const pluginOption = `
plugins: [
${dtsPlugin}
react(),
viteTsConfigPaths({
root: '../../',
}),
],
`;

View File

@ -1,4 +1,4 @@
import { parseJson, Tree, writeJson } from '@nrwl/devkit';
import { Tree, writeJson } from '@nrwl/devkit';
import * as reactAppConfig from './test-files/react-project.config.json';
import * as reactViteConfig from './test-files/react-vite-project.config.json';
import * as webAppConfig from './test-files/web-project.config.json';
@ -90,8 +90,7 @@ export function mockViteReactAppGenerator(tree: Tree): Tree {
tree.write(
`apps/${appName}/vite.config.ts`,
`/// <reference types="vitest" />
import { defineConfig } from 'vite';
`import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import tsconfigPaths from 'vite-tsconfig-paths';
@ -534,9 +533,7 @@ export function mockReactLibNonBuildableVitestRunnerGenerator(
tree.write(
`libs/${libName}/vite.config.ts`,
`
/// <reference types="vitest" />
import { defineConfig } from 'vite';
`import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import viteTsConfigPaths from 'vite-tsconfig-paths';

View File

@ -1,281 +1,221 @@
import { Tree } from '@nrwl/devkit';
import { createTreeWithEmptyV1Workspace } from '@nrwl/devkit/testing';
import { tsquery } from '@phenomnomnominal/tsquery';
import {
buildOption,
buildOptionObject,
conditionalConfig,
configNoDefineConfig,
dtsImportLine,
dtsPlugin,
hasEverything,
noBuildOptions,
noBuildOptionsHasTestOption,
noContentDefineConfig,
pluginOption,
someBuildOptions,
someBuildOptionsSomeTestOption,
testOption,
testOptionObject,
} from './test-files/test-vite-configs';
import { ensureBuildOptionsInViteConfig } from './vite-config-edit-utils';
describe('generator utils', () => {
describe('ensureBuildOptionsInViteConfig', () => {
let tree: Tree;
beforeEach(() => {
tree = createTreeWithEmptyV1Workspace();
});
describe('ensureBuildOptionsInViteConfig', () => {
let tree: Tree;
it("should add build options if build options don't exist", () => {
tree.write('apps/my-app/vite.config.ts', noBuildOptions);
ensureBuildOptionsInViteConfig(
tree,
'apps/my-app/vite.config.ts',
buildOption,
buildOptionObject,
dtsPlugin,
dtsImportLine,
pluginOption,
testOption,
testOptionObject,
{ build: false, test: true, serve: false }
);
const appFileContent = tree.read('apps/my-app/vite.config.ts', 'utf-8');
const file = tsquery.ast(appFileContent);
const buildNode = tsquery.query(
file,
'PropertyAssignment:has(Identifier[name="build"])'
);
expect(buildNode).toBeDefined();
expect(appFileContent).toMatchSnapshot();
});
const buildOption = `
// Configuration for building your library.
// See: https://vitejs.dev/guide/build.html#library-mode
build: {
lib: {
// Could also be a dictionary or array of multiple entry points.
entry: 'src/index.ts',
name: 'my-app',
fileName: 'index',
// Change this to the formats you want to support.
// Don't forgot to update your package.json as well.
formats: ['es', 'cjs']
},
rollupOptions: {
// External packages that should not be bundled into your library.
external: ["'react', 'react-dom', 'react/jsx-runtime'"]
}
},`;
const buildOptionObject = {
lib: {
entry: 'src/index.ts',
name: 'my-app',
fileName: 'index',
formats: ['es', 'cjs'],
},
rollupOptions: {
external: ["'react', 'react-dom', 'react/jsx-runtime'"],
},
};
const dtsPlugin = `dts({
tsConfigFilePath: join(__dirname, 'tsconfig.lib.json'),
// Faster builds by skipping tests. Set this to false to enable type checking.
skipDiagnostics: true,
}),`;
const dtsImportLine = `import dts from 'vite-plugin-dts';\nimport { join } from 'path';`;
it('should add new build options if some build options already exist', () => {
tree.write('apps/my-app/vite.config.ts', someBuildOptions);
ensureBuildOptionsInViteConfig(
tree,
'apps/my-app/vite.config.ts',
buildOption,
buildOptionObject,
dtsPlugin,
dtsImportLine,
pluginOption,
testOption,
testOptionObject,
{ build: false, test: true, serve: false }
);
const appFileContent = tree.read('apps/my-app/vite.config.ts', 'utf-8');
const file = tsquery.ast(appFileContent);
const buildNode = tsquery.query(
file,
'PropertyAssignment:has(Identifier[name="build"])'
);
expect(buildNode).toBeDefined();
expect(appFileContent).toMatchSnapshot();
});
const pluginOption = `
plugins: [
${dtsPlugin}
react(),
viteTsConfigPaths({
root: '../../',
}),
],
`;
it('should add build and test options if defineConfig is empty', () => {
tree.write('apps/my-app/vite.config.ts', noContentDefineConfig);
ensureBuildOptionsInViteConfig(
tree,
'apps/my-app/vite.config.ts',
buildOption,
buildOptionObject,
dtsPlugin,
dtsImportLine,
pluginOption,
testOption,
testOptionObject,
{ build: false, test: false, serve: false }
);
const appFileContent = tree.read('apps/my-app/vite.config.ts', 'utf-8');
const file = tsquery.ast(appFileContent);
const buildNode = tsquery.query(
file,
'PropertyAssignment:has(Identifier[name="build"])'
);
expect(buildNode).toBeDefined();
expect(appFileContent).toMatchSnapshot();
});
const noBuildOptions = `
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import viteTsConfigPaths from 'vite-tsconfig-paths';
it('should add build options if it is using conditional config - do nothing for test', () => {
tree.write('apps/my-app/vite.config.ts', conditionalConfig);
ensureBuildOptionsInViteConfig(
tree,
'apps/my-app/vite.config.ts',
buildOption,
buildOptionObject,
dtsPlugin,
dtsImportLine,
pluginOption,
testOption,
testOptionObject,
{ build: false, test: false, serve: false }
);
const appFileContent = tree.read('apps/my-app/vite.config.ts', 'utf-8');
const file = tsquery.ast(appFileContent);
const buildNode = tsquery.query(
file,
'PropertyAssignment:has(Identifier[name="build"])'
);
expect(buildNode).toBeDefined();
expect(appFileContent).toMatchSnapshot();
});
export default defineConfig({
plugins: [
react(),
viteTsConfigPaths({
root: '../../',
}),
],
it('should add build options if defineConfig is not used', () => {
tree.write('apps/my-app/vite.config.ts', configNoDefineConfig);
ensureBuildOptionsInViteConfig(
tree,
'apps/my-app/vite.config.ts',
buildOption,
buildOptionObject,
dtsPlugin,
dtsImportLine,
pluginOption,
testOption,
testOptionObject,
{ build: false, test: false, serve: false }
);
const appFileContent = tree.read('apps/my-app/vite.config.ts', 'utf-8');
const file = tsquery.ast(appFileContent);
const buildNode = tsquery.query(
file,
'PropertyAssignment:has(Identifier[name="build"])'
);
expect(buildNode).toBeDefined();
expect(appFileContent).toMatchSnapshot();
});
test: {
globals: true,
cache: {
dir: '../../node_modules/.vitest',
},
environment: 'jsdom',
include: ['src/**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'],
},
it('should not do anything if cannot understand syntax of vite config', () => {
tree.write('apps/my-app/vite.config.ts', `console.log('Unknown syntax')`);
ensureBuildOptionsInViteConfig(
tree,
'apps/my-app/vite.config.ts',
buildOption,
buildOptionObject,
dtsPlugin,
dtsImportLine,
pluginOption,
testOption,
testOptionObject,
{ build: false, test: false, serve: false }
);
const appFileContent = tree.read('apps/my-app/vite.config.ts', 'utf-8');
expect(appFileContent).toMatchSnapshot();
});
});
`;
it('should not do anything if project has everything setup already', () => {
tree.write('apps/my-app/vite.config.ts', hasEverything);
ensureBuildOptionsInViteConfig(
tree,
'apps/my-app/vite.config.ts',
buildOption,
buildOptionObject,
dtsPlugin,
dtsImportLine,
pluginOption,
testOption,
testOptionObject,
{ build: true, test: true, serve: true }
);
const appFileContent = tree.read('apps/my-app/vite.config.ts', 'utf-8');
expect(appFileContent).toMatchSnapshot();
});
const someBuildOptions = `
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import viteTsConfigPaths from 'vite-tsconfig-paths';
it('should add build option but not update test option if test already setup', () => {
tree.write('apps/my-app/vite.config.ts', noBuildOptionsHasTestOption);
ensureBuildOptionsInViteConfig(
tree,
'apps/my-app/vite.config.ts',
buildOption,
buildOptionObject,
dtsPlugin,
dtsImportLine,
pluginOption,
testOption,
testOptionObject,
{ build: false, test: true, serve: true }
);
const appFileContent = tree.read('apps/my-app/vite.config.ts', 'utf-8');
expect(appFileContent).toMatchSnapshot();
});
export default defineConfig({
plugins: [
react(),
viteTsConfigPaths({
root: '../../',
}),
],
test: {
globals: true,
cache: {
dir: '../../node_modules/.vitest',
},
environment: 'jsdom',
include: ['src/**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'],
},
build: {
my: 'option',
}
});
`;
const noContentDefineConfig = `
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import viteTsConfigPaths from 'vite-tsconfig-paths';
export default defineConfig({});
`;
const conditionalConfig = `
import { defineConfig } from 'vite';
export default defineConfig(({ command, mode, ssrBuild }) => {
if (command === 'serve') {
return {
port: 4200,
host: 'localhost',
}
} else {
// command === 'build'
return {
my: 'option',
}
}
})
`;
const configNoDefineConfig = `
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import viteTsConfigPaths from 'vite-tsconfig-paths';
export default {
plugins: [
react(),
viteTsConfigPaths({
root: '../../',
}),
],
};
`;
beforeEach(() => {
tree = createTreeWithEmptyV1Workspace();
});
it("should add build options if build options don't exist", () => {
tree.write('apps/my-app/vite.config.ts', noBuildOptions);
ensureBuildOptionsInViteConfig(
tree,
'apps/my-app/vite.config.ts',
buildOption,
buildOptionObject,
dtsPlugin,
dtsImportLine,
pluginOption
);
const appFileContent = tree.read('apps/my-app/vite.config.ts', 'utf-8');
const file = tsquery.ast(appFileContent);
const buildNode = tsquery.query(
file,
'PropertyAssignment:has(Identifier[name="build"])'
);
expect(buildNode).toBeDefined();
expect(appFileContent).toMatchSnapshot();
});
it('should add new build options if some build options already exist', () => {
tree.write('apps/my-app/vite.config.ts', someBuildOptions);
ensureBuildOptionsInViteConfig(
tree,
'apps/my-app/vite.config.ts',
buildOption,
buildOptionObject,
dtsPlugin,
dtsImportLine,
pluginOption
);
const appFileContent = tree.read('apps/my-app/vite.config.ts', 'utf-8');
const file = tsquery.ast(appFileContent);
const buildNode = tsquery.query(
file,
'PropertyAssignment:has(Identifier[name="build"])'
);
expect(buildNode).toBeDefined();
expect(appFileContent).toMatchSnapshot();
});
it('should add build options if defineConfig is empty', () => {
tree.write('apps/my-app/vite.config.ts', noContentDefineConfig);
ensureBuildOptionsInViteConfig(
tree,
'apps/my-app/vite.config.ts',
buildOption,
buildOptionObject,
dtsPlugin,
dtsImportLine,
pluginOption
);
const appFileContent = tree.read('apps/my-app/vite.config.ts', 'utf-8');
const file = tsquery.ast(appFileContent);
const buildNode = tsquery.query(
file,
'PropertyAssignment:has(Identifier[name="build"])'
);
expect(buildNode).toBeDefined();
expect(appFileContent).toMatchSnapshot();
});
it('should add build options if it is using conditional config', () => {
tree.write('apps/my-app/vite.config.ts', conditionalConfig);
ensureBuildOptionsInViteConfig(
tree,
'apps/my-app/vite.config.ts',
buildOption,
buildOptionObject,
dtsPlugin,
dtsImportLine,
pluginOption
);
const appFileContent = tree.read('apps/my-app/vite.config.ts', 'utf-8');
const file = tsquery.ast(appFileContent);
const buildNode = tsquery.query(
file,
'PropertyAssignment:has(Identifier[name="build"])'
);
expect(buildNode).toBeDefined();
expect(appFileContent).toMatchSnapshot();
});
it('should add build options if defineConfig is not used', () => {
tree.write('apps/my-app/vite.config.ts', configNoDefineConfig);
ensureBuildOptionsInViteConfig(
tree,
'apps/my-app/vite.config.ts',
buildOption,
buildOptionObject,
dtsPlugin,
dtsImportLine,
pluginOption
);
const appFileContent = tree.read('apps/my-app/vite.config.ts', 'utf-8');
const file = tsquery.ast(appFileContent);
const buildNode = tsquery.query(
file,
'PropertyAssignment:has(Identifier[name="build"])'
);
expect(buildNode).toBeDefined();
expect(appFileContent).toMatchSnapshot();
});
it('should not do anything if cannot understand syntax of vite config', () => {
tree.write('apps/my-app/vite.config.ts', `console.log('Unknown syntax')`);
ensureBuildOptionsInViteConfig(
tree,
'apps/my-app/vite.config.ts',
buildOption,
buildOptionObject,
dtsPlugin,
dtsImportLine,
pluginOption
);
const appFileContent = tree.read('apps/my-app/vite.config.ts', 'utf-8');
expect(appFileContent).toMatchSnapshot();
});
it('should update both test and build options - keep existing settings', () => {
tree.write('apps/my-app/vite.config.ts', someBuildOptionsSomeTestOption);
ensureBuildOptionsInViteConfig(
tree,
'apps/my-app/vite.config.ts',
buildOption,
buildOptionObject,
dtsPlugin,
dtsImportLine,
pluginOption,
testOption,
testOptionObject,
{ build: false, test: false, serve: true }
);
const appFileContent = tree.read('apps/my-app/vite.config.ts', 'utf-8');
expect(appFileContent).toMatchSnapshot();
});
});

View File

@ -2,59 +2,77 @@ import { applyChangesToString, ChangeType, Tree } from '@nrwl/devkit';
import { findNodes } from 'nx/src/utils/typescript';
import ts = require('typescript');
import { tsquery } from '@phenomnomnominal/tsquery';
import { TargetFlags } from './generator-utils';
export function ensureBuildOptionsInViteConfig(
tree: Tree,
path: string,
buildConfigContent: string,
buildConfigString: string,
buildConfigObject: {},
dtsPlugin: string,
dtsImportLine: string,
pluginOption: string
pluginOption: string,
testConfigString: string,
testConfigObject: {},
projectAlreadyHasViteTargets?: TargetFlags
): boolean {
const fileContent = tree.read(path, 'utf-8');
const file = tsquery.ast(fileContent);
const newContent = handlePluginNode(
file,
fileContent,
dtsPlugin,
dtsImportLine,
pluginOption
);
const buildUpdatedContent = handleBuildNode(
newContent ?? fileContent,
buildConfigContent,
buildConfigObject
);
let updatedContent = undefined;
if (buildUpdatedContent) {
tree.write(path, buildUpdatedContent);
if (!projectAlreadyHasViteTargets?.test && testConfigString?.length) {
updatedContent = handleBuildOrTestNode(
fileContent,
testConfigString,
testConfigObject,
'test'
);
}
if (!projectAlreadyHasViteTargets?.build && buildConfigString?.length) {
updatedContent = handlePluginNode(
updatedContent ?? fileContent,
dtsPlugin,
dtsImportLine,
pluginOption
);
updatedContent = handleBuildOrTestNode(
updatedContent ?? fileContent,
buildConfigString,
buildConfigObject,
'build'
);
}
if (updatedContent) {
tree.write(path, updatedContent);
return true;
} else {
return false;
}
}
function handleBuildNode(
function handleBuildOrTestNode(
updatedFileContent: string,
buildConfigContent: string,
buildConfigObject: {}
configContentString: string,
configContentObject: {},
name: 'build' | 'test'
): string | undefined {
const buildNode = tsquery.query(
updatedFileContent,
'PropertyAssignment:has(Identifier[name="build"])'
`PropertyAssignment:has(Identifier[name="${name}"])`
);
if (buildNode.length) {
return tsquery.replace(
updatedFileContent,
'PropertyAssignment:has(Identifier[name="build"])',
`PropertyAssignment:has(Identifier[name="${name}"])`,
(node: ts.Node) => {
const found = tsquery.query(node, 'ObjectLiteralExpression');
return `build: {
return `${name}: {
...${found?.[0].getText()},
...${JSON.stringify(buildConfigObject)}
...${JSON.stringify(configContentObject)}
}`;
}
);
@ -71,11 +89,16 @@ function handleBuildNode(
);
if (conditionalConfig.length) {
return transformConditionalConfig(
conditionalConfig,
updatedFileContent,
buildConfigContent
);
if (name === 'build') {
return transformConditionalConfig(
conditionalConfig,
updatedFileContent,
configContentString
);
} else {
// no test config in conditional config
return undefined;
}
} else {
const propertyAssignments = tsquery.query(
foundDefineConfig[0],
@ -87,7 +110,7 @@ function handleBuildNode(
{
type: ChangeType.Insert,
index: propertyAssignments[0].getStart(),
text: buildConfigContent,
text: configContentString,
},
]);
} else {
@ -95,7 +118,7 @@ function handleBuildNode(
{
type: ChangeType.Insert,
index: foundDefineConfig[0].getStart() + 14,
text: buildConfigContent,
text: configContentString,
},
]);
}
@ -117,7 +140,7 @@ function handleBuildNode(
{
type: ChangeType.Insert,
index: startOfObject + 1,
text: buildConfigContent,
text: configContentString,
},
]);
} catch {
@ -131,7 +154,6 @@ function transformCurrentBuildObject(
index: number,
returnStatements: ts.ReturnStatement[],
appFileContent: string,
buildConfigObject: {}
): string | undefined {
if (!returnStatements?.[index]) {
@ -244,12 +266,12 @@ function transformConditionalConfig(
}
function handlePluginNode(
file: ts.SourceFile,
appFileContent: string,
dtsPlugin: string,
dtsImportLine: string,
pluginOption: string
): string | undefined {
const file = tsquery.ast(appFileContent);
const pluginsNode = tsquery.query(
file,
'PropertyAssignment:has(Identifier[name="plugins"])'
@ -341,15 +363,7 @@ function handlePluginNode(
if (writeFile) {
if (!appFileContent.includes(`import dts from 'vite-plugin-dts'`)) {
if (appFileContent.includes('/// <reference types="vitest" />')) {
return appFileContent.replace(
'/// <reference types="vitest" />',
`/// <reference types="vitest" />
${dtsImportLine}\n`
);
} else {
return dtsImportLine + '\n' + appFileContent;
}
return dtsImportLine + '\n' + appFileContent;
}
return appFileContent;
}

View File

@ -160,7 +160,10 @@ describe('app', () => {
path: './tsconfig.spec.json',
},
]);
expect(tsconfig.compilerOptions.types).toMatchObject(['vite/client']);
expect(tsconfig.compilerOptions.types).toMatchObject([
'vite/client',
'vitest',
]);
expect(tree.exists('apps/my-app-e2e/cypress.config.ts')).toBeTruthy();
expect(tree.exists('apps/my-app/index.html')).toBeTruthy();
@ -563,7 +566,10 @@ describe('app', () => {
it('should create correct tsconfig compilerOptions', () => {
const tsconfigJson = readJson(viteAppTree, '/apps/my-app/tsconfig.json');
expect(tsconfigJson.compilerOptions.types).toMatchObject(['vite/client']);
expect(tsconfigJson.compilerOptions.types).toMatchObject([
'vite/client',
'vitest',
]);
});
it('should create index.html and vite.config file at the root of the app', () => {