Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(js): add publish target and generate minimal publish script for … #9806

Merged
merged 3 commits into from
Apr 12, 2022
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
57 changes: 57 additions & 0 deletions packages/js/src/generators/library/library.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -794,5 +794,62 @@ describe('lib', () => {
expect(tree.exists('libs/my-lib/package.json')).toBeTruthy();
});
});

describe('--publishable', () => {
it('should generate the build target', async () => {
await libraryGenerator(tree, {
...defaultOptions,
name: 'myLib',
publishable: true,
importPath: '@proj/my-lib',
compiler: 'tsc',
});

const config = readProjectConfiguration(tree, 'my-lib');
expect(config.targets.build).toEqual({
executor: '@nrwl/js:tsc',
options: {
assets: ['libs/my-lib/*.md'],
main: 'libs/my-lib/src/index.ts',
outputPath: 'dist/libs/my-lib',
tsConfig: 'libs/my-lib/tsconfig.lib.json',
},
outputs: ['{options.outputPath}'],
});
});

it('should generate the publish target', async () => {
await libraryGenerator(tree, {
...defaultOptions,
name: 'myLib',
publishable: true,
importPath: '@proj/my-lib',
compiler: 'tsc',
});

const config = readProjectConfiguration(tree, 'my-lib');
expect(config.targets.publish).toEqual({
executor: '@nrwl/workspace:run-commands',
options: {
command:
'node tools/scripts/publish.mjs my-lib {args.ver} {args.tag}',
cwd: 'dist/libs/my-lib',
},
dependsOn: [{ projects: 'self', target: 'build' }],
});
});

it('should generate publish script', async () => {
await libraryGenerator(tree, {
...defaultOptions,
name: 'myLib',
publishable: true,
importPath: '@proj/my-lib',
compiler: 'tsc',
});

expect(tree.exists('tools/scripts/publish.mjs')).toBeTruthy();
});
});
});
});
19 changes: 17 additions & 2 deletions packages/js/src/generators/library/library.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import {
getRootTsConfigPathInTree,
} from '@nrwl/workspace/src/utilities/typescript';
import { join } from 'path';
import { addMinimalPublishScript } from '../../utils/minimal-publish-script';
import { LibraryGeneratorSchema } from '../../utils/schema';
import { addSwcConfig } from '../../utils/swc/add-swc-config';
import { addSwcDependencies } from '../../utils/swc/add-swc-dependencies';
Expand Down Expand Up @@ -91,12 +92,13 @@ function addProject(
tags: options.parsedTags,
};

if (options.buildable && options.config != 'npm-scripts') {
if (options.buildable && options.config !== 'npm-scripts') {
const outputPath = `dist/${destinationDir}/${options.projectDirectory}`;
projectConfiguration.targets.build = {
executor: `@nrwl/js:${options.compiler}`,
outputs: ['{options.outputPath}'],
options: {
outputPath: `dist/${destinationDir}/${options.projectDirectory}`,
outputPath,
main: `${options.projectRoot}/src/index` + (options.js ? '.js' : '.ts'),
tsConfig: `${options.projectRoot}/tsconfig.lib.json`,
assets: [`${options.projectRoot}/*.md`],
Expand All @@ -106,6 +108,19 @@ function addProject(
if (options.compiler === 'swc' && options.skipTypeCheck) {
projectConfiguration.targets.build.options.skipTypeCheck = true;
}

if (options.publishable) {
const publishScriptPath = addMinimalPublishScript(tree);

projectConfiguration.targets.publish = {
executor: '@nrwl/workspace:run-commands',
options: {
command: `node ${publishScriptPath} ${options.name} {args.ver} {args.tag}`,
cwd: outputPath,
},
dependsOn: [{ projects: 'self', target: 'build' }],
};
}
}

if (options.config === 'workspace') {
Expand Down
49 changes: 49 additions & 0 deletions packages/js/src/utils/minimal-publish-script.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import type { Tree } from '@nrwl/devkit';

const publishScriptContent = `
/**
* This is a minimal script to publish your package to "npm".
* This is meant to be used as-is or customize as you see fit.
*
* This script is executed on "dist/path/to/library" as "cwd" by default.
*
* You might need to authenticate with NPM before running this script.
*/

import { execSync } from 'child_process';
import { readFileSync, writeFileSync } from 'fs';
import * as chalk from 'chalk';

// Executing publish script: node path/to/publish.mjs {name} --version {version} --tag {tag}
// Default "tag" to "next" so we won't publish the "latest" tag by accident.
const [, , name, version, tag = 'next'] = process.argv;

// A simple SemVer validation to validate the version
const validVersion = /^\\d+\\.\\d+\\.\\d(-\\w+\\.\\d+)?/;
if (!version || !validVersion.test(version)) {
console.error(chalk.bold.red(\`No version provided or version did not match Semantic Versioning, expected: #.#.#-tag, got \${version}\`));
nartc marked this conversation as resolved.
Show resolved Hide resolved
process.exit(1);
}

// Updating the version in "package.json" before publishing
try {
const json = JSON.parse(readFileSync(\`package.json\`).toString());
json.version = version;
writeFileSync(\`package.json\`, JSON.stringify(json, null, 2));
} catch (e) {
console.error(chalk.bold.red(\`Error reading package.json file from library build output.\`))
}

// Execute "npm publish" to publish
execSync(\`npm publish --access public\`);
`;

export function addMinimalPublishScript(tree: Tree) {
const publishScriptPath = 'tools/scripts/publish.mjs';

if (!tree.exists(publishScriptPath)) {
tree.write(publishScriptPath, publishScriptContent);
}

return publishScriptPath;
}