fix(vite): adjust config generation (#20367)
This commit is contained in:
parent
b9b75a79fc
commit
2c88282e8a
@ -26,11 +26,6 @@
|
||||
"description": "Skip type-checking via TypeScript. Skipping type-checking speeds up the build but type errors are not caught.",
|
||||
"default": false
|
||||
},
|
||||
"base": {
|
||||
"type": "string",
|
||||
"description": "Base public path when served in development or production.",
|
||||
"alias": "baseHref"
|
||||
},
|
||||
"configFile": {
|
||||
"type": "string",
|
||||
"description": "The name of the Vite.js configuration file.",
|
||||
@ -59,49 +54,6 @@
|
||||
},
|
||||
"default": []
|
||||
},
|
||||
"emptyOutDir": {
|
||||
"description": "When set to false, outputPath will not be emptied during the build process.",
|
||||
"type": "boolean",
|
||||
"default": true
|
||||
},
|
||||
"sourcemap": {
|
||||
"description": "Output sourcemaps. Use 'hidden' for use with error reporting tools without generating sourcemap comment.",
|
||||
"oneOf": [{ "type": "boolean" }, { "type": "string" }]
|
||||
},
|
||||
"target": {
|
||||
"description": "Browser compatibility target for the final bundle. For more info: https://vitejs.dev/config/build-options.html#build-target",
|
||||
"type": "string"
|
||||
},
|
||||
"minify": {
|
||||
"description": "Output sourcemaps. Use 'hidden' for use with error reporting tools without generating sourcemap comment.",
|
||||
"oneOf": [{ "type": "boolean" }, { "type": "string" }]
|
||||
},
|
||||
"manifest": {
|
||||
"description": "Output sourcemaps. Use 'hidden' for use with error reporting tools without generating sourcemap comment.",
|
||||
"oneOf": [{ "type": "boolean" }, { "type": "string" }]
|
||||
},
|
||||
"ssrManifest": {
|
||||
"description": "When set to true, the build will also generate an SSR manifest for determining style links and asset preload directives in production. When the value is a string, it will be used as the manifest file name.",
|
||||
"oneOf": [{ "type": "boolean" }, { "type": "string" }]
|
||||
},
|
||||
"ssr": {
|
||||
"description": "Produce SSR-oriented build. The value can be a string to directly specify the SSR entry, or true, which requires specifying the SSR entry via rollupOptions.input.",
|
||||
"oneOf": [{ "type": "boolean" }, { "type": "string" }]
|
||||
},
|
||||
"logLevel": {
|
||||
"type": "string",
|
||||
"description": "Adjust console output verbosity.",
|
||||
"enum": ["info", "warn", "error", "silent"]
|
||||
},
|
||||
"mode": { "type": "string", "description": "Mode to run the build in." },
|
||||
"force": {
|
||||
"description": "Force the optimizer to ignore the cache and re-bundle",
|
||||
"type": "boolean"
|
||||
},
|
||||
"cssCodeSplit": {
|
||||
"description": "Enable/disable CSS code splitting. When enabled, CSS imported in async chunks will be inlined into the async chunk itself and inserted when the chunk is loaded.",
|
||||
"type": "boolean"
|
||||
},
|
||||
"watch": {
|
||||
"description": "Enable re-building when files change.",
|
||||
"oneOf": [{ "type": "boolean" }, { "type": "object" }],
|
||||
|
||||
@ -27,45 +27,6 @@
|
||||
"type": "string",
|
||||
"description": "Path to the proxy configuration file.",
|
||||
"x-completion-type": "file"
|
||||
},
|
||||
"port": {
|
||||
"type": "number",
|
||||
"description": "Port to listen on.",
|
||||
"x-priority": "important"
|
||||
},
|
||||
"host": {
|
||||
"description": "Specify which IP addresses the server should listen on.",
|
||||
"oneOf": [{ "type": "boolean" }, { "type": "string" }]
|
||||
},
|
||||
"https": {
|
||||
"oneOf": [{ "type": "boolean" }, { "type": "object" }],
|
||||
"description": "Serve using HTTPS. https://vitejs.dev/config/server-options.html#server-https"
|
||||
},
|
||||
"hmr": {
|
||||
"description": "Enable hot module replacement. For more options, use the 'hmr' option in the Vite configuration file.",
|
||||
"type": "boolean"
|
||||
},
|
||||
"open": {
|
||||
"description": "Automatically open the app in the browser on server start. When the value is a string, it will be used as the URL's pathname.",
|
||||
"oneOf": [{ "type": "boolean" }, { "type": "string" }]
|
||||
},
|
||||
"cors": {
|
||||
"description": "Configure CORS for the dev server.",
|
||||
"type": "boolean"
|
||||
},
|
||||
"logLevel": {
|
||||
"type": "string",
|
||||
"description": "Adjust console output verbosity.",
|
||||
"enum": ["info", "warn", "error", "silent"]
|
||||
},
|
||||
"mode": { "type": "string", "description": "Mode to run the server in." },
|
||||
"clearScreen": {
|
||||
"description": "Set to false to prevent Vite from clearing the terminal screen when logging certain messages.",
|
||||
"type": "boolean"
|
||||
},
|
||||
"force": {
|
||||
"description": "Force the optimizer to ignore the cache and re-bundle",
|
||||
"type": "boolean"
|
||||
}
|
||||
},
|
||||
"definitions": {},
|
||||
|
||||
@ -22,29 +22,6 @@
|
||||
"description": "Path to the proxy configuration file.",
|
||||
"x-completion-type": "file"
|
||||
},
|
||||
"port": { "type": "number", "description": "Port to listen on." },
|
||||
"host": {
|
||||
"description": "Specify which IP addresses the server should listen on.",
|
||||
"oneOf": [{ "type": "boolean" }, { "type": "string" }]
|
||||
},
|
||||
"https": {
|
||||
"oneOf": [{ "type": "boolean" }, { "type": "object" }],
|
||||
"description": "Serve using HTTPS. https://vitejs.dev/config/server-options.html#server-https"
|
||||
},
|
||||
"open": {
|
||||
"description": "Automatically open the app in the browser on server start. When the value is a string, it will be used as the URL's pathname.",
|
||||
"oneOf": [{ "type": "boolean" }, { "type": "string" }]
|
||||
},
|
||||
"logLevel": {
|
||||
"type": "string",
|
||||
"description": "Adjust console output verbosity.",
|
||||
"enum": ["info", "warn", "error", "silent"]
|
||||
},
|
||||
"mode": { "type": "string", "description": "Mode to run the server in." },
|
||||
"clearScreen": {
|
||||
"description": "Set to false to prevent Vite from clearing the terminal screen when logging certain messages.",
|
||||
"type": "boolean"
|
||||
},
|
||||
"staticFilePath": {
|
||||
"type": "string",
|
||||
"description": "Path where the build artifacts are located. If not provided then it will be infered from the buildTarget executor options as outputPath",
|
||||
|
||||
@ -9,50 +9,12 @@
|
||||
"description": "Test using Vitest.",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"config": {
|
||||
"configFile": {
|
||||
"type": "string",
|
||||
"description": "The path to the local vitest config",
|
||||
"x-completion-type": "file",
|
||||
"x-completion-glob": "@(vitest|vite).config@(.js|.ts)"
|
||||
},
|
||||
"passWithNoTests": {
|
||||
"type": "boolean",
|
||||
"default": true,
|
||||
"description": "Pass the test even if no tests are found"
|
||||
},
|
||||
"testNamePattern": {
|
||||
"type": "string",
|
||||
"description": "Run tests with full names matching the pattern"
|
||||
},
|
||||
"mode": {
|
||||
"type": "string",
|
||||
"enum": ["test", "benchmark", "typecheck"],
|
||||
"default": "test",
|
||||
"description": "The mode that vitest will run on",
|
||||
"x-priority": "important"
|
||||
},
|
||||
"watch": {
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"description": "Enable watch mode"
|
||||
},
|
||||
"reporters": {
|
||||
"type": "array",
|
||||
"items": { "type": "string" },
|
||||
"description": "An array of reporters to pass to vitest"
|
||||
},
|
||||
"update": {
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"alias": "u",
|
||||
"description": "Update snapshots",
|
||||
"x-priority": "important"
|
||||
},
|
||||
"coverage": {
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"description": "Enable coverage report",
|
||||
"x-priority": "important"
|
||||
"x-completion-glob": "@(vitest|vite).config@(.js|.ts)",
|
||||
"aliases": ["config"]
|
||||
},
|
||||
"reportsDirectory": {
|
||||
"type": "string",
|
||||
@ -62,6 +24,10 @@
|
||||
"aliases": ["testFile"],
|
||||
"type": "array",
|
||||
"items": { "type": "string" }
|
||||
},
|
||||
"watch": {
|
||||
"description": "Watch files for changes and rerun tests related to changed files.",
|
||||
"type": "boolean"
|
||||
}
|
||||
},
|
||||
"required": [],
|
||||
|
||||
@ -38,7 +38,7 @@ describe('Nuxt Plugin', () => {
|
||||
it('should test application', async () => {
|
||||
const result = runCLI(`test ${app}`);
|
||||
expect(result).toContain(`Successfully ran target test for project ${app}`);
|
||||
});
|
||||
}, 150_000);
|
||||
|
||||
it('should lint application', async () => {
|
||||
const result = runCLI(`lint ${app}`);
|
||||
|
||||
@ -6,10 +6,8 @@ import {
|
||||
exists,
|
||||
fileExists,
|
||||
getPackageManagerCommand,
|
||||
killPorts,
|
||||
listFiles,
|
||||
newProject,
|
||||
promisifiedTreeKill,
|
||||
readFile,
|
||||
readJson,
|
||||
removeFile,
|
||||
@ -17,7 +15,6 @@ import {
|
||||
runCLI,
|
||||
runCommand,
|
||||
runCLIAsync,
|
||||
runCommandUntil,
|
||||
tmpProjPath,
|
||||
uniq,
|
||||
updateFile,
|
||||
@ -32,87 +29,11 @@ describe('Vite Plugin', () => {
|
||||
let proj: string;
|
||||
|
||||
describe('Vite on React apps', () => {
|
||||
describe('convert React webpack app to vite using the vite:configuration generator', () => {
|
||||
beforeEach(() => {
|
||||
proj = newProject();
|
||||
runCLI(`generate @nx/react:app ${myApp} --bundler=webpack`);
|
||||
runCLI(`generate @nx/vite:configuration ${myApp}`);
|
||||
});
|
||||
afterEach(() => cleanupProject());
|
||||
|
||||
it('should serve application in dev mode with custom options', async () => {
|
||||
const port = 4212;
|
||||
const p = await runCommandUntil(
|
||||
`run ${myApp}:serve --port=${port} --https=true`,
|
||||
(output) => {
|
||||
return (
|
||||
output.includes('Local:') &&
|
||||
output.includes(`:${port}`) &&
|
||||
output.includes('https')
|
||||
);
|
||||
}
|
||||
);
|
||||
try {
|
||||
await promisifiedTreeKill(p.pid, 'SIGKILL');
|
||||
await killPorts(port);
|
||||
} catch (e) {
|
||||
// ignore
|
||||
}
|
||||
}, 200_000);
|
||||
|
||||
it('should test application', async () => {
|
||||
const result = await runCLIAsync(`test ${myApp}`);
|
||||
expect(result.combinedOutput).toContain(
|
||||
`Successfully ran target test for project ${myApp}`
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('set up new React app with --bundler=vite option', () => {
|
||||
beforeEach(async () => {
|
||||
proj = newProject();
|
||||
runCLI(`generate @nx/react:app ${myApp} --bundler=vite`);
|
||||
createFile(`apps/${myApp}/public/hello.md`, `# Hello World`);
|
||||
updateFile(
|
||||
`apps/${myApp}/src/environments/environment.prod.ts`,
|
||||
`export const environment = {
|
||||
production: true,
|
||||
myTestVar: 'MyProductionValue',
|
||||
};`
|
||||
);
|
||||
updateFile(
|
||||
`apps/${myApp}/src/environments/environment.ts`,
|
||||
`export const environment = {
|
||||
production: false,
|
||||
myTestVar: 'MyDevelopmentValue',
|
||||
};`
|
||||
);
|
||||
|
||||
updateFile(
|
||||
`apps/${myApp}/src/app/app.tsx`,
|
||||
`
|
||||
import { environment } from './../environments/environment';
|
||||
export function App() {
|
||||
return (
|
||||
<>
|
||||
<h1>{environment.myTestVar}</h1>
|
||||
<p>Welcome ${myApp}!</p>
|
||||
</>
|
||||
);
|
||||
}
|
||||
export default App;
|
||||
`
|
||||
);
|
||||
|
||||
updateJson(join('apps', myApp, 'project.json'), (config) => {
|
||||
config.targets.build.options.fileReplacements = [
|
||||
{
|
||||
replace: `apps/${myApp}/src/environments/environment.ts`,
|
||||
with: `apps/${myApp}/src/environments/environment.prod.ts`,
|
||||
},
|
||||
];
|
||||
return config;
|
||||
});
|
||||
});
|
||||
afterEach(() => cleanupProject());
|
||||
it('should build application', async () => {
|
||||
@ -120,14 +41,6 @@ describe('Vite Plugin', () => {
|
||||
expect(readFile(`dist/apps/${myApp}/favicon.ico`)).toBeDefined();
|
||||
expect(readFile(`dist/apps/${myApp}/hello.md`)).toBeDefined();
|
||||
expect(readFile(`dist/apps/${myApp}/index.html`)).toBeDefined();
|
||||
const fileArray = listFiles(`dist/apps/${myApp}/assets`);
|
||||
const mainBundle = fileArray.find((file) => file.endsWith('.js'));
|
||||
expect(readFile(`dist/apps/${myApp}/assets/${mainBundle}`)).toContain(
|
||||
'MyProductionValue'
|
||||
);
|
||||
expect(
|
||||
readFile(`dist/apps/${myApp}/assets/${mainBundle}`)
|
||||
).not.toContain('MyDevelopmentValue');
|
||||
rmDist();
|
||||
}, 200_000);
|
||||
});
|
||||
@ -202,47 +115,6 @@ describe('Vite Plugin', () => {
|
||||
}, 200_000);
|
||||
});
|
||||
|
||||
describe('convert @nx/web webpack app to vite using the vite:configuration generator', () => {
|
||||
beforeEach(() => {
|
||||
proj = newProject();
|
||||
runCLI(`generate @nx/web:app ${myApp} --bundler=webpack`);
|
||||
runCLI(`generate @nx/vite:configuration ${myApp}`);
|
||||
});
|
||||
afterEach(() => cleanupProject());
|
||||
it('should build application', async () => {
|
||||
runCLI(`build ${myApp}`);
|
||||
expect(readFile(`dist/apps/${myApp}/index.html`)).toBeDefined();
|
||||
const fileArray = listFiles(`dist/apps/${myApp}/assets`);
|
||||
const mainBundle = fileArray.find((file) => file.endsWith('.js'));
|
||||
expect(
|
||||
readFile(`dist/apps/${myApp}/assets/${mainBundle}`)
|
||||
).toBeDefined();
|
||||
rmDist();
|
||||
}, 200_000);
|
||||
|
||||
it('should serve application in dev mode with custom port', async () => {
|
||||
const port = 4212;
|
||||
const p = await runCommandUntil(
|
||||
`run ${myApp}:serve --port=${port}`,
|
||||
(output) => {
|
||||
return output.includes('Local:') && output.includes(`:${port}`);
|
||||
}
|
||||
);
|
||||
try {
|
||||
await promisifiedTreeKill(p.pid, 'SIGKILL');
|
||||
await killPorts(port);
|
||||
} catch {
|
||||
// ignore
|
||||
}
|
||||
}, 200_000);
|
||||
|
||||
it('should test application', async () => {
|
||||
const result = await runCLIAsync(`test ${myApp}`);
|
||||
expect(result.combinedOutput).toContain(
|
||||
`Successfully ran target test for project ${myApp}`
|
||||
);
|
||||
});
|
||||
}),
|
||||
100_000;
|
||||
});
|
||||
|
||||
@ -363,6 +235,8 @@ export default App;
|
||||
import { nxViteTsPaths } from '@nx/vite/plugins/nx-tsconfig-paths.plugin';
|
||||
|
||||
export default defineConfig({
|
||||
root: __dirname,
|
||||
cacheDir: '../../node_modules/.vite/libs/${lib}',
|
||||
server: {
|
||||
port: 4200,
|
||||
host: 'localhost',
|
||||
@ -371,14 +245,18 @@ export default App;
|
||||
react(),
|
||||
nxViteTsPaths()
|
||||
],
|
||||
build: {
|
||||
outDir: '../../dist/libs/${lib}',
|
||||
},
|
||||
test: {
|
||||
globals: true,
|
||||
cache: {
|
||||
dir: './node_modules/.vitest',
|
||||
dir: '../../node_modules/.vitest',
|
||||
},
|
||||
environment: 'jsdom',
|
||||
include: ['src/**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'],
|
||||
coverage: {
|
||||
reportsDirectory: '../../coverage/libs/${lib}',
|
||||
provider: "v8",
|
||||
enabled: true,
|
||||
lines: 100,
|
||||
@ -531,7 +409,7 @@ export default defineConfig({
|
||||
import { nxViteTsPaths } from '@nx/vite/plugins/nx-tsconfig-paths.plugin';
|
||||
|
||||
export default defineConfig({
|
||||
cacheDir: './node_modules/.vite/root-app',
|
||||
cacheDir: '../../node_modules/.vite/root-app',
|
||||
server: {
|
||||
port: 4200,
|
||||
host: 'localhost',
|
||||
|
||||
@ -61,8 +61,8 @@ describe('Web Components Applications with bundler set as vite', () => {
|
||||
`dist/apps/${appName}/_should_remove.txt`,
|
||||
`dist/apps/_should_not_remove.txt`
|
||||
);
|
||||
runCLI(`build ${appName}`);
|
||||
runCLI(`build ${libName}`);
|
||||
runCLI(`build ${appName} --emptyOutDir`);
|
||||
runCLI(`build ${libName} --emptyOutDir`);
|
||||
checkFilesDoNotExist(
|
||||
`dist/apps/${appName}/_should_remove.txt`,
|
||||
`dist/libs/${libName}/_should_remove.txt`
|
||||
|
||||
@ -129,8 +129,12 @@ export default defineVitestConfig({
|
||||
cache: {
|
||||
dir: '../node_modules/.vitest',
|
||||
},
|
||||
include: ['my-app/src/**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'],
|
||||
environment: 'nuxt',
|
||||
include: ['src/**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'],
|
||||
coverage: {
|
||||
reportsDirectory: '../coverage/app5176218',
|
||||
provider: 'v8',
|
||||
},
|
||||
},
|
||||
});
|
||||
"
|
||||
|
||||
@ -58,8 +58,12 @@ export function addVitest(
|
||||
cache: {
|
||||
dir: '${projectOffsetFromRoot}node_modules/.vitest',
|
||||
},
|
||||
include: ['${projectRoot}/src/**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'],
|
||||
environment: 'nuxt',
|
||||
include: ['src/**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'],
|
||||
coverage: {
|
||||
reportsDirectory: '${projectOffsetFromRoot}coverage/app5176218',
|
||||
provider: 'v8',
|
||||
},
|
||||
},
|
||||
});
|
||||
`
|
||||
|
||||
@ -6,6 +6,7 @@ import react from '@vitejs/plugin-react';
|
||||
import { nxViteTsPaths } from '@nx/vite/plugins/nx-tsconfig-paths.plugin';
|
||||
|
||||
export default defineConfig({
|
||||
root: __dirname,
|
||||
cacheDir: '../node_modules/.vite/my-lib',
|
||||
|
||||
plugins: [react(), nxViteTsPaths()],
|
||||
@ -20,6 +21,7 @@ export default defineConfig({
|
||||
cache: { dir: '../node_modules/.vitest' },
|
||||
environment: 'jsdom',
|
||||
include: ['src/**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'],
|
||||
coverage: { reportsDirectory: '../coverage/my-lib', provider: 'v8' },
|
||||
},
|
||||
});
|
||||
"
|
||||
@ -34,6 +36,7 @@ import * as path from 'path';
|
||||
import { nxViteTsPaths } from '@nx/vite/plugins/nx-tsconfig-paths.plugin';
|
||||
|
||||
export default defineConfig({
|
||||
root: __dirname,
|
||||
cacheDir: '../node_modules/.vite/my-lib',
|
||||
|
||||
plugins: [
|
||||
@ -54,6 +57,7 @@ export default defineConfig({
|
||||
// Configuration for building your library.
|
||||
// See: https://vitejs.dev/guide/build.html#library-mode
|
||||
build: {
|
||||
outDir: '../dist/my-lib',
|
||||
lib: {
|
||||
// Could also be a dictionary or array of multiple entry points.
|
||||
entry: 'src/index.ts',
|
||||
@ -76,6 +80,11 @@ export default defineConfig({
|
||||
},
|
||||
environment: 'jsdom',
|
||||
include: ['src/**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'],
|
||||
|
||||
coverage: {
|
||||
reportsDirectory: '../coverage/my-lib',
|
||||
provider: 'v8',
|
||||
},
|
||||
},
|
||||
});
|
||||
"
|
||||
|
||||
@ -40,6 +40,11 @@
|
||||
"version": "17.1.0-beta.2",
|
||||
"description": "Move target defaults",
|
||||
"implementation": "./src/migrations/update-17-1-0/move-target-defaults"
|
||||
},
|
||||
"update-vite-config": {
|
||||
"version": "17.2.0-beta.10",
|
||||
"description": "Update vite config.",
|
||||
"implementation": "./src/migrations/update-17-2-0/update-vite-config"
|
||||
}
|
||||
},
|
||||
"packageJsonUpdates": {
|
||||
|
||||
@ -53,6 +53,7 @@
|
||||
"./src/executors/*/schema.json": "./src/executors/*/schema.json",
|
||||
"./src/executors/*.impl": "./src/executors/*.impl.js",
|
||||
"./src/executors/*/compat": "./src/executors/*/compat.js",
|
||||
"./plugins/nx-tsconfig-paths.plugin": "./plugins/nx-tsconfig-paths.plugin.js"
|
||||
"./plugins/nx-tsconfig-paths.plugin": "./plugins/nx-tsconfig-paths.plugin.js",
|
||||
"./plugins/rollup-replace-files.plugin": "./plugins/rollup-replace-files.plugin.js"
|
||||
}
|
||||
}
|
||||
|
||||
@ -3,9 +3,19 @@
|
||||
/**
|
||||
* @function replaceFiles
|
||||
* @param {FileReplacement[]} replacements
|
||||
* @return {({name: "rollup-plugin-replace-files", enforce: "pre", Promise<resolveId>})}
|
||||
* @return {({name: "rollup-plugin-replace-files", enforce: "pre" | "post" | undefined, Promise<resolveId>})}
|
||||
*/
|
||||
export default function replaceFiles(replacements: FileReplacement[]) {
|
||||
export default function replaceFiles(replacements: FileReplacement[]): {
|
||||
name: string;
|
||||
enforce: 'pre' | 'post' | undefined;
|
||||
resolveId(
|
||||
source: any,
|
||||
importer: any,
|
||||
options: any
|
||||
): Promise<{
|
||||
id: string;
|
||||
}>;
|
||||
} {
|
||||
if (!replacements?.length) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@ -1,14 +1,15 @@
|
||||
import {
|
||||
detectPackageManager,
|
||||
ExecutorContext,
|
||||
joinPathFragments,
|
||||
logger,
|
||||
offsetFromRoot,
|
||||
stripIndents,
|
||||
writeJsonFile,
|
||||
} from '@nx/devkit';
|
||||
import {
|
||||
getProjectTsConfigPath,
|
||||
getViteBuildOptions,
|
||||
getViteSharedConfig,
|
||||
normalizeViteConfigFilePath,
|
||||
} from '../../utils/options-utils';
|
||||
import { ViteBuildExecutorOptions } from './schema';
|
||||
import {
|
||||
@ -18,33 +19,63 @@ import {
|
||||
getLockFileName,
|
||||
} from '@nx/js';
|
||||
import { existsSync, writeFileSync } from 'fs';
|
||||
import { resolve } from 'path';
|
||||
import { relative, resolve } from 'path';
|
||||
import { createAsyncIterable } from '@nx/devkit/src/utils/async-iterable';
|
||||
import {
|
||||
createBuildableTsConfig,
|
||||
validateTypes,
|
||||
} from '../../utils/executor-utils';
|
||||
import { BuildOptions } from 'vite';
|
||||
|
||||
export async function* viteBuildExecutor(
|
||||
options: ViteBuildExecutorOptions,
|
||||
options: Record<string, any> & ViteBuildExecutorOptions,
|
||||
context: ExecutorContext
|
||||
) {
|
||||
// Allows ESM to be required in CJS modules. Vite will be published as ESM in the future.
|
||||
const { mergeConfig, build } = await (Function(
|
||||
const { mergeConfig, build, loadConfigFromFile } = await (Function(
|
||||
'return import("vite")'
|
||||
)() as Promise<typeof import('vite')>);
|
||||
|
||||
const projectRoot =
|
||||
context.projectsConfigurations.projects[context.projectName].root;
|
||||
|
||||
createBuildableTsConfig(projectRoot, options, context);
|
||||
|
||||
const normalizedOptions = normalizeOptions(options);
|
||||
const viteConfigPath = normalizeViteConfigFilePath(
|
||||
context.root,
|
||||
projectRoot,
|
||||
options.configFile
|
||||
);
|
||||
const root =
|
||||
projectRoot === '.'
|
||||
? process.cwd()
|
||||
: relative(context.cwd, joinPathFragments(context.root, projectRoot));
|
||||
|
||||
const { buildOptions, otherOptions } = await getExtraArgs(options);
|
||||
|
||||
const resolved = await loadConfigFromFile(
|
||||
{
|
||||
mode: otherOptions?.mode ?? 'production',
|
||||
command: 'build',
|
||||
},
|
||||
viteConfigPath
|
||||
);
|
||||
|
||||
const outDir =
|
||||
joinPathFragments(offsetFromRoot(projectRoot), options.outputPath) ??
|
||||
resolved?.config?.build?.outDir;
|
||||
|
||||
const buildConfig = mergeConfig(
|
||||
getViteSharedConfig(normalizedOptions, false, context),
|
||||
{
|
||||
build: getViteBuildOptions(normalizedOptions, context),
|
||||
// This should not be needed as it's going to be set in vite.config.ts
|
||||
// but leaving it here in case someone did not migrate correctly
|
||||
root: resolved.config.root ?? root,
|
||||
configFile: viteConfigPath,
|
||||
},
|
||||
{
|
||||
build: {
|
||||
outDir,
|
||||
...buildOptions,
|
||||
},
|
||||
...otherOptions,
|
||||
}
|
||||
);
|
||||
|
||||
@ -60,7 +91,14 @@ export async function* viteBuildExecutor(
|
||||
|
||||
const libraryPackageJson = resolve(projectRoot, 'package.json');
|
||||
const rootPackageJson = resolve(context.root, 'package.json');
|
||||
const distPackageJson = resolve(normalizedOptions.outputPath, 'package.json');
|
||||
|
||||
// Here, we want the outdir relative to the workspace root.
|
||||
// So, we calculate the relative path from the workspace root to the outdir.
|
||||
const outDirRelativeToWorkspaceRoot = outDir.replaceAll('../', '');
|
||||
const distPackageJson = resolve(
|
||||
outDirRelativeToWorkspaceRoot,
|
||||
'package.json'
|
||||
);
|
||||
|
||||
// Generate a package.json if option has been set.
|
||||
if (options.generatePackageJson) {
|
||||
@ -83,7 +121,10 @@ export async function* viteBuildExecutor(
|
||||
|
||||
builtPackageJson.type = 'module';
|
||||
|
||||
writeJsonFile(`${options.outputPath}/package.json`, builtPackageJson);
|
||||
writeJsonFile(
|
||||
`${outDirRelativeToWorkspaceRoot}/package.json`,
|
||||
builtPackageJson
|
||||
);
|
||||
const packageManager = detectPackageManager(context.root);
|
||||
|
||||
const lockFile = createLockFile(
|
||||
@ -92,7 +133,7 @@ export async function* viteBuildExecutor(
|
||||
packageManager
|
||||
);
|
||||
writeFileSync(
|
||||
`${options.outputPath}/${getLockFileName(packageManager)}`,
|
||||
`${outDirRelativeToWorkspaceRoot}/${getLockFileName(packageManager)}`,
|
||||
lockFile,
|
||||
{
|
||||
encoding: 'utf-8',
|
||||
@ -107,7 +148,7 @@ export async function* viteBuildExecutor(
|
||||
) {
|
||||
await copyAssets(
|
||||
{
|
||||
outputPath: normalizedOptions.outputPath,
|
||||
outputPath: outDirRelativeToWorkspaceRoot,
|
||||
assets: [
|
||||
{
|
||||
input: projectRoot,
|
||||
@ -142,22 +183,66 @@ export async function* viteBuildExecutor(
|
||||
} else {
|
||||
const output = watcherOrOutput?.['output'] || watcherOrOutput?.[0]?.output;
|
||||
const fileName = output?.[0]?.fileName || 'main.cjs';
|
||||
const outfile = resolve(normalizedOptions.outputPath, fileName);
|
||||
const outfile = resolve(outDirRelativeToWorkspaceRoot, fileName);
|
||||
yield { success: true, outfile };
|
||||
}
|
||||
}
|
||||
|
||||
function normalizeOptions(options: ViteBuildExecutorOptions) {
|
||||
const normalizedOptions = { ...options };
|
||||
|
||||
// coerce watch to null or {} to match with Vite's watch config
|
||||
if (options.watch === false) {
|
||||
normalizedOptions.watch = null;
|
||||
} else if (options.watch === true) {
|
||||
normalizedOptions.watch = {};
|
||||
async function getExtraArgs(options: ViteBuildExecutorOptions): Promise<{
|
||||
buildOptions: BuildOptions;
|
||||
otherOptions: Record<string, any>;
|
||||
}> {
|
||||
// support passing extra args to vite cli
|
||||
const schema = await import('./schema.json');
|
||||
const extraArgs = {};
|
||||
for (const key of Object.keys(options)) {
|
||||
if (!schema.properties[key]) {
|
||||
extraArgs[key] = options[key];
|
||||
}
|
||||
}
|
||||
|
||||
return normalizedOptions;
|
||||
const buildOptions = {} as BuildOptions;
|
||||
const buildSchemaKeys = [
|
||||
'target',
|
||||
'polyfillModulePreload',
|
||||
'modulePreload',
|
||||
'outDir',
|
||||
'assetsDir',
|
||||
'assetsInlineLimit',
|
||||
'cssCodeSplit',
|
||||
'cssTarget',
|
||||
'cssMinify',
|
||||
'sourcemap',
|
||||
'minify',
|
||||
'terserOptions',
|
||||
'rollupOptions',
|
||||
'commonjsOptions',
|
||||
'dynamicImportVarsOptions',
|
||||
'write',
|
||||
'emptyOutDir',
|
||||
'copyPublicDir',
|
||||
'manifest',
|
||||
'lib',
|
||||
'ssr',
|
||||
'ssrManifest',
|
||||
'ssrEmitAssets',
|
||||
'reportCompressedSize',
|
||||
'chunkSizeWarningLimit',
|
||||
'watch',
|
||||
];
|
||||
const otherOptions = {};
|
||||
for (const key of Object.keys(extraArgs)) {
|
||||
if (buildSchemaKeys.includes(key)) {
|
||||
buildOptions[key] = extraArgs[key];
|
||||
} else {
|
||||
otherOptions[key] = extraArgs[key];
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
buildOptions,
|
||||
otherOptions,
|
||||
};
|
||||
}
|
||||
|
||||
export default viteBuildExecutor;
|
||||
|
||||
18
packages/vite/src/executors/build/schema.d.ts
vendored
18
packages/vite/src/executors/build/schema.d.ts
vendored
@ -1,23 +1,11 @@
|
||||
import type { FileReplacement } from '../../plugins/rollup-replace-files.plugin';
|
||||
export interface ViteBuildExecutorOptions {
|
||||
outputPath: string;
|
||||
emptyOutDir?: boolean;
|
||||
base?: string;
|
||||
outputPath?: string;
|
||||
skipTypeCheck?: boolean;
|
||||
configFile?: string;
|
||||
fileReplacements?: FileReplacement[];
|
||||
force?: boolean;
|
||||
sourcemap?: boolean | 'inline' | 'hidden';
|
||||
minify?: boolean | 'esbuild' | 'terser';
|
||||
manifest?: boolean | string;
|
||||
ssrManifest?: boolean | string;
|
||||
logLevel?: 'info' | 'warn' | 'error' | 'silent';
|
||||
mode?: string;
|
||||
ssr?: boolean | string;
|
||||
watch?: object | boolean;
|
||||
target?: string | string[];
|
||||
watch?: boolean;
|
||||
generatePackageJson?: boolean;
|
||||
includeDevDependenciesInPackageJson?: boolean;
|
||||
cssCodeSplit?: boolean;
|
||||
buildLibsFromSource?: boolean;
|
||||
skipTypeCheck?: boolean;
|
||||
}
|
||||
|
||||
@ -28,11 +28,6 @@
|
||||
"description": "Skip type-checking via TypeScript. Skipping type-checking speeds up the build but type errors are not caught.",
|
||||
"default": false
|
||||
},
|
||||
"base": {
|
||||
"type": "string",
|
||||
"description": "Base public path when served in development or production.",
|
||||
"alias": "baseHref"
|
||||
},
|
||||
"configFile": {
|
||||
"type": "string",
|
||||
"description": "The name of the Vite.js configuration file.",
|
||||
@ -61,87 +56,6 @@
|
||||
},
|
||||
"default": []
|
||||
},
|
||||
"emptyOutDir": {
|
||||
"description": "When set to false, outputPath will not be emptied during the build process.",
|
||||
"type": "boolean",
|
||||
"default": true
|
||||
},
|
||||
"sourcemap": {
|
||||
"description": "Output sourcemaps. Use 'hidden' for use with error reporting tools without generating sourcemap comment.",
|
||||
"oneOf": [
|
||||
{
|
||||
"type": "boolean"
|
||||
},
|
||||
{
|
||||
"type": "string"
|
||||
}
|
||||
]
|
||||
},
|
||||
"target": {
|
||||
"description": "Browser compatibility target for the final bundle. For more info: https://vitejs.dev/config/build-options.html#build-target",
|
||||
"type": "string"
|
||||
},
|
||||
"minify": {
|
||||
"description": "Output sourcemaps. Use 'hidden' for use with error reporting tools without generating sourcemap comment.",
|
||||
"oneOf": [
|
||||
{
|
||||
"type": "boolean"
|
||||
},
|
||||
{
|
||||
"type": "string"
|
||||
}
|
||||
]
|
||||
},
|
||||
"manifest": {
|
||||
"description": "Output sourcemaps. Use 'hidden' for use with error reporting tools without generating sourcemap comment.",
|
||||
"oneOf": [
|
||||
{
|
||||
"type": "boolean"
|
||||
},
|
||||
{
|
||||
"type": "string"
|
||||
}
|
||||
]
|
||||
},
|
||||
"ssrManifest": {
|
||||
"description": "When set to true, the build will also generate an SSR manifest for determining style links and asset preload directives in production. When the value is a string, it will be used as the manifest file name.",
|
||||
"oneOf": [
|
||||
{
|
||||
"type": "boolean"
|
||||
},
|
||||
{
|
||||
"type": "string"
|
||||
}
|
||||
]
|
||||
},
|
||||
"ssr": {
|
||||
"description": "Produce SSR-oriented build. The value can be a string to directly specify the SSR entry, or true, which requires specifying the SSR entry via rollupOptions.input.",
|
||||
"oneOf": [
|
||||
{
|
||||
"type": "boolean"
|
||||
},
|
||||
{
|
||||
"type": "string"
|
||||
}
|
||||
]
|
||||
},
|
||||
"logLevel": {
|
||||
"type": "string",
|
||||
"description": "Adjust console output verbosity.",
|
||||
"enum": ["info", "warn", "error", "silent"]
|
||||
},
|
||||
"mode": {
|
||||
"type": "string",
|
||||
"description": "Mode to run the build in."
|
||||
},
|
||||
"force": {
|
||||
"description": "Force the optimizer to ignore the cache and re-bundle",
|
||||
"type": "boolean"
|
||||
},
|
||||
"cssCodeSplit": {
|
||||
"description": "Enable/disable CSS code splitting. When enabled, CSS imported in async chunks will be inlined into the async chunk itself and inserted when the chunk is loaded.",
|
||||
"type": "boolean"
|
||||
},
|
||||
"watch": {
|
||||
"description": "Enable re-building when files change.",
|
||||
"oneOf": [
|
||||
|
||||
@ -1,16 +1,20 @@
|
||||
import { ExecutorContext } from '@nx/devkit';
|
||||
import type { InlineConfig, ViteDevServer } from 'vite';
|
||||
import { ExecutorContext, joinPathFragments } from '@nx/devkit';
|
||||
import {
|
||||
loadConfigFromFile,
|
||||
type InlineConfig,
|
||||
type ViteDevServer,
|
||||
} from 'vite';
|
||||
|
||||
import {
|
||||
getNxTargetOptions,
|
||||
getViteBuildOptions,
|
||||
getViteServerOptions,
|
||||
getViteSharedConfig,
|
||||
normalizeViteConfigFilePath,
|
||||
} from '../../utils/options-utils';
|
||||
|
||||
import { ViteDevServerExecutorOptions } from './schema';
|
||||
import { ViteBuildExecutorOptions } from '../build/schema';
|
||||
import { createBuildableTsConfig } from '../../utils/executor-utils';
|
||||
import { relative } from 'path';
|
||||
|
||||
export async function* viteDevServerExecutor(
|
||||
options: ViteDevServerExecutorOptions,
|
||||
@ -23,7 +27,10 @@ export async function* viteDevServerExecutor(
|
||||
|
||||
const projectRoot =
|
||||
context.projectsConfigurations.projects[context.projectName].root;
|
||||
|
||||
const root =
|
||||
projectRoot === '.'
|
||||
? process.cwd()
|
||||
: relative(context.cwd, joinPathFragments(context.root, projectRoot));
|
||||
createBuildableTsConfig(projectRoot, options, context);
|
||||
|
||||
// Retrieve the option for the configured buildTarget.
|
||||
@ -31,20 +38,33 @@ export async function* viteDevServerExecutor(
|
||||
options.buildTarget,
|
||||
context
|
||||
);
|
||||
|
||||
// Merge the options from the build and dev-serve targets.
|
||||
// The latter takes precedence.
|
||||
const mergedOptions = {
|
||||
...buildTargetOptions,
|
||||
...options,
|
||||
};
|
||||
|
||||
// Add the server specific configuration.
|
||||
const serverConfig: InlineConfig = mergeConfig(
|
||||
getViteSharedConfig(mergedOptions, options.clearScreen, context),
|
||||
const viteConfigPath = normalizeViteConfigFilePath(
|
||||
context.root,
|
||||
projectRoot,
|
||||
buildTargetOptions.configFile
|
||||
);
|
||||
const extraArgs = await getExtraArgs(options);
|
||||
const resolved = await loadConfigFromFile(
|
||||
{
|
||||
build: getViteBuildOptions(mergedOptions, context),
|
||||
server: await getViteServerOptions(mergedOptions, context),
|
||||
mode: extraArgs?.mode ?? 'production',
|
||||
command: 'build',
|
||||
},
|
||||
viteConfigPath
|
||||
);
|
||||
|
||||
const serverConfig: InlineConfig = mergeConfig(
|
||||
{
|
||||
// This should not be needed as it's going to be set in vite.config.ts
|
||||
// but leaving it here in case someone did not migrate correctly
|
||||
root: resolved.config.root ?? root,
|
||||
configFile: viteConfigPath,
|
||||
},
|
||||
{
|
||||
server: {
|
||||
...(await getViteServerOptions(options, context)),
|
||||
...extraArgs,
|
||||
},
|
||||
...extraArgs,
|
||||
}
|
||||
);
|
||||
|
||||
@ -90,3 +110,18 @@ async function runViteDevServer(server: ViteDevServer): Promise<void> {
|
||||
}
|
||||
|
||||
export default viteDevServerExecutor;
|
||||
|
||||
async function getExtraArgs(
|
||||
options: ViteDevServerExecutorOptions
|
||||
): Promise<InlineConfig> {
|
||||
// support passing extra args to vite cli
|
||||
const schema = await import('./schema.json');
|
||||
const extraArgs = {};
|
||||
for (const key of Object.keys(options)) {
|
||||
if (!schema.properties[key]) {
|
||||
extraArgs[key] = options[key];
|
||||
}
|
||||
}
|
||||
|
||||
return extraArgs as InlineConfig;
|
||||
}
|
||||
|
||||
@ -2,14 +2,4 @@ export interface ViteDevServerExecutorOptions {
|
||||
buildTarget: string;
|
||||
buildLibsFromSource?: boolean;
|
||||
proxyConfig?: string;
|
||||
port?: number;
|
||||
host?: string | boolean;
|
||||
https?: boolean | Json;
|
||||
hmr?: boolean;
|
||||
open?: string | boolean;
|
||||
cors?: boolean;
|
||||
logLevel?: 'info' | 'warn' | 'error' | 'silent';
|
||||
mode?: string;
|
||||
clearScreen?: boolean;
|
||||
force?: boolean;
|
||||
}
|
||||
|
||||
@ -30,69 +30,6 @@
|
||||
"type": "string",
|
||||
"description": "Path to the proxy configuration file.",
|
||||
"x-completion-type": "file"
|
||||
},
|
||||
"port": {
|
||||
"type": "number",
|
||||
"description": "Port to listen on.",
|
||||
"x-priority": "important"
|
||||
},
|
||||
"host": {
|
||||
"description": "Specify which IP addresses the server should listen on.",
|
||||
"oneOf": [
|
||||
{
|
||||
"type": "boolean"
|
||||
},
|
||||
{
|
||||
"type": "string"
|
||||
}
|
||||
]
|
||||
},
|
||||
"https": {
|
||||
"oneOf": [
|
||||
{
|
||||
"type": "boolean"
|
||||
},
|
||||
{
|
||||
"type": "object"
|
||||
}
|
||||
],
|
||||
"description": "Serve using HTTPS. https://vitejs.dev/config/server-options.html#server-https"
|
||||
},
|
||||
"hmr": {
|
||||
"description": "Enable hot module replacement. For more options, use the 'hmr' option in the Vite configuration file.",
|
||||
"type": "boolean"
|
||||
},
|
||||
"open": {
|
||||
"description": "Automatically open the app in the browser on server start. When the value is a string, it will be used as the URL's pathname.",
|
||||
"oneOf": [
|
||||
{
|
||||
"type": "boolean"
|
||||
},
|
||||
{
|
||||
"type": "string"
|
||||
}
|
||||
]
|
||||
},
|
||||
"cors": {
|
||||
"description": "Configure CORS for the dev server.",
|
||||
"type": "boolean"
|
||||
},
|
||||
"logLevel": {
|
||||
"type": "string",
|
||||
"description": "Adjust console output verbosity.",
|
||||
"enum": ["info", "warn", "error", "silent"]
|
||||
},
|
||||
"mode": {
|
||||
"type": "string",
|
||||
"description": "Mode to run the server in."
|
||||
},
|
||||
"clearScreen": {
|
||||
"description": "Set to false to prevent Vite from clearing the terminal screen when logging certain messages.",
|
||||
"type": "boolean"
|
||||
},
|
||||
"force": {
|
||||
"description": "Force the optimizer to ignore the cache and re-bundle",
|
||||
"type": "boolean"
|
||||
}
|
||||
},
|
||||
"definitions": {},
|
||||
|
||||
@ -1,27 +1,30 @@
|
||||
import { ExecutorContext, parseTargetString, runExecutor } from '@nx/devkit';
|
||||
import {
|
||||
ExecutorContext,
|
||||
joinPathFragments,
|
||||
offsetFromRoot,
|
||||
parseTargetString,
|
||||
runExecutor,
|
||||
} from '@nx/devkit';
|
||||
import type { InlineConfig, PreviewServer } from 'vite';
|
||||
import {
|
||||
getNxTargetOptions,
|
||||
getViteBuildOptions,
|
||||
getVitePreviewOptions,
|
||||
getViteSharedConfig,
|
||||
normalizeViteConfigFilePath,
|
||||
} from '../../utils/options-utils';
|
||||
import { ViteBuildExecutorOptions } from '../build/schema';
|
||||
import { VitePreviewServerExecutorOptions } from './schema';
|
||||
|
||||
interface CustomBuildTargetOptions {
|
||||
outputPath: string;
|
||||
}
|
||||
import { relative } from 'path';
|
||||
|
||||
export async function* vitePreviewServerExecutor(
|
||||
options: VitePreviewServerExecutorOptions,
|
||||
context: ExecutorContext
|
||||
) {
|
||||
// Allows ESM to be required in CJS modules. Vite will be published as ESM in the future.
|
||||
const { mergeConfig, preview } = await (Function(
|
||||
const { mergeConfig, preview, loadConfigFromFile } = await (Function(
|
||||
'return import("vite")'
|
||||
)() as Promise<typeof import('vite')>);
|
||||
|
||||
const projectRoot =
|
||||
context.projectsConfigurations.projects[context.projectName].root;
|
||||
const target = parseTargetString(options.buildTarget, context);
|
||||
const targetConfiguration =
|
||||
context.projectsConfigurations.projects[target.project]?.targets[
|
||||
@ -36,35 +39,63 @@ export async function* vitePreviewServerExecutor(
|
||||
targetConfiguration.executor !== '@nrwl/vite:build';
|
||||
|
||||
// Retrieve the option for the configured buildTarget.
|
||||
const buildTargetOptions:
|
||||
| ViteBuildExecutorOptions
|
||||
| CustomBuildTargetOptions = getNxTargetOptions(
|
||||
const buildTargetOptions: ViteBuildExecutorOptions = getNxTargetOptions(
|
||||
options.buildTarget,
|
||||
context
|
||||
);
|
||||
const viteConfigPath = normalizeViteConfigFilePath(
|
||||
context.root,
|
||||
projectRoot,
|
||||
buildTargetOptions.configFile
|
||||
);
|
||||
const extraArgs = await getExtraArgs(options);
|
||||
const resolved = await loadConfigFromFile(
|
||||
{
|
||||
mode: extraArgs?.mode ?? 'production',
|
||||
command: 'build',
|
||||
},
|
||||
viteConfigPath
|
||||
);
|
||||
|
||||
const outputPath = options.staticFilePath ?? buildTargetOptions.outputPath;
|
||||
const outDir =
|
||||
options.staticFilePath ??
|
||||
joinPathFragments(
|
||||
offsetFromRoot(projectRoot),
|
||||
buildTargetOptions.outputPath
|
||||
) ??
|
||||
resolved?.config?.build?.outDir;
|
||||
|
||||
if (!outputPath) {
|
||||
if (!outDir) {
|
||||
throw new Error(
|
||||
`Could not infer the "outputPath". It should either be a property of the "${options.buildTarget}" buildTarget or provided explicitly as a "staticFilePath" option.`
|
||||
`Could not infer the "outputPath" or "outDir". It should be set in your vite.config.ts, or as a property of the "${options.buildTarget}" buildTarget or provided explicitly as a "staticFilePath" option.`
|
||||
);
|
||||
}
|
||||
const root =
|
||||
projectRoot === '.'
|
||||
? process.cwd()
|
||||
: relative(context.cwd, joinPathFragments(context.root, projectRoot));
|
||||
|
||||
// Merge the options from the build and preview-serve targets.
|
||||
// The latter takes precedence.
|
||||
const mergedOptions = {
|
||||
...{ watch: {} },
|
||||
build: {
|
||||
outDir,
|
||||
},
|
||||
...(isCustomBuildTarget ? {} : buildTargetOptions),
|
||||
...options,
|
||||
outputPath,
|
||||
...extraArgs,
|
||||
};
|
||||
|
||||
// Retrieve the server configuration.
|
||||
const serverConfig: InlineConfig = mergeConfig(
|
||||
getViteSharedConfig(mergedOptions, options.clearScreen, context),
|
||||
{
|
||||
build: getViteBuildOptions(mergedOptions, context),
|
||||
// This should not be needed as it's going to be set in vite.config.ts
|
||||
// but leaving it here in case someone did not migrate correctly
|
||||
root: resolved.config.root ?? root,
|
||||
configFile: viteConfigPath,
|
||||
},
|
||||
{
|
||||
...mergedOptions,
|
||||
preview: getVitePreviewOptions(mergedOptions, context),
|
||||
}
|
||||
);
|
||||
@ -146,3 +177,18 @@ function closeServer(server?: PreviewServer): Promise<void> {
|
||||
}
|
||||
|
||||
export default vitePreviewServerExecutor;
|
||||
|
||||
async function getExtraArgs(
|
||||
options: VitePreviewServerExecutorOptions
|
||||
): Promise<InlineConfig> {
|
||||
// support passing extra args to vite cli
|
||||
const schema = await import('./schema.json');
|
||||
const extraArgs = {};
|
||||
for (const key of Object.keys(options)) {
|
||||
if (!schema.properties[key]) {
|
||||
extraArgs[key] = options[key];
|
||||
}
|
||||
}
|
||||
|
||||
return extraArgs as InlineConfig;
|
||||
}
|
||||
|
||||
@ -1,12 +1,5 @@
|
||||
export interface VitePreviewServerExecutorOptions {
|
||||
buildTarget: string;
|
||||
proxyConfig?: string;
|
||||
port?: number;
|
||||
host?: string | boolean;
|
||||
https?: boolean | Json;
|
||||
open?: string | boolean;
|
||||
logLevel?: 'info' | 'warn' | 'error' | 'silent';
|
||||
mode?: string;
|
||||
clearScreen?: boolean;
|
||||
staticFilePath?: string;
|
||||
}
|
||||
|
||||
@ -25,56 +25,6 @@
|
||||
"description": "Path to the proxy configuration file.",
|
||||
"x-completion-type": "file"
|
||||
},
|
||||
"port": {
|
||||
"type": "number",
|
||||
"description": "Port to listen on."
|
||||
},
|
||||
"host": {
|
||||
"description": "Specify which IP addresses the server should listen on.",
|
||||
"oneOf": [
|
||||
{
|
||||
"type": "boolean"
|
||||
},
|
||||
{
|
||||
"type": "string"
|
||||
}
|
||||
]
|
||||
},
|
||||
"https": {
|
||||
"oneOf": [
|
||||
{
|
||||
"type": "boolean"
|
||||
},
|
||||
{
|
||||
"type": "object"
|
||||
}
|
||||
],
|
||||
"description": "Serve using HTTPS. https://vitejs.dev/config/server-options.html#server-https"
|
||||
},
|
||||
"open": {
|
||||
"description": "Automatically open the app in the browser on server start. When the value is a string, it will be used as the URL's pathname.",
|
||||
"oneOf": [
|
||||
{
|
||||
"type": "boolean"
|
||||
},
|
||||
{
|
||||
"type": "string"
|
||||
}
|
||||
]
|
||||
},
|
||||
"logLevel": {
|
||||
"type": "string",
|
||||
"description": "Adjust console output verbosity.",
|
||||
"enum": ["info", "warn", "error", "silent"]
|
||||
},
|
||||
"mode": {
|
||||
"type": "string",
|
||||
"description": "Mode to run the server in."
|
||||
},
|
||||
"clearScreen": {
|
||||
"description": "Set to false to prevent Vite from clearing the terminal screen when logging certain messages.",
|
||||
"type": "boolean"
|
||||
},
|
||||
"staticFilePath": {
|
||||
"type": "string",
|
||||
"description": "Path where the build artifacts are located. If not provided then it will be infered from the buildTarget executor options as outputPath",
|
||||
|
||||
36
packages/vite/src/executors/test/lib/nx-reporter.ts
Normal file
36
packages/vite/src/executors/test/lib/nx-reporter.ts
Normal file
@ -0,0 +1,36 @@
|
||||
import type { File, Reporter } from 'vitest';
|
||||
|
||||
export class NxReporter implements Reporter {
|
||||
deferred: {
|
||||
promise: Promise<boolean>;
|
||||
resolve: (val: boolean) => void;
|
||||
};
|
||||
|
||||
constructor(private watch: boolean) {
|
||||
this.setupDeferred();
|
||||
}
|
||||
|
||||
async *[Symbol.asyncIterator]() {
|
||||
do {
|
||||
const hasErrors = await this.deferred.promise;
|
||||
yield { hasErrors };
|
||||
this.setupDeferred();
|
||||
} while (this.watch);
|
||||
}
|
||||
|
||||
private setupDeferred() {
|
||||
let resolve: (val: boolean) => void;
|
||||
this.deferred = {
|
||||
promise: new Promise((res) => {
|
||||
resolve = res;
|
||||
}),
|
||||
resolve,
|
||||
};
|
||||
}
|
||||
|
||||
onFinished(files: File[], errors?: unknown[]) {
|
||||
const hasErrors =
|
||||
files.some((f) => f.result?.state === 'fail') || errors?.length > 0;
|
||||
this.deferred.resolve(hasErrors);
|
||||
}
|
||||
}
|
||||
88
packages/vite/src/executors/test/lib/utils.ts
Normal file
88
packages/vite/src/executors/test/lib/utils.ts
Normal file
@ -0,0 +1,88 @@
|
||||
import {
|
||||
ExecutorContext,
|
||||
joinPathFragments,
|
||||
logger,
|
||||
stripIndents,
|
||||
} from '@nx/devkit';
|
||||
import { VitestExecutorOptions } from '../schema';
|
||||
import { normalizeViteConfigFilePath } from '../../../utils/options-utils';
|
||||
import { relative } from 'path';
|
||||
import { NxReporter } from './nx-reporter';
|
||||
|
||||
export async function getOptions(
|
||||
options: VitestExecutorOptions,
|
||||
context: ExecutorContext,
|
||||
projectRoot: string,
|
||||
extraArgs: Record<string, any>
|
||||
) {
|
||||
// Allows ESM to be required in CJS modules. Vite will be published as ESM in the future.
|
||||
const { loadConfigFromFile, mergeConfig } = await (Function(
|
||||
'return import("vite")'
|
||||
)() as Promise<typeof import('vite')>);
|
||||
|
||||
const viteConfigPath = normalizeViteConfigFilePath(
|
||||
context.root,
|
||||
projectRoot,
|
||||
options.configFile
|
||||
);
|
||||
|
||||
if (!viteConfigPath) {
|
||||
throw new Error(
|
||||
stripIndents`
|
||||
Unable to load test config from config file ${viteConfigPath}.
|
||||
|
||||
Please make sure that vitest is configured correctly,
|
||||
or use the @nx/vite:vitest generator to configure it for you.
|
||||
You can read more here: https://nx.dev/nx-api/vite/generators/vitest
|
||||
`
|
||||
);
|
||||
}
|
||||
|
||||
const resolved = await loadConfigFromFile(
|
||||
{
|
||||
mode: extraArgs?.mode ?? 'production',
|
||||
command: 'serve',
|
||||
},
|
||||
viteConfigPath
|
||||
);
|
||||
|
||||
if (!viteConfigPath || !resolved?.config?.['test']) {
|
||||
logger.warn(stripIndents`Unable to load test config from config file ${
|
||||
resolved?.path ?? viteConfigPath
|
||||
}
|
||||
Some settings may not be applied as expected.
|
||||
You can manually set the config in the project, ${
|
||||
context.projectName
|
||||
}, configuration.
|
||||
`);
|
||||
}
|
||||
const root =
|
||||
projectRoot === '.'
|
||||
? process.cwd()
|
||||
: relative(context.cwd, joinPathFragments(context.root, projectRoot));
|
||||
|
||||
const settings = {
|
||||
...extraArgs,
|
||||
// This should not be needed as it's going to be set in vite.config.ts
|
||||
// but leaving it here in case someone did not migrate correctly
|
||||
root: resolved.config.root ?? root,
|
||||
configFile: viteConfigPath,
|
||||
};
|
||||
|
||||
return mergeConfig(resolved?.config?.['test'] ?? {}, settings);
|
||||
}
|
||||
|
||||
export async function getExtraArgs(
|
||||
options: VitestExecutorOptions
|
||||
): Promise<Record<string, any>> {
|
||||
// support passing extra args to vite cli
|
||||
const schema = await import('../schema.json');
|
||||
const extraArgs: Record<string, any> = {};
|
||||
for (const key of Object.keys(options)) {
|
||||
if (!schema.properties[key]) {
|
||||
extraArgs[key] = options[key];
|
||||
}
|
||||
}
|
||||
|
||||
return extraArgs;
|
||||
}
|
||||
10
packages/vite/src/executors/test/schema.d.ts
vendored
10
packages/vite/src/executors/test/schema.d.ts
vendored
@ -1,12 +1,6 @@
|
||||
export interface VitestExecutorOptions {
|
||||
config?: string;
|
||||
passWithNoTests?: boolean;
|
||||
testNamePattern?: string;
|
||||
mode?: 'test' | 'benchmark' | 'typecheck';
|
||||
reporters?: string[];
|
||||
watch?: boolean;
|
||||
update?: boolean;
|
||||
configFile?: string;
|
||||
reportsDirectory?: string;
|
||||
coverage?: boolean;
|
||||
testFiles?: string[];
|
||||
watch?: boolean;
|
||||
}
|
||||
|
||||
@ -6,52 +6,12 @@
|
||||
"description": "Test using Vitest.",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"config": {
|
||||
"configFile": {
|
||||
"type": "string",
|
||||
"description": "The path to the local vitest config",
|
||||
"x-completion-type": "file",
|
||||
"x-completion-glob": "@(vitest|vite).config@(.js|.ts)"
|
||||
},
|
||||
"passWithNoTests": {
|
||||
"type": "boolean",
|
||||
"default": true,
|
||||
"description": "Pass the test even if no tests are found"
|
||||
},
|
||||
"testNamePattern": {
|
||||
"type": "string",
|
||||
"description": "Run tests with full names matching the pattern"
|
||||
},
|
||||
"mode": {
|
||||
"type": "string",
|
||||
"enum": ["test", "benchmark", "typecheck"],
|
||||
"default": "test",
|
||||
"description": "The mode that vitest will run on",
|
||||
"x-priority": "important"
|
||||
},
|
||||
"watch": {
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"description": "Enable watch mode"
|
||||
},
|
||||
"reporters": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": "An array of reporters to pass to vitest"
|
||||
},
|
||||
"update": {
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"alias": "u",
|
||||
"description": "Update snapshots",
|
||||
"x-priority": "important"
|
||||
},
|
||||
"coverage": {
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"description": "Enable coverage report",
|
||||
"x-priority": "important"
|
||||
"x-completion-glob": "@(vitest|vite).config@(.js|.ts)",
|
||||
"aliases": ["config"]
|
||||
},
|
||||
"reportsDirectory": {
|
||||
"type": "string",
|
||||
@ -61,6 +21,10 @@
|
||||
"aliases": ["testFile"],
|
||||
"type": "array",
|
||||
"items": { "type": "string" }
|
||||
},
|
||||
"watch": {
|
||||
"description": "Watch files for changes and rerun tests related to changed files.",
|
||||
"type": "boolean"
|
||||
}
|
||||
},
|
||||
"required": [],
|
||||
|
||||
@ -1,51 +1,9 @@
|
||||
import {
|
||||
ExecutorContext,
|
||||
joinPathFragments,
|
||||
logger,
|
||||
readJsonFile,
|
||||
stripIndents,
|
||||
workspaceRoot,
|
||||
} from '@nx/devkit';
|
||||
import type { CoverageOptions, File, Reporter } from 'vitest';
|
||||
import { ExecutorContext, workspaceRoot } from '@nx/devkit';
|
||||
import { VitestExecutorOptions } from './schema';
|
||||
import { join, relative, resolve } from 'path';
|
||||
import { existsSync } from 'fs';
|
||||
import { resolve } from 'path';
|
||||
import { registerTsConfigPaths } from '@nx/js/src/internal';
|
||||
|
||||
class NxReporter implements Reporter {
|
||||
deferred: {
|
||||
promise: Promise<boolean>;
|
||||
resolve: (val: boolean) => void;
|
||||
};
|
||||
|
||||
constructor(private watch: boolean) {
|
||||
this.setupDeferred();
|
||||
}
|
||||
|
||||
async *[Symbol.asyncIterator]() {
|
||||
do {
|
||||
const hasErrors = await this.deferred.promise;
|
||||
yield { hasErrors };
|
||||
this.setupDeferred();
|
||||
} while (this.watch);
|
||||
}
|
||||
|
||||
private setupDeferred() {
|
||||
let resolve: (val: boolean) => void;
|
||||
this.deferred = {
|
||||
promise: new Promise((res) => {
|
||||
resolve = res;
|
||||
}),
|
||||
resolve,
|
||||
};
|
||||
}
|
||||
|
||||
onFinished(files: File[], errors?: unknown[]) {
|
||||
const hasErrors =
|
||||
files.some((f) => f.result?.state === 'fail') || errors?.length > 0;
|
||||
this.deferred.resolve(hasErrors);
|
||||
}
|
||||
}
|
||||
import { NxReporter } from './lib/nx-reporter';
|
||||
import { getExtraArgs, getOptions } from './lib/utils';
|
||||
|
||||
export async function* vitestExecutor(
|
||||
options: VitestExecutorOptions,
|
||||
@ -53,18 +11,32 @@ export async function* vitestExecutor(
|
||||
) {
|
||||
const projectRoot =
|
||||
context.projectsConfigurations.projects[context.projectName].root;
|
||||
|
||||
registerTsConfigPaths(resolve(workspaceRoot, projectRoot, 'tsconfig.json'));
|
||||
|
||||
const { startVitest } = await (Function(
|
||||
'return import("vitest/node")'
|
||||
)() as Promise<typeof import('vitest/node')>);
|
||||
|
||||
const nxReporter = new NxReporter(options.watch);
|
||||
const settings = await getSettings(options, context, projectRoot);
|
||||
settings.reporters.push(nxReporter);
|
||||
const extraArgs = await getExtraArgs(options);
|
||||
const resolvedOptions =
|
||||
(await getOptions(options, context, projectRoot, extraArgs)) ?? {};
|
||||
|
||||
const nxReporter = new NxReporter(resolvedOptions['watch']);
|
||||
if (resolvedOptions['reporters'] === undefined) {
|
||||
resolvedOptions['reporters'] = [];
|
||||
} else if (typeof resolvedOptions['reporters'] === 'string') {
|
||||
resolvedOptions['reporters'] = [resolvedOptions['reporters']];
|
||||
}
|
||||
resolvedOptions['reporters'].push(nxReporter);
|
||||
|
||||
const cliFilters = options.testFiles ?? [];
|
||||
|
||||
const ctx = await startVitest(options.mode, cliFilters, settings);
|
||||
const ctx = await startVitest(
|
||||
resolvedOptions['mode'] ?? 'test',
|
||||
cliFilters,
|
||||
resolvedOptions
|
||||
);
|
||||
|
||||
let hasErrors = false;
|
||||
|
||||
@ -77,7 +49,7 @@ export async function* vitestExecutor(
|
||||
}
|
||||
};
|
||||
|
||||
if (options.watch) {
|
||||
if (resolvedOptions['watch'] === true) {
|
||||
process.on('SIGINT', processExit);
|
||||
process.on('SIGTERM', processExit);
|
||||
process.on('exit', processExit);
|
||||
@ -94,111 +66,4 @@ export async function* vitestExecutor(
|
||||
};
|
||||
}
|
||||
|
||||
async function getSettings(
|
||||
options: VitestExecutorOptions,
|
||||
context: ExecutorContext,
|
||||
projectRoot: string
|
||||
) {
|
||||
// Allows ESM to be required in CJS modules. Vite will be published as ESM in the future.
|
||||
const { loadConfigFromFile } = await (Function(
|
||||
'return import("vite")'
|
||||
)() as Promise<typeof import('vite')>);
|
||||
|
||||
const packageJsonPath = join(workspaceRoot, 'package.json');
|
||||
const packageJson = existsSync(packageJsonPath)
|
||||
? readJsonFile(packageJsonPath)
|
||||
: undefined;
|
||||
let provider: 'v8' | 'istanbul' | 'custom';
|
||||
if (
|
||||
packageJson?.dependencies?.['@vitest/coverage-istanbul'] ||
|
||||
packageJson?.devDependencies?.['@vitest/coverage-istanbul']
|
||||
) {
|
||||
provider = 'istanbul';
|
||||
} else {
|
||||
provider = 'v8';
|
||||
}
|
||||
const offset = relative(workspaceRoot, context.cwd);
|
||||
// if reportsDirectory is not provided vitest will remove all files in the project root
|
||||
// when coverage is enabled in the vite.config.ts
|
||||
const coverage: CoverageOptions = options.reportsDirectory
|
||||
? {
|
||||
enabled: options.coverage,
|
||||
reportsDirectory: options.reportsDirectory,
|
||||
provider,
|
||||
}
|
||||
: ({} as CoverageOptions);
|
||||
|
||||
const viteConfigPath = options.config
|
||||
? options.config // config is expected to be from the workspace root
|
||||
: findViteConfig(joinPathFragments(context.root, projectRoot));
|
||||
|
||||
if (!viteConfigPath) {
|
||||
throw new Error(
|
||||
stripIndents`
|
||||
Unable to load test config from config file ${viteConfigPath}.
|
||||
|
||||
Please make sure that vitest is configured correctly,
|
||||
or use the @nx/vite:vitest generator to configure it for you.
|
||||
You can read more here: https://nx.dev/nx-api/vite/generators/vitest
|
||||
`
|
||||
);
|
||||
}
|
||||
|
||||
const resolvedProjectRoot = resolve(workspaceRoot, projectRoot);
|
||||
const resolvedViteConfigPath = resolve(
|
||||
workspaceRoot,
|
||||
projectRoot,
|
||||
relative(resolvedProjectRoot, viteConfigPath)
|
||||
);
|
||||
|
||||
const resolved = await loadConfigFromFile(
|
||||
{
|
||||
mode: options.mode,
|
||||
command: 'serve',
|
||||
},
|
||||
resolvedViteConfigPath,
|
||||
resolvedProjectRoot
|
||||
);
|
||||
|
||||
if (!viteConfigPath || !resolved?.config?.['test']) {
|
||||
logger.warn(stripIndents`Unable to load test config from config file ${
|
||||
resolved?.path ?? viteConfigPath
|
||||
}
|
||||
Some settings may not be applied as expected.
|
||||
You can manually set the config in the project, ${
|
||||
context.projectName
|
||||
}, configuration.
|
||||
`);
|
||||
}
|
||||
|
||||
const settings = {
|
||||
...options,
|
||||
// when running nx from the project root, the root will get appended to the cwd.
|
||||
// creating an invalid path and no tests will be found.
|
||||
// instead if we are not at the root, let the cwd be root.
|
||||
root: offset === '' ? resolvedProjectRoot : workspaceRoot,
|
||||
config: resolvedViteConfigPath,
|
||||
reporters: [
|
||||
...(options.reporters ?? []),
|
||||
...((resolved?.config?.['test']?.reporters as string[]) ?? []),
|
||||
'default',
|
||||
] as (string | Reporter)[],
|
||||
coverage: { ...coverage, ...resolved?.config?.['test']?.coverage },
|
||||
};
|
||||
|
||||
return settings;
|
||||
}
|
||||
|
||||
function findViteConfig(projectRootFullPath: string): string {
|
||||
const allowsExt = ['js', 'mjs', 'ts', 'cjs', 'mts', 'cts'];
|
||||
|
||||
for (const ext of allowsExt) {
|
||||
if (
|
||||
existsSync(joinPathFragments(projectRootFullPath, `vite.config.${ext}`))
|
||||
) {
|
||||
return joinPathFragments(projectRootFullPath, `vite.config.${ext}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default vitestExecutor;
|
||||
|
||||
@ -9,7 +9,8 @@ import * as path from 'path';
|
||||
import { nxViteTsPaths } from '@nx/vite/plugins/nx-tsconfig-paths.plugin';
|
||||
|
||||
export default defineConfig({
|
||||
cacheDir: '../../node_modules/.vite/react-lib-nonb-jest',
|
||||
root: __dirname,
|
||||
cacheDir: '../../node_modules/.vite/libs/react-lib-nonb-jest',
|
||||
|
||||
plugins: [
|
||||
react(),
|
||||
@ -29,6 +30,7 @@ export default defineConfig({
|
||||
// Configuration for building your library.
|
||||
// See: https://vitejs.dev/guide/build.html#library-mode
|
||||
build: {
|
||||
outDir: '../../dist/libs/react-lib-nonb-jest',
|
||||
lib: {
|
||||
// Could also be a dictionary or array of multiple entry points.
|
||||
entry: 'src/index.ts',
|
||||
@ -56,7 +58,8 @@ import * as path from 'path';
|
||||
import { nxViteTsPaths } from '@nx/vite/plugins/nx-tsconfig-paths.plugin';
|
||||
|
||||
export default defineConfig({
|
||||
cacheDir: '../../node_modules/.vite/react-lib-nonb-jest',
|
||||
root: __dirname,
|
||||
cacheDir: '../../node_modules/.vite/libs/react-lib-nonb-jest',
|
||||
|
||||
plugins: [
|
||||
react(),
|
||||
@ -76,6 +79,7 @@ export default defineConfig({
|
||||
// Configuration for building your library.
|
||||
// See: https://vitejs.dev/guide/build.html#library-mode
|
||||
build: {
|
||||
outDir: '../../dist/libs/react-lib-nonb-jest',
|
||||
lib: {
|
||||
// Could also be a dictionary or array of multiple entry points.
|
||||
entry: 'src/index.ts',
|
||||
@ -98,6 +102,11 @@ export default defineConfig({
|
||||
},
|
||||
environment: 'jsdom',
|
||||
include: ['src/**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'],
|
||||
|
||||
coverage: {
|
||||
reportsDirectory: '../../coverage/libs/react-lib-nonb-jest',
|
||||
provider: 'v8',
|
||||
},
|
||||
},
|
||||
});
|
||||
"
|
||||
@ -143,8 +152,9 @@ import { nxViteTsPaths } from '@nx/vite/plugins/nx-tsconfig-paths.plugin';
|
||||
export default defineConfig({
|
||||
// Configuration for building your library.
|
||||
// See: https://vitejs.dev/guide/build.html#library-mode
|
||||
cacheDir: '../../node_modules/.vite/react-lib-nonb-vitest',
|
||||
cacheDir: '../../node_modules/.vite/libs/react-lib-nonb-vitest',
|
||||
build: {
|
||||
outDir: '../../dist/libs/react-lib-nonb-vitest',
|
||||
lib: {
|
||||
// Could also be a dictionary or array of multiple entry points.
|
||||
entry: 'src/index.ts',
|
||||
@ -174,6 +184,10 @@ export default defineConfig({
|
||||
cache: { dir: '../../node_modules/.vitest' },
|
||||
environment: 'jsdom',
|
||||
include: ['src/**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'],
|
||||
coverage: {
|
||||
reportsDirectory: '../../coverage/libs/react-lib-nonb-vitest',
|
||||
provider: 'v8',
|
||||
},
|
||||
},
|
||||
});
|
||||
"
|
||||
@ -271,7 +285,8 @@ import react from '@vitejs/plugin-react';
|
||||
import { nxViteTsPaths } from '@nx/vite/plugins/nx-tsconfig-paths.plugin';
|
||||
|
||||
export default defineConfig({
|
||||
cacheDir: '../../node_modules/.vite/my-test-react-app',
|
||||
root: __dirname,
|
||||
cacheDir: '../../node_modules/.vite/apps/my-test-react-app',
|
||||
|
||||
server: {
|
||||
port: 4200,
|
||||
@ -289,6 +304,10 @@ export default defineConfig({
|
||||
// worker: {
|
||||
// plugins: [ nxViteTsPaths() ],
|
||||
// },
|
||||
|
||||
build: {
|
||||
outDir: '../../dist/apps/my-test-react-app',
|
||||
},
|
||||
});
|
||||
"
|
||||
`;
|
||||
@ -409,7 +428,8 @@ import { defineConfig } from 'vite';
|
||||
import { nxViteTsPaths } from '@nx/vite/plugins/nx-tsconfig-paths.plugin';
|
||||
|
||||
export default defineConfig({
|
||||
cacheDir: '../../node_modules/.vite/my-test-web-app',
|
||||
root: __dirname,
|
||||
cacheDir: '../../node_modules/.vite/apps/my-test-web-app',
|
||||
|
||||
server: {
|
||||
port: 4200,
|
||||
@ -427,6 +447,10 @@ export default defineConfig({
|
||||
// worker: {
|
||||
// plugins: [ nxViteTsPaths() ],
|
||||
// },
|
||||
|
||||
build: {
|
||||
outDir: '../../dist/apps/my-test-web-app',
|
||||
},
|
||||
});
|
||||
"
|
||||
`;
|
||||
@ -534,7 +558,8 @@ import react from '@vitejs/plugin-react';
|
||||
import { nxViteTsPaths } from '@nx/vite/plugins/nx-tsconfig-paths.plugin';
|
||||
|
||||
export default defineConfig({
|
||||
cacheDir: '../../node_modules/.vite/my-test-react-app',
|
||||
root: __dirname,
|
||||
cacheDir: '../../node_modules/.vite/apps/my-test-react-app',
|
||||
|
||||
server: {
|
||||
port: 4200,
|
||||
@ -553,6 +578,10 @@ export default defineConfig({
|
||||
// plugins: [ nxViteTsPaths() ],
|
||||
// },
|
||||
|
||||
build: {
|
||||
outDir: '../../dist/apps/my-test-react-app',
|
||||
},
|
||||
|
||||
test: {
|
||||
globals: true,
|
||||
cache: {
|
||||
@ -560,6 +589,11 @@ export default defineConfig({
|
||||
},
|
||||
environment: 'jsdom',
|
||||
include: ['src/**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'],
|
||||
|
||||
coverage: {
|
||||
reportsDirectory: '../../coverage/apps/my-test-react-app',
|
||||
provider: 'v8',
|
||||
},
|
||||
},
|
||||
});
|
||||
"
|
||||
|
||||
@ -33,10 +33,11 @@ export async function viteConfigurationGenerator(
|
||||
) {
|
||||
const tasks: GeneratorCallback[] = [];
|
||||
|
||||
const { targets, projectType, root } = readProjectConfiguration(
|
||||
tree,
|
||||
schema.project
|
||||
);
|
||||
const {
|
||||
targets,
|
||||
projectType,
|
||||
root: projectRoot,
|
||||
} = readProjectConfiguration(tree, schema.project);
|
||||
let buildTargetName = 'build';
|
||||
let serveTargetName = 'serve';
|
||||
let testTargetName = 'test';
|
||||
@ -147,7 +148,7 @@ export async function viteConfigurationGenerator(
|
||||
|
||||
deleteWebpackConfig(
|
||||
tree,
|
||||
root,
|
||||
projectRoot,
|
||||
targets?.[buildTargetName]?.options?.webpackConfig
|
||||
);
|
||||
|
||||
@ -159,7 +160,7 @@ export async function viteConfigurationGenerator(
|
||||
includeLib: schema.includeLib,
|
||||
compiler: schema.compiler,
|
||||
testEnvironment: schema.testEnvironment,
|
||||
rootProject: root === '.',
|
||||
rootProject: projectRoot === '.',
|
||||
});
|
||||
tasks.push(initTask);
|
||||
|
||||
@ -178,7 +179,10 @@ export async function viteConfigurationGenerator(
|
||||
|
||||
if (projectType === 'library') {
|
||||
// update tsconfig.lib.json to include vite/client
|
||||
updateJson(tree, joinPathFragments(root, 'tsconfig.lib.json'), (json) => {
|
||||
updateJson(
|
||||
tree,
|
||||
joinPathFragments(projectRoot, 'tsconfig.lib.json'),
|
||||
(json) => {
|
||||
if (!json.compilerOptions) {
|
||||
json.compilerOptions = {};
|
||||
}
|
||||
@ -195,7 +199,8 @@ export async function viteConfigurationGenerator(
|
||||
};
|
||||
}
|
||||
return json;
|
||||
});
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
if (!schema.newProject) {
|
||||
|
||||
@ -93,6 +93,10 @@ describe('@nx/vite:init', () => {
|
||||
expect(vitestDefaults).toEqual({
|
||||
cache: true,
|
||||
inputs: ['default', '^production'],
|
||||
options: {
|
||||
passWithNoTests: true,
|
||||
reporters: ['default'],
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@ -34,23 +34,8 @@ function checkDependenciesInstalled(host: Tree, schema: InitGeneratorSchema) {
|
||||
// base deps
|
||||
devDependencies['@nx/vite'] = nxVersion;
|
||||
devDependencies['vite'] = viteVersion;
|
||||
|
||||
// Do not install latest version if vitest already exists
|
||||
// because version 0.32 and newer versions break nuxt-vitest
|
||||
// https://github.com/vitest-dev/vitest/issues/3540
|
||||
// https://github.com/danielroe/nuxt-vitest/issues/213#issuecomment-1588728111
|
||||
if (
|
||||
!packageJson.dependencies['vitest'] &&
|
||||
!packageJson.devDependencies['vitest']
|
||||
) {
|
||||
devDependencies['vitest'] = vitestVersion;
|
||||
}
|
||||
if (
|
||||
!packageJson.dependencies['@vitest/ui'] &&
|
||||
!packageJson.devDependencies['@vitest/ui']
|
||||
) {
|
||||
devDependencies['@vitest/ui'] = vitestVersion;
|
||||
}
|
||||
|
||||
if (schema.testEnvironment === 'jsdom') {
|
||||
devDependencies['jsdom'] = jsdomVersion;
|
||||
@ -93,7 +78,7 @@ function moveToDevDependencies(tree: Tree) {
|
||||
});
|
||||
}
|
||||
|
||||
export function createVitestConfig(tree: Tree) {
|
||||
export function updateNxJsonSettings(tree: Tree) {
|
||||
const nxJson = readNxJson(tree);
|
||||
|
||||
const productionFileSet = nxJson.namedInputs?.production;
|
||||
@ -113,13 +98,26 @@ export function createVitestConfig(tree: Tree) {
|
||||
'default',
|
||||
productionFileSet ? '^production' : '^default',
|
||||
];
|
||||
nxJson.targetDefaults['@nx/vite:test'].options ??= {
|
||||
passWithNoTests: true,
|
||||
reporters: ['default'],
|
||||
};
|
||||
|
||||
nxJson.targetDefaults['@nx/vite:build'] ??= {};
|
||||
|
||||
nxJson.targetDefaults['@nx/vite:build'].options ??= {
|
||||
reportCompressedSize: true,
|
||||
commonjsOptions: {
|
||||
transformMixedEsModules: true,
|
||||
},
|
||||
};
|
||||
|
||||
updateNxJson(tree, nxJson);
|
||||
}
|
||||
|
||||
export async function initGenerator(tree: Tree, schema: InitGeneratorSchema) {
|
||||
moveToDevDependencies(tree);
|
||||
createVitestConfig(tree);
|
||||
updateNxJsonSettings(tree);
|
||||
const tasks = [];
|
||||
|
||||
tasks.push(
|
||||
|
||||
@ -7,7 +7,8 @@ import react from '@vitejs/plugin-react';
|
||||
import { nxViteTsPaths } from '@nx/vite/plugins/nx-tsconfig-paths.plugin';
|
||||
|
||||
export default defineConfig({
|
||||
cacheDir: '../../node_modules/.vite/my-test-react-app',
|
||||
root: __dirname,
|
||||
cacheDir: '../../node_modules/.vite/apps/my-test-react-app',
|
||||
|
||||
plugins: [react(), nxViteTsPaths()],
|
||||
|
||||
@ -27,6 +28,10 @@ export default defineConfig({
|
||||
environment: 'jsdom',
|
||||
include: ['src/**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'],
|
||||
includeSource: ['src/**/*.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'],
|
||||
coverage: {
|
||||
reportsDirectory: '../../coverage/apps/my-test-react-app',
|
||||
provider: 'v8',
|
||||
},
|
||||
},
|
||||
});
|
||||
"
|
||||
@ -39,7 +44,8 @@ import react from '@vitejs/plugin-react';
|
||||
import { nxViteTsPaths } from '@nx/vite/plugins/nx-tsconfig-paths.plugin';
|
||||
|
||||
export default defineConfig({
|
||||
cacheDir: '../../node_modules/.vite/my-test-react-app',
|
||||
root: __dirname,
|
||||
cacheDir: '../../node_modules/.vite/apps/my-test-react-app',
|
||||
|
||||
plugins: [react(), nxViteTsPaths()],
|
||||
|
||||
@ -55,6 +61,11 @@ export default defineConfig({
|
||||
},
|
||||
environment: 'jsdom',
|
||||
include: ['src/**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'],
|
||||
|
||||
coverage: {
|
||||
reportsDirectory: '../../coverage/apps/my-test-react-app',
|
||||
provider: 'v8',
|
||||
},
|
||||
},
|
||||
});
|
||||
"
|
||||
@ -67,7 +78,8 @@ import react from '@vitejs/plugin-react';
|
||||
import { nxViteTsPaths } from '@nx/vite/plugins/nx-tsconfig-paths.plugin';
|
||||
|
||||
export default defineConfig({
|
||||
cacheDir: '../../node_modules/.vite/react-lib-nonb-jest',
|
||||
root: __dirname,
|
||||
cacheDir: '../../node_modules/.vite/libs/react-lib-nonb-jest',
|
||||
|
||||
plugins: [react(), nxViteTsPaths()],
|
||||
|
||||
@ -83,6 +95,11 @@ export default defineConfig({
|
||||
},
|
||||
environment: 'jsdom',
|
||||
include: ['src/**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'],
|
||||
|
||||
coverage: {
|
||||
reportsDirectory: '../../coverage/libs/react-lib-nonb-jest',
|
||||
provider: 'v8',
|
||||
},
|
||||
},
|
||||
});
|
||||
"
|
||||
|
||||
@ -6,6 +6,7 @@
|
||||
},
|
||||
"include": [
|
||||
"vite.config.ts",
|
||||
"vitest.config.ts",
|
||||
"src/**/*.test.ts",
|
||||
"src/**/*.spec.ts",
|
||||
"src/**/*.test.tsx",
|
||||
|
||||
@ -65,6 +65,7 @@ export async function vitestGenerator(
|
||||
],
|
||||
imports: [`import react from '@vitejs/plugin-react'`],
|
||||
plugins: ['react()'],
|
||||
coverageProvider: schema.coverageProvider,
|
||||
},
|
||||
true
|
||||
);
|
||||
|
||||
@ -55,7 +55,6 @@ describe('vitest generator', () => {
|
||||
{
|
||||
"executor": "@nx/vite:test",
|
||||
"options": {
|
||||
"passWithNoTests": true,
|
||||
"reportsDirectory": "../../coverage/apps/my-test-react-app",
|
||||
},
|
||||
"outputs": [
|
||||
@ -102,6 +101,7 @@ describe('vitest generator', () => {
|
||||
"extends": "./tsconfig.json",
|
||||
"include": [
|
||||
"vite.config.ts",
|
||||
"vitest.config.ts",
|
||||
"src/**/*.test.ts",
|
||||
"src/**/*.spec.ts",
|
||||
"src/**/*.test.tsx",
|
||||
|
||||
@ -0,0 +1,156 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`change-vite-ts-paths-plugin migration should add build outDir to vite.config.ts 1`] = `
|
||||
"/// <reference types="vitest" />
|
||||
import { defineConfig } from 'vite';
|
||||
import react from '@vitejs/plugin-react';
|
||||
import viteTsConfigPaths from 'vite-tsconfig-paths';
|
||||
|
||||
export default defineConfig({
|
||||
root: __dirname,
|
||||
build: {
|
||||
outDir: '../../dist/apps/demo',
|
||||
},
|
||||
cacheDir: '../../node_modules/.vite/demo',
|
||||
server: {
|
||||
port: 4200,
|
||||
host: 'localhost',
|
||||
},
|
||||
|
||||
preview: {
|
||||
port: 4300,
|
||||
host: 'localhost',
|
||||
},
|
||||
|
||||
plugins: [
|
||||
react(),
|
||||
viteTsConfigPaths({
|
||||
root: '../../',
|
||||
}),
|
||||
],
|
||||
|
||||
// Uncomment this if you are using workers.
|
||||
// worker: {
|
||||
// plugins: [
|
||||
// viteTsConfigPaths({
|
||||
// root: '../../',
|
||||
// }),
|
||||
// ],
|
||||
// },
|
||||
|
||||
test: {
|
||||
coverage: {
|
||||
reportsDirectory: '../../coverage/apps/demo',
|
||||
provider: 'v8',
|
||||
},
|
||||
globals: true,
|
||||
cache: {
|
||||
dir: '../../node_modules/.vitest',
|
||||
},
|
||||
environment: 'jsdom',
|
||||
include: ['src/**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'],
|
||||
},
|
||||
});
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`change-vite-ts-paths-plugin migration should add build outDir to vite.config.ts if build exists 1`] = `
|
||||
"/// <reference types="vitest" />
|
||||
import { defineConfig } from 'vite';
|
||||
import react from '@vitejs/plugin-react';
|
||||
import viteTsConfigPaths from 'vite-tsconfig-paths';
|
||||
|
||||
export default defineConfig({
|
||||
root: __dirname,
|
||||
cacheDir: '../../node_modules/.vite/demo2',
|
||||
server: {
|
||||
port: 4200,
|
||||
host: 'localhost',
|
||||
},
|
||||
|
||||
preview: {
|
||||
port: 4300,
|
||||
host: 'localhost',
|
||||
},
|
||||
|
||||
plugins: [
|
||||
react(),
|
||||
viteTsConfigPaths({
|
||||
root: '../../',
|
||||
}),
|
||||
],
|
||||
|
||||
build: {
|
||||
outDir: '../dist/demo2',
|
||||
someProperty: 'someValue',
|
||||
},
|
||||
|
||||
test: {
|
||||
coverage: {
|
||||
reportsDirectory: '../coverage/demo2',
|
||||
provider: 'v8',
|
||||
},
|
||||
globals: true,
|
||||
cache: {
|
||||
dir: '../../node_modules/.vitest',
|
||||
},
|
||||
environment: 'jsdom',
|
||||
include: ['src/**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'],
|
||||
},
|
||||
});
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`change-vite-ts-paths-plugin migration should add file replacements to vite.config.ts 1`] = `
|
||||
"/// <reference types="vitest" />
|
||||
import replaceFiles from '@nx/vite/plugins/rollup-replace-files.plugin';
|
||||
import { defineConfig } from 'vite';
|
||||
import react from '@vitejs/plugin-react';
|
||||
import viteTsConfigPaths from 'vite-tsconfig-paths';
|
||||
|
||||
export default defineConfig({
|
||||
root: __dirname,
|
||||
cacheDir: '../../node_modules/.vite/demo3',
|
||||
server: {
|
||||
port: 4200,
|
||||
host: 'localhost',
|
||||
},
|
||||
|
||||
preview: {
|
||||
port: 4300,
|
||||
host: 'localhost',
|
||||
},
|
||||
|
||||
plugins: [
|
||||
replaceFiles([
|
||||
{
|
||||
replace: 'demo3/src/environments/environment.ts',
|
||||
with: 'demo3/src/environments/environment.prod.ts',
|
||||
},
|
||||
]),
|
||||
react(),
|
||||
viteTsConfigPaths({
|
||||
root: '../../',
|
||||
}),
|
||||
],
|
||||
|
||||
build: {
|
||||
outDir: '../dist/demo3',
|
||||
someProperty: 'someValue',
|
||||
},
|
||||
|
||||
test: {
|
||||
coverage: {
|
||||
reportsDirectory: '../coverage/demo3',
|
||||
provider: 'v8',
|
||||
},
|
||||
globals: true,
|
||||
cache: {
|
||||
dir: '../../node_modules/.vitest',
|
||||
},
|
||||
environment: 'jsdom',
|
||||
include: ['src/**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'],
|
||||
},
|
||||
});
|
||||
"
|
||||
`;
|
||||
@ -0,0 +1,74 @@
|
||||
import { ChangeType, applyChangesToString } from '@nx/devkit';
|
||||
import { FileReplacement } from '../../../../plugins/rollup-replace-files.plugin';
|
||||
import { tsquery } from '@phenomnomnominal/tsquery';
|
||||
|
||||
export function addFileReplacements(
|
||||
configContents: string,
|
||||
fileReplacements: FileReplacement[]
|
||||
): string {
|
||||
const pluginsObject = tsquery.query(
|
||||
configContents,
|
||||
`PropertyAssignment:has(Identifier[name="plugins"])`
|
||||
)?.[0];
|
||||
const replaceFilesPlugin = tsquery.query(
|
||||
configContents,
|
||||
`PropertyAssignment:has(Identifier[name="plugins"]) CallExpression:has(Identifier[name="replaceFiles"])`
|
||||
)?.[0];
|
||||
|
||||
const firstImportDeclaration = tsquery.query(
|
||||
configContents,
|
||||
'ImportDeclaration'
|
||||
)?.[0];
|
||||
|
||||
if (pluginsObject) {
|
||||
if (replaceFilesPlugin) {
|
||||
return configContents;
|
||||
} else {
|
||||
return applyChangesToString(configContents, [
|
||||
{
|
||||
type: ChangeType.Insert,
|
||||
index: pluginsObject.getStart() + `plugins: [`.length + 1,
|
||||
text: `replaceFiles(${JSON.stringify(fileReplacements)}),`,
|
||||
},
|
||||
firstImportDeclaration
|
||||
? {
|
||||
type: ChangeType.Insert,
|
||||
index: firstImportDeclaration.getStart(),
|
||||
text: `import replaceFiles from '@nx/vite/plugins/rollup-replace-files.plugin';\n`,
|
||||
}
|
||||
: {
|
||||
type: ChangeType.Insert,
|
||||
index: 0,
|
||||
text: `import replaceFiles from '@nx/vite/plugins/rollup-replace-files.plugin';\n`,
|
||||
},
|
||||
]);
|
||||
}
|
||||
} else {
|
||||
const foundDefineConfig = tsquery.query(
|
||||
configContents,
|
||||
'CallExpression:has(Identifier[name="defineConfig"])'
|
||||
)?.[0];
|
||||
|
||||
if (!foundDefineConfig) {
|
||||
return;
|
||||
}
|
||||
return applyChangesToString(configContents, [
|
||||
{
|
||||
type: ChangeType.Insert,
|
||||
index: foundDefineConfig.getStart() + 14,
|
||||
text: `plugins: [replaceFiles(${JSON.stringify(fileReplacements)})],`,
|
||||
},
|
||||
firstImportDeclaration
|
||||
? {
|
||||
type: ChangeType.Insert,
|
||||
index: firstImportDeclaration.getStart(),
|
||||
text: `import replaceFiles from '@nx/vite/plugins/rollup-replace-files.plugin';`,
|
||||
}
|
||||
: {
|
||||
type: ChangeType.Insert,
|
||||
index: 0,
|
||||
text: `import replaceFiles from '@nx/vite/plugins/rollup-replace-files.plugin';`,
|
||||
},
|
||||
]);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,149 @@
|
||||
import {
|
||||
ChangeType,
|
||||
ProjectConfiguration,
|
||||
Tree,
|
||||
applyChangesToString,
|
||||
joinPathFragments,
|
||||
logger,
|
||||
offsetFromRoot,
|
||||
updateProjectConfiguration,
|
||||
} from '@nx/devkit';
|
||||
import { tsquery } from '@phenomnomnominal/tsquery';
|
||||
import ts = require('typescript');
|
||||
|
||||
export function updateBuildOutDirAndRoot(
|
||||
options: Record<string, any>,
|
||||
configContents: string,
|
||||
projectConfig: ProjectConfiguration,
|
||||
targetName: string,
|
||||
tree: Tree,
|
||||
projectName: string
|
||||
): string {
|
||||
const foundDefineConfig = tsquery.query(
|
||||
configContents,
|
||||
'CallExpression:has(Identifier[name="defineConfig"])'
|
||||
)?.[0];
|
||||
|
||||
if (!foundDefineConfig) {
|
||||
logger.warn(`
|
||||
Could not find defineConfig in your vite.config file.
|
||||
Please add the build.outDir and root options to your vite.config file.
|
||||
`);
|
||||
}
|
||||
|
||||
configContents = fixBuild(
|
||||
options,
|
||||
configContents,
|
||||
projectConfig,
|
||||
targetName,
|
||||
tree,
|
||||
projectName,
|
||||
foundDefineConfig
|
||||
);
|
||||
|
||||
configContents = addRoot(configContents, foundDefineConfig);
|
||||
|
||||
return configContents;
|
||||
}
|
||||
|
||||
function fixBuild(
|
||||
options: Record<string, any>,
|
||||
configContents: string,
|
||||
projectConfig: ProjectConfiguration,
|
||||
targetName: string,
|
||||
tree: Tree,
|
||||
projectName: string,
|
||||
foundDefineConfig?: ts.Node
|
||||
) {
|
||||
let outputPath = '';
|
||||
|
||||
// In vite.config.ts, we want to keep the path relative to workspace root
|
||||
if (options.outputPath) {
|
||||
outputPath = joinPathFragments(
|
||||
offsetFromRoot(projectConfig.root),
|
||||
options.outputPath
|
||||
);
|
||||
} else {
|
||||
outputPath = joinPathFragments(
|
||||
offsetFromRoot(projectConfig.root),
|
||||
'dist',
|
||||
projectConfig.root
|
||||
);
|
||||
}
|
||||
|
||||
// In project.json, we want to keep the path starting from workspace root
|
||||
projectConfig.targets[targetName].options.outputPath = options.outputPath
|
||||
? options.outputPath
|
||||
: joinPathFragments('dist', projectConfig.root);
|
||||
updateProjectConfiguration(tree, projectName, projectConfig);
|
||||
|
||||
const buildObject = tsquery.query(
|
||||
configContents,
|
||||
`PropertyAssignment:has(Identifier[name="build"])`
|
||||
)?.[0];
|
||||
let buildOutDir: ts.Node[];
|
||||
if (buildObject) {
|
||||
buildOutDir = tsquery.query(
|
||||
buildObject,
|
||||
`PropertyAssignment:has(Identifier[name="outDir"])`
|
||||
);
|
||||
}
|
||||
|
||||
if (buildOutDir?.length > 0) {
|
||||
return configContents;
|
||||
} else if (buildObject) {
|
||||
// has build, has no outDir
|
||||
// so add outDir
|
||||
return applyChangesToString(configContents, [
|
||||
{
|
||||
type: ChangeType.Insert,
|
||||
index: buildObject.getStart() + `build: {`.length + 1,
|
||||
text: `outDir: '${outputPath}',`,
|
||||
},
|
||||
]);
|
||||
} else {
|
||||
return addBuildProperty(configContents, outputPath, foundDefineConfig);
|
||||
}
|
||||
}
|
||||
|
||||
function addRoot(
|
||||
configFileContents: string,
|
||||
foundDefineConfig?: ts.Node
|
||||
): string {
|
||||
const rootOption = tsquery.query(
|
||||
configFileContents,
|
||||
`PropertyAssignment:has(Identifier[name="root"]) Identifier[name="__dirname"]`
|
||||
)?.[0];
|
||||
|
||||
if (rootOption || !foundDefineConfig) {
|
||||
return configFileContents;
|
||||
} else {
|
||||
return applyChangesToString(configFileContents, [
|
||||
{
|
||||
type: ChangeType.Insert,
|
||||
index: foundDefineConfig.getStart() + 14,
|
||||
text: `root: __dirname,`,
|
||||
},
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
function addBuildProperty(
|
||||
configFileContents: string,
|
||||
outputPath: string,
|
||||
foundDefineConfig: ts.Node
|
||||
): string {
|
||||
if (foundDefineConfig) {
|
||||
return applyChangesToString(configFileContents, [
|
||||
{
|
||||
type: ChangeType.Insert,
|
||||
index: foundDefineConfig.getStart() + 14,
|
||||
text: `build: {
|
||||
outDir: '${outputPath}',
|
||||
},`,
|
||||
},
|
||||
]);
|
||||
} else {
|
||||
return configFileContents;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,88 @@
|
||||
import {
|
||||
ChangeType,
|
||||
ProjectConfiguration,
|
||||
applyChangesToString,
|
||||
joinPathFragments,
|
||||
offsetFromRoot,
|
||||
} from '@nx/devkit';
|
||||
import { tsquery } from '@phenomnomnominal/tsquery';
|
||||
import ts = require('typescript');
|
||||
|
||||
export function updateTestConfig(
|
||||
configContents: string,
|
||||
projectConfig: ProjectConfiguration
|
||||
): string {
|
||||
const testObject = tsquery.query(
|
||||
configContents,
|
||||
`PropertyAssignment:has(Identifier[name="test"])`
|
||||
)?.[0];
|
||||
let testCoverageDir: ts.Node;
|
||||
let testCoverage: ts.Node;
|
||||
let provider: ts.Node;
|
||||
if (testObject) {
|
||||
testCoverage = tsquery.query(
|
||||
testObject,
|
||||
`PropertyAssignment:has(Identifier[name="coverage"])`
|
||||
)?.[0];
|
||||
if (testCoverage) {
|
||||
testCoverageDir = tsquery.query(
|
||||
testCoverage,
|
||||
`PropertyAssignment:has(Identifier[name="reportsDirectory"])`
|
||||
)?.[0];
|
||||
provider = tsquery.query(
|
||||
testCoverage,
|
||||
`PropertyAssignment:has(Identifier[name="provider"])`
|
||||
)?.[0];
|
||||
}
|
||||
}
|
||||
|
||||
let coverageDir = '';
|
||||
|
||||
if (projectConfig.targets?.test?.options?.reportsDirectory) {
|
||||
coverageDir = projectConfig.targets?.test?.options?.reportsDirectory;
|
||||
} else {
|
||||
coverageDir = joinPathFragments(
|
||||
offsetFromRoot(projectConfig.root),
|
||||
'coverage',
|
||||
projectConfig.root
|
||||
);
|
||||
}
|
||||
|
||||
if (testCoverageDir) {
|
||||
// Do nothing
|
||||
} else if (testCoverage) {
|
||||
// has test.coverage, has no reportsDirectory
|
||||
// so add reportsDirectory
|
||||
configContents = applyChangesToString(configContents, [
|
||||
{
|
||||
type: ChangeType.Insert,
|
||||
index: testCoverage.getStart() + `coverage: {`.length + 1,
|
||||
text: `reportsDirectory: '${coverageDir}',`,
|
||||
},
|
||||
]);
|
||||
if (!provider) {
|
||||
configContents = applyChangesToString(configContents, [
|
||||
{
|
||||
type: ChangeType.Insert,
|
||||
index: testCoverage.getStart() + `coverage: {`.length + 1,
|
||||
text: `provider: 'v8',`,
|
||||
},
|
||||
]);
|
||||
}
|
||||
} else if (testObject) {
|
||||
configContents = applyChangesToString(configContents, [
|
||||
{
|
||||
type: ChangeType.Insert,
|
||||
index: testObject.getStart() + `test: {`.length + 1,
|
||||
text: `coverage: {
|
||||
reportsDirectory: '${coverageDir}',
|
||||
provider: 'v8',
|
||||
},`,
|
||||
},
|
||||
]);
|
||||
} else {
|
||||
// has no test so do nothing
|
||||
}
|
||||
|
||||
return configContents;
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
import { Tree, joinPathFragments } from '@nx/devkit';
|
||||
|
||||
export function findViteConfig(tree: Tree, searchRoot: string) {
|
||||
const allowsExt = ['js', 'mjs', 'ts', 'cjs', 'mts', 'cts'];
|
||||
|
||||
for (const ext of allowsExt) {
|
||||
if (tree.exists(joinPathFragments(searchRoot, `vite.config.${ext}`))) {
|
||||
return joinPathFragments(searchRoot, `vite.config.${ext}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,262 @@
|
||||
import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing';
|
||||
import {
|
||||
Tree,
|
||||
addProjectConfiguration,
|
||||
readProjectConfiguration,
|
||||
} from '@nx/devkit';
|
||||
|
||||
import updateBuildDir from './update-vite-config';
|
||||
|
||||
describe('change-vite-ts-paths-plugin migration', () => {
|
||||
let tree: Tree;
|
||||
|
||||
beforeEach(() => {
|
||||
tree = createTreeWithEmptyWorkspace({ layout: 'apps-libs' });
|
||||
});
|
||||
|
||||
it('should add build outDir to vite.config.ts', async () => {
|
||||
addProject1(tree, 'demo');
|
||||
await updateBuildDir(tree);
|
||||
expect(tree.read('apps/demo/vite.config.ts', 'utf-8')).toMatchSnapshot();
|
||||
expect(
|
||||
readProjectConfiguration(tree, 'demo').targets.build.options.outputPath
|
||||
).toBe('dist/apps/demo');
|
||||
});
|
||||
|
||||
it('should add build outDir to vite.config.ts if build exists', async () => {
|
||||
addProject2(tree, 'demo2');
|
||||
await updateBuildDir(tree);
|
||||
expect(tree.read('demo2/vite.config.ts', 'utf-8')).toMatchSnapshot();
|
||||
expect(
|
||||
readProjectConfiguration(tree, 'demo2').targets.build.options.outputPath
|
||||
).toBe('dist/demo2');
|
||||
});
|
||||
|
||||
it('should add file replacements to vite.config.ts', async () => {
|
||||
addProject3(tree, 'demo3');
|
||||
await updateBuildDir(tree);
|
||||
expect(tree.read('demo3/vite.config.ts', 'utf-8')).toMatchSnapshot();
|
||||
expect(
|
||||
readProjectConfiguration(tree, 'demo3').targets.build.options.outputPath
|
||||
).toBe('dist/demo3');
|
||||
});
|
||||
});
|
||||
|
||||
function addProject1(tree: Tree, name: string) {
|
||||
addProjectConfiguration(tree, name, {
|
||||
root: `apps/${name}`,
|
||||
sourceRoot: `apps/${name}/src`,
|
||||
targets: {
|
||||
build: {
|
||||
executor: '@nx/vite:build',
|
||||
outputs: ['{options.outputPath}'],
|
||||
defaultConfiguration: 'production',
|
||||
options: {
|
||||
outputPath: `dist/apps/${name}`,
|
||||
buildLibsFromSource: false,
|
||||
},
|
||||
configurations: {
|
||||
development: {
|
||||
mode: 'development',
|
||||
},
|
||||
production: {
|
||||
mode: 'production',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
tree.write(
|
||||
`apps/${name}/vite.config.ts`,
|
||||
`
|
||||
/// <reference types="vitest" />
|
||||
import { defineConfig } from 'vite';
|
||||
import react from '@vitejs/plugin-react';
|
||||
import viteTsConfigPaths from 'vite-tsconfig-paths';
|
||||
|
||||
export default defineConfig({
|
||||
cacheDir: '../../node_modules/.vite/${name}',
|
||||
server: {
|
||||
port: 4200,
|
||||
host: 'localhost',
|
||||
},
|
||||
|
||||
preview: {
|
||||
port: 4300,
|
||||
host: 'localhost',
|
||||
},
|
||||
|
||||
plugins: [
|
||||
react(),
|
||||
viteTsConfigPaths({
|
||||
root: '../../'
|
||||
})
|
||||
],
|
||||
|
||||
// Uncomment this if you are using workers.
|
||||
// worker: {
|
||||
// plugins: [
|
||||
// viteTsConfigPaths({
|
||||
// root: '../../',
|
||||
// }),
|
||||
// ],
|
||||
// },
|
||||
|
||||
test: {
|
||||
globals: true,
|
||||
cache: {
|
||||
dir: '../../node_modules/.vitest',
|
||||
},
|
||||
environment: 'jsdom',
|
||||
include: ['src/**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'],
|
||||
},
|
||||
});
|
||||
|
||||
`
|
||||
);
|
||||
}
|
||||
|
||||
function addProject2(tree: Tree, name: string) {
|
||||
addProjectConfiguration(tree, name, {
|
||||
root: `${name}`,
|
||||
sourceRoot: `${name}/src`,
|
||||
targets: {
|
||||
build: {
|
||||
executor: '@nx/vite:build',
|
||||
outputs: ['{options.outputPath}'],
|
||||
defaultConfiguration: 'production',
|
||||
options: {
|
||||
outputPath: `dist/${name}`,
|
||||
},
|
||||
configurations: {
|
||||
development: {
|
||||
mode: 'development',
|
||||
},
|
||||
production: {
|
||||
mode: 'production',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
tree.write(
|
||||
`${name}/vite.config.ts`,
|
||||
`
|
||||
/// <reference types="vitest" />
|
||||
import { defineConfig } from 'vite';
|
||||
import react from '@vitejs/plugin-react';
|
||||
import viteTsConfigPaths from 'vite-tsconfig-paths';
|
||||
|
||||
export default defineConfig({
|
||||
cacheDir: '../../node_modules/.vite/${name}',
|
||||
server: {
|
||||
port: 4200,
|
||||
host: 'localhost',
|
||||
},
|
||||
|
||||
preview: {
|
||||
port: 4300,
|
||||
host: 'localhost',
|
||||
},
|
||||
|
||||
plugins: [
|
||||
react(),
|
||||
viteTsConfigPaths({
|
||||
root: '../../'
|
||||
})
|
||||
],
|
||||
|
||||
build: {
|
||||
someProperty: 'someValue',
|
||||
},
|
||||
|
||||
test: {
|
||||
globals: true,
|
||||
cache: {
|
||||
dir: '../../node_modules/.vitest',
|
||||
},
|
||||
environment: 'jsdom',
|
||||
include: ['src/**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'],
|
||||
},
|
||||
});
|
||||
|
||||
`
|
||||
);
|
||||
}
|
||||
|
||||
function addProject3(tree: Tree, name: string) {
|
||||
addProjectConfiguration(tree, name, {
|
||||
root: `${name}`,
|
||||
sourceRoot: `${name}/src`,
|
||||
targets: {
|
||||
build: {
|
||||
executor: '@nx/vite:build',
|
||||
outputs: ['{options.outputPath}'],
|
||||
defaultConfiguration: 'production',
|
||||
options: {
|
||||
outputPath: `dist/${name}`,
|
||||
},
|
||||
configurations: {
|
||||
development: {
|
||||
mode: 'development',
|
||||
},
|
||||
production: {
|
||||
mode: 'production',
|
||||
fileReplacements: [
|
||||
{
|
||||
replace: `${name}/src/environments/environment.ts`,
|
||||
with: `${name}/src/environments/environment.prod.ts`,
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
tree.write(
|
||||
`${name}/vite.config.ts`,
|
||||
`
|
||||
/// <reference types="vitest" />
|
||||
import { defineConfig } from 'vite';
|
||||
import react from '@vitejs/plugin-react';
|
||||
import viteTsConfigPaths from 'vite-tsconfig-paths';
|
||||
|
||||
export default defineConfig({
|
||||
cacheDir: '../../node_modules/.vite/${name}',
|
||||
server: {
|
||||
port: 4200,
|
||||
host: 'localhost',
|
||||
},
|
||||
|
||||
preview: {
|
||||
port: 4300,
|
||||
host: 'localhost',
|
||||
},
|
||||
|
||||
plugins: [
|
||||
react(),
|
||||
viteTsConfigPaths({
|
||||
root: '../../'
|
||||
})
|
||||
],
|
||||
|
||||
build: {
|
||||
someProperty: 'someValue',
|
||||
},
|
||||
|
||||
test: {
|
||||
globals: true,
|
||||
cache: {
|
||||
dir: '../../node_modules/.vitest',
|
||||
},
|
||||
environment: 'jsdom',
|
||||
include: ['src/**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'],
|
||||
},
|
||||
});
|
||||
|
||||
`
|
||||
);
|
||||
}
|
||||
@ -0,0 +1,55 @@
|
||||
import { Tree, formatFiles, getProjects, joinPathFragments } from '@nx/devkit';
|
||||
import { forEachExecutorOptions } from '@nx/devkit/src/generators/executor-options-utils';
|
||||
import { ViteBuildExecutorOptions } from '../../executors/build/schema';
|
||||
import { updateBuildOutDirAndRoot } from './lib/edit-build-config';
|
||||
import { updateTestConfig } from './lib/edit-test-config';
|
||||
import { addFileReplacements } from './lib/add-file-replacements';
|
||||
|
||||
export default async function updateBuildDir(tree: Tree) {
|
||||
const projects = getProjects(tree);
|
||||
forEachExecutorOptions<ViteBuildExecutorOptions>(
|
||||
tree,
|
||||
'@nx/vite:build',
|
||||
(options, projectName, targetName) => {
|
||||
const projectConfig = projects.get(projectName);
|
||||
const config =
|
||||
options.configFile || findViteConfig(tree, projectConfig.root);
|
||||
if (!config || !tree.exists(config)) {
|
||||
return;
|
||||
}
|
||||
let configContents = tree.read(config, 'utf-8');
|
||||
|
||||
configContents = updateBuildOutDirAndRoot(
|
||||
options,
|
||||
configContents,
|
||||
projectConfig,
|
||||
targetName,
|
||||
tree,
|
||||
projectName
|
||||
);
|
||||
|
||||
configContents = updateTestConfig(configContents, projectConfig);
|
||||
|
||||
if (options.fileReplacements?.length > 0) {
|
||||
configContents = addFileReplacements(
|
||||
configContents,
|
||||
options.fileReplacements
|
||||
);
|
||||
}
|
||||
|
||||
tree.write(config, configContents);
|
||||
}
|
||||
);
|
||||
|
||||
await formatFiles(tree);
|
||||
}
|
||||
|
||||
function findViteConfig(tree: Tree, searchRoot: string) {
|
||||
const allowsExt = ['js', 'mjs', 'ts', 'cjs', 'mts', 'cts'];
|
||||
|
||||
for (const ext of allowsExt) {
|
||||
if (tree.exists(joinPathFragments(searchRoot, `vite.config.${ext}`))) {
|
||||
return joinPathFragments(searchRoot, `vite.config.${ext}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -32,9 +32,9 @@ export function createBuildableTsConfig(
|
||||
context: ExecutorContext
|
||||
) {
|
||||
const tsConfig = resolve(projectRoot, 'tsconfig.json');
|
||||
options.buildLibsFromSource ??= true;
|
||||
options['buildLibsFromSource'] ??= true;
|
||||
|
||||
if (!options.buildLibsFromSource) {
|
||||
if (!options['buildLibsFromSource']) {
|
||||
const { dependencies } = calculateProjectBuildableDependencies(
|
||||
context.taskGraph,
|
||||
context.projectGraph,
|
||||
|
||||
@ -170,17 +170,13 @@ export function addOrChangeTestTarget(
|
||||
) {
|
||||
const project = readProjectConfiguration(tree, options.project);
|
||||
|
||||
const coveragePath = joinPathFragments(
|
||||
const reportsDirectory = joinPathFragments(
|
||||
offsetFromRoot(project.root),
|
||||
'coverage',
|
||||
project.root === '.' ? options.project : project.root
|
||||
);
|
||||
const testOptions: VitestExecutorOptions = {
|
||||
passWithNoTests: true,
|
||||
// vitest runs in the project root so we have to offset to the workspaceRoot
|
||||
reportsDirectory: joinPathFragments(
|
||||
offsetFromRoot(project.root),
|
||||
coveragePath
|
||||
),
|
||||
reportsDirectory,
|
||||
};
|
||||
|
||||
project.targets ??= {};
|
||||
@ -205,6 +201,7 @@ export function addOrChangeBuildTarget(
|
||||
target: string
|
||||
) {
|
||||
const project = readProjectConfiguration(tree, options.project);
|
||||
|
||||
const buildOptions: ViteBuildExecutorOptions = {
|
||||
outputPath: joinPathFragments(
|
||||
'dist',
|
||||
@ -219,8 +216,8 @@ export function addOrChangeBuildTarget(
|
||||
project.targets[target].options?.fileReplacements;
|
||||
|
||||
if (project.targets[target].executor === '@nxext/vite:build') {
|
||||
buildOptions.base = project.targets[target].options?.baseHref;
|
||||
buildOptions.sourcemap = project.targets[target].options?.sourcemaps;
|
||||
buildOptions['base'] = project.targets[target].options?.baseHref;
|
||||
buildOptions['sourcemap'] = project.targets[target].options?.sourcemaps;
|
||||
}
|
||||
project.targets[target].options = { ...buildOptions };
|
||||
project.targets[target].executor = '@nx/vite:build';
|
||||
@ -257,9 +254,6 @@ export function addOrChangeServeTarget(
|
||||
const serveTarget = project.targets[target];
|
||||
const serveOptions: ViteDevServerExecutorOptions = {
|
||||
buildTarget: `${options.project}:build`,
|
||||
https: project.targets[target].options?.https,
|
||||
hmr: project.targets[target].options?.hmr,
|
||||
open: project.targets[target].options?.open,
|
||||
};
|
||||
if (serveTarget.executor === '@nxext/vite:dev') {
|
||||
serveOptions.proxyConfig = project.targets[target].options.proxyConfig;
|
||||
@ -316,8 +310,8 @@ export function addPreviewTarget(
|
||||
if (target.executor === '@nxext/vite:dev') {
|
||||
previewOptions.proxyConfig = target.options.proxyConfig;
|
||||
}
|
||||
previewOptions.https = target.options?.https;
|
||||
previewOptions.open = target.options?.open;
|
||||
previewOptions['https'] = target.options?.https;
|
||||
previewOptions['open'] = target.options?.open;
|
||||
}
|
||||
|
||||
// Adds a preview target.
|
||||
@ -486,17 +480,21 @@ export interface ViteConfigFileOptions {
|
||||
rollupOptionsExternal?: string[];
|
||||
imports?: string[];
|
||||
plugins?: string[];
|
||||
coverageProvider?: 'v8' | 'istanbul' | 'custom';
|
||||
}
|
||||
|
||||
export function createOrEditViteConfig(
|
||||
tree: Tree,
|
||||
options: ViteConfigFileOptions,
|
||||
onlyVitest: boolean,
|
||||
projectAlreadyHasViteTargets?: TargetFlags
|
||||
projectAlreadyHasViteTargets?: TargetFlags,
|
||||
vitestFileName?: boolean
|
||||
) {
|
||||
const projectConfig = readProjectConfiguration(tree, options.project);
|
||||
const { root: projectRoot } = readProjectConfiguration(tree, options.project);
|
||||
|
||||
const viteConfigPath = `${projectConfig.root}/vite.config.ts`;
|
||||
const viteConfigPath = vitestFileName
|
||||
? `${projectRoot}/vitest.config.ts`
|
||||
: `${projectRoot}/vite.config.ts`;
|
||||
|
||||
const buildOption = onlyVitest
|
||||
? ''
|
||||
@ -505,6 +503,7 @@ export function createOrEditViteConfig(
|
||||
// Configuration for building your library.
|
||||
// See: https://vitejs.dev/guide/build.html#library-mode
|
||||
build: {
|
||||
outDir: '${offsetFromRoot(projectRoot)}dist/${projectRoot}',
|
||||
lib: {
|
||||
// Could also be a dictionary or array of multiple entry points.
|
||||
entry: 'src/index.ts',
|
||||
@ -517,9 +516,13 @@ export function createOrEditViteConfig(
|
||||
rollupOptions: {
|
||||
// External packages that should not be bundled into your library.
|
||||
external: [${options.rollupOptionsExternal ?? ''}]
|
||||
}
|
||||
},
|
||||
},`
|
||||
: ``;
|
||||
: `
|
||||
build: {
|
||||
outDir: '${offsetFromRoot(projectRoot)}dist/${projectRoot}',
|
||||
},
|
||||
`;
|
||||
|
||||
const imports: string[] = options.imports ? options.imports : [];
|
||||
|
||||
@ -546,15 +549,21 @@ export function createOrEditViteConfig(
|
||||
? `test: {
|
||||
globals: true,
|
||||
cache: {
|
||||
dir: '${offsetFromRoot(projectConfig.root)}node_modules/.vitest'
|
||||
dir: '${offsetFromRoot(projectRoot)}node_modules/.vitest'
|
||||
},
|
||||
environment: '${options.testEnvironment ?? 'jsdom'}',
|
||||
include: ['src/**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'],
|
||||
${
|
||||
options.inSourceTests
|
||||
? `includeSource: ['src/**/*.{js,mjs,cjs,ts,mts,cts,jsx,tsx}']`
|
||||
? `includeSource: ['src/**/*.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'],`
|
||||
: ''
|
||||
}
|
||||
coverage: {
|
||||
reportsDirectory: '${offsetFromRoot(projectRoot)}coverage/${projectRoot}',
|
||||
provider: ${
|
||||
options.coverageProvider ? `'${options.coverageProvider}'` : `'v8'`
|
||||
},
|
||||
}
|
||||
},`
|
||||
: '';
|
||||
|
||||
@ -591,8 +600,8 @@ export function createOrEditViteConfig(
|
||||
// },`;
|
||||
|
||||
const cacheDir = `cacheDir: '${offsetFromRoot(
|
||||
projectConfig.root
|
||||
)}node_modules/.vite/${options.project}',`;
|
||||
projectRoot
|
||||
)}node_modules/.vite/${projectRoot}',`;
|
||||
|
||||
if (tree.exists(viteConfigPath)) {
|
||||
handleViteConfigFileExists(
|
||||
@ -604,7 +613,8 @@ export function createOrEditViteConfig(
|
||||
plugins,
|
||||
testOption,
|
||||
cacheDir,
|
||||
offsetFromRoot(projectConfig.root),
|
||||
offsetFromRoot(projectRoot),
|
||||
projectRoot,
|
||||
projectAlreadyHasViteTargets
|
||||
);
|
||||
return;
|
||||
@ -617,6 +627,7 @@ export function createOrEditViteConfig(
|
||||
import { nxViteTsPaths } from '@nx/vite/plugins/nx-tsconfig-paths.plugin';
|
||||
|
||||
export default defineConfig({
|
||||
root: __dirname,
|
||||
${cacheDir}
|
||||
${devServerOption}
|
||||
${previewServerOption}
|
||||
@ -773,6 +784,7 @@ function handleViteConfigFileExists(
|
||||
testOption: string,
|
||||
cacheDir: string,
|
||||
offsetFromRoot: string,
|
||||
projectRoot: string,
|
||||
projectAlreadyHasViteTargets?: TargetFlags
|
||||
) {
|
||||
if (
|
||||
@ -788,7 +800,8 @@ function handleViteConfigFileExists(
|
||||
);
|
||||
}
|
||||
|
||||
const buildOptionObject = {
|
||||
const buildOptionObject = options.includeLib
|
||||
? {
|
||||
lib: {
|
||||
entry: 'src/index.ts',
|
||||
name: options.project,
|
||||
@ -798,6 +811,10 @@ function handleViteConfigFileExists(
|
||||
rollupOptions: {
|
||||
external: options.rollupOptionsExternal ?? [],
|
||||
},
|
||||
outDir: `${offsetFromRoot}dist/${projectRoot}`,
|
||||
}
|
||||
: {
|
||||
outDir: `${offsetFromRoot}dist/${projectRoot}`,
|
||||
};
|
||||
|
||||
const testOptionObject = {
|
||||
@ -807,6 +824,10 @@ function handleViteConfigFileExists(
|
||||
},
|
||||
environment: options.testEnvironment ?? 'jsdom',
|
||||
include: ['src/**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'],
|
||||
coverage: {
|
||||
reportsDirectory: `${offsetFromRoot}coverage/${projectRoot}`,
|
||||
provider: `${options.coverageProvider ?? 'v8'}`,
|
||||
},
|
||||
};
|
||||
|
||||
const changed = ensureViteConfigIsCorrect(
|
||||
|
||||
@ -6,23 +6,14 @@ import {
|
||||
readTargetOptions,
|
||||
} from '@nx/devkit';
|
||||
import { existsSync } from 'fs';
|
||||
import { relative } from 'path';
|
||||
import {
|
||||
BuildOptions,
|
||||
InlineConfig,
|
||||
PluginOption,
|
||||
PreviewOptions,
|
||||
ServerOptions,
|
||||
} from 'vite';
|
||||
import { PreviewOptions, ServerOptions } from 'vite';
|
||||
import { ViteDevServerExecutorOptions } from '../executors/dev-server/schema';
|
||||
import { VitePreviewServerExecutorOptions } from '../executors/preview-server/schema';
|
||||
import replaceFiles from '../../plugins/rollup-replace-files.plugin';
|
||||
import { ViteBuildExecutorOptions } from '../executors/build/schema';
|
||||
|
||||
/**
|
||||
* Returns the path to the vite config file or undefined when not found.
|
||||
*/
|
||||
export function normalizeViteConfigFilePath(
|
||||
contextRoot: string,
|
||||
projectRoot: string,
|
||||
configFile?: string
|
||||
): string | undefined {
|
||||
@ -35,11 +26,28 @@ export function normalizeViteConfigFilePath(
|
||||
}
|
||||
return normalized;
|
||||
}
|
||||
return existsSync(joinPathFragments(projectRoot, 'vite.config.ts'))
|
||||
? joinPathFragments(projectRoot, 'vite.config.ts')
|
||||
: existsSync(joinPathFragments(projectRoot, 'vite.config.js'))
|
||||
? joinPathFragments(projectRoot, 'vite.config.js')
|
||||
: undefined;
|
||||
|
||||
const allowsExt = ['js', 'mjs', 'ts', 'cjs', 'mts', 'cts'];
|
||||
|
||||
for (const ext of allowsExt) {
|
||||
if (
|
||||
existsSync(
|
||||
joinPathFragments(contextRoot, projectRoot, `vite.config.${ext}`)
|
||||
)
|
||||
) {
|
||||
return joinPathFragments(contextRoot, projectRoot, `vite.config.${ext}`);
|
||||
} else if (
|
||||
existsSync(
|
||||
joinPathFragments(contextRoot, projectRoot, `vitest.config.${ext}`)
|
||||
)
|
||||
) {
|
||||
return joinPathFragments(
|
||||
contextRoot,
|
||||
projectRoot,
|
||||
`vitest.config.${ext}`
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function getProjectTsConfigPath(
|
||||
@ -75,36 +83,6 @@ export function getViteServerProxyConfigPath(
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds the shared options for vite.
|
||||
*
|
||||
* Most shared options are derived from the build target.
|
||||
*/
|
||||
export function getViteSharedConfig(
|
||||
options: ViteBuildExecutorOptions,
|
||||
clearScreen: boolean | undefined,
|
||||
context: ExecutorContext
|
||||
): InlineConfig {
|
||||
const projectRoot =
|
||||
context.projectsConfigurations.projects[context.projectName].root;
|
||||
|
||||
const root =
|
||||
projectRoot === '.'
|
||||
? process.cwd()
|
||||
: relative(context.cwd, joinPathFragments(context.root, projectRoot));
|
||||
|
||||
return {
|
||||
mode: options.mode,
|
||||
root,
|
||||
base: options.base,
|
||||
configFile: normalizeViteConfigFilePath(projectRoot, options.configFile),
|
||||
plugins: [replaceFiles(options.fileReplacements) as PluginOption],
|
||||
optimizeDeps: { force: options.force },
|
||||
clearScreen: clearScreen,
|
||||
logLevel: options.logLevel,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds the options for the vite dev server.
|
||||
*/
|
||||
@ -119,12 +97,6 @@ export async function getViteServerOptions(
|
||||
const projectRoot =
|
||||
context.projectsConfigurations.projects[context.projectName].root;
|
||||
const serverOptions: ServerOptions = {
|
||||
host: options.host,
|
||||
port: options.port,
|
||||
https: options.https,
|
||||
hmr: options.hmr,
|
||||
open: options.open,
|
||||
cors: options.cors,
|
||||
fs: {
|
||||
allow: [
|
||||
searchForWorkspaceRoot(joinPathFragments(projectRoot)),
|
||||
@ -145,53 +117,14 @@ export async function getViteServerOptions(
|
||||
return serverOptions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds the build options for the vite.
|
||||
*/
|
||||
export function getViteBuildOptions(
|
||||
options: ViteBuildExecutorOptions,
|
||||
context: ExecutorContext
|
||||
): BuildOptions {
|
||||
const projectRoot =
|
||||
context.projectsConfigurations.projects[context.projectName].root;
|
||||
|
||||
const outputPath = joinPathFragments(
|
||||
'dist',
|
||||
projectRoot != '.' ? projectRoot : context.projectName
|
||||
);
|
||||
|
||||
return {
|
||||
outDir: relative(projectRoot, options.outputPath ?? outputPath),
|
||||
emptyOutDir: options.emptyOutDir,
|
||||
reportCompressedSize: true,
|
||||
cssCodeSplit: options.cssCodeSplit,
|
||||
target: options.target,
|
||||
commonjsOptions: {
|
||||
transformMixedEsModules: true,
|
||||
},
|
||||
sourcemap: options.sourcemap,
|
||||
minify: options.minify,
|
||||
manifest: options.manifest,
|
||||
ssrManifest: options.ssrManifest,
|
||||
ssr: options.ssr,
|
||||
watch: options.watch as BuildOptions['watch'],
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds the options for the vite preview server.
|
||||
*/
|
||||
export function getVitePreviewOptions(
|
||||
options: VitePreviewServerExecutorOptions,
|
||||
options: Record<string, any>,
|
||||
context: ExecutorContext
|
||||
): PreviewOptions {
|
||||
const serverOptions: ServerOptions = {
|
||||
host: options.host,
|
||||
port: options.port,
|
||||
https: options.https,
|
||||
open: options.open,
|
||||
};
|
||||
|
||||
const serverOptions: ServerOptions = {};
|
||||
const proxyConfigPath = getViteServerProxyConfigPath(
|
||||
options.proxyConfig,
|
||||
context
|
||||
|
||||
@ -85,7 +85,12 @@ function handleBuildOrTestNode(
|
||||
let updatedPropsString = '';
|
||||
for (const prop of existingProperties) {
|
||||
const propName = prop.name.getText();
|
||||
if (!configContentObject[propName] && propName !== 'dir') {
|
||||
if (
|
||||
!configContentObject[propName] &&
|
||||
propName !== 'dir' &&
|
||||
propName !== 'reportsDirectory' &&
|
||||
propName !== 'provider'
|
||||
) {
|
||||
updatedPropsString += `'${propName}': ${prop.initializer.getText()},\n`;
|
||||
}
|
||||
}
|
||||
|
||||
@ -46,6 +46,7 @@ import vue from '@vitejs/plugin-vue';
|
||||
import { nxViteTsPaths } from '@nx/vite/plugins/nx-tsconfig-paths.plugin';
|
||||
|
||||
export default defineConfig({
|
||||
root: __dirname,
|
||||
cacheDir: '../node_modules/.vite/test',
|
||||
|
||||
server: {
|
||||
@ -65,6 +66,10 @@ export default defineConfig({
|
||||
// plugins: [ nxViteTsPaths() ],
|
||||
// },
|
||||
|
||||
build: {
|
||||
outDir: '../dist/test',
|
||||
},
|
||||
|
||||
test: {
|
||||
globals: true,
|
||||
cache: {
|
||||
@ -72,6 +77,11 @@ export default defineConfig({
|
||||
},
|
||||
environment: 'jsdom',
|
||||
include: ['src/**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'],
|
||||
|
||||
coverage: {
|
||||
reportsDirectory: '../coverage/test',
|
||||
provider: 'v8',
|
||||
},
|
||||
},
|
||||
});
|
||||
"
|
||||
@ -141,7 +151,6 @@ exports[`application generator should set up project correctly with given option
|
||||
"executor": "@nx/vite:test",
|
||||
"outputs": ["{options.reportsDirectory}"],
|
||||
"options": {
|
||||
"passWithNoTests": true,
|
||||
"reportsDirectory": "../coverage/test"
|
||||
}
|
||||
},
|
||||
|
||||
@ -36,6 +36,7 @@ import * as path from 'path';
|
||||
import { nxViteTsPaths } from '@nx/vite/plugins/nx-tsconfig-paths.plugin';
|
||||
|
||||
export default defineConfig({
|
||||
root: __dirname,
|
||||
cacheDir: '../node_modules/.vite/my-lib',
|
||||
|
||||
plugins: [
|
||||
@ -56,6 +57,7 @@ export default defineConfig({
|
||||
// Configuration for building your library.
|
||||
// See: https://vitejs.dev/guide/build.html#library-mode
|
||||
build: {
|
||||
outDir: '../dist/my-lib',
|
||||
lib: {
|
||||
// Could also be a dictionary or array of multiple entry points.
|
||||
entry: 'src/index.ts',
|
||||
@ -78,6 +80,11 @@ export default defineConfig({
|
||||
},
|
||||
environment: 'jsdom',
|
||||
include: ['src/**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'],
|
||||
|
||||
coverage: {
|
||||
reportsDirectory: '../coverage/my-lib',
|
||||
provider: 'v8',
|
||||
},
|
||||
},
|
||||
});
|
||||
"
|
||||
|
||||
@ -404,7 +404,6 @@ describe('app', () => {
|
||||
it('should setup the nrwl vite:build builder if bundler is vite', async () => {
|
||||
await applicationGenerator(tree, {
|
||||
name: 'my-app',
|
||||
|
||||
bundler: 'vite',
|
||||
projectNameAndRootFormat: 'as-provided',
|
||||
});
|
||||
|
||||
@ -22,7 +22,9 @@ export default async function addDroppedDependencies(tree: Tree) {
|
||||
projectConfiguration.targets ?? {}
|
||||
)) {
|
||||
for (const droppedDependency of droppedDependencies) {
|
||||
if (targetConfiguration.executor?.startsWith(droppedDependency + ':')) {
|
||||
if (
|
||||
targetConfiguration?.['executor']?.startsWith(droppedDependency + ':')
|
||||
) {
|
||||
devDependencies[droppedDependency] = NX_VERSION;
|
||||
}
|
||||
}
|
||||
@ -35,7 +37,9 @@ export default async function addDroppedDependencies(tree: Tree) {
|
||||
nxJson?.targetDefaults ?? {}
|
||||
)) {
|
||||
for (const droppedDependency of droppedDependencies) {
|
||||
if (targetConfiguration.executor?.startsWith(droppedDependency + ':')) {
|
||||
if (
|
||||
targetConfiguration?.['executor']?.startsWith(droppedDependency + ':')
|
||||
) {
|
||||
devDependencies[droppedDependency] = NX_VERSION;
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user