From e8acab6ae0b51d76f19cb411baabc976a43ef870 Mon Sep 17 00:00:00 2001 From: Emily Xiong Date: Wed, 5 Mar 2025 05:29:07 -0500 Subject: [PATCH] feat(vue): add release option to vue publishable libraries (#29867) --- ...-publishable-libraries-ts-solution.test.ts | 57 ++++++++++++++++++- .../src/release-publishable-libraries.test.ts | 56 +++++++++++++++++- .../library/lib/create-library-files.ts | 4 +- .../library/lib/normalize-options.ts | 2 +- .../src/generators/library/library.spec.ts | 1 - .../vue/src/generators/library/library.ts | 47 +++++++++------ 6 files changed, 144 insertions(+), 23 deletions(-) diff --git a/e2e/release/src/release-publishable-libraries-ts-solution.test.ts b/e2e/release/src/release-publishable-libraries-ts-solution.test.ts index a77f628b68..4f0a977c5b 100644 --- a/e2e/release/src/release-publishable-libraries-ts-solution.test.ts +++ b/e2e/release/src/release-publishable-libraries-ts-solution.test.ts @@ -52,7 +52,7 @@ describe('release publishable libraries in workspace with ts solution setup', () beforeAll(async () => { newProject({ - packages: ['@nx/js', '@nx/react'], + packages: ['@nx/js', '@nx/react', '@nx/vue'], preset: 'ts', }); @@ -192,4 +192,59 @@ describe('release publishable libraries in workspace with ts solution setup', () NX Successfully ran target nx-release-publish for project @proj/{project-name} `); }); + + it('should be able to release publishable vue library', async () => { + const vueLib = uniq('my-pkg-'); + runCLI( + `generate @nx/vue:lib packages/${vueLib} --bundler=vite --publishable --importPath=@proj/${vueLib} --no-interactive` + ); + runCLI('sync'); + + const releaseOutput = runCLI(`release --specifier 0.0.4 --yes`); + expect(releaseOutput).toMatchInlineSnapshot(` + NX Executing pre-version command + NX Running release version for project: @proj/{project-name} + @proj/{project-name} 🔍 Reading data for package "@proj/{project-name}" from packages/{project-name}/package.json + @proj/{project-name} 📄 Resolved the current version as 0.0.1 from packages/{project-name}/package.json + @proj/{project-name} 📄 Using the provided version specifier "0.0.4". + @proj/{project-name} ✍️ New version 0.0.4 written to packages/{project-name}/package.json + "name": "@proj/{project-name}", + - "version": "0.0.1", + + "version": "0.0.4", + "type": "module", + NX Updating PM lock file + NX Staging changed files with git + NX Generating an entry in CHANGELOG.md for v0.0.4 + + ## 0.0.4 (YYYY-MM-DD) + + + + This was a version bump only, there were no code changes. + + + ## 0.0.3 (YYYY-MM-DD) + This was a version bump only, there were no code changes. + NX Staging changed files with git + NX Committing changes with git + NX Tagging commit with git + NX Running target nx-release-publish for project @proj/{project-name}: + - @proj/{project-name} + > nx run @proj/{project-name}:nx-release-publish + 📦 @proj/{project-name}@0.0.4 + === Tarball Contents === + XXB README.md + XXB dist/index.d.ts + XXB dist/index.d.ts.map + XXB dist/index.js + XXXB package.json + === Tarball Details === + name: @proj/{project-name} + version: 0.0.4 + filename: proj-{project-name}-0.0.4.tgz + package size: XXXB + unpacked size: XXXB + shasum: {SHASUM} + integrity: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX + total files: X + Published to ${e2eRegistryUrl} with tag "latest" + NX Successfully ran target nx-release-publish for project @proj/{project-name} + `); + }); }); diff --git a/e2e/release/src/release-publishable-libraries.test.ts b/e2e/release/src/release-publishable-libraries.test.ts index c4c2f38e2f..0396a4f76d 100644 --- a/e2e/release/src/release-publishable-libraries.test.ts +++ b/e2e/release/src/release-publishable-libraries.test.ts @@ -52,7 +52,7 @@ describe('release publishable libraries', () => { beforeAll(async () => { newProject({ - packages: ['@nx/js', '@nx/react', '@nx/angular'], + packages: ['@nx/js', '@nx/react', '@nx/angular', '@nx/vue'], }); // Normalize git committer information so it is deterministic in snapshots @@ -248,4 +248,58 @@ describe('release publishable libraries', () => { NX Successfully ran target nx-release-publish for project {project-name} `); }); + + it('should be able to release publishable vue library', async () => { + const vueLib = uniq('my-pkg-'); + runCLI( + `generate @nx/vue:lib packages/${vueLib} --bundler=vite --publishable --importPath=@proj/${vueLib} --no-interactive` + ); + runCLI('sync'); + + const releaseOutput = runCLI(`release --specifier 0.0.5 --yes`); + expect(releaseOutput).toMatchInlineSnapshot(` + NX Executing pre-version command + NX Running release version for project: {project-name} + {project-name} 🔍 Reading data for package "@proj/{project-name}" from dist/packages/{project-name}/package.json + {project-name} 📄 Resolved the current version as 0.0.4 from git tag "v0.0.4". + {project-name} 📄 Using the provided version specifier "0.0.5". + {project-name} ✍️ New version 0.0.5 written to dist/packages/{project-name}/package.json + "name": "@proj/{project-name}", + - "version": "0.0.1", + + "version": "0.0.5", + "main": "./index.js", + NX Staging changed files with git + No files to stage. Skipping git add. + NX Generating an entry in CHANGELOG.md for v0.0.5 + + ## 0.0.5 (YYYY-MM-DD) + + + + This was a version bump only, there were no code changes. + + + ## 0.0.4 (YYYY-MM-DD) + This was a version bump only, there were no code changes. + NX Staging changed files with git + NX Committing changes with git + NX Tagging commit with git + NX Running target nx-release-publish for project {project-name}: + - {project-name} + > nx run {project-name}:nx-release-publish + 📦 @proj/{project-name}@0.0.5 + === Tarball Contents === + XXB README.md + XXB index.d.ts + XXB index.mjs + XXXB package.json + === Tarball Details === + name: @proj/{project-name} + version: 0.0.5 + filename: proj-{project-name}-0.0.5.tgz + package size: XXXB + unpacked size: XXXB + shasum: {SHASUM} + integrity: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX + total files: X + Published to ${e2eRegistryUrl} with tag "latest" + NX Successfully ran target nx-release-publish for project {project-name} + `); + }); }); diff --git a/packages/vue/src/generators/library/lib/create-library-files.ts b/packages/vue/src/generators/library/lib/create-library-files.ts index 323a3d80f5..8f1aa406dd 100644 --- a/packages/vue/src/generators/library/lib/create-library-files.ts +++ b/packages/vue/src/generators/library/lib/create-library-files.ts @@ -36,15 +36,15 @@ export function createLibraryFiles(host: Tree, options: NormalizedSchema) { (options.publishable || options.bundler !== 'none') ) { writeJson(host, joinPathFragments(options.projectRoot, 'package.json'), { - name: options.name, + name: options.importPath ?? options.projectName, version: '0.0.1', main: './index.js', types: './index.d.ts', exports: { '.': { + types: './index.d.ts', import: './index.mjs', require: './index.js', - types: './index.d.ts', }, }, }); diff --git a/packages/vue/src/generators/library/lib/normalize-options.ts b/packages/vue/src/generators/library/lib/normalize-options.ts index 20c77064f8..1a22e103df 100644 --- a/packages/vue/src/generators/library/lib/normalize-options.ts +++ b/packages/vue/src/generators/library/lib/normalize-options.ts @@ -58,7 +58,7 @@ export async function normalizeOptions( addPlugin, ...options, projectName: isUsingTsSolutionConfig - ? getImportPath(host, projectName) + ? importPath ?? getImportPath(host, projectName) : projectName, bundler, fileName, diff --git a/packages/vue/src/generators/library/library.spec.ts b/packages/vue/src/generators/library/library.spec.ts index e86afabf8b..26f9b6937c 100644 --- a/packages/vue/src/generators/library/library.spec.ts +++ b/packages/vue/src/generators/library/library.spec.ts @@ -577,7 +577,6 @@ module.exports = [ [ "name", "version", - "private", "module", "types", "exports", diff --git a/packages/vue/src/generators/library/library.ts b/packages/vue/src/generators/library/library.ts index 2a0f8d4701..53f93ff3f5 100644 --- a/packages/vue/src/generators/library/library.ts +++ b/packages/vue/src/generators/library/library.ts @@ -4,10 +4,11 @@ import { GeneratorCallback, installPackagesTask, joinPathFragments, + readProjectConfiguration, runTasksInSerial, toJS, Tree, - updateJson, + updateProjectConfiguration, writeJson, } from '@nx/devkit'; import { addTsConfigPath, initGenerator as jsInitGenerator } from '@nx/js'; @@ -23,13 +24,17 @@ import { ensureDependencies } from '../../utils/ensure-dependencies'; import { logShowProjectCommand } from '@nx/devkit/src/utils/log-show-project-command'; import { getRelativeCwd } from '@nx/devkit/src/generators/artifact-name-and-directory-utils'; import { relative } from 'path'; -import { getImportPath } from '@nx/js/src/utils/get-import-path'; import { addProjectToTsSolutionWorkspace, updateTsconfigFiles, } from '@nx/js/src/utils/typescript/ts-solution-setup'; import { determineEntryFields } from './lib/determine-entry-fields'; import { sortPackageJsonFields } from '@nx/js/src/utils/package-json/sort-fields'; +import { + addReleaseConfigForNonTsSolution, + addReleaseConfigForTsSolution, + releaseTasks, +} from '@nx/js/src/generators/library/utils/add-release-config'; export function libraryGenerator(tree: Tree, schema: Schema) { return libraryGeneratorInternal(tree, { addPlugin: false, ...schema }); @@ -38,8 +43,6 @@ export function libraryGenerator(tree: Tree, schema: Schema) { export async function libraryGeneratorInternal(tree: Tree, schema: Schema) { const tasks: GeneratorCallback[] = []; - tasks.push(await jsInitGenerator(tree, { ...schema, skipFormat: true })); - const options = await normalizeOptions(tree, schema); if (options.publishable === true && !schema.importPath) { throw new Error( @@ -47,6 +50,8 @@ export async function libraryGeneratorInternal(tree: Tree, schema: Schema) { ); } + tasks.push(await jsInitGenerator(tree, { ...options, skipFormat: true })); + // If we are using the new TS solution // We need to update the workspace file (package.json or pnpm-workspaces.yaml) to include the new project if (options.isUsingTsSolutionConfig) { @@ -55,9 +60,8 @@ export async function libraryGeneratorInternal(tree: Tree, schema: Schema) { if (options.isUsingTsSolutionConfig) { writeJson(tree, joinPathFragments(options.projectRoot, 'package.json'), { - name: getImportPath(tree, options.name), + name: options.projectName, version: '0.0.1', - private: true, ...determineEntryFields(options), files: options.publishable ? ['dist', '!**/*.tsbuildinfo'] : undefined, nx: options.parsedTags?.length @@ -67,7 +71,7 @@ export async function libraryGeneratorInternal(tree: Tree, schema: Schema) { : undefined, }); } else { - addProjectConfiguration(tree, options.name, { + addProjectConfiguration(tree, options.projectName, { root: options.projectRoot, sourceRoot: joinPathFragments(options.projectRoot, 'src'), projectType: 'library', @@ -114,16 +118,6 @@ export async function libraryGeneratorInternal(tree: Tree, schema: Schema) { }); } - if ( - !options.isUsingTsSolutionConfig && - (options.publishable || options.bundler !== 'none') - ) { - updateJson(tree, `${options.projectRoot}/package.json`, (json) => { - json.name = options.importPath; - return json; - }); - } - if (!options.skipTsConfig && !options.isUsingTsSolutionConfig) { addTsConfigPath(tree, options.importPath, [ joinPathFragments( @@ -156,6 +150,25 @@ export async function libraryGeneratorInternal(tree: Tree, schema: Schema) { sortPackageJsonFields(tree, options.projectRoot); + if (options.publishable) { + const projectConfig = readProjectConfiguration(tree, options.projectName); + if (options.isUsingTsSolutionConfig) { + await addReleaseConfigForTsSolution( + tree, + options.projectName, + projectConfig + ); + } else { + await addReleaseConfigForNonTsSolution( + tree, + options.projectName, + projectConfig + ); + } + updateProjectConfiguration(tree, options.projectName, projectConfig); + tasks.push(await releaseTasks(tree)); + } + if (!options.skipFormat) await formatFiles(tree); // Always run install to link packages.