diff --git a/docs/generated/packages/vite/executors/build.json b/docs/generated/packages/vite/executors/build.json index 0941b4f2549f8..2b2a671b0188f 100644 --- a/docs/generated/packages/vite/executors/build.json +++ b/docs/generated/packages/vite/executors/build.json @@ -92,6 +92,14 @@ "description": "Enable re-building when files change.", "oneOf": [{ "type": "boolean" }, { "type": "object" }], "default": false + }, + "generatePackageJson": { + "description": "Generate a package.json for the build output.", + "type": "boolean" + }, + "includeDevDependenciesInPackageJson": { + "description": "Include devDependencies in the generated package.json.", + "type": "boolean" } }, "definitions": {}, diff --git a/e2e/vite/src/vite.test.ts b/e2e/vite/src/vite.test.ts index b0f21ff96522c..cf220859a7814 100644 --- a/e2e/vite/src/vite.test.ts +++ b/e2e/vite/src/vite.test.ts @@ -9,6 +9,7 @@ import { newProject, promisifiedTreeKill, readFile, + readJson, rmDist, runCLI, runCLIAsync, @@ -144,6 +145,55 @@ describe('Vite Plugin', () => { expect(fileExists(`dist/apps/${myApp}/package.json`)).toBeFalsy(); rmDist(); }, 200_000); + + it('should build application with new package json generation', async () => { + runCLI(`build ${myApp} --generatePackageJson`); + 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(); + + const packageJson = readJson(`dist/apps/${myApp}/package.json`); + expect(packageJson).toEqual({ + name: myApp, + version: '0.0.1', + type: 'module', + }); + rmDist(); + }, 200_000); + + it('should build application with existing package json generation', async () => { + createFile( + `apps/${myApp}/package.json`, + JSON.stringify({ + name: 'my-existing-app', + version: '1.0.1', + scripts: { + start: 'node server.js', + }, + }) + ); + runCLI(`build ${myApp} --generatePackageJson`); + 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(); + + const packageJson = readJson(`dist/apps/${myApp}/package.json`); + expect(packageJson).toEqual({ + name: 'my-existing-app', + version: '1.0.1', + type: 'module', + scripts: { + start: 'node server.js', + }, + }); + rmDist(); + }, 200_000); }); describe('convert @nx/web webpack app to vite using the vite:configuration generator', () => { diff --git a/packages/vite/src/executors/build/build.impl.ts b/packages/vite/src/executors/build/build.impl.ts index fbe367427efe9..48779fa937f6b 100644 --- a/packages/vite/src/executors/build/build.impl.ts +++ b/packages/vite/src/executors/build/build.impl.ts @@ -1,13 +1,18 @@ import 'dotenv/config'; -import { ExecutorContext } from '@nx/devkit'; +import { ExecutorContext, writeJsonFile } from '@nx/devkit'; import { build, InlineConfig, mergeConfig } from 'vite'; import { getViteBuildOptions, getViteSharedConfig, } from '../../utils/options-utils'; import { ViteBuildExecutorOptions } from './schema'; -import { copyAssets } from '@nx/js'; -import { existsSync } from 'fs'; +import { + copyAssets, + createLockFile, + createPackageJson, + getLockFileName, +} from '@nx/js'; +import { existsSync, writeFileSync } from 'fs'; import { resolve } from 'path'; import { createAsyncIterable } from '@nx/devkit/src/utils/async-iterable'; @@ -37,8 +42,29 @@ export async function* viteBuildExecutor( const rootPackageJson = resolve(context.root, 'package.json'); const distPackageJson = resolve(normalizedOptions.outputPath, 'package.json'); + // Generate a package.json if option has been set. + if (options.generatePackageJson) { + const builtPackageJson = createPackageJson( + context.projectName, + context.projectGraph, + { + target: context.targetName, + root: context.root, + isProduction: !options.includeDevDependenciesInPackageJson, // By default we remove devDependencies since this is a production build. + } + ); + + builtPackageJson.type = 'module'; + + writeJsonFile(`${options.outputPath}/package.json`, builtPackageJson); + + const lockFile = createLockFile(builtPackageJson); + writeFileSync(`${options.outputPath}/${getLockFileName()}`, lockFile, { + encoding: 'utf-8', + }); + } // For buildable libs, copy package.json if it exists. - if ( + else if ( !existsSync(distPackageJson) && existsSync(libraryPackageJson) && rootPackageJson !== libraryPackageJson diff --git a/packages/vite/src/executors/build/schema.d.ts b/packages/vite/src/executors/build/schema.d.ts index bdb574454752e..7578e3a3e1a1a 100644 --- a/packages/vite/src/executors/build/schema.d.ts +++ b/packages/vite/src/executors/build/schema.d.ts @@ -15,4 +15,6 @@ export interface ViteBuildExecutorOptions { ssr?: boolean | string; watch?: object | boolean; target?: string | string[]; + generatePackageJson?: boolean; + includeDevDependenciesInPackageJson?: boolean; } diff --git a/packages/vite/src/executors/build/schema.json b/packages/vite/src/executors/build/schema.json index 0668d10a05e76..a9cb452828b65 100644 --- a/packages/vite/src/executors/build/schema.json +++ b/packages/vite/src/executors/build/schema.json @@ -139,6 +139,14 @@ } ], "default": false + }, + "generatePackageJson": { + "description": "Generate a package.json for the build output.", + "type": "boolean" + }, + "includeDevDependenciesInPackageJson": { + "description": "Include devDependencies in the generated package.json.", + "type": "boolean" } }, "definitions": {},