fix(vite): improve vite configuration (#13978)
This commit is contained in:
parent
c51c178923
commit
6c6fd7ce1d
@ -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', () => {
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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';
|
||||
|
||||
@ -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, {
|
||||
|
||||
@ -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';
|
||||
|
||||
@ -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;
|
||||
});
|
||||
|
||||
|
||||
@ -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'\\"]}}
|
||||
}
|
||||
|
||||
});
|
||||
"
|
||||
`;
|
||||
|
||||
@ -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).
|
||||
`);
|
||||
}
|
||||
}
|
||||
|
||||
254
packages/vite/src/utils/test-files/test-vite-configs.ts
Normal file
254
packages/vite/src/utils/test-files/test-vite-configs.ts
Normal 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: '../../',
|
||||
}),
|
||||
],
|
||||
`;
|
||||
@ -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';
|
||||
|
||||
|
||||
@ -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();
|
||||
});
|
||||
});
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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', () => {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user